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 for p
in self
.pitches
:
232 str = str + pitch_to_lily_string (p
)
234 if len (self
.pitches
) > 1:
236 elif len (self
.pitches
) == 0:
239 str = str + sd
+ '(' * len (self
.slurstart
) + ')' * len (self
.slurstart
)
240 for s
in self
.scripts
:
243 str = self
.note_prefix
+str + self
.note_suffix
244 str = self
.chord_prefix
+ str + self
.chord_suffix
252 def append_entry (self
, e
):
253 self
.entries
.append (e
)
254 def append_chord (self
,c
):
255 self
.chords
.append (c
)
256 self
.entries
.append (c
)
257 def last_chord (self
):
258 return self
.chords
[-1]
259 def __init__ (self
, fn
):
262 'tagline' :'automatically converted from Musedata',
263 'copyright' : 'all rights reserved -- free for noncommercial use'
264 # musedata license (argh)
270 lines
= open (fn
).readlines ()
271 lines
= map (lambda x
: re
.sub ("\r$", '', x
), lines
)
272 lines
= self
.parse_header (lines
)
273 lines
= self
.append_lines (lines
)
274 str = string
.join (lines
, '\n')
275 lines
= re
.split ('[\n\r]+', str)
276 self
.parse_body (lines
)
278 def parse_header (self
, lines
):
279 enter
= string
.split (lines
[3], ' ')
280 self
.header_dict
['enteredby'] = string
.join (enter
[1:])
281 self
.header_dict
['enteredon'] = enter
[0]
282 self
.header_dict
['opus'] = lines
[4]
283 self
.header_dict
['source'] = lines
[5]
284 self
.header_dict
['title'] = lines
[6]
285 self
.header_dict
['subtitle'] = lines
[7]
286 self
.header_dict
['instrument']= lines
[8]
287 self
.header_dict
['musedatamisc'] =lines
[9]
288 self
.header_dict
['musedatagroups'] =lines
[10]
289 self
.header_dict
['musedatagroupnumber']=lines
[11]
293 if lines
[0][0] == '$':
298 def parse_musical_attributes (self
,l
):
299 atts
= re
.split('([A-Z][0-9]?):', l
)
309 self
.divs_per_q
= string
.atoi (found
['Q'])
313 self
.append_entry (Attribute_set (found
))
314 def append_entry (self
, e
):
315 self
.entries
.append (e
)
317 def parse_line_comment (self
,l
):
320 def parse_note_line (self
,l
):
323 print DIGITS
+DIGITS
+DIGITS
338 ch
= self
.last_chord ()
342 self
.append_chord (ch
)
345 ch
.cue
= ch
.cue
or cue
346 ch
.grace
= ch
.grace
or grace
348 while pi
[0] in SPACES
:
352 name
= ((ord (pi
[0]) -ord('A')) + 5) % 7
355 while pi
and pi
[0] in '#f':
362 oct = string
.atoi (pi
) - 3
364 pittup
= (oct, name
,alter
)
365 ch
.add_pitch (pittup
)
376 if ch
.cue
or ch
.grace
:
383 base_dur
= 1 << (9 - (ord (c
) - ord ('0')))
391 base_dur
= (4 * self
.divs_per_q
* fact
[1]) / (string
.atoi (di
)* fact
[0])
392 ch
.set_duration (base_dur
)
394 ch
.tied
= ch
.tied
or tied
398 elif l
[26:27] == ']':
402 additional
= l
[32:44]
405 ch
.slurstart
.append( 0)
408 ch
.slurstop
.append( 0)
426 scr
= script_table
[c
]
430 sys
.stderr
.write ("\nFixme: script `%s' not done\n" % c
)
433 sylls
= string
.split (text
,'|')
436 ch
.add_syllable (syl
)
439 def parse_measure_line (self
,l
):
440 self
.append_entry (Measure_start())
443 def parse_duration (l
):
445 while l
[0] in '0123456789':
449 num
= string
.atoi (s
)
457 if num
% multiplier
== 0 and den
% f
== 0:
458 num
= num
/ multiplier
460 current_dots
= current_dots
+ d
463 sys
.stderr
.write ('huh. Durations left')
464 return '%s%s' % (den
, '.' * current_dots
)
466 def append_lines (self
,ls
):
470 nls
[-1] = nls
[-1]+l
[1:]
477 for e
in self
.entries
:
479 next
= ' ' + e
.dump()
480 if len (ln
) + len (next
) > 72:
487 s
= '\\notes {\n %s \n}' % s
490 def parse_body (self
,lines
):
498 comment_switch
= not comment_switch
507 self
.parse_musical_attributes (l
)
509 self
.parse_line_comment (l
)
511 self
.parse_musical_directions (l
)
512 elif c
in 'ABCDEFGr ':
513 self
.parse_note_line (l
)
515 self
.parse_measure_line (l
)
519 pass # ignore sound & print
521 sys
.stderr
.write ("\nUnrecognized record `%s'\n"% l
)
529 """Usage: musedata2ly [OPTIONS]... FILE1 [FILE2 ...]
531 Convert musedata to LilyPond.
534 -h,--help print this help
535 -o,--output=FILE set output filename to FILE
536 -v,--version show version information
537 -r,--ref=REF read background information from ref-file REF
539 Musedata (http://www.ccarh.org/musedata/) is an electronic library of
540 classical music scores, currently comprising XXX scores. The music is
541 encoded in so-called Musedata format
542 (http://www.ccarh.org/publications/books/beyondmidi/online/musedata).
543 musedata2ly converts a set of musedata files to one .ly file, and will
544 include a \header field if a .ref file is supplied.
546 This converter is not complete -- this is left to the user as an excercise.
548 Report bugs to bug-lilypond@gnu.org.
550 Written by Han-Wen Nienhuys <hanwen@cs.uu.nl>.
555 def print_version ():
556 sys
.stdout
.write ("""musedata2ly (GNU LilyPond) %s
558 This is free software. It is covered by the GNU General Public License,
559 and you are welcome to change it and/or distribute copies of it under
560 certain conditions. Invoke as `midi2ly --warranty' for more information.
562 Copyright (c) 2000--2003 by Han-Wen Nienhuys <hanwen@cs.uu.nl>.
565 sys
.stderr
.write ("%s from LilyPond %s\n" % (program_name
, version
))
569 (options
, files
) = getopt
.getopt (sys
.argv
[1:], 'r:vo:h', ['verbose', 'ref=', 'help','version', 'output='])
575 if o
== '--help' or o
== '-h':
578 elif o
== '--version' or o
== '-v':
581 elif o
== '--ref' or o
== '-r':
583 elif o
== '--output' or o
== '-o':
585 elif o
== '--verbose' :
604 sys
.stderr
.write ('Processing `%s\'\n' % f
)
608 id = os
.path
.basename (f
)
609 id = re
.sub ('[^a-zA-Z0-9]', 'x', id)
612 return chr (ord (match
.group ()) - ord('0') + ord('A'))
614 id = re
.sub ('[0-9]', num2let
, id)
617 ly
=ly
+ '\n\n%s = \\context Staff = "%s" %s\n\n' % (id, id, e
.dump ())
619 found_ids
= found_ids
+ '\\%s\n' % id
621 found_ids
= '\n\n\n\\score { << %s >> } ' % found_ids
625 head
= Ref_parser (ref_file
)
630 t
= head
.dict['title']
631 st
= head
.dict['subtitle']
637 t
= re
.sub ("^ +(.*) +$", r
"\1", t
)
638 t
= re
.sub ("\\.", '', t
)
639 out_filename
= re
.sub ('[^a-zA-Z0-9-]', '-', t
)
640 out_filename
= out_filename
+ '.ly'
641 ly_head
= head
.dump ()
644 out_filename
= 'musedata.ly'
646 sys
.stderr
.write ('Writing `%s\'\n' % out_filename
)
648 fo
= open (out_filename
, 'w')
649 fo
.write ('%% lily was here -- automatically converted by musedata.ly\n')
650 fo
.write(ly_head
+ ly
+ found_ids
)