<commit_before>#!/usr/bin/env python

# pycdg - CDG/MP3+G Karaoke Player

# Copyright (C) 2005  <NAME> (<EMAIL>)
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


# OVERVIEW
#
# pycdg is a CDG karaoke player which supports MP3+G and OGG+G tracks.
#
# The player uses the pygame library (www.pygame.org), and can therefore
# run on any operating system that runs pygame (currently Linux, Windows
# and OSX).
#
# You can use this file as a standalone player, or together with
# PyKaraoke. PyKaraoke provides a graphical user interface, playlists,
# searchable song database etc.
#
# For those writing a media player or similar project who would like
# CDG support, this module has been designed to be easily incorporated
# into such projects and is released under the LGPL.


# REQUIREMENTS
#
# pycdg requires the following to be installed on your system:
# . Python (www.python.org)
# . Pygame (www.pygame.org)

# . Numeric module (numpy.sourceforge.net) (actually, this is required
#    only if you do not use the compiled C low-level CDG implementation in
#    _pycdgAux.c)


# USAGE INSTRUCTIONS
#
# To start the player, pass the CDG filename/path on the command line:
#       python pycdg.py /songs/theboxer.cdg
#
# You can also incorporate a CDG player in your own projects by
# importing this module. The class cdgPlayer is exported by the
# module. You can import and start it as follows:
#   import pycdg
#   player = pycdg.cdgPlayer("/songs/theboxer.cdg")
#   player.Play()
# If you do this, you must also arrange to call pycdg.manager.Poll()
# from time to time, at least every 100 milliseconds or so, to allow
# the player to do its work.
#
# The class also exports Close(), Pause(), Rewind(), GetPos().
#
# There are two optional parameters to the initialiser, errorNotifyCallback
# and doneCallback:
#
# errorNotifyCallback, if provided, will be used to print out any error
# messages (e.g. song file not found). This allows the module to fit 
# together well with GUI playlist managers by utilising the same GUI's
# error popup window mechanism (or similar). If no callback is provided,
# errors are printed to stdout. errorNotifyCallback should take one 
# parameter, the error string, e.g.:
#   def errorPopup (ErrorString):
#       msgBox (ErrorString)
#
# doneCallback can be used to register a callback so that the player
# calls you back when the song is finished playing. The callback should
# take no parameters, e.g.:
#   def songFinishedCallback():
#       msgBox ("Song is finished")
#
# To register callbacks, pass the functions in to the initialiser:
#   cdgPlayer ("/songs/theboxer.cdg", errorPopup, songFinishedCallback)
# These parameters are optional and default to None.
#
# If the initialiser fails (e.g. the song file is not present), __init__
# raises an exception.


# IMPLEMENTATION DETAILS
#

# pycdg is implemented as a handful of python modules.  All of the CDG
# decoding is handled in the C module _pycdgAux.c, or in the
# equivalent (but slightly slower) pycdgAux.py if the C module is not
# available for some reason.  This Python implementation of
# pycdgAux.py uses the python Numeric module, which provides fast
# handling of the arrays of pixel data for the display.
#
# Audio playback and video display capabilities come from the pygame
# library.
#
# All of the information on the CDG file format was learned
# from the fabulous "CDG Revealed" tutorial at www.jbum.com.
#

# Previous implementations ran the player within a thread; this is no
# longer the case.  Instead, it is the caller's responsibility to call
# pycdg.manager.Poll() every once in a while to ensure that the player
# gets enough CPU time to do its work.  Ideally, this should be at
# least every 100 milliseconds or so to guarantee good video and audio
# response time.
#
# At each call to Poll(), the player checks the current time in the
# song. It reads the CDG file at the correct location for the current
# position of the song, and decodes the CDG commands stored there. If
# the CDG command requires a screen update, a local array of pixels is
# updated to reflect the new graphic information. Rather than update
# directly to the screen for every command, updates are cached and
# output to the screen a certain number of times per second
# (configurable). Performing the scaling and blitting required for
# screen updates might consume a lot of CPU horsepower, so we reduce
# the load further by dividing the screen into 24 segments. Only those
# segments that have changed are scaled and blitted. If the user
# resizes the window or we get a full-screen modification, the entire
# screen is updated, but during normal CD+G operation only a small
# number of segments are likely to be changed at update time.
#
# NOTE: Pygame does not currently support querying the length
# of an MP3 track, therefore the GetLength() method is not
# currently implemented.
#
# Here follows a description of the important data stored by
# the class:
#
# CdgPacketReader.__cdgColourTable[]
# Store the colours for each colour index (0-15).
# These are set using the load colour look up table commands.
#
# CdgPacketReader.__cdgSurfarray[300][216]
# Surfarray object containing pixel colours for the full 300x216 screen.
# The border area is not actually displayed on the screen, however we
# need to store the pixel colours there as they are set when Scroll
# commands are used. This stores the actual pygame colour value, not
# indeces into our colour table.
#
# CdgPacketReader.__cdgPixelColours[300][216]
# Store the colour index for every single pixel. The values stored
# are indeces into our colour table, rather than actual pygame
# colour representations. It's unfortunate that we need to store 
# all this data, when in fact the pixel colour is available from
# cdgSurfarray, but we need it for the Tile Block XOR command.
# The XOR command performs an XOR of the colour index currently
# at the pixel, with the new colour index. We therefore need to
# know the actual colour index at that pixel - we can't do a 
# get_at() on the screen, or look in cdgSurfarray, and map the RGB
# colour back to a colour index because some CDG files have the 
# same colour in two places in the table, making it impossible to
# determine which index is relevant for the XOR.
#
# CdgPacketReader.__cdgPresetColourIndex 
# Preset Colour (index into colour table)
#
# CdgPacketReader.__cdgPresetColourIndex 
# Border Colour (index into colour table)
#
# CdgPacketReader.__updatedTiles
# Bitmask to mark which screen segments have been updated.
# This is used to reduce the amount of effort required in
# scaling the output video. This is an expensive operation
# which must be done for every screen update so we divide
# the screen into 24 segments and only update those segments
# which have actually been updated.

from pykconstants import *
from pykplayer import pykPlayer
from pykenv import env
from pykmanager import manager
import sys, pygame, os, string, math, re

import _pycdgAux as aux

CDG_DISPLAY_WIDTH   = 294
CDG_DISPLAY_HEIGHT  = 204

CDG_FULL_WIDTH      = 300
CDG_FULL_HEIGHT     = 216
<commit_msg>pycdg: Use the C version if available, or fall back to the Python version.<commit_after>#!/usr/bin/env python

# pycdg - CDG/MP3+G Karaoke Player

# Copyright (C) 2005  <NAME> (<EMAIL>)
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


# OVERVIEW
#
# pycdg is a CDG karaoke player which supports MP3+G and OGG+G tracks.
#
# The player uses the pygame library (www.pygame.org), and can therefore
# run on any operating system that runs pygame (currently Linux, Windows
# and OSX).
#
# You can use this file as a standalone player, or together with
# PyKaraoke. PyKaraoke provides a graphical user interface, playlists,
# searchable song database etc.
#
# For those writing a media player or similar project who would like
# CDG support, this module has been designed to be easily incorporated
# into such projects and is released under the LGPL.


# REQUIREMENTS
#
# pycdg requires the following to be installed on your system:
# . Python (www.python.org)
# . Pygame (www.pygame.org)

# . Numeric module (numpy.sourceforge.net) (actually, this is required
#    only if you do not use the compiled C low-level CDG implementation in
#    _pycdgAux.c)


# USAGE INSTRUCTIONS
#
# To start the player, pass the CDG filename/path on the command line:
#       python pycdg.py /songs/theboxer.cdg
#
# You can also incorporate a CDG player in your own projects by
# importing this module. The class cdgPlayer is exported by the
# module. You can import and start it as follows:
#   import pycdg
#   player = pycdg.cdgPlayer("/songs/theboxer.cdg")
#   player.Play()
# If you do this, you must also arrange to call pycdg.manager.Poll()
# from time to time, at least every 100 milliseconds or so, to allow
# the player to do its work.
#
# The class also exports Close(), Pause(), Rewind(), GetPos().
#
# There are two optional parameters to the initialiser, errorNotifyCallback
# and doneCallback:
#
# errorNotifyCallback, if provided, will be used to print out any error
# messages (e.g. song file not found). This allows the module to fit 
# together well with GUI playlist managers by utilising the same GUI's
# error popup window mechanism (or similar). If no callback is provided,
# errors are printed to stdout. errorNotifyCallback should take one 
# parameter, the error string, e.g.:
#   def errorPopup (ErrorString):
#       msgBox (ErrorString)
#
# doneCallback can be used to register a callback so that the player
# calls you back when the song is finished playing. The callback should
# take no parameters, e.g.:
#   def songFinishedCallback():
#       msgBox ("Song is finished")
#
# To register callbacks, pass the functions in to the initialiser:
#   cdgPlayer ("/songs/theboxer.cdg", errorPopup, songFinishedCallback)
# These parameters are optional and default to None.
#
# If the initialiser fails (e.g. the song file is not present), __init__
# raises an exception.


# IMPLEMENTATION DETAILS
#

# pycdg is implemented as a handful of python modules.  All of the CDG
# decoding is handled in the C module _pycdgAux.c, or in the
# equivalent (but slightly slower) pycdgAux.py if the C module is not
# available for some reason.  This Python implementation of
# pycdgAux.py uses the python Numeric module, which provides fast
# handling of the arrays of pixel data for the display.
#
# Audio playback and video display capabilities come from the pygame
# library.
#
# All of the information on the CDG file format was learned
# from the fabulous "CDG Revealed" tutorial at www.jbum.com.
#

# Previous implementations ran the player within a thread; this is no
# longer the case.  Instead, it is the caller's responsibility to call
# pycdg.manager.Poll() every once in a while to ensure that the player
# gets enough CPU time to do its work.  Ideally, this should be at
# least every 100 milliseconds or so to guarantee good video and audio
# response time.
#
# At each call to Poll(), the player checks the current time in the
# song. It reads the CDG file at the correct location for the current
# position of the song, and decodes the CDG commands stored there. If
# the CDG command requires a screen update, a local array of pixels is
# updated to reflect the new graphic information. Rather than update
# directly to the screen for every command, updates are cached and
# output to the screen a certain number of times per second
# (configurable). Performing the scaling and blitting required for
# screen updates might consume a lot of CPU horsepower, so we reduce
# the load further by dividing the screen into 24 segments. Only those
# segments that have changed are scaled and blitted. If the user
# resizes the window or we get a full-screen modification, the entire
# screen is updated, but during normal CD+G operation only a small
# number of segments are likely to be changed at update time.
#
# NOTE: Pygame does not currently support querying the length
# of an MP3 track, therefore the GetLength() method is not
# currently implemented.
#
# Here follows a description of the important data stored by
# the class:
#
# CdgPacketReader.__cdgColourTable[]
# Store the colours for each colour index (0-15).
# These are set using the load colour look up table commands.
#
# CdgPacketReader.__cdgSurfarray[300][216]
# Surfarray object containing pixel colours for the full 300x216 screen.
# The border area is not actually displayed on the screen, however we
# need to store the pixel colours there as they are set when Scroll
# commands are used. This stores the actual pygame colour value, not
# indeces into our colour table.
#
# CdgPacketReader.__cdgPixelColours[300][216]
# Store the colour index for every single pixel. The values stored
# are indeces into our colour table, rather than actual pygame
# colour representations. It's unfortunate that we need to store 
# all this data, when in fact the pixel colour is available from
# cdgSurfarray, but we need it for the Tile Block XOR command.
# The XOR command performs an XOR of the colour index currently
# at the pixel, with the new colour index. We therefore need to
# know the actual colour index at that pixel - we can't do a 
# get_at() on the screen, or look in cdgSurfarray, and map the RGB
# colour back to a colour index because some CDG files have the 
# same colour in two places in the table, making it impossible to
# determine which index is relevant for the XOR.
#
# CdgPacketReader.__cdgPresetColourIndex 
# Preset Colour (index into colour table)
#
# CdgPacketReader.__cdgPresetColourIndex 
# Border Colour (index into colour table)
#
# CdgPacketReader.__updatedTiles
# Bitmask to mark which screen segments have been updated.
# This is used to reduce the amount of effort required in
# scaling the output video. This is an expensive operation
# which must be done for every screen update so we divide
# the screen into 24 segments and only update those segments
# which have actually been updated.

from pykconstants import *
from pykplayer import pykPlayer
from pykenv import env
from pykmanager import manager
import sys, pygame, os, string, math, re

# Import the optimised C version if available, or fall back to Python
try:
    import _pycdgAux as aux
except:
    import pycdgAux as aux

CDG_DISPLAY_WIDTH   = 294
CDG_DISPLAY_HEIGHT  = 204

CDG_FULL_WIDTH      = 300
CDG_FULL_HEIGHT     = 216

{'fraction_non_alphanumeric': 0.05780823656323371, 'fraction_numerical': 0.008376166000380734, 'mean_word_length': 4.153695225637672, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 8, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7067584', 'n_tokens_mistral': 4449, 'n_tokens_neox': 4264, 'n_words': 2325}