+1.3.84
+======
+
+* pmx2ly, PMX to LilyPond conversion. Succesfully converts barsant.pmx.
+
+* musedata2ly, a Musedata to LilyPond convertor. Succesfully converts
+wtk1-fugue2
+
+* bugfixes for dynamics: make sure that dynamic alignments encompass
+the dynamics they support, and that any columns they attach to aren't
+prematurely killed.
+
+* bugfix: make sure \time gets noticed early enough.
+
1.3.83
======
* Smobified Translator and Translator_group, junked
Translator_group_identifier.
-
* \pushproperty and \popproperty withing \translator, similar to
predefining \property, ie.
* Glen Prideaux lyric phrasing engraver. See
input/test/lyric-phrasing.ly
-
-
-
1.3.73
======
* Removed \interscoreline after the last line, prevents some
@mudelafile{lyric-combine.ly}
+Multiple stanzas
+
+@mudelafile{lyrics-multi-stanza.ly}
+
@section Multiple notes
Rests should not collide with beams, stems and noteheads. Rests may
-* Finale (.etf) import program.
+* Finale (.etf), PMX (.pmx) and musedata import tools.
* Point and click functionality using emacs and Xdvi.
* Typography: More elegant slurs, aligned dynamics, text crescendos,
-* Nice lyrics placement: Automagical phrasing and melisma alignment.
+* Better lyrics placement: Automagical phrasing, melisma alignment,
+ stanza numbering.
-* Part combining for orchestral scores and hymns: Automagical combining
- and separating of two voices, with Solo/`a2 indications as appropriate.
+* Part combining for orchestral scores and hymns: two voices are
+ combined automatic into a staff automatically, including Solo/`a2
+ indications as appropriate.
* Chordnames are now configurable in every respect
* Finished ouverture Coriolan as full orchestral score example.
* AsciiScript [check if broken, decide wether to keep]
+
+* Translations into Japanese and Russian
PACKAGE_NAME=LilyPond
MAJOR_VERSION=1
MINOR_VERSION=3
-PATCH_LEVEL=83
+PATCH_LEVEL=84
MY_PATCH_LEVEL=
# use the above to send patches: MY_PATCH_LEVEL is always empty for a
+++ /dev/null
-#!@PYTHON@
-
-# musedata = musedata.stanford.edu
-# musedata = COBOL for musicians.
-# todo: rewrite this.
-
-import re
-import sys
-import string
-
-f = open (sys.argv[1])
-lines =f.readlines()
-
-def chomp (x):
- return re.sub ('[\r\n \t]+$','', x)
-
-lines = map (chomp, lines)
-
-default_header_dict = {
- 'tagline' :'automatically converted from Musedata',
- 'copyright' : 'all rights reserved -- free for noncommercial use'
- }
-
-# Jezus, wat een ranzig formaat. (2am)
-def parse_header (lines):
- d = default_header_dict
- enter = string.split (lines[3], ' ')
- d['enteredby'] = string.join (enter[1:])
- d['enteredon'] = enter[0]
- d['opus'] = lines[4]
- d['source'] = lines[5]
- d['title'] = lines[6]
- d['subtitle'] = lines[7]
- d['instrument']= lines[8]
- d['musedatamisc'] =lines[9]
- d['musedatagroups'] =lines[10]
- d['musedatagroupnumber']=lines[11]
-
- return d
-
-clef_dict = {
-04: 'treble',
-13 : 'alto',
-22: 'bass',
-
-}
-
-def get_clef(s):
- return '\\clef "%s";\n' % clef_dict [string.atoi (s)]
-
-def get_mudela_notename (p, ac):
- if p > 5:
- p = p - 7
- s = chr (p + ord ('c'))
- infix = 'i'
- if ac < 0:
- infix = 'e'
- ac = -ac
-
- while ac:
- s = s + infix + 's'
- ac = ac - 1
- return s
-
-def get_key (s):
- i = string.atoi (s)
- return ''
-
-def get_timesig (s):
- return '\\time %s;\n' % s
-
-
-divisions = 4
-def get_divisions_per_quarter (s):
- divisions = string.atoi (s)
- return ''
-
-def get_directive (s):
- return '%% %s\n' % s
-
-def get_transposing (s):
- return ''
-
-def get_num_instruments (s):
- return ''
-
-attr_dict = {
- 'C' : get_clef,
- 'K' : get_key ,
- 'T' : get_timesig,
- 'Q' : get_divisions_per_quarter,
- 'D' : get_directive,
- 'X' : get_transposing,
- 'I': get_num_instruments,
- }
-
-def parse_musical_attributes (l):
- s = ''
- l = l[1:]
- atts = re.split('[ \t]+', l)
- for a in atts:
- if not a:
- continue
- m = re.search ('(.):(.*)', a)
- if m == None:
- print 'Huh, unknown attr `%s\'' % a
- continue
-
- s = s + attr_dict[m.group(1)](m.group (2))
- return s
-
-
-def get_mudela_pitch (n, a, o):
- c = '\''
- if o < 1:
- c = ','
- o = 1 - o
-
- return get_mudela_notename (n,a) + '%s' % c * o
-
-def dump_header (h, out):
- out.write ('\\header {\n')
- for tup in h.items ():
- out.write ('\t%s = \"%s\";\n' % tup)
- out.write ('}\n')
-
-header_dict = parse_header (lines[0:12])
-dump_header (header_dict, sys.stdout)
-
-
-lines = lines [12:]
-
-
-def parse_line_comment (l):
- return re.sub ('@' , '%' , l)
-
-def parse_note_line (l):
- pitch = ((ord (l[0]) -ord('A')) + 5) % 7
- acc = 0
- l= l[1:]
- while l[0] == 'f':
- l= l[1:]
- acc = acc - 1
- while l[0] == '#':
- l= l[1:]
- acc = acc + 1
- while l[0] in ' \t':
- l= l[1:]
-
- oct = 0
- if l[0] in '0123456789':
- oct = string.atoi (l[0]) - 4
- l= l[1:]
-
- while l[0] in ' \t':
- l= l[1:]
-
-
- print get_mudela_pitch (pitch,acc,oct), parse_duration(l[:2])
- l = l[2:]
-
-
-
-
-def parse_duration (l):
- s = ''
- while l[0] in '0123456789':
- s = s + l[0]
- l= l[1:]
- print l
- num = string.atoi (s)
- den = 4 * divisions
-
- current_dots = 0
- try_dots = [3, 2, 1]
- for d in try_dots:
- f = 1 << d
- multiplier = (2*f-1)
- if num % multiplier == 0 and den % f == 0:
- num = num / multiplier
- den = den / f
- current_dots = current_dots + d
-
- if num <> 1:
- sys.stderr.write ('huh. Durations left')
- return '%s%s' % (den, '.' * current_dots)
-
-comment_switch = 0
-for l in lines:
- if l[0] == '&':
- comment_switch = not comment_switch
- if comment_switch:
- l= l[1:]
- print '%{'
- else:
- print '%}'
-
- if comment_switch:
- print l
- continue
-
- if 0:
- pass
- elif l[0] == '$':
- print parse_musical_attributes (l)
- elif l[0] == '@':
- parse_line_comment (l)
-
- elif l[0] in 'ABCDEFG':
- parse_note_line (l)
+++ /dev/null
-#!@PYTHON@
-
-# (urg! wat een pokkeformaat (pokkenformaat?))
-
-import string
-import sys
-import re
-
-fn = sys.argv[1]
-
-ls = open (fn).readlines ()
-def stripcomment (l):
- return re.sub ('[ \t]*%.*$\n', '', l)
-
-def stripwhite (l):
- return re.sub ('[ \n\t]+', ' ', l)
-
-def stripeols (l):
- return re.sub ('^ ', '', re.sub (' $', '', l))
-
-ls = map (stripcomment, ls)
-ls = map (stripwhite, ls)
-ls = map (stripeols, ls)
-
-
-ls = filter (lambda x: x <> '', ls)
-
-opening = ls[0]
-ls = ls[1:]
-
-
-opening = map (string.atoi, re.split ('[\t ]+', opening))
-
-(no_staffs, no_instruments, timesig_num,timesig_den, ptimesig_num,
- ptimesig_den, pickup_beats,keysig_number) = tuple (opening)
-
-
-opening = ls[0]
-ls = ls[1:]
-
-# ignore this.
-# opening = map (string.atoi, re.split ('[\t ]+', opening))
-# (no_pages,no_systems, musicsize, fracindent) = tuple (opening)
-
-instruments = []
-while len (instruments) < no_instruments:
- instruments.append (ls[0])
- ls = ls[1:]
-
-class Staff:
- def __init__ (self):
- self.voices = ([],[])
- self.clef = None
- self.instrument = 0
-l = ls[0]
-ls = ls[1:]
-
-staffs = map (lambda x: Staff (), range(0, no_staffs))
-staff_idx = 0
-
-for s in staffs:
- s.clef = l[0]
- l = l[1:]
-
-# dump path
-ls = ls[1:]
-
-# dump more ?
-ls = ls[2:]
-
-actab = {-2: 'eses', -1: 'es', 0 : '', 1: 'is', 2:'isis'}
-
-def pitch_to_lily_string (tup):
- (o,n,a) = tup
-
- nm = chr((n + 2) % 7 + ord ('a'))
- nm = nm + actab[a]
- if o > 0:
- nm = nm + "'" * o
- elif o < 0:
- nm = nm + "," * -o
- return nm
-
-class Chord:
- def __init__ (self):
- self.pitches = []
- self.dots = 0
- self.basic_duration = 0
-
- def dump (self):
- str = ''
-
- for p in self.pitches:
- if str:
- str = str + ' '
- str = str + pitch_to_lily_string (p)
-
- if len (self.pitches) > 1:
- str = '<%s>' % str
- elif len (self.pitches) == 0:
- str = 'r'
-
-
- sd = ''
- if self.basic_duration == 0.5:
- sd = '\\breve'
- else:
- sd = '%d' % self.basic_duration
-
- str = str + sd + '.' * self.dots
- return str
-
-
-input_left = string.join (ls, ' ')
-
-
-input_left = re.sub ('[ \t\n]+', ' ', input_left)
-
-SPACE=' \t\n'
-DIGITS ='0123456789'
-basicdur_table = {
- 9: 0.5,
- 0: 0 ,
- 2: 2 ,
- 4: 4 ,
- 8: 8 ,
- 1: 16,
- 3: 32,
- 6: 64
- }
-
-class Parser:
- def __init__ (self):
- self.chords = []
- self.forced_duration = None
- self.last_octave = 4
-
- def parse_note (self, str):
- ch = Chord ()
-
- name = None
- if str[0] <> 'r':
- name = (ord (str[0]) - ord('a') + 5) % 7
- str = str[1:]
-
- forced_duration = 0
- alteration = 0
- dots = 0
- oct = None
- durdigit = None
- multibar = 0
- while str[0] in 'dsfmnul0123456789.,':
- c = str[0]
- str = str[1:]
- if c == 'f':
- alteration = alteration -1
- elif c == 'n':
- alteration = 0
- elif c == 'm':
- multibar = 1
- elif c == 's':
- alteration = alteration +1
- elif c == 'd':
- dots = dots + 1
- elif c in DIGITS and durdigit == None:
- durdigit = string.atoi (c)
- elif c in DIGITS:
- oct = string.atoi (c) - 4
- elif c == '.':
- dots = dots+ 1
- forced_duration = 2
- elif c == ',':
- forced_duration = 2
-
-
- if durdigit:
- ch.basic_duration = basicdur_table[durdigit]
- self.last_basic_duration = ch.basic_duration
- else:
- ch.basic_duration = self.last_basic_duration
-
- if name:
- if oct:
- self.last_octave =oct
- else:
- oct = self.last_octave
-
- if name:
- ch.pitches.append ((oct, name, alteration))
-
- ch.dots = dots
-
-
- if forced_duration:
- self.forced_duration = ch.basic_duration / forced_duration
-
-
- self.chords.append (ch)
- while str[0] in SPACE:
- str = str [1:]
- return str
-
-
-parser = Parser()
-while input_left:
- while input_left[0] in 'abcdefgr':
- input_left = parser.parse_note (input_left)
- print input_left[0]
-
- sys.stderr.write ("\nHuh? Unknown directive %s" %input_left[0:1])
- input_left = input_left[1:]
-
-
-
-for c in parser.chords:
- print c.dump ()
-
--- /dev/null
+
+\score { \notes { c4-1-2-3 }}
--- /dev/null
+% Tests a number of features:
+% * Lyric_phrasing_engraver
+% * Stanza_number_engraver
+% * Automatic melismata on beamed notes
+
+\version "1.3.59";
+\include "english.ly"
+
+\header{
+ title = "Crowned with Honour";
+ composer = "Oliver Holden (1765-1844)";
+ poet = "Thomas Kelly (1769-1855)";
+}
+
+allup = \notes{
+ \property Voice.verticalDirection = \up
+ \property Voice.slurVerticalDirection = \up
+ \property Voice.tieVerticalDirection = \up
+ \property Voice.dynamicDirection = \up
+ \autoBeamOff
+}
+alldown = \notes{
+ \property Voice.verticalDirection = \down
+ \property Voice.slurVerticalDirection = \down
+ \property Voice.tieVerticalDirection = \down
+ \property Voice.dynamicDirection = \down
+ \autoBeamOff
+}
+
+Global = \notes{
+ \key g \major;
+ \time 4/4;
+ \partial 4;
+}
+
+Soprano = \notes \relative c' {
+ \allup
+ d4 | g g b b a g a b a g b a g( a )g % modified to test melisma align right
+
+ [a8 b] | b4 % modified to test melisma align left
+ a g b [d16 d c8] [b a] b4 % modified to test beam melisma
+% a4 | b a g b [d8 \melisma c] \melismaEnd [b \melisma a] \melismaEnd b4
+
+ d d2 d e d4( cs8 ~ )cs d2.
+
+ b4 | d b g b [a8 g] [a b] a4
+% b4 | d b g b [a8 \melisma g] \melismaEnd [a \melisma b] \melismaEnd a4
+
+ g d'2 c b4.( c8 )a4 a g2.
+}
+Alto = \notes \relative c'{
+ \alldown
+ d4 | d d g g fs g fs g fs e g fs d2.
+ d4 | g d b g' [b8 a] [g fs] g4 fs g2 a g fs4( e8 )g fs2.
+ d4 | g g d g [fs8 e] [fs g] fs4 g f2 e d4.( d8 )d4 fs4 d2.
+}
+Tenor = \notes \relative c{
+ \allup
+ d4 | b' b d d c b c d c b d c b2.
+ a4 | b a g b [d8 c] [b a] b4 a b2 c b a a2.
+ g4 | b d b d [c8 b] [c d] c4 b g2 g g4.( a8 [fs )a] c4 b2.
+}
+Bass = \notes \relative c{
+ \alldown
+ d4 | g g g g d d d g d e d d g,2.
+ d'4 | g d b g' [b8 a] [g fs] g4 d g2 fs e a d,2.
+ g4 | g g g g d d d e b2 c d2. d4 g,2.
+}
+
+TheLyrics = \lyrics <
+ {
+ \context LyricVoice = "Soprano-1"
+ \property LyricVoice .stanza = "1:"
+ \property LyricVoice .stz = "(1)"
+ The4 head that once was crowned with thorns
+ Is crowned with glo -- ry now;
+ A roy -- al di -- a -- dem a -- dorns
+ The might -- y Vic -- tor's brow.
+ A roy -- al di -- a -- dem a -- dorns
+ The might -- y Vic -- tor's brow.
+ }
+ {
+ \context LyricVoice = "Soprano-2"
+ \property LyricVoice .stanza = "2:"
+ \property LyricVoice .stz = "(2)"
+ The4 high -- est place that heav'n af -- fords
+ Is His by sov -- 'reign right;
+ The King of kings, the Lord of lords,
+ He reigns in glo -- ry bright,
+ The King of kings, the Lord of lords,
+ He reigns in glo -- ry bright.
+ }
+ {
+ \context LyricVoice = "Soprano-3"
+ \property LyricVoice .stanza = "3:"
+ \property LyricVoice .stz = "(3)"
+ The joy of all who dwell a -- bove,
+ The joy of saints be -- low,
+ To4 whom He man -- i -- fests His love,
+ And grants His name to know,
+ To4 whom He man -- i -- fests His love,
+ And grants His name to4 know.
+ }
+>
+
+
+\score{
+ \context ChoirStaff
+ \notes
+ <
+ \property Score.barNumberScriptPadding = #10.0
+ \context Staff = "treblestaff"{
+ <
+ \context Voice = "Soprano" { }
+ \context Voice = "Alto" { }
+ >
+ }
+ \context Lyrics = mainlyrics { }
+ \context Staff = "treblestaff"{
+ <
+ \Global
+ \addlyrics { \context Voice = "Soprano" \Soprano }
+ { \context Lyrics = mainlyrics \TheLyrics }
+ \context Voice = "Alto" \Alto
+ >
+ \bar "|.";
+ }
+ \context Staff = "bassstaff"{
+ \clef "bass";
+ <
+ \context Voice = "Tenor" { \Tenor }
+ \context Voice = "Bass" { \Bass }
+ >
+ \bar "|.";
+ }
+ >
+
+ \paper {
+ \translator{
+ \VoiceContext
+ automaticMelismata = ##t;
+ noAutoBeaming = ##t;
+ \remove "Auto_beam_engraver";
+ }
+
+ }
+}
+++ /dev/null
-% Tests a number of features:
-% * Lyric_phrasing_engraver
-% * Stanza_number_engraver
-% * Automatic melismata on beamed notes
-
-\version "1.3.59";
-\include "english.ly"
-
-\header{
- title = "Crowned with Honour";
- composer = "Oliver Holden (1765-1844)";
- poet = "Thomas Kelly (1769-1855)";
-}
-
-allup = \notes{
- \property Voice.verticalDirection = \up
- \property Voice.slurVerticalDirection = \up
- \property Voice.tieVerticalDirection = \up
- \property Voice.dynamicDirection = \up
- \autoBeamOff
-}
-alldown = \notes{
- \property Voice.verticalDirection = \down
- \property Voice.slurVerticalDirection = \down
- \property Voice.tieVerticalDirection = \down
- \property Voice.dynamicDirection = \down
- \autoBeamOff
-}
-
-Global = \notes{
- \key g \major;
- \time 4/4;
- \partial 4;
-}
-
-Soprano = \notes \relative c' {
- \allup
- d4 | g g b b a g a b a g b a g( a )g % modified to test melisma align right
-
- [a8 b] | b4 % modified to test melisma align left
- a g b [d16 d c8] [b a] b4 % modified to test beam melisma
-% a4 | b a g b [d8 \melisma c] \melismaEnd [b \melisma a] \melismaEnd b4
-
- d d2 d e d4( cs8 ~ )cs d2.
-
- b4 | d b g b [a8 g] [a b] a4
-% b4 | d b g b [a8 \melisma g] \melismaEnd [a \melisma b] \melismaEnd a4
-
- g d'2 c b4.( c8 )a4 a g2.
-}
-Alto = \notes \relative c'{
- \alldown
- d4 | d d g g fs g fs g fs e g fs d2.
- d4 | g d b g' [b8 a] [g fs] g4 fs g2 a g fs4( e8 )g fs2.
- d4 | g g d g [fs8 e] [fs g] fs4 g f2 e d4.( d8 )d4 fs4 d2.
-}
-Tenor = \notes \relative c{
- \allup
- d4 | b' b d d c b c d c b d c b2.
- a4 | b a g b [d8 c] [b a] b4 a b2 c b a a2.
- g4 | b d b d [c8 b] [c d] c4 b g2 g g4.( a8 [fs )a] c4 b2.
-}
-Bass = \notes \relative c{
- \alldown
- d4 | g g g g d d d g d e d d g,2.
- d'4 | g d b g' [b8 a] [g fs] g4 d g2 fs e a d,2.
- g4 | g g g g d d d e b2 c d2. d4 g,2.
-}
-
-TheLyrics = \lyrics <
- {
- \context LyricVoice = "Soprano-1"
- \property LyricVoice .stanza = "1:"
- \property LyricVoice .stz = "(1)"
- The4 head that once was crowned with thorns
- Is crowned with glo -- ry now;
- A roy -- al di -- a -- dem a -- dorns
- The might -- y Vic -- tor's brow.
- A roy -- al di -- a -- dem a -- dorns
- The might -- y Vic -- tor's brow.
- }
- {
- \context LyricVoice = "Soprano-2"
- \property LyricVoice .stanza = "2:"
- \property LyricVoice .stz = "(2)"
- The4 high -- est place that heav'n af -- fords
- Is His by sov -- 'reign right;
- The King of kings, the Lord of lords,
- He reigns in glo -- ry bright,
- The King of kings, the Lord of lords,
- He reigns in glo -- ry bright.
- }
- {
- \context LyricVoice = "Soprano-3"
- \property LyricVoice .stanza = "3:"
- \property LyricVoice .stz = "(3)"
- The joy of all who dwell a -- bove,
- The joy of saints be -- low,
- To4 whom He man -- i -- fests His love,
- And grants His name to know,
- To4 whom He man -- i -- fests His love,
- And grants His name to4 know.
- }
->
-
-
-\score{
- \context ChoirStaff
- \notes
- <
- \property Score.barNumberScriptPadding = #10.0
- \context Staff = "treblestaff"{
- <
- \context Voice = "Soprano" { }
- \context Voice = "Alto" { }
- >
- }
- \context Lyrics = mainlyrics { }
- \context Staff = "treblestaff"{
- <
- \Global
- \addlyrics { \context Voice = "Soprano" \Soprano }
- { \context Lyrics = mainlyrics \TheLyrics }
- \context Voice = "Alto" \Alto
- >
- \bar "|.";
- }
- \context Staff = "bassstaff"{
- \clef "bass";
- <
- \context Voice = "Tenor" { \Tenor }
- \context Voice = "Bass" { \Bass }
- >
- \bar "|.";
- }
- >
-
- \paper {
- \translator{
- \VoiceContext
- automaticMelismata = ##t;
- noAutoBeaming = ##t;
- \remove "Auto_beam_engraver";
- }
-
- }
-}
Axis_group_interface::set_axes (staffline_p_, Y_AXIS, Y_AXIS);
Score_element * it = unsmob_element (get_property ("currentCommandColumn"));
- Pointer_group_interface (it, "bounded-by-me").add_element (staffline_p_);
+
staffline_p_->set_bound(LEFT,it);
announce_element (staffline_p_, 0);
Score_element * it = unsmob_element (get_property ("currentCommandColumn"));
- Pointer_group_interface (it, "bounded-by-me").add_element (staffline_p_);
+
staffline_p_->set_bound(RIGHT,it);
typeset_element (staffline_p_);
#include "directional-element-interface.hh"
-static SCM Directional_element_interface::direction_sym;
+SCM Directional_element_interface::direction_sym;
static void
init_functions ()
else
{
assert (!finished_cresc_p_);
- cresc_p_->set_bound (RIGHT, unsmob_element (get_property ("currentMusicalColumn")));
+ Score_element* cc = unsmob_element (get_property ("currentMusicalColumn"));
+
+ cresc_p_->set_bound (RIGHT, cc);
+
finished_cresc_p_ = cresc_p_;
cresc_p_ = 0;
current_cresc_req_ = 0;
+ "Spanner", SCM_UNDEFINED);
}
- cresc_p_->set_bound (LEFT, unsmob_element (get_property ("currentMusicalColumn")));
+ Score_element *cc = unsmob_element (get_property ("currentMusicalColumn"));
+ cresc_p_->set_bound (LEFT, cc);
/*
if (finished_line_spanner_)
{
Side_position::add_staff_support (finished_line_spanner_);
-
+#if 0
if (!finished_line_spanner_->get_bound (LEFT))
{
Score_element * cmc
finished_line_spanner_->set_bound (RIGHT,
finished_line_spanner_->get_bound (LEFT));
-
+#endif
+ extend_spanner_over_elements (finished_line_spanner_);
typeset_element (finished_line_spanner_);
finished_line_spanner_ = 0;
}
void add_bound_item (Spanner*, Item* n);
+void extend_spanner_over_elements (Score_element* span);
#endif
Score_element * it
= unsmob_element (get_property (ly_symbol2scm ("currentCommandColumn")));
- Pointer_group_interface (it, "bounded-by-me").add_element (staffline_p_);
+
staffline_p_->set_bound(RIGHT,it);
Engraver_group_engraver::typeset_element (staffline_p_);
staffline_p_ = 0;
Score_element * it
= unsmob_element (get_property (ly_symbol2scm ("currentCommandColumn")));
staffline_p_->set_bound(LEFT,it);
- Pointer_group_interface (it, "bounded-by-me").add_element (staffline_p_);
Engraver::announce_element (staffline_p_,0);
}
void
usage ()
{
- identify (&cout);
- cout << "\n";
+
+ /*
+ No version number or newline here. It confuses help2man
+ */
cout << _f ("Usage: %s [OPTION]... [FILE]...", "lilypond");
cout << "\n\n";
cout << _ ("Typeset music and or play MIDI from FILE");
Axis_group_interface::set_interface (this);
Axis_group_interface::set_axes (this, X_AXIS, X_AXIS);
Spaceable_element::set_interface (this);
- set_elt_property ("bounded-by-me", SCM_EOL);
+
line_l_=0;
rank_i_ = -1;
}
Engraver_group_engraver::do_removal_processing();
scoreline_l_->set_bound(RIGHT,command_column_l_);
command_column_l_->set_elt_property ("breakable", SCM_BOOL_T);
-
typeset_all ();
-
set_columns (0,0);
}
void
Score_engraver::do_pre_move_processing()
{
+ // this generates all items.
+ Engraver_group_engraver::do_pre_move_processing();
+
+ typeset_all();
if (to_boolean (command_column_l_->get_elt_property ("breakable")))
{
breaks_i_ ++;
if (! (breaks_i_%8))
progress_indication ("[" + to_str ( breaks_i_) + "]");
}
- // this generates all items.
- Engraver_group_engraver::do_pre_move_processing();
-
- typeset_all();
}
void
if (*current[i])
{
scoreline_l_->add_column ((*current[i]));
+#if 0
+ /*
+ TODO: delay this decision.
+ */
if (!Paper_column::used_b (*current[i]))
{
(*current[i])->suicide ();
*current[i] =0;
}
+#endif
}
if (news[i])
*current[i] = news[i];
#include "paper-column.hh"
#include "line-of-score.hh"
#include "break-align-item.hh"
-
+#include "group-interface.hh"
void
Spanner::do_break_processing ()
{
set_parent (i, X_AXIS);
}
+
+ /*
+ Signal that this column needs to be kept alive. They need to be
+ kept alive to have meaningful position and linebreaking.
+
+ [maybe we should try keeping all columns alive?, and perhaps
+ inherit position from their (non-)musical brother]
+
+ */
+ if (dynamic_cast<Paper_column*> (i))
+ {
+ Pointer_group_interface (i, "bounded-by-me").add_element (this);
+ }
}
else
sp->set_bound (RIGHT, it);
}
+
+static void
+extend_spanner_over_item (Item *it, SCM extremal_pair)
+{
+ if (!it)
+ return;
+ Item * col = it->column_l ();
+ Item * i1 = dynamic_cast<Item*> (unsmob_element (gh_car (extremal_pair)));
+ Item * i2 = dynamic_cast<Item*> (unsmob_element (gh_cdr (extremal_pair)));
+ int r = Paper_column::rank_i (col);
+ if (!i1 || r < Paper_column::rank_i (i1->column_l ()))
+ {
+ gh_set_car_x (extremal_pair, it->self_scm ());
+ }
+ if (!i2 || r > Paper_column::rank_i (i2->column_l ()))
+ {
+ gh_set_cdr_x (extremal_pair, it->self_scm ());
+ }
+}
+
+static void
+extend_spanner_over_elements (SCM value, SCM extremal_pair)
+{
+ if (gh_pair_p (value))
+ {
+ extend_spanner_over_elements (gh_car (value), extremal_pair);
+ extend_spanner_over_elements (gh_cdr (value), extremal_pair);
+ }
+ else if (unsmob_element (value))
+ {
+ if (Spanner * sp = dynamic_cast<Spanner*> (unsmob_element(value)))
+ {
+ extend_spanner_over_item (sp->get_bound (LEFT), extremal_pair);
+ extend_spanner_over_item (sp->get_bound (RIGHT), extremal_pair);
+ }
+ else if (Item * it= dynamic_cast<Item*> (unsmob_element(value)))
+ extend_spanner_over_item (it, extremal_pair);
+ }
+}
+
+
+/*
+ Make sure that the left and right bounds encompasses all objects it
+ points to.
+
+ TODO: maybe be more specific. Most probably fucks up if someone sets
+ a pointer to the staffsymbol in S
+*/
+void
+extend_spanner_over_elements (Score_element*s)
+{
+ Spanner*sp = dynamic_cast<Spanner*> (s);
+
+ SCM s1 = sp->get_bound (LEFT) ? sp->get_bound (LEFT)->self_scm () : SCM_EOL;
+ SCM s2 = sp->get_bound (RIGHT) ? sp->get_bound (RIGHT)->self_scm () : SCM_EOL;
+
+ SCM pair = gh_cons (s1,s2);
+ extend_spanner_over_elements (sp->mutable_property_alist_, pair);
+
+ Score_element *p1 = unsmob_element (gh_car (pair));
+ Score_element* p2 = unsmob_element (gh_cdr (pair));
+ sp->set_bound (LEFT,p1);
+ sp->set_bound (RIGHT, p2);
+
+ //extra precaution.
+}
+
return false;
}
}
+
+ /*
+ We have to do this soon enough. Maybe we'd better disguise
+ \time as a \property. Then all settings will be `immediate'.
+ */
+ if (Time_signature_change_req *c
+ = dynamic_cast <Time_signature_change_req *> (t))
+ set_time_signature (c->beats_i_, c->one_beat_i_);
timing_req_l_arr_.push(t);
return true;
}
return false;
}
+
void
Timing_translator::do_process_music()
{
for (int i=0; i < timing_req_l_arr_.size (); i++)
{
- Timing_req * tr_l = timing_req_l_arr_[i];
-
- if (Time_signature_change_req *m_l = dynamic_cast <Time_signature_change_req *> (tr_l))
- {
- int b_i= m_l->beats_i_;
- int o_i = m_l->one_beat_i_;
- set_time_signature (b_i, o_i);
- }
- else if (dynamic_cast <Barcheck_req *> (tr_l))
+ if (!dynamic_cast <Barcheck_req *> (timing_req_l_arr_[i]))
+ continue;
+ if (measure_position ())
{
- if (measure_position ())
- {
- Moment nm;
- tr_l ->origin ()->warning (_f ("barcheck failed at: %s",
- measure_position ().str ()));
- // resync
- daddy_trans_l_->set_property("measurePosition", nm.make_scm ());
- }
+ timing_req_l_arr_[i]->origin ()->warning (_f ("barcheck failed at: %s",
+ measure_position ().str ()));
+ Moment zero;
+
+ // resync
+ daddy_trans_l_->set_property("measurePosition", zero.make_scm ());
}
}
}
-
void
Timing_translator::do_pre_move_processing()
{
Begin3
Title: LilyPond
-Version: 1.3.83
-Entered-date: 01SEP00
+Version: 1.3.84
+Entered-date: 02SEP00
Description:
Keywords: music notation typesetting midi fonts engraving
Author: hanwen@cs.uu.nl (Han-Wen Nienhuys)
janneke@gnu.org (Jan Nieuwenhuizen)
Maintained-by: hanwen@stack.nl (Han-Wen Nienhuys)
Primary-site: sunsite.unc.edu /pub/Linux/apps/sound/convert
- 1000k lilypond-1.3.83.tar.gz
+ 1000k lilypond-1.3.84.tar.gz
Original-site: ftp.cs.uu.nl /pub/GNU/LilyPond/development/
- 1000k lilypond-1.3.83.tar.gz
+ 1000k lilypond-1.3.84.tar.gz
Copying-policy: GPL
End
Name: lilypond
-Version: 1.3.83
+Version: 1.3.84
Release: 1
Copyright: GPL
Group: Applications/Publishing
-Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.3.83.tar.gz
+Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.3.84.tar.gz
Summary: A program for printing sheet music.
URL: http://www.cs.uu.nl/~hanwen/lilypond
# Icon: lilypond-icon.gif
trscale = map(lambda x, k=transposition: transpose(x, k), cscale)
return trscale
+def EDU_to_duration (edu):
+ log = 1
+ d = 4096
+ while d > edu:
+ d = d >> 1
+ log = log << 1
+
+ edu = edu - d
+ dots = 0
+ if edu == d /2:
+ dots = 1
+ elif edu == d*3/4:
+ dots = 2
+ return (log, dots)
+
+def rat_to_lily_duration (rat):
+ (n,d) = rat
+
+ basedur = 1
+ while d and d % 2 == 0:
+ basedur = basedur << 1
+ d = d >> 1
+
+ str = 's%d' % basedur
+ if n <> 1:
+ str = str + '*%d' % n
+ if d <> 1:
+ str = str + '/%d' % d
+
+ return str
def gcd (a,b):
if b == 0:
(p,q) = a
return (-p,q)
+
+
def rat_subtract (a,b ):
return rat_add (a, rat_neg (b))
return str
-def EDU_to_duration (edu):
- log = 1
- d = 4096
- while d > edu:
- d = d >> 1
- log = log << 1
-
- edu = edu - d
- dots = 0
- if edu == d /2:
- dots = 1
- elif edu == d*3/4:
- dots = 2
- return (log, dots)
-
-def rat_to_lily_duration (rat):
- (n,d) = rat
- basedur = 1
- while d and d % 2 == 0:
- basedur = basedur << 1
- d = d >> 1
-
- str = 's%d' % basedur
- if n <> 1:
- str = str + '*%d' % n
- if d <> 1:
- str = str + '/%d' % d
-
- return str
-
class Chord:
def __init__ (self, finale_entry):
e.prev = self.chords[e.finale[0][1]]
e.next = self.chords[e.finale[0][2]]
-
-
-
-
-
def identify():
sys.stderr.write ("%s from LilyPond %s\n" % (program_name, version))
def help ():
- print r"""
-Convert ETF to LilyPond.
+ print """Usage: etf2ly [OPTION]... ETF-FILE
-Usage: etf2ly [OPTION]... ETF-FILE
+Convert ETF to LilyPond.
Options:
- -h, --help this help
- -o, --output=FILE set output filename to FILE
- -v, --version version information
+ -h,--help this help
+ -o,--output=FILE set output filename to FILE
+ -v,--version version information
Enigma Transport Format is a format used by Coda Music Technology's
Finale product. This program will convert a subset of ETF to a
ready-to-use lilypond file.
+Report bugs to bug-gnu-music@gnu.org
+Written by Han-Wen Nienhuys <hanwen@cs.uu.nl>
"""
def print_version ():
- print r"""etf2ly (GNU lilypond) %s""" % version
+ print r"""etf2ly (GNU lilypond) %s
+
+This is free software. It is covered by the GNU General Public License,
+and you are welcome to change it and/or distribute copies of it under
+certain conditions. Invoke as `midi2ly --warranty' for more information.
+
+Copyright (c) 2000 by Han-Wen Nienhuys <hanwen@cs.uu.nl>
+""" % version
--- /dev/null
+#!@PYTHON@
+
+# musedata = musedata.stanford.edu
+# musedata = COBOL for musicians.
+
+
+# TODO
+#
+# * clefs,
+# * keys,
+# * staffs,
+# * multiple voices (they use `Backspace' (shudder)
+# * tuplets
+#
+
+import re
+import sys
+import string
+import getopt
+import os
+program_name = 'musedata2ly'
+version = '@TOPLEVEL_VERSION@'
+if version == '@' + 'TOPLEVEL_VERSION' + '@':
+ version = '(unknown version)' # uGUHGUHGHGUGH
+
+
+
+ref_header_dict = {
+ 'COM': 'composer',
+ 'OPR': 'collection',
+ 'OTL': 'title',
+ 'OMV': 'subtitle',
+ 'YOR': 'source',
+ 'AGN': 'instrument',
+ 'END': 'encodingdate',
+ 'CDT': 'date',
+ 'OCY': 'composedin',
+ 'AST': 'genre',
+ 'YEC': 'copyright',
+ 'YEM': 'license',
+ 'YEN': 'encodingcountry',
+ 'EED': 'editor',
+ 'SCA': 'opus',
+ 'ONM': 'onm',
+ 'ENC': 'musedataencoder',
+ 'KEY': 'musedatakey',
+ 'AFT': 'musedatastage'
+ }
+
+
+class Ref_parser:
+ def __init__ (self, fn):
+ self.dict = {}
+
+ ls = open (fn).readlines ()
+ self.parse (ls)
+ def parse (self,ls):
+ for l in ls:
+ m = re.match('!!!([A-Z]+):[ \t]+(.*)$',l)
+ if m:
+ key = m.group(1)
+ val = m.group (2)
+ val = re.sub ('[ \t]+', ' ', val)
+ try:
+
+ key =ref_header_dict [key]
+ except KeyError:
+ sys.stderr.write ('\nUnknown ref key \`%s\'' % key)
+ s = ''
+ try:
+ s = self.dict[key]
+ except KeyError:
+ pass
+
+ s = s + val
+ self.dict[key] = s
+ def dump( self):
+ str = ''
+ for (k,v) in self.dict.items ():
+ str = str +' %s = "%s";\n' % (k,v)
+ str = '\\header {\n%s}' % str
+ return str
+
+verbose = 0
+
+
+actab = {-2: 'eses', -1: 'es', 0 : '', 1: 'is', 2:'isis'}
+
+def pitch_to_lily_string (tup):
+ (o,n,a) = tup
+
+ nm = chr((n + 2) % 7 + ord ('a'))
+ nm = nm + actab[a]
+ if o > 0:
+ nm = nm + "'" * o
+ elif o < 0:
+ nm = nm + "," * -o
+ return nm
+
+def get_key (s):
+ i = string.atoi (s)
+ return ''
+
+def get_timesig (s):
+ return '\\time %s;\n' % s
+
+
+divisions = 4
+def get_divisions_per_quarter (s):
+ divisions = string.atoi (s)
+ return ''
+
+def get_directive (s):
+ return '%% %s\n' % s
+
+def get_transposing (s):
+ return ''
+
+def get_num_instruments (s):
+ return ''
+
+def get_mudela_notename (p, ac):
+ if p > 5:
+ p = p - 7
+ s = chr (p + ord ('c'))
+ infix = 'i'
+ if ac < 0:
+ infix = 'e'
+ ac = -ac
+
+ while ac:
+ s = s + infix + 's'
+ ac = ac - 1
+ return s
+def get_clef ():
+ return ''
+
+SPACES = ' '
+DIGITS = "0123456789"
+
+
+clef_dict = {
+04: 'treble',
+13 : 'alto',
+22: 'bass',
+}
+attr_dict = {
+ 'C' : get_clef,
+ 'K' : get_key ,
+ 'T' : get_timesig,
+ 'Q' : get_divisions_per_quarter,
+ 'D' : get_directive,
+ 'X' : get_transposing,
+ 'I': get_num_instruments,
+ }
+
+
+script_table = {
+'v': '\\upbow',
+'n': '\\downbow',
+'o': '\\harmonic',
+'0': '"openstring',
+'Q': '\\thumb',
+'>': '^',
+'V': '^',
+'.': '.',
+'_': '-',
+'=': '"det leg"',
+'i': '|',
+'s': '"\\\\textsharp"',
+'n': '"\\\\textnatural"',
+'b': '"\\\\textflat"',
+'F': '\\fermata',
+'E': '\\fermata',
+}
+
+class Attribute_set:
+ def __init__ (self, dict):
+ self.dict = dict
+ def dump (self):
+ return ''
+
+class Chord:
+ def __init__ (self):
+ self.pitches = []
+ self.grace = 0
+ self.cue = 0
+ self.slurstart = []
+ self.slurstop = []
+ self.scripts = []
+ self.syllables = []
+ self.dots = 0
+ self.basic_duration = 4
+ self.tied = 0
+
+ self.note_suffix = self.note_prefix = ''
+ self.chord_suffix = self.chord_prefix = ''
+
+ def add_script (self,s):
+ self.scripts.append (s)
+ def set_duration (self, d):
+ self.basic_duration = d
+ def add_syllable (self, s):
+ self.syllables.append (s)
+ def add_pitch (self,t):
+ self.pitches.append (t)
+
+ def dump (self):
+ str = ''
+
+ sd = ''
+ if self.basic_duration == 0.5:
+ sd = '\\breve'
+ else:
+ sd = '%d' % self.basic_duration
+
+ sd = sd + '.' * self.dots
+ for p in self.pitches:
+ if str:
+ str = str + ' '
+ str = str + pitch_to_lily_string (p) + sd
+
+ for s in self.scripts:
+ str = str + '-' + s
+
+ str = self.note_prefix +str + self.note_suffix
+
+ if len (self.pitches) > 1:
+ str = '<%s>' % str
+ elif len (self.pitches) == 0:
+ str = 'r' + sd
+
+ str = self.chord_prefix + str + self.chord_suffix
+
+ return str
+
+class Parser:
+ def append_entry (self, e):
+ self.entries.append (e)
+ def append_chord (self,c ):
+ self.chords.append (c)
+ self.entries.append (c)
+ def last_chord (self):
+ return self.chords[-1]
+ def __init__ (self, fn):
+ self.divs_per_q = 1
+ self.header_dict = {
+ 'tagline' :'automatically converted from Musedata',
+ 'copyright' : 'all rights reserved -- free for noncommercial use'
+ # musedata license (argh)
+ }
+ self.entries = []
+ self.chords = []
+
+ lines = open (fn).readlines ()
+ lines = self.parse_header (lines)
+ lines = self.append_lines (lines)
+ str = string.join (lines, '\n')
+ lines = re.split ('[\n\r]+', str)
+ self.parse_body (lines)
+
+ def parse_header (self, lines):
+ enter = string.split (lines[3], ' ')
+ self.header_dict['enteredby'] = string.join (enter[1:])
+ self.header_dict['enteredon'] = enter[0]
+ self.header_dict['opus'] = lines[4]
+ self.header_dict['source'] = lines[5]
+ self.header_dict['title'] = lines[6]
+ self.header_dict['subtitle'] = lines[7]
+ self.header_dict['instrument']= lines[8]
+ self.header_dict['musedatamisc'] =lines[9]
+ self.header_dict['musedatagroups'] =lines[10]
+ self.header_dict['musedatagroupnumber']=lines[11]
+ lines = lines[12:]
+ comment = 0
+ while lines:
+ if lines[0][0] == '$':
+ break
+ lines = lines[1:]
+ return lines
+
+ def parse_musical_attributes (self,l):
+ atts = re.split('([A-Z][0-9]?):', l)
+ atts = atts[1:]
+ found = {}
+ while len (atts):
+ id = atts[0]
+ val = atts[1]
+ atts = atts[2:]
+ found[id] = val
+
+ try:
+ self.divs_per_q = string.atoi (found['Q'])
+ except KeyError:
+ pass
+
+ self.append_entry (Attribute_set (found))
+ def append_entry (self, e):
+ self.entries.append (e)
+
+ def parse_line_comment (self,l):
+ pass
+
+ def parse_note_line (self,l):
+ ch = None
+ if verbose:
+ print DIGITS+DIGITS+DIGITS
+ print l
+ pi = l[0:5]
+ di = l[5:8]
+ tied = l[8:9] == '-'
+
+ cue = grace = 0
+ if (pi[0] == 'g'):
+ grace = 1
+ pi = pi[1:]
+ elif (pi[0] == 'c'):
+ cue = 1
+ pi = pi[1:]
+
+ if pi[0] == ' ':
+ ch = self.last_chord ()
+ pi = pi[1:]
+ else:
+ ch = Chord ()
+ self.append_chord (ch)
+
+
+ ch.cue = ch.cue or cue
+ ch.grace = ch.grace or grace
+
+ while pi[0] in SPACES:
+ pi = pi[1:]
+
+ if pi[0] <> 'r':
+ name = ((ord (pi[0]) -ord('A')) + 5) % 7
+ alter = 0
+ pi = pi[1:]
+ while pi and pi[0] in '#f':
+ if pi[0] == '#':
+ alter = alter + 1
+ else:
+ alter = alter - 1
+ pi = pi[1:]
+
+ oct = string.atoi (pi) - 3
+
+ pittup = (oct, name ,alter)
+ ch.add_pitch (pittup)
+
+ base_dur = None
+ if ch.cue or ch.grace:
+ c = di[2]
+ if c == '0':
+ ch.accaciatura = 1
+ elif c == 'A':
+ base_dur = 0.5
+ else:
+ base_dur = 1 << (9 - (ord (c) - ord ('0')))
+ else:
+ base_dur = (4 * self.divs_per_q) / string.atoi (di)
+ ch.set_duration (base_dur)
+
+ ch.tied = ch.tied or tied
+ dots = 0
+
+
+ if l[18:19] == '.':
+ dots = 1
+ elif l[18:19] == ':':
+ dots = 2
+
+ if l[26:27] == '[':
+ ch.start_beam = 1
+ elif l[26:27] == ']':
+ ch.end_beam = 1
+
+
+ additional = l[32:44]
+ for c in additional:
+ try:
+ s = list('([{z').index (c)
+ ch.slurstart.append( s)
+ sluropen = list(')]}x').index (c)
+ ch.slurstop.append( s)
+ except ValueError:
+ pass
+ if c == '*':
+ ch.start_tuplet = 1
+ continue
+ elif c == '!':
+ ch.stop_tuplet = 1
+ continue
+
+ if c in DIGITS:
+ ch.add_script (c)
+ continue
+
+ if c == ' ' :
+ continue
+
+ try:
+ scr = script_table[c]
+ ch.add_script (scr)
+ c = None
+ except KeyError:
+ sys.stderr.write ("\nFixme: script `%s' not done\n" % c)
+
+ text = l[40:81]
+ sylls = string.split (text,'|')
+
+ for syl in sylls:
+ ch.add_syllable (syl)
+
+
+ def parse_measure_line (self,l):
+ pass
+
+
+ def parse_duration (l):
+ s = ''
+ while l[0] in '0123456789':
+ s = s + l[0]
+ l= l[1:]
+ print l
+ num = string.atoi (s)
+ den = 4 * divisions
+
+ current_dots = 0
+ try_dots = [3, 2, 1]
+ for d in try_dots:
+ f = 1 << d
+ multiplier = (2*f-1)
+ if num % multiplier == 0 and den % f == 0:
+ num = num / multiplier
+ den = den / f
+ current_dots = current_dots + d
+
+ if num <> 1:
+ sys.stderr.write ('huh. Durations left')
+ return '%s%s' % (den, '.' * current_dots)
+
+ def append_lines (self,ls):
+ nls = []
+ for l in ls:
+ if l[0] == 'a':
+ nls[-1] = nls[-1]+l[1:]
+ else:
+ nls.append(l)
+ return nls
+ def dump (self):
+ s = ''
+ ln = ''
+ for e in self.entries:
+
+ next = ' ' + e.dump()
+ if len (ln) + len (next) > 72:
+ s = s +ln + '\n'
+ ln = ''
+ ln = ln + next
+
+ s = s + ln
+
+ s = '\\notes {\n %s \n}' % s
+ return s
+
+ def parse_body (self,lines):
+ comment_switch = 0
+ for l in lines:
+
+
+ c = l[0]
+ if c == '&':
+ comment_switch = not comment_switch
+ continue
+
+ if comment_switch:
+ continue
+
+ if 0:
+ pass
+ elif c == '$':
+ self.parse_musical_attributes (l)
+ elif c == '@':
+ self.parse_line_comment (l)
+ elif c == '*':
+ self.parse_musical_directions (l)
+ elif c in 'ABCDEFGr ':
+ self.parse_note_line (l)
+ elif c == 'm':
+ self.parse_measure_line (l)
+ elif c == '/':
+ break
+ elif c in 'PS':
+ pass # ignore sound & print
+ else:
+ sys.stderr.write ("\nUnrecognized record `%s'\n"% l)
+
+
+
+
+
+def help ():
+ sys.stdout.write (
+"""Usage: musedata2ly [OPTION]... FILE1 [FILE2 ...]
+
+Convert musedata to LilyPond.
+
+Options:
+ -h,--help this help
+ -o,--output=FILE set output filename to FILE
+ -v,--version version information
+ -r,--ref=REF read background information from ref-file REF
+
+Musedata (http://www.ccarh.org/musedata/) is an electronic library of
+classical music scores, currently comprising XXX scores. The music is
+encoded in so-called Musedata format
+(http://www.ccarh.org/publications/books/beyondmidi/online/musedata).
+musedata2ly converts a set of musedata files to one .ly file, and will
+include a \header field if a .ref file is supplied
+
+Report bugs to bug-gnu-music@gnu.org.
+
+Written by Han-Wen Nienhuys <hanwen@cs.uu.nl>
+""")
+
+
+def print_version ():
+ sys.stdout.write ("""musedata2ly (GNU LilyPond) %s
+
+This is free software. It is covered by the GNU General Public License,
+and you are welcome to change it and/or distribute copies of it under
+certain conditions. Invoke as `midi2ly --warranty' for more information.
+
+Copyright (c) 2000 by Han-Wen Nienhuys <hanwen@cs.uu.nl>
+""" % version)
+def identify():
+ sys.stderr.write ("%s from LilyPond %s\n" % (program_name, version))
+
+
+
+(options, files) = getopt.getopt (sys.argv[1:], 'r:vo:h', ['ref=', 'help','version', 'output='])
+out_filename = None
+ref_file = None
+for opt in options:
+ o = opt[0]
+ a = opt[1]
+ if o== '--help' or o == '-h':
+ help ()
+ sys.exit (0)
+ elif o == '--version' or o == '-v':
+ print_version ()
+ sys.exit(0)
+ elif o == '--ref' or o == '-r':
+ ref_file = a
+ elif o == '--output' or o == '-o':
+ out_filename = a
+ else:
+ print o
+ raise getopt.error
+
+identify()
+
+
+
+ly = ''
+
+
+found_ids = ''
+for f in files:
+ if f == '-':
+ f = ''
+
+ sys.stderr.write ('Processing `%s\'\n' % f)
+
+ e = Parser(f)
+
+ id = os.path.basename (f)
+ id = re.sub ('[^a-zA-Z0-9]', 'x', id)
+ id = 'voice%s' % id
+ ly =ly + '\n\n%s = \\context Staff = "%s" %s\n\n' % (id, id, e.dump ())
+
+ found_ids = found_ids + '\\%s\n' % id
+
+found_ids = '\n\n\n\\score { < %s > } ' % found_ids
+
+ly_head = ''
+if ref_file:
+ head = Ref_parser (ref_file)
+ if not out_filename:
+ t = ''
+ st = ''
+ try:
+ t = head.dict['title']
+ st= head.dict['subtitle']
+ except KeyError:
+ pass
+
+ t = t + '-' +st
+
+ t = re.sub ("^ +(.*) +$", r"\1", t)
+ t = re.sub ("\\.", '', t)
+ out_filename = re.sub ('[^a-zA-Z0-9-]', '-', t)
+ out_filename = out_filename+ '.ly'
+ ly_head = head.dump ()
+
+if not out_filename:
+ out_filename = 'musedata.ly'
+
+sys.stderr.write ('Writing `%s\'\n' % out_filename)
+
+fo = open (out_filename, 'w')
+fo.write ('%% lily was here -- automatically converted by musedata.ly\n')
+fo.write(ly_head + ly + found_ids)
+fo.close ()
+
--- /dev/null
+#!@PYTHON@
+
+# (urg! wat een pokkeformaat (pokkenformaat?))
+import os
+import string
+import sys
+import re
+import getopt
+
+program_name = 'pmx2ly'
+version = '@TOPLEVEL_VERSION@'
+if version == '@' + 'TOPLEVEL_VERSION' + '@':
+ version = '(unknown version)' # uGUHGUHGHGUGH
+
+
+def encodeint (i):
+ return chr ( i + ord ('A'))
+
+def stripcomment (l):
+ return re.sub ('[ \t]*%.*$\n', '', l)
+
+def stripwhite (l):
+ return re.sub ('[ \n\t]+', ' ', l)
+
+def stripeols (l):
+ return re.sub ('^ ', '', re.sub (' $', '', l))
+
+actab = {-2: 'eses', -1: 'es', 0 : '', 1: 'is', 2:'isis'}
+
+def pitch_to_lily_string (tup):
+ (o,n,a) = tup
+
+ nm = chr((n + 2) % 7 + ord ('a'))
+ nm = nm + actab[a]
+ if o > 0:
+ nm = nm + "'" * o
+ elif o < 0:
+ nm = nm + "," * -o
+ return nm
+
+def gcd (a,b):
+ if b == 0:
+ return a
+ c = a
+ while c:
+ c = a % b
+ a = b
+ b = c
+ return a
+
+def rat_simplify (r):
+ (n,d) = r
+ if d < 0:
+ d = -d
+ n = -n
+ if n == 0:
+ return (0,1)
+ else:
+ g = gcd (n, d)
+ return (n/g, d/g)
+
+def rat_multiply (a,b):
+ (x,y) = a
+ (p,q) = b
+
+ return rat_simplify ((x*p, y*q))
+
+def rat_divide (a,b):
+ (p,q) = b
+ return rat_multiply (a, (q,p))
+
+tuplet_table = {
+ 2: 3,
+ 3: 2,
+ 5: 4
+}
+
+
+def rat_add (a,b):
+ (x,y) = a
+ (p,q) = b
+
+ return rat_simplify ((x*q + p*y, y*q))
+
+def rat_neg (a):
+ (p,q) = a
+ return (-p,q)
+
+
+def rat_larger (a,b):
+ return rat_subtract (a, b )[0] > 0
+
+def rat_subtract (a,b ):
+ return rat_add (a, rat_neg (b))
+
+def rat_to_duration (frac):
+ log = 1
+ d = (1,1)
+ while rat_larger (d, frac):
+ d = rat_multiply (d, (1,2))
+ log = log << 1
+
+ frac = rat_subtract (frac, d)
+ dots = 0
+ if frac == rat_multiply (d, (1,2)):
+ dots = 1
+ elif frac == rat_multiply (d, (3,4)):
+ dots = 2
+ return (log, dots)
+
+
+class Barcheck :
+ def __init__ (self):
+ pass
+ def dump (self):
+ return '|\n'
+
+class Beam:
+ def __init__ (self, ch):
+ self.char = ch
+ def dump (self):
+ return self.char
+
+class Slur:
+ def __init__ (self,id):
+ self.id = id
+ self.start_chord = None
+ self.end_chord = None
+ def calculate (self):
+ s =self.start_chord
+ e= self.end_chord
+
+ if e and s:
+ s.note_suffix = s.note_suffix + '('
+ e.note_prefix = ')' + e.note_prefix
+ else:
+ sys.stderr.write ("\nOrphaned slur")
+
+class Voice:
+ def __init__ (self):
+ self.entries = []
+ self.chords = []
+ self.staff = None
+ self.current_slurs = []
+ self.slurs = []
+ def toggle_slur (self, id):
+
+ for s in self.current_slurs:
+ if s.id == id:
+ self.current_slurs.remove (s)
+ s.end_chord = self.chords[-1]
+ return
+ s = Slur (id)
+ s.start_chord = self.chords[-1]
+ self.current_slurs.append (s)
+ self.slurs.append (s)
+
+ def last_chord (self):
+ return self.chords[-1]
+ def add_chord (self, ch):
+ self.chords.append (ch)
+ self.entries.append (ch)
+ def add_nonchord (self, nch):
+ self.entries.append (nch)
+
+ def idstring (self):
+ return 'staff%svoice%s ' % (encodeint (self.staff.number) , encodeint(self.number))
+ def dump (self):
+ str = ''
+ ln = ''
+ for e in self.entries:
+ next = ' ' + e.dump ()
+ if next[-1] == '\n':
+ str = str + ln + next
+ ln = ''
+ continue
+
+ if len (ln) +len (next) > 72:
+ str = str+ ln + '\n'
+ ln = ''
+ ln = ln + next
+
+
+ str = str + ln
+ id = self.idstring ()
+
+ str = '%s = \\notes { \n %s }\n '% (id, str)
+ return str
+ def calculate_graces (self):
+ lastgr = 0
+ lastc = None
+ for c in self.chords:
+ if c.grace and not lastgr:
+ c.chord_prefix = c.chord_prefix + '\\grace { '
+ elif not c.grace and lastgr:
+ lastc.chord_suffix = lastc.chord_suffix + ' } '
+ lastgr = c.grace
+ lastc = c
+ def calculate (self):
+ self.calculate_graces ()
+ for s in self.slurs:
+ s.calculate ()
+
+class Clef:
+ def __init__ (self, cl):
+ self.type = cl
+ def dump(self):
+ return '\\clef %s;' % self.type
+
+clef_table = {
+ 'b':'bass' ,
+ 'r':'baritone',
+ 'n':'tenor',
+ 'a':'alto',
+ 'm':'mezzosoprano',
+ 's':'soprano',
+ 't':'treble',
+ 'f':'frenchviolin',
+ }
+class Staff:
+ def __init__ (self):
+ self.voices = (Voice (), Voice())
+ self.clef = None
+ self.instrument = 0
+ self.voice_idx = 0
+ self.number = None
+
+ i = 0
+ for v in self.voices:
+ v.staff = self
+ v.number = i
+ i = i+1
+ def set_clef (self, letter):
+
+ clstr = clef_table[letter]
+ self.voices[0].add_nonchord (Clef (clstr))
+
+ def current_voice (self):
+ return self.voices[self.voice_idx]
+ def next_voice (self):
+ self.voice_idx = (self.voice_idx + 1)%len (self.voices)
+
+ def calculate (self):
+ for v in self.voices:
+ v.calculate ()
+ def idstring (self):
+ return 'staff%s' % encodeint (self.number)
+ def dump (self):
+ str = ''
+
+ refs = ''
+ for v in self.voices:
+ str = str + v.dump()
+ refs = refs + '\\' + v.idstring ()+ ' '
+
+ str = str + '\n\n%s = \\context Staff = %s \n < \n %s >\n\n\n'% (self.idstring (), self.idstring (), refs)
+ return str
+
+class Tuplet:
+ def __init__ (self, number, base, dots):
+ self.chords = []
+ self.number = number
+ self.replaces = tuplet_table[number]
+ self.base = base
+ self.dots = dots
+
+ length = (1,base)
+ if dots == 1:
+ length = rat_multiply (length, (3,2))
+ elif dots == 2:
+ length = rat_multiply (length, (7,4))
+
+ length = rat_multiply (length, (1,self.replaces))
+
+ (nb,nd) =rat_to_duration (length)
+
+ self.note_base = nb
+ self.note_dots = nd
+
+ def add_chord (self, ch):
+ ch.dots = self.note_dots
+ ch.basic_duration = self.note_base
+ self.chords.append (ch)
+
+ if len (self.chords) == 1:
+ ch.chord_prefix = '\\times %d/%d { ' % (self.replaces, self.number)
+ elif len (self.chords) == self.number:
+ ch.chord_suffix = ' }'
+
+class Chord:
+ def __init__ (self):
+ self.pitches = []
+ self.dots = 0
+ self.basic_duration = 0
+ self.scripts = []
+ self.grace = 0
+ self.chord_prefix = ''
+ self.chord_suffix = ''
+ self.note_prefix = ''
+ self.note_suffix = ''
+
+ def dump (self):
+ str = ''
+
+ sd = ''
+ if self.basic_duration == 0.5:
+ sd = '\\breve'
+ else:
+ sd = '%d' % self.basic_duration
+ sd = sd + '.' * self.dots
+ for p in self.pitches:
+ if str:
+ str = str + ' '
+ str = str + pitch_to_lily_string (p) + sd
+
+ for s in self.scripts:
+ str = str + '-' + s
+
+ str = self.note_prefix +str + self.note_suffix
+
+ if len (self.pitches) > 1:
+ str = '<%s>' % str
+ elif len (self.pitches) == 0:
+ str = 'r' + sd
+
+ str = self.chord_prefix + str + self.chord_suffix
+
+ return str
+
+SPACE=' \t\n'
+DIGITS ='0123456789'
+basicdur_table = {
+ 9: 0.5,
+ 0: 0 ,
+ 2: 2 ,
+ 4: 4 ,
+ 8: 8 ,
+ 1: 16,
+ 3: 32,
+ 6: 64
+ }
+
+
+ornament_table = {
+ 't': '\\prall',
+ 'm': '\\mordent',
+ 'x': '"x"',
+ '+': '+',
+ 'u': '"pizz"',
+ 'p': '|',
+ '(': '"paren"',
+ ')': '"paren"',
+ 'g': '"segno"',
+ '.': '.',
+ 'fd': '\\fermata',
+ 'f': '\\fermata',
+ '_': '-',
+ 'T': '\\trill',
+ '>': '>',
+ '^': '^',
+ }
+
+class Parser:
+ def __init__ (self, filename):
+ self.staffs = []
+ self.forced_duration = None
+ self.last_name = 0
+ self.last_oct = 0
+ self.tuplets_expected = 0
+ self.tuplets = []
+ self.last_basic_duration = 4
+
+ self.parse (filename)
+
+ def set_staffs (self, number):
+ self.staffs = map (lambda x: Staff (), range(0, number))
+
+ self.staff_idx = 0
+
+ i =0
+ for s in self.staffs:
+ s.number = i
+ i = i+1
+ def current_staff (self):
+ return self.staffs[self.staff_idx]
+
+ def current_voice (self):
+ return self.current_staff ().current_voice ()
+
+ def next_staff (self):
+ self.staff_idx = (self.staff_idx + 1)% len (self.staffs)
+
+ def parse_note (self, str):
+ name = None
+ ch = None
+
+ grace = 0
+ if str[0] == 'G':
+ grace = 1
+ str = str[1:]
+
+ if str[0] == 'z':
+ ch = self.current_voice().last_chord()
+ str = str[1:]
+ else:
+ ch = Chord ()
+ self.current_voice().add_chord (ch)
+ if str[0] <> 'r':
+ name = (ord (str[0]) - ord('a') + 5) % 7
+
+ str = str[1:]
+
+ ch.grace = ch.grace or grace
+
+ forced_duration = 0
+ alteration = 0
+ dots = 0
+ oct = None
+ durdigit = None
+ multibar = 0
+ tupnumber = 0
+ extra_oct = 0
+ while str[0] in 'dsfmnul0123456789.,+-':
+ c = str[0]
+ str = str[1:]
+ if c == 'f':
+ alteration = alteration -1
+ elif c == 'n':
+ alteration = 0
+ elif c == 'm':
+ multibar = 1
+ elif c == 's':
+ alteration = alteration +1
+ elif c == 'd':
+ dots = dots + 1
+ elif c in DIGITS and durdigit == None and \
+ self.tuplets_expected == 0:
+ durdigit = string.atoi (c)
+ elif c in DIGITS:
+ oct = string.atoi (c) - 3
+ elif c == '+':
+ extra_oct = extra_oct + 1
+ elif c == '-':
+ extra_oct = extra_oct - 1
+ elif c == '.':
+ dots = dots+ 1
+ forced_duration = 2
+ elif c == ',':
+ forced_duration = 2
+
+ if str[0] == 'x':
+ str = str[1:]
+ tupnumber = string.atoi (str[0])
+ str = str[1:]
+ str=re.sub (r'^n?f?[+-0-9.]+', '' , str)
+
+
+ if durdigit:
+ try:
+ basic_duration = basicdur_table[durdigit]
+ self.last_basic_duration = basic_duration
+ except KeyError:
+ sys.stderr.write ("""
+Huh? expected duration, found %d Left was `%s'""" % (durdigit, str[:20]))
+
+ basic_duration = 4
+ else:
+ basic_duration = self.last_basic_duration
+
+
+
+ if name <> None and oct == None:
+ e = 0
+ if self.last_name < name and name -self.last_name > 3:
+ e = -1
+ elif self.last_name > name and self.last_name -name > 3:
+ e = 1
+
+ oct = self.last_oct +e + extra_oct
+
+ if name <> None:
+ self.last_oct = oct
+ self.last_name = name
+
+ if name <> None:
+ ch.pitches.append ((oct, name, alteration))
+
+ # do before adding to tuplet.
+ ch.basic_duration = basic_duration
+ ch.dots = dots
+
+ if forced_duration:
+ self.forced_duration = ch.basic_duration / forced_duration
+
+ if tupnumber:
+ tup =Tuplet (tupnumber, basic_duration, dots)
+ self.tuplets_expected = tupnumber
+ self.tuplets.append (tup)
+
+ if self.tuplets_expected > 0:
+ self.tuplets[-1].add_chord (ch)
+ self.tuplets_expected = self.tuplets_expected - 1
+
+ return str
+ def parse_basso_continuo (self, str):
+ while str[0] in DIGITS +'#n-':
+ scr = str[0]
+
+ if scr == '#':
+ scr = '\\\\textsharp'
+
+ if len(scr)>1 or scr not in DIGITS:
+ scr = '"%s"' % scr
+
+ self.current_voice().last_chord ().scripts.append (scr)
+ str=str[1:]
+ return str
+ def parse_beams (self,str):
+ c = str[0]
+ # self.current_voice().add_nonchord (Beam(c))
+ if str[0] == '[':
+ str = str[1:]
+ while str[0] in '+-0123456789':
+ str=str[1:]
+ else:
+ str = str[1:]
+
+ return str
+
+ def clean (self, ls):
+ ls = map (stripcomment, ls)
+ ls = map (stripwhite, ls)
+ ls = map (stripeols, ls)
+
+
+ ls = filter (lambda x: x <> '', ls)
+ return ls
+
+ def parse_header (self, ls):
+
+ opening = ls[0]
+ ls = ls[1:]
+
+
+ opening = map (string.atoi, re.split ('[\t ]+', opening))
+
+ (no_staffs, no_instruments, timesig_num,timesig_den, ptimesig_num,
+ ptimesig_den, pickup_beats,keysig_number) = tuple (opening)
+
+ opening = ls[0]
+ ls = ls[1:]
+
+ # ignore this.
+ # opening = map (string.atoi, re.split ('[\t ]+', opening))
+ # (no_pages,no_systems, musicsize, fracindent) = tuple (opening)
+
+ instruments = []
+ while len (instruments) < no_instruments:
+ instruments.append (ls[0])
+ ls = ls[1:]
+
+
+ l = ls[0]
+ ls = ls[1:]
+
+
+ self.set_staffs (no_staffs)
+ for s in self.staffs:
+ s.set_clef(l[0])
+ l = l[1:]
+
+ # dump path
+ ls = ls[1:]
+
+ # dump more ?
+ ls = ls[2:]
+
+ return ls
+
+ def parse_ornament (self, left):
+ left = left[1:]
+ e = self.current_voice ().last_chord ()
+
+ id = left[0]
+ left = left[1:]
+ if left[0] == 'd':
+ id = id +'d'
+ left = left [1:]
+
+ orn = '"orn"'
+ try:
+ orn = ornament_table[id]
+ except KeyError:
+ sys.stderr.write ("unknown ornament `%s'\n" % id)
+
+ e.scripts.append (orn)
+ return left
+ def parse_barcheck (self, left):
+ self.current_voice ().add_nonchord (Barcheck ())
+
+ return left [1:]
+
+ def parse_slur (self, left):
+ left = left[1:]
+
+ id = None
+
+ if re.match ('[A-Z0-9]', left[0]):
+ id = left[0]
+ left= left[1:]
+ while left[0] in 'uld0123456789+-.':
+ left= left[1:]
+
+ self.current_voice ().toggle_slur (id)
+ return left
+
+ def parse_mumbo_jumbo (self,left):
+ left = left[1:]
+ while left and left[0] <> '\\':
+ left = left[1:]
+
+ left = left[1:]
+ return left
+ def parsex (self,left):
+ left = left[1:]
+ while left[0] in DIGITS:
+ left = left[1:]
+
+ return left
+
+ def parse_body (self, left):
+ left = re.sub ('[ \t\n]+', ' ', left)
+
+ while left:
+ c = left[0]
+ if c in 'Gzabcdefgr':
+ left = self.parse_note (left)
+ elif c in DIGITS + 'n#-':
+ left = self.parse_basso_continuo (left)
+ elif c in SPACE:
+ left = left[1:]
+ elif c == 's':
+ left = self.parse_slur (left)
+ elif c == '|':
+ left = self.parse_barcheck (left)
+ elif c == 'o':
+ left = self.parse_ornament (left)
+ elif c == 'x':
+ left = self.parsex (left)
+ elif c in "[]":
+ left = self.parse_beams (left)
+ elif left[:2] == "//":
+ self.current_staff().next_voice ()
+ left = left[2:]
+ elif c == '/':
+ self.next_staff ()
+ left = left[1:]
+ elif c == '\\':
+ left = self.parse_mumbo_jumbo(left)
+ else:
+ sys.stderr.write ("""
+Huh? Unknown directive `%s', before `%s'""" % (c, left[:20] ))
+ left = left[1:]
+
+ for c in self.staffs:
+ c.calculate ()
+
+ def dump (self):
+ str = ''
+
+ refs = ''
+ for s in self.staffs:
+ str = str + s.dump ()
+ refs = '\\' + s.idstring() + refs
+
+ str = str + "\n\n\\score { <\n %s\n > }" % refs
+ return str
+
+
+ def parse (self,fn):
+ ls = open (fn).readlines ()
+ ls = self.clean (ls)
+ ls = self.parse_header (ls)
+ left = string.join (ls, ' ')
+ self.parse_body (left)
+
+
+
+
+def help ():
+ sys.stdout.write (
+"""Usage: pmx2ly [OPTION]... PMX-FILE
+
+Convert PMX to LilyPond.
+
+Options:
+ -h, --help this help
+ -o, --output=FILE set output filename to FILE
+ -v, --version version information
+
+PMX is a Musixtex preprocessor written by Don Simons, see
+http://www.gmd.de/Misc/Music/musixtex/software/pmx/
+
+Report bugs to bug-gnu-music@gnu.org.
+
+Written by Han-Wen Nienhuys <hanwen@cs.uu.nl>
+""")
+
+
+def print_version ():
+ sys.stdout.write ("""pmx2ly (GNU LilyPond) %s
+
+This is free software. It is covered by the GNU General Public License,
+and you are welcome to change it and/or distribute copies of it under
+certain conditions. Invoke as `midi2ly --warranty' for more information.
+
+Copyright (c) 2000 by Han-Wen Nienhuys <hanwen@cs.uu.nl>
+""" % version)
+def identify():
+ sys.stderr.write ("%s from LilyPond %s\n" % (program_name, version))
+
+
+
+(options, files) = getopt.getopt (sys.argv[1:], 'vo:h', ['help','version', 'output='])
+out_filename = None
+for opt in options:
+ o = opt[0]
+ a = opt[1]
+ if o== '--help' or o == '-h':
+ help ()
+ sys.exit (0)
+ if o == '--version' or o == '-v':
+ print_version ()
+ sys.exit(0)
+
+ if o == '--output' or o == '-o':
+ out_filename = a
+ else:
+ print o
+ raise getopt.error
+
+identify()
+
+for f in files:
+ if f == '-':
+ f = ''
+
+ sys.stderr.write ('Processing `%s\'\n' % f)
+ e = Parser(f)
+ if not out_filename:
+ out_filename = os.path.basename (re.sub ('(?i).pmx$', '.ly', f))
+
+ if out_filename == f:
+ out_filename = os.path.basename (f + '.ly')
+
+ sys.stderr.write ('Writing `%s\'' % out_filename)
+ ly = e.dump()
+
+
+
+ fo = open (out_filename, 'w')
+ fo.write ('%% lily was here -- automatically converted by pmx2ly from %s\n' % f)
+ fo.write(ly)
+ fo.close ()
+
+