3 # musedata = musedata.stanford.edu
4 # musedata = COBOL for musicians.
12 # * multiple voices (they use `Backspace' (shudder)
17 # I completely forgot how this was supposed to work --hwn 5/2002
26 program_name
= 'musedata2ly'
27 version
= '@TOPLEVEL_VERSION@'
28 if version
== '@' + 'TOPLEVEL_VERSION' + '@':
29 version
= '(unknown version)' # uGUHGUHGHGUGH
40 'END': 'encodingdate',
46 'YEN': 'encodingcountry',
50 'ENC': 'musedataencoder',
52 'AFT': 'musedatastage'
57 def __init__ (self
, fn
):
60 ls
= open (fn
).readlines ()
64 m
= re
.match('!!!([A-Z]+):[ \t]+(.*)$',l
)
68 val
= re
.sub ('[ \t]+', ' ', val
)
71 key
=ref_header_dict
[key
]
73 sys
.stderr
.write ('\nUnknown ref key \`%s\'' % key
)
84 for (k
,v
) in self
.dict.items ():
85 str = str +' %s = "%s"\n' % (k
,v
)
86 str = '\\header {\n%s}' % str
92 actab
= {-2: 'eses', -1: 'es', 0 : '', 1: 'is', 2:'isis'}
94 def pitch_to_lily_string (tup
):
97 nm
= chr((n
+ 2) % 7 + ord ('a'))
110 return '\\time %s\n' % s
114 def get_divisions_per_quarter (s
):
115 divisions
= string
.atoi (s
)
118 def get_directive (s
):
121 def get_transposing (s
):
124 def get_num_instruments (s
):
127 def get_lilypond_notename (p
, ac
):
130 s
= chr (p
+ ord ('c'))
144 DIGITS
= "0123456789"
156 'Q' : get_divisions_per_quarter
,
158 'X' : get_transposing
,
159 'I': get_num_instruments
,
163 def __init__ (self
, dict):
167 if self
. dict.has_key ('T'):
168 s
= s
+ get_timesig (self
.dict['T'])
185 's': '"\\\\textsharp"',
186 'n': '"\\\\textnatural"',
187 'b': '"\\\\textflat"',
203 self
.basic_duration
= 4
206 self
.note_suffix
= self
.note_prefix
= ''
207 self
.chord_suffix
= self
.chord_prefix
= ''
209 def add_script (self
,s
):
210 self
.scripts
.append (s
)
211 def set_duration (self
, d
):
212 self
.basic_duration
= d
213 def add_syllable (self
, s
):
214 self
.syllables
.append (s
)
215 def add_pitch (self
,t
):
216 self
.pitches
.append (t
)
222 if self
.basic_duration
== 0.5:
225 sd
= '%d' % self
.basic_duration
227 sd
= sd
+ '.' * self
.dots
229 str = ')' * len (self
.slurstart
) + str
231 for p
in self
.pitches
:
234 str = str + pitch_to_lily_string (p
) + sd
235 str = str + '(' * len (self
.slurstart
)
238 for s
in self
.scripts
:
241 str = self
.note_prefix
+str + self
.note_suffix
243 if len (self
.pitches
) > 1:
245 elif len (self
.pitches
) == 0:
248 str = self
.chord_prefix
+ str + self
.chord_suffix
257 def append_entry (self
, e
):
258 self
.entries
.append (e
)
259 def append_chord (self
,c
):
260 self
.chords
.append (c
)
261 self
.entries
.append (c
)
262 def last_chord (self
):
263 return self
.chords
[-1]
264 def __init__ (self
, fn
):
267 'tagline' :'automatically converted from Musedata',
268 'copyright' : 'all rights reserved -- free for noncommercial use'
269 # musedata license (argh)
275 lines
= open (fn
).readlines ()
276 lines
= map (lambda x
: re
.sub ("\r$", '', x
), lines
)
277 lines
= self
.parse_header (lines
)
278 lines
= self
.append_lines (lines
)
279 str = string
.join (lines
, '\n')
280 lines
= re
.split ('[\n\r]+', str)
281 self
.parse_body (lines
)
283 def parse_header (self
, lines
):
284 enter
= string
.split (lines
[3], ' ')
285 self
.header_dict
['enteredby'] = string
.join (enter
[1:])
286 self
.header_dict
['enteredon'] = enter
[0]
287 self
.header_dict
['opus'] = lines
[4]
288 self
.header_dict
['source'] = lines
[5]
289 self
.header_dict
['title'] = lines
[6]
290 self
.header_dict
['subtitle'] = lines
[7]
291 self
.header_dict
['instrument']= lines
[8]
292 self
.header_dict
['musedatamisc'] =lines
[9]
293 self
.header_dict
['musedatagroups'] =lines
[10]
294 self
.header_dict
['musedatagroupnumber']=lines
[11]
298 if lines
[0][0] == '$':
303 def parse_musical_attributes (self
,l
):
304 atts
= re
.split('([A-Z][0-9]?):', l
)
314 self
.divs_per_q
= string
.atoi (found
['Q'])
318 self
.append_entry (Attribute_set (found
))
319 def append_entry (self
, e
):
320 self
.entries
.append (e
)
322 def parse_line_comment (self
,l
):
325 def parse_note_line (self
,l
):
328 print DIGITS
+DIGITS
+DIGITS
343 ch
= self
.last_chord ()
347 self
.append_chord (ch
)
350 ch
.cue
= ch
.cue
or cue
351 ch
.grace
= ch
.grace
or grace
353 while pi
[0] in SPACES
:
357 name
= ((ord (pi
[0]) -ord('A')) + 5) % 7
360 while pi
and pi
[0] in '#f':
367 oct = string
.atoi (pi
) - 3
369 pittup
= (oct, name
,alter
)
370 ch
.add_pitch (pittup
)
381 if ch
.cue
or ch
.grace
:
388 base_dur
= 1 << (9 - (ord (c
) - ord ('0')))
396 base_dur
= (4 * self
.divs_per_q
* fact
[1]) / (string
.atoi (di
)* fact
[0])
397 ch
.set_duration (base_dur
)
399 ch
.tied
= ch
.tied
or tied
403 elif l
[26:27] == ']':
407 additional
= l
[32:44]
410 ch
.slurstart
.append( 0)
413 ch
.slurstop
.append( 0)
431 scr
= script_table
[c
]
435 sys
.stderr
.write ("\nFixme: script `%s' not done\n" % c
)
438 sylls
= string
.split (text
,'|')
441 ch
.add_syllable (syl
)
444 def parse_measure_line (self
,l
):
445 self
.append_entry (Measure_start())
448 def parse_duration (l
):
450 while l
[0] in '0123456789':
454 num
= string
.atoi (s
)
462 if num
% multiplier
== 0 and den
% f
== 0:
463 num
= num
/ multiplier
465 current_dots
= current_dots
+ d
468 sys
.stderr
.write ('huh. Durations left')
469 return '%s%s' % (den
, '.' * current_dots
)
471 def append_lines (self
,ls
):
475 nls
[-1] = nls
[-1]+l
[1:]
482 for e
in self
.entries
:
484 next
= ' ' + e
.dump()
485 if len (ln
) + len (next
) > 72:
492 s
= '\\notes {\n %s \n}' % s
495 def parse_body (self
,lines
):
503 comment_switch
= not comment_switch
512 self
.parse_musical_attributes (l
)
514 self
.parse_line_comment (l
)
516 self
.parse_musical_directions (l
)
517 elif c
in 'ABCDEFGr ':
518 self
.parse_note_line (l
)
520 self
.parse_measure_line (l
)
524 pass # ignore sound & print
526 sys
.stderr
.write ("\nUnrecognized record `%s'\n"% l
)
534 """Usage: musedata2ly [OPTION]... FILE1 [FILE2 ...]
536 Convert musedata to LilyPond.
540 -o,--output=FILE set output filename to FILE
541 -v,--version version information
542 -r,--ref=REF read background information from ref-file REF
544 Musedata (http://www.ccarh.org/musedata/) is an electronic library of
545 classical music scores, currently comprising XXX scores. The music is
546 encoded in so-called Musedata format
547 (http://www.ccarh.org/publications/books/beyondmidi/online/musedata).
548 musedata2ly converts a set of musedata files to one .ly file, and will
549 include a \header field if a .ref file is supplied
551 This converter is not complete -- this is left to the user as an excercise.
553 Report bugs to bug-lilypond@gnu.org.
555 Written by Han-Wen Nienhuys <hanwen@cs.uu.nl>
559 def print_version ():
560 sys
.stdout
.write ("""musedata2ly (GNU LilyPond) %s
562 This is free software. It is covered by the GNU General Public License,
563 and you are welcome to change it and/or distribute copies of it under
564 certain conditions. Invoke as `midi2ly --warranty' for more information.
566 Copyright (c) 2000--2002 by Han-Wen Nienhuys <hanwen@cs.uu.nl>
569 sys
.stderr
.write ("%s from LilyPond %s\n" % (program_name
, version
))
573 (options
, files
) = getopt
.getopt (sys
.argv
[1:], 'r:vo:h', ['verbose', 'ref=', 'help','version', 'output='])
579 if o
== '--help' or o
== '-h':
582 elif o
== '--version' or o
== '-v':
585 elif o
== '--ref' or o
== '-r':
587 elif o
== '--output' or o
== '-o':
589 elif o
== '--verbose' :
608 sys
.stderr
.write ('Processing `%s\'\n' % f
)
612 id = os
.path
.basename (f
)
613 id = re
.sub ('[^a-zA-Z0-9]', 'x', id)
616 return chr (ord (match
.group ()) - ord('0') + ord('A'))
618 id = re
.sub ('[0-9]', num2let
, id)
621 ly
=ly
+ '\n\n%s = \\context Staff = "%s" %s\n\n' % (id, id, e
.dump ())
623 found_ids
= found_ids
+ '\\%s\n' % id
625 found_ids
= '\n\n\n\\score { < %s > } ' % found_ids
629 head
= Ref_parser (ref_file
)
634 t
= head
.dict['title']
635 st
= head
.dict['subtitle']
641 t
= re
.sub ("^ +(.*) +$", r
"\1", t
)
642 t
= re
.sub ("\\.", '', t
)
643 out_filename
= re
.sub ('[^a-zA-Z0-9-]', '-', t
)
644 out_filename
= out_filename
+ '.ly'
645 ly_head
= head
.dump ()
648 out_filename
= 'musedata.ly'
650 sys
.stderr
.write ('Writing `%s\'\n' % out_filename
)
652 fo
= open (out_filename
, 'w')
653 fo
.write ('%% lily was here -- automatically converted by musedata.ly\n')
654 fo
.write(ly_head
+ ly
+ found_ids
)