From: Jan Nieuwenhuizen Date: Fri, 19 Oct 2001 13:32:51 +0000 (+0200) Subject: patch::: 1.5.18.jcn1 X-Git-Tag: release/1.5.19~2 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=d199e9078b3e945b8b77715951f8cdc69165a05f;p=lilypond.git patch::: 1.5.18.jcn1 1.5.18.jcn1 =========== * Moved python modules to ./python. * Better python module stepmake support. * Bugfix ly2dvi etc: LILYPONDPREFIX should override datadir. 1.5.18 ====== --- diff --git a/CHANGES b/CHANGES index 032bb58916..adf38b49a5 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,15 @@ +1.5.18.jcn1 +=========== + +* Moved python modules to ./python. + +* Better python module stepmake support. + +* Bugfix ly2dvi etc: LILYPONDPREFIX should override datadir. + +1.5.18 +====== + 1.5.17.jcn6 - aka: `pgwit! Ah, dacht dat-i zo wel aardig was.' =========== diff --git a/GNUmakefile.in b/GNUmakefile.in index ef6ea571a0..2f578fcd5e 100644 --- a/GNUmakefile.in +++ b/GNUmakefile.in @@ -8,9 +8,10 @@ depth = . # descent order into subdirectories # -SUBDIRS = buildscripts scripts flower lily \ +SUBDIRS = buildscripts python scripts \ + flower lily \ mf ly tex ps scm \ - modules midi2ly po make intl \ + midi2ly po make intl \ debian $(builddir)/stepmake \ Documentation input \ mutopia ports diff --git a/VERSION b/VERSION index af64987802..e1235b82e6 100644 --- a/VERSION +++ b/VERSION @@ -2,7 +2,7 @@ PACKAGE_NAME=LilyPond MAJOR_VERSION=1 MINOR_VERSION=5 PATCH_LEVEL=18 -MY_PATCH_LEVEL= +MY_PATCH_LEVEL=jcn1 # use the above to send patches: MY_PATCH_LEVEL is always empty for a # released version. diff --git a/buildscripts/GNUmakefile b/buildscripts/GNUmakefile index c8f569c25b..08b617bd20 100755 --- a/buildscripts/GNUmakefile +++ b/buildscripts/GNUmakefile @@ -1,11 +1,7 @@ depth = .. -#STEPMAKE_TEMPLATES=script install install-out po STEPMAKE_TEMPLATES=script install po -INSTALLATION_FILES=$(outdir)/gettext.py $(outdir)/lilylib.py -INSTALLATION_DIR=$(datadir)/python - include $(depth)/make/stepmake.make # Should we install these? This should be handled by sysadmin or diff --git a/buildscripts/gettext.py.in b/buildscripts/gettext.py.in index e34cc77a2e..e69de29bb2 100644 --- a/buildscripts/gettext.py.in +++ b/buildscripts/gettext.py.in @@ -1,329 +0,0 @@ -"""This module allows python programs to use GNU gettext message catalogs. - -Author: James Henstridge -(This is loosely based on gettext.pl in the GNU gettext distribution) - -The best way to use it is like so: - import gettext - gettext.bindtextdomain(PACKAGE, LOCALEDIR) - gettext.textdomain(PACKAGE) - _ = gettext.gettext - print _('Hello World') - -where PACKAGE is the domain for this package, and LOCALEDIR is usually -'$prefix/share/locale' where $prefix is the install prefix. - -If you have more than one catalog to use, you can directly create catalog -objects. These objects are created as so: - import gettext - cat = gettext.Catalog(PACKAGE, localedir=LOCALEDIR) - _ = cat.gettext - print _('Hello World') - -The catalog object can also be accessed as a dictionary (ie cat['hello']). - -There are also some experimental features. You can add to the catalog, just -as you would with a normal dictionary. When you are finished, you can call -its save method, which will create a new .mo file containing all the -translations: - import gettext - cat = Catalog() - cat['Hello'] = 'konichiwa' - cat.save('./tmp.mo') - -Once you have written an internationalized program, you can create a .po file -for it with "xgettext --keyword=_ fillename ...". Then do the translation and -compile it into a .mo file, ready for use with this module. Note that you -will have to use C style strings (ie. use double quotes) for proper string -extraction. -""" -import os, string - -prefix = '/usr/local' -localedir = prefix + '/share/locale' - -def _expandLang(str): - langs = [str] - # remove charset ... - if '.' in str: - langs.append(string.split(str, '.')[0]) - # also add 2 character language code ... - if len(str) > 2: - langs.append(str[:2]) - return langs - -lang = [] -for env in 'LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG': - if os.environ.has_key(env): - lang = string.split(os.environ[env], ':') - lang = map(_expandLang, lang) - lang = reduce(lambda a, b: a + b, lang) - break -if 'C' not in lang: - lang.append('C') - -# remove duplicates -i = 0 -while i < len(lang): - j = i + 1 - while j < len(lang): - if lang[i] == lang[j]: - del lang[j] - else: - j = j + 1 - i = i + 1 -del i, j - -if os.environ.has_key('PY_XGETTEXT'): - xgettext = os.environ['PY_XGETTEXT'] -else: - xgettext = None - -del os, string - -error = 'gettext.error' - -def _lsbStrToInt(str): - return ord(str[0]) + \ - (ord(str[1]) << 8) + \ - (ord(str[2]) << 16) + \ - (ord(str[3]) << 24) -def _msbStrToInt(str): - return (ord(str[0]) << 24) + \ - (ord(str[1]) << 16) + \ - (ord(str[2]) << 8) + \ - ord(str[3]) -def _intToLsbStr(int): - return chr(int & 0xff) + \ - chr((int >> 8) & 0xff) + \ - chr((int >> 16) & 0xff) + \ - chr((int >> 24) & 0xff) - -def _getpos(levels = 0): - """Returns the position in the code where the function was called. - The function uses some knowledge about python stack frames.""" - import sys - # get access to the stack frame by generating an exception. - try: - raise RuntimeError - except RuntimeError: - frame = sys.exc_traceback.tb_frame - frame = frame.f_back # caller's frame - while levels > 0: - frame = frame.f_back - levels = levels - 1 - return (frame.f_globals['__name__'], - frame.f_code.co_name, - frame.f_lineno) - -class Catalog: - def __init__(self, domain=None, localedir=localedir): - self.domain = domain - self.localedir = localedir - self.cat = {} - if not domain: return - for self.lang in lang: - if self.lang == 'C': - return - catalog = "%s//%s/LC_MESSAGES/%s.mo" % ( - localedir, self.lang, domain) - try: - f = open(catalog, "rb") - buffer = f.read() - del f - break - except IOError: - pass - else: - return # assume C locale - - strToInt = _lsbStrToInt - if strToInt(buffer[:4]) != 0x950412de: - # catalog is encoded with MSB offsets. - strToInt = _msbStrToInt - if strToInt(buffer[:4]) != 0x950412de: - # magic number doesn't match - raise error, 'Bad magic number in %s' % (catalog,) - - self.revision = strToInt(buffer[4:8]) - nstrings = strToInt(buffer[8:12]) - origTabOffset = strToInt(buffer[12:16]) - transTabOffset = strToInt(buffer[16:20]) - for i in range(nstrings): - origLength = strToInt(buffer[origTabOffset: - origTabOffset+4]) - origOffset = strToInt(buffer[origTabOffset+4: - origTabOffset+8]) - origTabOffset = origTabOffset + 8 - origStr = buffer[origOffset:origOffset+origLength] - - transLength = strToInt(buffer[transTabOffset: - transTabOffset+4]) - transOffset = strToInt(buffer[transTabOffset+4: - transTabOffset+8]) - transTabOffset = transTabOffset + 8 - transStr = buffer[transOffset:transOffset+transLength] - - self.cat[origStr] = transStr - - def gettext(self, string): - """Get the translation of a given string""" - if self.cat.has_key(string): - return self.cat[string] - else: - return string - # allow catalog access as cat(str) and cat[str] and cat.gettext(str) - __getitem__ = gettext - __call__ = gettext - - # this is experimental code for producing mo files from Catalog objects - def __setitem__(self, string, trans): - """Set the translation of a given string""" - self.cat[string] = trans - def save(self, file): - """Create a .mo file from a Catalog object""" - try: - f = open(file, "wb") - except IOError: - raise error, "can't open " + file + " for writing" - f.write(_intToLsbStr(0x950412de)) # magic number - f.write(_intToLsbStr(0)) # revision - f.write(_intToLsbStr(len(self.cat))) # nstrings - - oIndex = []; oData = '' - tIndex = []; tData = '' - for orig, trans in self.cat.items(): - oIndex.append((len(orig), len(oData))) - oData = oData + orig + '\0' - tIndex.append((len(trans), len(tData))) - tData = tData + trans + '\0' - oIndexOfs = 20 - tIndexOfs = oIndexOfs + 8 * len(oIndex) - oDataOfs = tIndexOfs + 8 * len(tIndex) - tDataOfs = oDataOfs + len(oData) - f.write(_intToLsbStr(oIndexOfs)) - f.write(_intToLsbStr(tIndexOfs)) - for length, offset in oIndex: - f.write(_intToLsbStr(length)) - f.write(_intToLsbStr(offset + oDataOfs)) - for length, offset in tIndex: - f.write(_intToLsbStr(length)) - f.write(_intToLsbStr(offset + tDataOfs)) - f.write(oData) - f.write(tData) - -_cat = None -_cats = {} - -if xgettext: - class Catalog: - def __init__(self, domain, localedir): - self.domain = domain - self.localedir = localedir - self._strings = {} - def gettext(self, string): - # there is always one level of redirection for calls - # to this function - pos = _getpos(2) # get this function's caller - if self._strings.has_key(string): - if pos not in self._strings[string]: - self._strings[string].append(pos) - else: - self._strings[string] = [pos] - return string - __getitem__ = gettext - __call__ = gettext - def __setitem__(self, item, data): - pass - def save(self, file): - pass - def output(self, fp): - import string - fp.write('# POT file for domain %s\n' % (self.domain,)) - for str in self._strings.keys(): - pos = map(lambda x: "%s(%s):%d" % x, - self._strings[str]) - pos.sort() - length = 80 - for p in pos: - if length + len(p) > 74: - fp.write('\n#:') - length = 2 - fp.write(' ') - fp.write(p) - length = length + 1 + len(p) - fp.write('\n') - if '\n' in str: - fp.write('msgid ""\n') - lines = string.split(str, '\n') - lines = map(lambda x: - '"%s\\n"\n' % (x,), - lines[:-1]) + \ - ['"%s"\n' % (lines[-1],)] - fp.writelines(lines) - else: - fp.write('msgid "%s"\n' % (str,)) - fp.write('msgstr ""\n') - - import sys - if hasattr(sys, 'exitfunc'): - _exitchain = sys.exitfunc - else: - _exitchain = None - def exitfunc(dir=xgettext, _exitchain=_exitchain): - # actually output all the .pot files. - import os - for file in _cats.keys(): - fp = open(os.path.join(dir, file + '.pot'), 'w') - cat = _cats[file] - cat.output(fp) - fp.close() - if _exitchain: _exitchain() - sys.exitfunc = exitfunc - del sys, exitfunc, _exitchain, xgettext - -def bindtextdomain(domain, localedir=localedir): - global _cat - if not _cats.has_key(domain): - _cats[domain] = Catalog(domain, localedir) - if not _cat: _cat = _cats[domain] - -def textdomain(domain): - global _cat - if not _cats.has_key(domain): - _cats[domain] = Catalog(domain) - _cat = _cats[domain] - -def gettext(string): - if _cat == None: raise error, "No catalog loaded" - return _cat.gettext(string) - -_ = gettext - -def dgettext(domain, string): - if domain is None: - return gettext(string) - if not _cats.has_key(domain): - raise error, "Domain '" + domain + "' not loaded" - return _cats[domain].gettext(string) - -def test(): - import sys - global localedir - if len(sys.argv) not in (2, 3): - print "Usage: %s DOMAIN [LOCALEDIR]" % (sys.argv[0],) - sys.exit(1) - domain = sys.argv[1] - if len(sys.argv) == 3: - bindtextdomain(domain, sys.argv[2]) - textdomain(domain) - info = gettext('') # this is where special info is often stored - if info: - print "Info for domain %s, lang %s." % (domain, _cat.lang) - print info - else: - print "No info given in mo file." - -if __name__ == '__main__': - test() - diff --git a/buildscripts/lilylib.py.in b/buildscripts/lilylib.py.in index 10ee45aa9c..e69de29bb2 100644 --- a/buildscripts/lilylib.py.in +++ b/buildscripts/lilylib.py.in @@ -1,187 +0,0 @@ -# lilylib.py -- options and stuff -# -# source file of the GNU LilyPond music typesetter - -import os -from __main__ import * - -try: - import gettext - gettext.bindtextdomain ('lilypond', '@localedir@') - gettext.textdomain ('lilypond') - _ = gettext.gettext -except: - def _ (s): - return s - -program_version = '@TOPLEVEL_VERSION@' -if program_version == '@' + 'TOPLEVEL_VERSION' + '@': - program_version = '1.5.17' - - -original_dir = os.getcwd () -temp_dir = os.path.join (original_dir, '%s.dir' % program_name) - -errorport = sys.stderr -keep_temp_dir_p = 0 -verbose_p = 0 - - -def identify (): - sys.stdout.write ('%s (GNU LilyPond) %s\n' % (program_name, program_version)) - -def warranty (): - identify () - sys.stdout.write ('\n') - sys.stdout.write (_ ('Copyright (c) %s by' % ' 2001')) - sys.stdout.write ('\n') - sys.stdout.write (' Han-Wen Nienhuys') - sys.stdout.write (' Jan Nieuwenhuizen') - sys.stdout.write ('\n') - sys.stdout.write (_ (r''' -Distributed under terms of the GNU General Public License. It comes with -NO WARRANTY.''')) - sys.stdout.write ('\n') - -def progress (s): - errorport.write (s + '\n') - -def warning (s): - progress (_ ("warning: ") + s) - -def error (s): - - - '''Report the error S. Exit by raising an exception. Please - do not abuse by trying to catch this error. If you do not want - a stack trace, write to the output directly. - - RETURN VALUE - - None - - ''' - - progress (_ ("error: ") + s) - raise _ ("Exiting ... ") - -def getopt_args (opts): - '''Construct arguments (LONG, SHORT) for getopt from list of options.''' - short = '' - long = [] - for o in opts: - if o[1]: - short = short + o[1] - if o[0]: - short = short + ':' - if o[2]: - l = o[2] - if o[0]: - l = l + '=' - long.append (l) - return (short, long) - -def option_help_str (o): - '''Transform one option description (4-tuple ) into neatly formatted string''' - sh = ' ' - if o[1]: - sh = '-%s' % o[1] - - sep = ' ' - if o[1] and o[2]: - sep = ',' - - long = '' - if o[2]: - long= '--%s' % o[2] - - arg = '' - if o[0]: - if o[2]: - arg = '=' - arg = arg + o[0] - return ' ' + sh + sep + long + arg - - -def options_help_str (opts): - '''Convert a list of options into a neatly formatted string''' - w = 0 - strs =[] - helps = [] - - for o in opts: - s = option_help_str (o) - strs.append ((s, o[3])) - if len (s) > w: - w = len (s) - - str = '' - for s in strs: - str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0]) + 3), s[1]) - return str - -def help (): - ls = [(_ ("Usage: %s [OPTION]... FILE") % program_name), - ('\n\n'), - (help_summary), - ('\n\n'), - (_ ("Options:")), - ('\n'), - (options_help_str (option_definitions)), - ('\n\n'), - (_ ("Report bugs to %s") % 'bug-lilypond@gnu.org'), - ('\n')] - map (sys.stdout.write, ls) - -def setup_temp (): - """ - Create a temporary directory, and return its name. - """ - global temp_dir - if not keep_temp_dir_p: - temp_dir = tempfile.mktemp (program_name) - try: - os.mkdir (temp_dir, 0777) - except OSError: - pass - - return temp_dir - - -def system (cmd, ignore_error = 0): - """Run CMD. If IGNORE_ERROR is set, don't complain when CMD returns non zero. - - RETURN VALUE - - Exit status of CMD - """ - - if verbose_p: - progress (_ ("Invoking `%s\'") % cmd) - st = os.system (cmd) - if st: - name = re.match ('[ \t]*([^ \t]*)', cmd).group (1) - msg = name + ': ' + _ ("command exited with value %d") % st - if ignore_error: - warning (msg + ' ' + _ ("(ignored)") + ' ') - else: - error (msg) - - return st - - -def cleanup_temp (): - if not keep_temp_dir_p: - if verbose_p: - progress (_ ("Cleaning %s...") % temp_dir) - shutil.rmtree (temp_dir) - - -def strip_extension (f, ext): - (p, e) = os.path.splitext (f) - if e == ext: - e = '' - return p + e - -# END Library - diff --git a/make/lilypond-vars.make b/make/lilypond-vars.make index 3395536e9f..be760f25ae 100644 --- a/make/lilypond-vars.make +++ b/make/lilypond-vars.make @@ -16,7 +16,7 @@ export DVIPSMAKEPK := mktexpk --destdir $(topdir)/mf/out endif export LILYPONDPREFIX:=$(depth)/ -export PYTHONPATH:=$(buildscript-dir)/$(outdir):$(PYTHONPATH) +export PYTHONPATH:=$(topdir)/python:$(PYTHONPATH) # guile load path? diff --git a/midi2ly/GNUmakefile b/midi2ly/GNUmakefile index 3ef74f698a..9982b30164 100644 --- a/midi2ly/GNUmakefile +++ b/midi2ly/GNUmakefile @@ -8,7 +8,7 @@ MODULE_NAME = midi2ly-old SUBDIRS = include MODULE_LIBS=$(depth)/flower -HELP2MAN_EXECS = midi2ly +HELP2MAN_EXECS = midi2ly-old STEPMAKE_TEMPLATES=c++ executable po help2man include $(depth)/make/stepmake.make diff --git a/modules/GNUmakefile b/modules/GNUmakefile index 61cfea23e5..e69de29bb2 100644 --- a/modules/GNUmakefile +++ b/modules/GNUmakefile @@ -1,16 +0,0 @@ -depth = .. - -# Hmm, name dir midi too, then? -NAME=midi - - -# compile fucks up on without autoconf -I flag. -STEPMAKE_TEMPLATES=c install python-module - -INSTALLATION_FILES=$(outdir)/midi.so -INSTALLATION_DIR=$(datadir)/python - -# do nothing; module ins't used yet. - -include $(depth)/make/stepmake.make - diff --git a/modules/midi.c b/modules/midi.c index a5fab33c30..e69de29bb2 100644 --- a/modules/midi.c +++ b/modules/midi.c @@ -1,427 +0,0 @@ -/* - midi.c -- implement Python midi parser module - - source file of the GNU LilyPond music typesetter - - (c) 2001 Han-Wen Nienhuys - Jan Nieuwenhuizen - -*/ - -/* - -python2 -import midi -s = open ("s.midi").read () -midi.parse_track (s) -midi.parse (s) - -*/ - -#include "config.h" - -/* urg */ -#if HAVE_PYTHON2_PYTHON_H -#include -#elif HAVE_PYTHON2_1_PYTHON_H -#include -#elif HAVE_PYTHON2_0_PYTHON_H -#include -#elif HAVE_PYTHON1_5_PYTHON_H -#include -#elif HAVE_PYTHON_PYTHON_H -#define assert(x) -#include -#elif HAVE_PYTHON_H -#define assert(x) -#include -#else -#error Need Python.h -#endif - -#if 0 -int x = 0; -int *track = &x; -#define debug_print(f, args...) fprintf (stderr, "%s:%d: track: %p :" f, __FUNCTION__, __LINE__, *track, ##args) -#else -#define debug_print(f, args...) -#endif - -static PyObject *Midi_error; -static PyObject *Midi_warning; - -static PyObject * -midi_error (char *s) -{ - PyErr_SetString (Midi_error, s); - return 0; -} - -static PyObject * -midi_warning (char *s) -{ - PyErr_SetString (Midi_warning, s); - return 0; -} - - -typedef struct message { - unsigned char msg; - char * description; -} message_t; - -message_t channelVoiceMessages[] = { - 0x80, "NOTE_OFF", - 0x90, "NOTE_ON", - 0xA0, "POLYPHONIC_KEY_PRESSURE", - 0xB0, "CONTROLLER_CHANGE", - 0xC0, "PROGRAM_CHANGE", - 0xD0, "CHANNEL_KEY_PRESSURE", - 0xE0, "PITCH_BEND", - 0,0 -}; - -message_t channelModeMessages[] = { - 0x78, "ALL_SOUND_OFF", - 0x79, "RESET_ALL_CONTROLLERS", - 0x7A, "LOCAL_CONTROL", - 0x7B, "ALL_NOTES_OFF", - 0x7C, "OMNI_MODE_OFF", - 0x7D, "OMNI_MODE_ON", - 0x7E, "MONO_MODE_ON", - 0x7F, "POLY_MODE_ON", - 0,0 -}; - -message_t metaEvents[] = { - 0x00, "SEQUENCE_NUMBER", - 0x01, "TEXT_EVENT", - 0x02, "COPYRIGHT_NOTICE", - 0x03, "SEQUENCE_TRACK_NAME", - 0x04, "INSTRUMENT_NAME", - 0x05, "LYRIC", - 0x06, "MARKER", - 0x07, "CUE_POINT", - 0x20, "MIDI_CHANNEL_PREFIX", - 0x21, "MIDI_PORT", - 0x2F, "END_OF_TRACK", - 0x51, "SET_TEMPO", - 0x54, "SMTPE_OFFSET", - 0x58, "TIME_SIGNATURE", - 0x59, "KEY_SIGNATURE", - 0x7F, "SEQUENCER_SPECIFIC_META_EVENT", - 0xFF, "META_EVENT", - 0,0 -}; - -void -add_constants (PyObject *dict) -{ - message_t * p[] = {metaEvents, channelModeMessages, channelVoiceMessages ,0}; - int i,j; - for ( j =0; p[j]; j++) - for ( i = 0; p[j][i].description; i++) - PyDict_SetItemString (dict, p[j][i].description, Py_BuildValue ("i", p[j][i].msg)); -} - -unsigned long int -get_number (unsigned char ** str, unsigned char * end_str, int length) -{ - /* # MIDI uses big-endian for everything */ - long sum = 0; - int i = 0; - - for (; i < length; i++) - sum = (sum << 8) + (unsigned char) (*str)[i]; - - *str += length; - debug_print ("%d:\n", sum); - return sum; -} - -unsigned long int -get_variable_length_number (unsigned char **str, unsigned char * end_str) -{ - long sum = 0; - int i = 0; - while (*str < end_str) - { - unsigned char x = **str; - (*str) ++; - sum = (sum << 7) + (x & 0x7F); - if (!(x & 0x80)) - break; - } - debug_print ("%d:\n", sum); - return sum; -} - -PyObject * -read_one_byte (unsigned char **track, unsigned char *end, - unsigned char x) -{ - PyObject *pyev = Py_BuildValue ("(i)", x); - debug_print ("%x:%s", x, "event\n"); - - return pyev; -} - -PyObject * -read_two_bytes (unsigned char **track, unsigned char *end, - unsigned char x) -{ - PyObject *pyev = Py_BuildValue ("(ii)", x, (*track)[0]); - *track += 1; - debug_print ("%x:%s", x, "event\n"); - return pyev; -} - -PyObject * -read_three_bytes (unsigned char **track, unsigned char *end, - unsigned char x) -{ - PyObject *pyev = Py_BuildValue ("(iii)", x, (*track)[0], - (*track)[1]); - - *track += 2; - debug_print ("%x:%s", x, "event\n"); - return pyev; -} - -PyObject * -read_string (unsigned char **track, unsigned char *end) -{ - unsigned long length = get_variable_length_number (track, end); - if (length > end - *track) - length = end - *track; - - *track += length; - return Py_BuildValue ("s#", ((*track) -length), length); -} - -typedef PyObject* (*Read_midi_event) - (unsigned char **track, unsigned char *end, - unsigned char x); - - -static PyObject * -read_f0_byte (unsigned char **track, unsigned char *end, - unsigned char x) - -{ - debug_print ("%x:%s", x, "event\n"); - if (x == 0xff) - { - unsigned char z = (*track)[0 ]; - *track += 1; - debug_print ("%x:%s", z, "f0-event\n"); - - return Py_BuildValue ("(iiO)", x, z, read_string (track, end)); - } - - return Py_BuildValue ("(iO)", x, read_string (track, end)); -} - -Read_midi_event read_midi_event [16] = -{ - read_one_byte, // 0 - read_one_byte, // 10 - read_one_byte, // 20 - read_one_byte, // 30 - read_one_byte, // 40 - read_one_byte, // 50 - read_one_byte, // 60 data entry. - read_two_bytes, // 70 all notes off - read_three_bytes, // 80 note off - read_three_bytes, // 90 note on - read_three_bytes, // a0 poly aftertouch - read_three_bytes, // b0 control - read_two_bytes, // c0 prog change - read_two_bytes, // d0 ch aftertouch - read_three_bytes, // e0 pitchwheel range - read_f0_byte, // f0 -}; - - -static PyObject * -read_event (unsigned char **track, unsigned char *end, PyObject *time, - unsigned char *running_status) -{ - int rsb_skip = ((**track & 0x80)) ? 1 :0; - - unsigned char x = (rsb_skip) ? (*track)[0]: *running_status; - - PyObject * bare_event = 0; - debug_print ("%x:%s", x, "event\n"); - *running_status = x; - *track += rsb_skip; - - // printf ("%x %x %d next %x\n", x, (*track)[0], rsb_skip, (*track)[1]); - bare_event = (*read_midi_event[x >> 4]) (track, end, x); - if (bare_event) - return Py_BuildValue ("(OO)", time, bare_event); - else - return NULL; -} - -static PyObject * -midi_parse_track (unsigned char **track, unsigned char *track_end) -{ - unsigned int time = 0; - unsigned char running_status; - unsigned long track_len, track_size; - PyObject *pytrack = 0; - - debug_print ("%s", "\n"); - - track_size = track_end - *track; - - debug_print ("%s", "\n"); - if (strcmp (*track, "MTrk")) - return midi_error (__FUNCTION__ ": MTrk expected"); - - *track += 4; - - track_len = get_number (track, *track + 4, 4); - - - debug_print ("track_len: %u\n", track_len); - debug_print ("track_size: %u\n", track_size); - debug_print ("track begin: %p\n", track); - debug_print ("track end: %p\n", track + track_len); - - if (track_len > track_size) - return midi_error (__FUNCTION__ ": track size corrupt"); - - pytrack = PyList_New (0); - - track_end = *track + track_len; - - { - PyObject *pytime = PyInt_FromLong (0L); - while (*track < track_end) - { - long dt = get_variable_length_number(track, track_end); - PyObject *pyev = 0; - - time += dt; - if (dt) - pytime = PyInt_FromLong (time); - - pyev = read_event (track, track_end, pytime, - &running_status); - if (pyev) - PyList_Append (pytrack, pyev); - } - } - - *track = track_end; - return pytrack; -} - - -static PyObject * -pymidi_parse_track (PyObject *self, PyObject *args) -{ - unsigned char *track, *track_end; - unsigned long track_size, track_len; - - PyObject * sobj = PyTuple_GetItem (args, 0); - - debug_print ("%s", "\n"); - if (!PyArg_ParseTuple (args, "s#", &track, &track_size)) - return 0; - - if (track_size < 0) - return midi_error (__FUNCTION__ ": negative track size"); - - track_end = track + track_size; - - return midi_parse_track (&track, track_end); -} - -static PyObject * -midi_parse (unsigned char **midi,unsigned char *midi_end) -{ - PyObject *pymidi = 0; - unsigned long header_len; - unsigned format, tracks; - int division; - int i; - - debug_print ("%s", "\n"); - - /* Header */ - header_len = get_number (midi, *midi + 4, 4); - - - if (header_len < 6) - return midi_error (__FUNCTION__ ": header too short"); - - format = get_number (midi, *midi + 2, 2); - tracks = get_number (midi, *midi + 2, 2); - - if (tracks > 32) - return midi_error (__FUNCTION__ ": too many tracks"); - - division = get_number (midi, *midi + 2, 2) * 4; - - - if (division < 0) - /* return midi_error ("can't handle non-metrical time"); */ - ; - *midi += header_len - 6; - - pymidi = PyList_New (0); - - /* Tracks */ - for (i = 0; i < tracks; i++) - PyList_Append (pymidi, midi_parse_track (midi, midi_end)); - - pymidi = Py_BuildValue ("(OO)", Py_BuildValue ("(ii)", format, division), - pymidi); - return pymidi; -} - -static PyObject * -pymidi_parse (PyObject *self, PyObject *args) -{ - unsigned char *midi, *midi_end; - unsigned long midi_size, midi_len; - - PyObject *sobj = PyTuple_GetItem (args, 0); - - debug_print ("%s", "\n"); - if (!PyArg_ParseTuple (args, "s#", &midi, &midi_size)) - return 0; - - if (strcmp (midi, "MThd")) - return midi_error (__FUNCTION__ ": MThd expected"); - - midi += 4; - - midi_end = midi + midi_size; - - return midi_parse (&midi, midi_end); -} - - -static PyMethodDef MidiMethods[] = -{ - {"parse", pymidi_parse, 1}, - {"parse_track", pymidi_parse_track, 1}, - {0, 0} /* Sentinel */ -}; - -initmidi () -{ - PyObject *m, *d; - m = Py_InitModule ("midi", MidiMethods); - d = PyModule_GetDict (m); - - Midi_error = PyString_FromString ("midi.error"); - PyDict_SetItemString (d, "error", Midi_error); - add_constants (d); - Midi_warning = PyString_FromString ("midi.warning"); - PyDict_SetItemString (d, "warning", Midi_warning); -} diff --git a/python/GNUmakefile b/python/GNUmakefile new file mode 100644 index 0000000000..5cab304d0e --- /dev/null +++ b/python/GNUmakefile @@ -0,0 +1,10 @@ +depth = .. + +INSTALLATION_FILES=$(PY_MODULES) $(OUT_PY_MODULES) $(OUT_SO_MODULES) +INSTALLATION_DIR=$(datadir)/python + +STEPMAKE_TEMPLATES=c python-module install po + +include $(depth)/make/stepmake.make + +$(outdir)/midi.lo: $(outdir)/config.h diff --git a/python/gettext.py.in b/python/gettext.py.in new file mode 100644 index 0000000000..e34cc77a2e --- /dev/null +++ b/python/gettext.py.in @@ -0,0 +1,329 @@ +"""This module allows python programs to use GNU gettext message catalogs. + +Author: James Henstridge +(This is loosely based on gettext.pl in the GNU gettext distribution) + +The best way to use it is like so: + import gettext + gettext.bindtextdomain(PACKAGE, LOCALEDIR) + gettext.textdomain(PACKAGE) + _ = gettext.gettext + print _('Hello World') + +where PACKAGE is the domain for this package, and LOCALEDIR is usually +'$prefix/share/locale' where $prefix is the install prefix. + +If you have more than one catalog to use, you can directly create catalog +objects. These objects are created as so: + import gettext + cat = gettext.Catalog(PACKAGE, localedir=LOCALEDIR) + _ = cat.gettext + print _('Hello World') + +The catalog object can also be accessed as a dictionary (ie cat['hello']). + +There are also some experimental features. You can add to the catalog, just +as you would with a normal dictionary. When you are finished, you can call +its save method, which will create a new .mo file containing all the +translations: + import gettext + cat = Catalog() + cat['Hello'] = 'konichiwa' + cat.save('./tmp.mo') + +Once you have written an internationalized program, you can create a .po file +for it with "xgettext --keyword=_ fillename ...". Then do the translation and +compile it into a .mo file, ready for use with this module. Note that you +will have to use C style strings (ie. use double quotes) for proper string +extraction. +""" +import os, string + +prefix = '/usr/local' +localedir = prefix + '/share/locale' + +def _expandLang(str): + langs = [str] + # remove charset ... + if '.' in str: + langs.append(string.split(str, '.')[0]) + # also add 2 character language code ... + if len(str) > 2: + langs.append(str[:2]) + return langs + +lang = [] +for env in 'LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG': + if os.environ.has_key(env): + lang = string.split(os.environ[env], ':') + lang = map(_expandLang, lang) + lang = reduce(lambda a, b: a + b, lang) + break +if 'C' not in lang: + lang.append('C') + +# remove duplicates +i = 0 +while i < len(lang): + j = i + 1 + while j < len(lang): + if lang[i] == lang[j]: + del lang[j] + else: + j = j + 1 + i = i + 1 +del i, j + +if os.environ.has_key('PY_XGETTEXT'): + xgettext = os.environ['PY_XGETTEXT'] +else: + xgettext = None + +del os, string + +error = 'gettext.error' + +def _lsbStrToInt(str): + return ord(str[0]) + \ + (ord(str[1]) << 8) + \ + (ord(str[2]) << 16) + \ + (ord(str[3]) << 24) +def _msbStrToInt(str): + return (ord(str[0]) << 24) + \ + (ord(str[1]) << 16) + \ + (ord(str[2]) << 8) + \ + ord(str[3]) +def _intToLsbStr(int): + return chr(int & 0xff) + \ + chr((int >> 8) & 0xff) + \ + chr((int >> 16) & 0xff) + \ + chr((int >> 24) & 0xff) + +def _getpos(levels = 0): + """Returns the position in the code where the function was called. + The function uses some knowledge about python stack frames.""" + import sys + # get access to the stack frame by generating an exception. + try: + raise RuntimeError + except RuntimeError: + frame = sys.exc_traceback.tb_frame + frame = frame.f_back # caller's frame + while levels > 0: + frame = frame.f_back + levels = levels - 1 + return (frame.f_globals['__name__'], + frame.f_code.co_name, + frame.f_lineno) + +class Catalog: + def __init__(self, domain=None, localedir=localedir): + self.domain = domain + self.localedir = localedir + self.cat = {} + if not domain: return + for self.lang in lang: + if self.lang == 'C': + return + catalog = "%s//%s/LC_MESSAGES/%s.mo" % ( + localedir, self.lang, domain) + try: + f = open(catalog, "rb") + buffer = f.read() + del f + break + except IOError: + pass + else: + return # assume C locale + + strToInt = _lsbStrToInt + if strToInt(buffer[:4]) != 0x950412de: + # catalog is encoded with MSB offsets. + strToInt = _msbStrToInt + if strToInt(buffer[:4]) != 0x950412de: + # magic number doesn't match + raise error, 'Bad magic number in %s' % (catalog,) + + self.revision = strToInt(buffer[4:8]) + nstrings = strToInt(buffer[8:12]) + origTabOffset = strToInt(buffer[12:16]) + transTabOffset = strToInt(buffer[16:20]) + for i in range(nstrings): + origLength = strToInt(buffer[origTabOffset: + origTabOffset+4]) + origOffset = strToInt(buffer[origTabOffset+4: + origTabOffset+8]) + origTabOffset = origTabOffset + 8 + origStr = buffer[origOffset:origOffset+origLength] + + transLength = strToInt(buffer[transTabOffset: + transTabOffset+4]) + transOffset = strToInt(buffer[transTabOffset+4: + transTabOffset+8]) + transTabOffset = transTabOffset + 8 + transStr = buffer[transOffset:transOffset+transLength] + + self.cat[origStr] = transStr + + def gettext(self, string): + """Get the translation of a given string""" + if self.cat.has_key(string): + return self.cat[string] + else: + return string + # allow catalog access as cat(str) and cat[str] and cat.gettext(str) + __getitem__ = gettext + __call__ = gettext + + # this is experimental code for producing mo files from Catalog objects + def __setitem__(self, string, trans): + """Set the translation of a given string""" + self.cat[string] = trans + def save(self, file): + """Create a .mo file from a Catalog object""" + try: + f = open(file, "wb") + except IOError: + raise error, "can't open " + file + " for writing" + f.write(_intToLsbStr(0x950412de)) # magic number + f.write(_intToLsbStr(0)) # revision + f.write(_intToLsbStr(len(self.cat))) # nstrings + + oIndex = []; oData = '' + tIndex = []; tData = '' + for orig, trans in self.cat.items(): + oIndex.append((len(orig), len(oData))) + oData = oData + orig + '\0' + tIndex.append((len(trans), len(tData))) + tData = tData + trans + '\0' + oIndexOfs = 20 + tIndexOfs = oIndexOfs + 8 * len(oIndex) + oDataOfs = tIndexOfs + 8 * len(tIndex) + tDataOfs = oDataOfs + len(oData) + f.write(_intToLsbStr(oIndexOfs)) + f.write(_intToLsbStr(tIndexOfs)) + for length, offset in oIndex: + f.write(_intToLsbStr(length)) + f.write(_intToLsbStr(offset + oDataOfs)) + for length, offset in tIndex: + f.write(_intToLsbStr(length)) + f.write(_intToLsbStr(offset + tDataOfs)) + f.write(oData) + f.write(tData) + +_cat = None +_cats = {} + +if xgettext: + class Catalog: + def __init__(self, domain, localedir): + self.domain = domain + self.localedir = localedir + self._strings = {} + def gettext(self, string): + # there is always one level of redirection for calls + # to this function + pos = _getpos(2) # get this function's caller + if self._strings.has_key(string): + if pos not in self._strings[string]: + self._strings[string].append(pos) + else: + self._strings[string] = [pos] + return string + __getitem__ = gettext + __call__ = gettext + def __setitem__(self, item, data): + pass + def save(self, file): + pass + def output(self, fp): + import string + fp.write('# POT file for domain %s\n' % (self.domain,)) + for str in self._strings.keys(): + pos = map(lambda x: "%s(%s):%d" % x, + self._strings[str]) + pos.sort() + length = 80 + for p in pos: + if length + len(p) > 74: + fp.write('\n#:') + length = 2 + fp.write(' ') + fp.write(p) + length = length + 1 + len(p) + fp.write('\n') + if '\n' in str: + fp.write('msgid ""\n') + lines = string.split(str, '\n') + lines = map(lambda x: + '"%s\\n"\n' % (x,), + lines[:-1]) + \ + ['"%s"\n' % (lines[-1],)] + fp.writelines(lines) + else: + fp.write('msgid "%s"\n' % (str,)) + fp.write('msgstr ""\n') + + import sys + if hasattr(sys, 'exitfunc'): + _exitchain = sys.exitfunc + else: + _exitchain = None + def exitfunc(dir=xgettext, _exitchain=_exitchain): + # actually output all the .pot files. + import os + for file in _cats.keys(): + fp = open(os.path.join(dir, file + '.pot'), 'w') + cat = _cats[file] + cat.output(fp) + fp.close() + if _exitchain: _exitchain() + sys.exitfunc = exitfunc + del sys, exitfunc, _exitchain, xgettext + +def bindtextdomain(domain, localedir=localedir): + global _cat + if not _cats.has_key(domain): + _cats[domain] = Catalog(domain, localedir) + if not _cat: _cat = _cats[domain] + +def textdomain(domain): + global _cat + if not _cats.has_key(domain): + _cats[domain] = Catalog(domain) + _cat = _cats[domain] + +def gettext(string): + if _cat == None: raise error, "No catalog loaded" + return _cat.gettext(string) + +_ = gettext + +def dgettext(domain, string): + if domain is None: + return gettext(string) + if not _cats.has_key(domain): + raise error, "Domain '" + domain + "' not loaded" + return _cats[domain].gettext(string) + +def test(): + import sys + global localedir + if len(sys.argv) not in (2, 3): + print "Usage: %s DOMAIN [LOCALEDIR]" % (sys.argv[0],) + sys.exit(1) + domain = sys.argv[1] + if len(sys.argv) == 3: + bindtextdomain(domain, sys.argv[2]) + textdomain(domain) + info = gettext('') # this is where special info is often stored + if info: + print "Info for domain %s, lang %s." % (domain, _cat.lang) + print info + else: + print "No info given in mo file." + +if __name__ == '__main__': + test() + diff --git a/python/lilylib.py.in b/python/lilylib.py.in new file mode 100644 index 0000000000..1da987020c --- /dev/null +++ b/python/lilylib.py.in @@ -0,0 +1,176 @@ +# lilylib.py -- options and stuff +# +# source file of the GNU LilyPond music typesetter + +import os +from __main__ import * +try: + import gettext + gettext.bindtextdomain ('lilypond', localedir) + gettext.textdomain ('lilypond') + _ = gettext.gettext +except: + def _ (s): + return s + +if program_version == '@' + 'TOPLEVEL_VERSION' + '@': + program_version = '1.5.17' + +def identify (): + sys.stdout.write ('%s (GNU LilyPond) %s\n' % (program_name, program_version)) + +def warranty (): + identify () + sys.stdout.write ('\n') + sys.stdout.write (_ ('Copyright (c) %s by' % ' 2001')) + sys.stdout.write ('\n') + sys.stdout.write (' Han-Wen Nienhuys') + sys.stdout.write (' Jan Nieuwenhuizen') + sys.stdout.write ('\n') + sys.stdout.write (_ (r''' +Distributed under terms of the GNU General Public License. It comes with +NO WARRANTY.''')) + sys.stdout.write ('\n') + +def progress (s): + errorport.write (s + '\n') + +def warning (s): + progress (_ ("warning: ") + s) + +def error (s): + + + '''Report the error S. Exit by raising an exception. Please + do not abuse by trying to catch this error. If you do not want + a stack trace, write to the output directly. + + RETURN VALUE + + None + + ''' + + progress (_ ("error: ") + s) + raise _ ("Exiting ... ") + +def getopt_args (opts): + '''Construct arguments (LONG, SHORT) for getopt from list of options.''' + short = '' + long = [] + for o in opts: + if o[1]: + short = short + o[1] + if o[0]: + short = short + ':' + if o[2]: + l = o[2] + if o[0]: + l = l + '=' + long.append (l) + return (short, long) + +def option_help_str (o): + '''Transform one option description (4-tuple ) into neatly formatted string''' + sh = ' ' + if o[1]: + sh = '-%s' % o[1] + + sep = ' ' + if o[1] and o[2]: + sep = ',' + + long = '' + if o[2]: + long= '--%s' % o[2] + + arg = '' + if o[0]: + if o[2]: + arg = '=' + arg = arg + o[0] + return ' ' + sh + sep + long + arg + + +def options_help_str (opts): + '''Convert a list of options into a neatly formatted string''' + w = 0 + strs =[] + helps = [] + + for o in opts: + s = option_help_str (o) + strs.append ((s, o[3])) + if len (s) > w: + w = len (s) + + str = '' + for s in strs: + str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0]) + 3), s[1]) + return str + +def help (): + ls = [(_ ("Usage: %s [OPTION]... FILE") % program_name), + ('\n\n'), + (help_summary), + ('\n\n'), + (_ ("Options:")), + ('\n'), + (options_help_str (option_definitions)), + ('\n\n'), + (_ ("Report bugs to %s") % 'bug-lilypond@gnu.org'), + ('\n')] + map (sys.stdout.write, ls) + +def setup_temp (): + """ + Create a temporary directory, and return its name. + """ + global temp_dir + if not keep_temp_dir_p: + temp_dir = tempfile.mktemp (program_name) + try: + os.mkdir (temp_dir, 0777) + except OSError: + pass + + return temp_dir + + +def system (cmd, ignore_error = 0): + """Run CMD. If IGNORE_ERROR is set, don't complain when CMD returns non zero. + + RETURN VALUE + + Exit status of CMD + """ + + if verbose_p: + progress (_ ("Invoking `%s\'") % cmd) + st = os.system (cmd) + if st: + name = re.match ('[ \t]*([^ \t]*)', cmd).group (1) + msg = name + ': ' + _ ("command exited with value %d") % st + if ignore_error: + warning (msg + ' ' + _ ("(ignored)") + ' ') + else: + error (msg) + + return st + + +def cleanup_temp (): + if not keep_temp_dir_p: + if verbose_p: + progress (_ ("Cleaning %s...") % temp_dir) + shutil.rmtree (temp_dir) + + +def strip_extension (f, ext): + (p, e) = os.path.splitext (f) + if e == ext: + e = '' + return p + e + +# END Library + diff --git a/python/midi.c b/python/midi.c new file mode 100644 index 0000000000..a5fab33c30 --- /dev/null +++ b/python/midi.c @@ -0,0 +1,427 @@ +/* + midi.c -- implement Python midi parser module + + source file of the GNU LilyPond music typesetter + + (c) 2001 Han-Wen Nienhuys + Jan Nieuwenhuizen + +*/ + +/* + +python2 +import midi +s = open ("s.midi").read () +midi.parse_track (s) +midi.parse (s) + +*/ + +#include "config.h" + +/* urg */ +#if HAVE_PYTHON2_PYTHON_H +#include +#elif HAVE_PYTHON2_1_PYTHON_H +#include +#elif HAVE_PYTHON2_0_PYTHON_H +#include +#elif HAVE_PYTHON1_5_PYTHON_H +#include +#elif HAVE_PYTHON_PYTHON_H +#define assert(x) +#include +#elif HAVE_PYTHON_H +#define assert(x) +#include +#else +#error Need Python.h +#endif + +#if 0 +int x = 0; +int *track = &x; +#define debug_print(f, args...) fprintf (stderr, "%s:%d: track: %p :" f, __FUNCTION__, __LINE__, *track, ##args) +#else +#define debug_print(f, args...) +#endif + +static PyObject *Midi_error; +static PyObject *Midi_warning; + +static PyObject * +midi_error (char *s) +{ + PyErr_SetString (Midi_error, s); + return 0; +} + +static PyObject * +midi_warning (char *s) +{ + PyErr_SetString (Midi_warning, s); + return 0; +} + + +typedef struct message { + unsigned char msg; + char * description; +} message_t; + +message_t channelVoiceMessages[] = { + 0x80, "NOTE_OFF", + 0x90, "NOTE_ON", + 0xA0, "POLYPHONIC_KEY_PRESSURE", + 0xB0, "CONTROLLER_CHANGE", + 0xC0, "PROGRAM_CHANGE", + 0xD0, "CHANNEL_KEY_PRESSURE", + 0xE0, "PITCH_BEND", + 0,0 +}; + +message_t channelModeMessages[] = { + 0x78, "ALL_SOUND_OFF", + 0x79, "RESET_ALL_CONTROLLERS", + 0x7A, "LOCAL_CONTROL", + 0x7B, "ALL_NOTES_OFF", + 0x7C, "OMNI_MODE_OFF", + 0x7D, "OMNI_MODE_ON", + 0x7E, "MONO_MODE_ON", + 0x7F, "POLY_MODE_ON", + 0,0 +}; + +message_t metaEvents[] = { + 0x00, "SEQUENCE_NUMBER", + 0x01, "TEXT_EVENT", + 0x02, "COPYRIGHT_NOTICE", + 0x03, "SEQUENCE_TRACK_NAME", + 0x04, "INSTRUMENT_NAME", + 0x05, "LYRIC", + 0x06, "MARKER", + 0x07, "CUE_POINT", + 0x20, "MIDI_CHANNEL_PREFIX", + 0x21, "MIDI_PORT", + 0x2F, "END_OF_TRACK", + 0x51, "SET_TEMPO", + 0x54, "SMTPE_OFFSET", + 0x58, "TIME_SIGNATURE", + 0x59, "KEY_SIGNATURE", + 0x7F, "SEQUENCER_SPECIFIC_META_EVENT", + 0xFF, "META_EVENT", + 0,0 +}; + +void +add_constants (PyObject *dict) +{ + message_t * p[] = {metaEvents, channelModeMessages, channelVoiceMessages ,0}; + int i,j; + for ( j =0; p[j]; j++) + for ( i = 0; p[j][i].description; i++) + PyDict_SetItemString (dict, p[j][i].description, Py_BuildValue ("i", p[j][i].msg)); +} + +unsigned long int +get_number (unsigned char ** str, unsigned char * end_str, int length) +{ + /* # MIDI uses big-endian for everything */ + long sum = 0; + int i = 0; + + for (; i < length; i++) + sum = (sum << 8) + (unsigned char) (*str)[i]; + + *str += length; + debug_print ("%d:\n", sum); + return sum; +} + +unsigned long int +get_variable_length_number (unsigned char **str, unsigned char * end_str) +{ + long sum = 0; + int i = 0; + while (*str < end_str) + { + unsigned char x = **str; + (*str) ++; + sum = (sum << 7) + (x & 0x7F); + if (!(x & 0x80)) + break; + } + debug_print ("%d:\n", sum); + return sum; +} + +PyObject * +read_one_byte (unsigned char **track, unsigned char *end, + unsigned char x) +{ + PyObject *pyev = Py_BuildValue ("(i)", x); + debug_print ("%x:%s", x, "event\n"); + + return pyev; +} + +PyObject * +read_two_bytes (unsigned char **track, unsigned char *end, + unsigned char x) +{ + PyObject *pyev = Py_BuildValue ("(ii)", x, (*track)[0]); + *track += 1; + debug_print ("%x:%s", x, "event\n"); + return pyev; +} + +PyObject * +read_three_bytes (unsigned char **track, unsigned char *end, + unsigned char x) +{ + PyObject *pyev = Py_BuildValue ("(iii)", x, (*track)[0], + (*track)[1]); + + *track += 2; + debug_print ("%x:%s", x, "event\n"); + return pyev; +} + +PyObject * +read_string (unsigned char **track, unsigned char *end) +{ + unsigned long length = get_variable_length_number (track, end); + if (length > end - *track) + length = end - *track; + + *track += length; + return Py_BuildValue ("s#", ((*track) -length), length); +} + +typedef PyObject* (*Read_midi_event) + (unsigned char **track, unsigned char *end, + unsigned char x); + + +static PyObject * +read_f0_byte (unsigned char **track, unsigned char *end, + unsigned char x) + +{ + debug_print ("%x:%s", x, "event\n"); + if (x == 0xff) + { + unsigned char z = (*track)[0 ]; + *track += 1; + debug_print ("%x:%s", z, "f0-event\n"); + + return Py_BuildValue ("(iiO)", x, z, read_string (track, end)); + } + + return Py_BuildValue ("(iO)", x, read_string (track, end)); +} + +Read_midi_event read_midi_event [16] = +{ + read_one_byte, // 0 + read_one_byte, // 10 + read_one_byte, // 20 + read_one_byte, // 30 + read_one_byte, // 40 + read_one_byte, // 50 + read_one_byte, // 60 data entry. + read_two_bytes, // 70 all notes off + read_three_bytes, // 80 note off + read_three_bytes, // 90 note on + read_three_bytes, // a0 poly aftertouch + read_three_bytes, // b0 control + read_two_bytes, // c0 prog change + read_two_bytes, // d0 ch aftertouch + read_three_bytes, // e0 pitchwheel range + read_f0_byte, // f0 +}; + + +static PyObject * +read_event (unsigned char **track, unsigned char *end, PyObject *time, + unsigned char *running_status) +{ + int rsb_skip = ((**track & 0x80)) ? 1 :0; + + unsigned char x = (rsb_skip) ? (*track)[0]: *running_status; + + PyObject * bare_event = 0; + debug_print ("%x:%s", x, "event\n"); + *running_status = x; + *track += rsb_skip; + + // printf ("%x %x %d next %x\n", x, (*track)[0], rsb_skip, (*track)[1]); + bare_event = (*read_midi_event[x >> 4]) (track, end, x); + if (bare_event) + return Py_BuildValue ("(OO)", time, bare_event); + else + return NULL; +} + +static PyObject * +midi_parse_track (unsigned char **track, unsigned char *track_end) +{ + unsigned int time = 0; + unsigned char running_status; + unsigned long track_len, track_size; + PyObject *pytrack = 0; + + debug_print ("%s", "\n"); + + track_size = track_end - *track; + + debug_print ("%s", "\n"); + if (strcmp (*track, "MTrk")) + return midi_error (__FUNCTION__ ": MTrk expected"); + + *track += 4; + + track_len = get_number (track, *track + 4, 4); + + + debug_print ("track_len: %u\n", track_len); + debug_print ("track_size: %u\n", track_size); + debug_print ("track begin: %p\n", track); + debug_print ("track end: %p\n", track + track_len); + + if (track_len > track_size) + return midi_error (__FUNCTION__ ": track size corrupt"); + + pytrack = PyList_New (0); + + track_end = *track + track_len; + + { + PyObject *pytime = PyInt_FromLong (0L); + while (*track < track_end) + { + long dt = get_variable_length_number(track, track_end); + PyObject *pyev = 0; + + time += dt; + if (dt) + pytime = PyInt_FromLong (time); + + pyev = read_event (track, track_end, pytime, + &running_status); + if (pyev) + PyList_Append (pytrack, pyev); + } + } + + *track = track_end; + return pytrack; +} + + +static PyObject * +pymidi_parse_track (PyObject *self, PyObject *args) +{ + unsigned char *track, *track_end; + unsigned long track_size, track_len; + + PyObject * sobj = PyTuple_GetItem (args, 0); + + debug_print ("%s", "\n"); + if (!PyArg_ParseTuple (args, "s#", &track, &track_size)) + return 0; + + if (track_size < 0) + return midi_error (__FUNCTION__ ": negative track size"); + + track_end = track + track_size; + + return midi_parse_track (&track, track_end); +} + +static PyObject * +midi_parse (unsigned char **midi,unsigned char *midi_end) +{ + PyObject *pymidi = 0; + unsigned long header_len; + unsigned format, tracks; + int division; + int i; + + debug_print ("%s", "\n"); + + /* Header */ + header_len = get_number (midi, *midi + 4, 4); + + + if (header_len < 6) + return midi_error (__FUNCTION__ ": header too short"); + + format = get_number (midi, *midi + 2, 2); + tracks = get_number (midi, *midi + 2, 2); + + if (tracks > 32) + return midi_error (__FUNCTION__ ": too many tracks"); + + division = get_number (midi, *midi + 2, 2) * 4; + + + if (division < 0) + /* return midi_error ("can't handle non-metrical time"); */ + ; + *midi += header_len - 6; + + pymidi = PyList_New (0); + + /* Tracks */ + for (i = 0; i < tracks; i++) + PyList_Append (pymidi, midi_parse_track (midi, midi_end)); + + pymidi = Py_BuildValue ("(OO)", Py_BuildValue ("(ii)", format, division), + pymidi); + return pymidi; +} + +static PyObject * +pymidi_parse (PyObject *self, PyObject *args) +{ + unsigned char *midi, *midi_end; + unsigned long midi_size, midi_len; + + PyObject *sobj = PyTuple_GetItem (args, 0); + + debug_print ("%s", "\n"); + if (!PyArg_ParseTuple (args, "s#", &midi, &midi_size)) + return 0; + + if (strcmp (midi, "MThd")) + return midi_error (__FUNCTION__ ": MThd expected"); + + midi += 4; + + midi_end = midi + midi_size; + + return midi_parse (&midi, midi_end); +} + + +static PyMethodDef MidiMethods[] = +{ + {"parse", pymidi_parse, 1}, + {"parse_track", pymidi_parse_track, 1}, + {0, 0} /* Sentinel */ +}; + +initmidi () +{ + PyObject *m, *d; + m = Py_InitModule ("midi", MidiMethods); + d = PyModule_GetDict (m); + + Midi_error = PyString_FromString ("midi.error"); + PyDict_SetItemString (d, "error", Midi_error); + add_constants (d); + Midi_warning = PyString_FromString ("midi.warning"); + PyDict_SetItemString (d, "warning", Midi_warning); +} diff --git a/scripts/GNUmakefile b/scripts/GNUmakefile index 1df3d26a3b..1039423e47 100644 --- a/scripts/GNUmakefile +++ b/scripts/GNUmakefile @@ -2,6 +2,7 @@ depth = .. SEXECUTABLES=convert-ly lilypond-book ly2dvi abc2ly as2text etf2ly musedata2ly pmx2ly mup2ly midi2ly STEPMAKE_TEMPLATES=script help2man po +LOCALSTEPMAKE_TEMPLATES = lilypond HELP2MAN_EXECS = $(SEXECUTABLES) include $(depth)/make/stepmake.make diff --git a/scripts/ly2dvi.py b/scripts/ly2dvi.py index eaceb590af..d442753fe9 100644 --- a/scripts/ly2dvi.py +++ b/scripts/ly2dvi.py @@ -67,19 +67,25 @@ import operator import tempfile import traceback -datadir = '' - -if '@datadir@' == ('@' + 'datadir' + '@'): +# if set, LILYPONDPREFIX must take prevalence +# if datadir is not set, we're doing a build and LILYPONDPREFIX +datadir = '@datadir@' +if os.environ.has_key ('LILYPONDPREFIX') \ + or '@datadir@' == '@' + 'datadir' + '@': datadir = os.environ['LILYPONDPREFIX'] else: datadir = '@datadir@' -while datadir[-1] == os.sep: - datadir = datadir[:-1] - - sys.path.append (os.path.join (datadir, 'python')) -sys.path.append (os.path.join (datadir, 'buildscripts/out')) +sys.path.append (os.path.join (datadir, 'python/out')) + +program_name = 'ly2dvi' +program_version = '@TOPLEVEL_VERSION@' +original_dir = os.getcwd () +temp_dir = os.path.join (original_dir, '%s.dir' % program_name) +errorport = sys.stderr +keep_temp_dir_p = 0 +verbose_p = 0 try: import gettext @@ -99,8 +105,6 @@ try: except: pass -program_name = 'ly2dvi' -package_name = 'lilypond' help_summary = _ ("Generate .dvi with LaTeX for LilyPond") option_definitions = [ @@ -122,8 +126,6 @@ option_definitions = [ from lilylib import * -# verbose_p = 1 # arg! - layout_fields = ['dedication', 'title', 'subtitle', 'subsubtitle', 'footer', 'head', 'composer', 'arranger', 'instrument', 'opus', 'piece', 'metre', 'meter', 'poet', 'texttranslator'] @@ -498,7 +500,7 @@ def find_pfa_fonts (name): return pfa -(sh, long) = getopt_args (__main__.option_definitions) +(sh, long) = getopt_args (option_definitions) try: (options, files) = getopt.getopt(sys.argv[1:], sh, long) except getopt.error, s: diff --git a/scripts/midi2ly.py b/scripts/midi2ly.py index 3e29526add..6540628632 100644 --- a/scripts/midi2ly.py +++ b/scripts/midi2ly.py @@ -22,37 +22,50 @@ TODO: other converters, while leaving midi specific stuff here ''' +import os +import sys + +# if set, LILYPONDPREFIX must take prevalence +# if datadir is not set, we're doing a build and LILYPONDPREFIX +datadir = '@datadir@' +if os.environ.has_key ('LILYPONDPREFIX') \ + or '@datadir@' == '@' + 'datadir' + '@': + datadir = os.environ['LILYPONDPREFIX'] +else: + datadir = '@datadir@' + +sys.path.append (os.path.join (datadir, 'python')) +sys.path.append (os.path.join (datadir, 'python/out')) + + import getopt import __main__ import sys import string - -sys.path.append ('@datadir@/python') -sys.path.append ('@datadir@/buildscripts/out') -sys.path.append ('@datadir@/modules/out') - import midi + +localedir = '@localedir@' try: import gettext - gettext.bindtextdomain ('lilypond', '@localedir@') + gettext.bindtextdomain ('lilypond', localedir) gettext.textdomain ('lilypond') _ = gettext.gettext except: def _ (s): return s -# Attempt to fix problems with limited stack size set by Python! -# Sets unlimited stack size. Note that the resource module only -# is available on UNIX. -try: - import resource - resource.setrlimit (resource.RLIMIT_STACK, (-1, -1)) -except: - pass +program_name = 'midi2ly' +program_version = '@TOPLEVEL_VERSION@' + +errorport = sys.stderr +verbose_p = 0 + +# temp_dir = os.path.join (original_dir, '%s.dir' % program_name) +# original_dir = os.getcwd () +# keep_temp_dir_p = 0 + -program_name = 'midi2ly [experimental]' -package_name = 'lilypond' help_summary = _ ("Convert MIDI to LilyPond source") option_definitions = [ @@ -70,7 +83,9 @@ option_definitions = [ ('', 'x', 'text-lyrics', _ ("treat every text as a lyric")), ] -from lilylib import * +# from lilylib import * +import lilylib + class Duration: @@ -796,7 +811,7 @@ def convert_midi (f, o): s = s + ' \\context Lyrics=%s \\%s\n' % (track, track) s = s + ' >\n}\n' - progress (_ ("%s output to `%s'...") % ('LY', o)) + lilylib.progress (_ ("%s output to `%s'...") % ('LY', o)) if o == '-': h = sys.stdout @@ -807,7 +822,7 @@ def convert_midi (f, o): h.close () -(sh, long) = getopt_args (__main__.option_definitions) +(sh, long) = lilylib.getopt_args (option_definitions) try: (options, files) = getopt.getopt(sys.argv[1:], sh, long) except getopt.error, s: @@ -815,7 +830,7 @@ except getopt.error, s: errorport.write (_ ("error: ") + _ ("getopt says: `%s\'" % s)) errorport.write ('\n') errorport.write ('\n') - help () + lilylib.help () sys.exit (2) for opt in options: @@ -825,7 +840,7 @@ for opt in options: if 0: pass elif o == '--help' or o == '-h': - help () + lilylib.help () errorport.write ('\n') errorport.write (_ ("Example:")) errorport.write (r''' @@ -838,7 +853,7 @@ for opt in options: elif o == '--verbose' or o == '-V': verbose_p = 1 elif o == '--version' or o == '-v': - identify () + lilylib.identify () sys.exit (0) elif o == '--warranty' or o == '-w': status = system ('lilypond -w', ignore_error = 1) @@ -882,7 +897,7 @@ for opt in options: if not files or files[0] == '-': # FIXME: read from stdin when files[0] = '-' - help () + lilylib.help () errorport.write (program_name + ":" + _ ("error: ") + _ ("no files specified on command line.") + '\n') sys.exit (2) @@ -890,9 +905,9 @@ if not files or files[0] == '-': for f in files: g = f - g = strip_extension (g, '.midi') - g = strip_extension (g, '.mid') - g = strip_extension (g, '.MID') + g = lilylib.strip_extension (g, '.midi') + g = lilylib.strip_extension (g, '.mid') + g = lilylib.strip_extension (g, '.MID') (outdir, outbase) = ('','') if not output_name: diff --git a/scripts/mup2ly.py b/scripts/mup2ly.py index f7b7da1eff..81279de3f8 100644 --- a/scripts/mup2ly.py +++ b/scripts/mup2ly.py @@ -34,9 +34,26 @@ import __main__ import operator import tempfile -sys.path.append ('@datadir@/python') -sys.path.append ('@datadir@/buildscripts/out') -sys.path.append ('@datadir@/modules/out') + +# if set, LILYPONDPREFIX must take prevalence +# if datadir is not set, we're doing a build and LILYPONDPREFIX +datadir = '@datadir@' +if os.environ.has_key ('LILYPONDPREFIX') \ + or '@datadir@' == '@' + 'datadir' + '@': + datadir = os.environ['LILYPONDPREFIX'] +else: + datadir = '@datadir@' + +sys.path.append (os.path.join (datadir, 'python')) +sys.path.append (os.path.join (datadir, 'python/out')) + +program_name = 'ly2dvi' +program_version = '@TOPLEVEL_VERSION@' +original_dir = os.getcwd () +temp_dir = os.path.join (original_dir, '%s.dir' % program_name) +errorport = sys.stderr +keep_temp_dir_p = 0 +verbose_p = 0 try: import gettext @@ -47,17 +64,8 @@ except: def _ (s): return s -# Attempt to fix problems with limited stack size set by Python! -# Sets unlimited stack size. Note that the resource module only -# is available on UNIX. -try: - import resource - resource.setrlimit (resource.RLIMIT_STACK, (-1, -1)) -except: - pass program_name = 'mup2ly' -package_name = 'lilypond' help_summary = _ ("Convert mup to LilyPond source") option_definitions = [ diff --git a/scripts/update-lily.py b/scripts/update-lily.py index e60de66dba..76d9068fe5 100644 --- a/scripts/update-lily.py +++ b/scripts/update-lily.py @@ -32,15 +32,38 @@ import sys import __main__ +# if set, LILYPONDPREFIX must take prevalence +# if datadir is not set, we're doing a build and LILYPONDPREFIX +datadir = '@datadir@' +if os.environ.has_key ('LILYPONDPREFIX') \ + or '@datadir@' == '@' + 'datadir' + '@': + datadir = os.environ['LILYPONDPREFIX'] +else: + datadir = '@datadir@' + +sys.path.append (os.path.join (datadir, 'python')) +sys.path.append (os.path.join (datadir, 'python/out')) + +program_name = 'build-lily' +program_version = '@TOPLEVEL_VERSION@' + +original_dir = os.getcwd () +temp_dir = os.path.join (original_dir, '%s.dir' % program_name) +errorport = sys.stderr +keep_temp_dir_p = 0 +verbose_p = 0 +remove_previous_p = 0 + url = 'file:/home/ftp/pub/gnu/LilyPond/development/lilypond-*.tar.gz' url = 'ftp://appel.lilypond.org/pub/gnu/LilyPond/development/lilypond-*.tar.gz' url = 'ftp://ftp.cs.uu.nl/pub/GNU/LilyPond/development/lilypond-*.tar.gz' -remove_previous_p = 0 + +build_root = os.path.join (os.environ ['HOME'], 'usr', 'src') +release_dir = build_root + '/releases' +patch_dir = build_root + '/patches' -sys.path.append ('@datadir@/python') -sys.path.append ('@datadir@/buildscripts/out') try: import gettext @@ -61,17 +84,8 @@ except: pass -program_name = 'build-lily' -package_name = 'lilypond' help_summary = _ ("Fetch and rebuild from latest source package") -build_root = os.path.join (os.environ ['HOME'], 'usr', 'src') -release_dir = build_root + '/releases' -patch_dir = build_root + '/patches' -original_dir = os.getcwd () -temp_dir = os.path.join (original_dir, '%s.dir' % program_name) - - option_definitions = [ ('DIR', 'b', 'build-root', _ ("unpack and build in DIR [%s]") % build_root), ('COMMAND', 'c', 'command', _ ("execute COMMAND, subtitute:") \ diff --git a/stepmake/stepmake/python-module-rules.make b/stepmake/stepmake/python-module-rules.make index b37eb61110..e8087596eb 100644 --- a/stepmake/stepmake/python-module-rules.make +++ b/stepmake/stepmake/python-module-rules.make @@ -1,3 +1,3 @@ -$(PYTHON_MODULE): $(outdir)/config.h $(LO_FILES) - $(LD) $(SHARED_FLAGS) -o $@ $(LO_FILES) $(LDFLAGS) +$(outdir)/%$(SHARED_LIB_SUFFIX): $(outdir)/%.lo + $(LD) $(SHARED_FLAGS) -o $@ $< $(LDFLAGS) diff --git a/stepmake/stepmake/python-module-targets.make b/stepmake/stepmake/python-module-targets.make index 6d4f607785..8b47ce0a46 100644 --- a/stepmake/stepmake/python-module-targets.make +++ b/stepmake/stepmake/python-module-targets.make @@ -1 +1 @@ -default: $(PYTHON_MODULE) \ No newline at end of file +default: $(OUT_PY_MODULES) $(OUT_SO_MODULES) \ No newline at end of file diff --git a/stepmake/stepmake/python-module-vars.make b/stepmake/stepmake/python-module-vars.make index 372264046c..59eb76153d 100644 --- a/stepmake/stepmake/python-module-vars.make +++ b/stepmake/stepmake/python-module-vars.make @@ -1,7 +1,6 @@ +PY_MODULES = $(wildcard *.py) +PY_IN_FILES = $(wildcard *.py.in) +OUT_PY_MODULES = $($(addprefix $(outdir)/, $(PY_IN_FILES:.in=) SHARED_LIB_SUFFIX = .so - -PYTHON_MODULE = $(outdir)/$(NAME)$(SHARED_LIB_SUFFIX) -INSTALL_SHARED_LIBRARY = $(SHARED_LIB_PREFIX)$(NAME)$(SHARED_LIB_SUFFIX) - -LO_FILES += $(addprefix $(outdir)/, $(Y_FILES:.y=.lo) $(C_FILES:.c=.lo) $(L_FILES:.l=.lo)) +OUT_SO_MODULES = $(addprefix $(outdir)/, $(C_FILES:.c=$(SHARED_LIB_SUFFIX)))