3 # midi2ly.py -- LilyPond midi import script
5 # This file is part of LilyPond, the GNU music typesetter.
7 # Copyright (C) 1998--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
8 # Jan Nieuwenhuizen <janneke@gnu.org>
10 # LilyPond is free software: you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation, either version 3 of the License, or
13 # (at your option) any later version.
15 # LilyPond is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
39 ################################################################
44 scale_steps
= [0, 2, 4, 5, 7, 9, 11]
52 start_quant_clocks
= 0
54 duration_quant_clocks
= 0
55 allowed_tuplet_clocks
= []
58 ################################################################
61 program_name
= sys
.argv
[0]
62 program_version
= '@TOPLEVEL_VERSION@'
64 authors
= ('Jan Nieuwenhuizen <janneke@gnu.org>',
65 'Han-Wen Nienhuys <hanwen@xs4all.nl>')
67 errorport
= sys
.stderr
70 sys
.stdout
.write ('%s (GNU LilyPond) %s\n' % (program_name
, program_version
))
74 ly
.encoded_write (sys
.stdout
, '''
81 ''' % ( _ ('Copyright (c) %s by') % '1998--2011',
83 _ ('Distributed under terms of the GNU General Public License.'),
84 _ ('It comes with NO WARRANTY.')))
87 ly
.encoded_write (errorport
, s
+ '\n')
90 progress (_ ("warning: ") + s
)
93 progress (_ ("error: ") + s
)
94 raise Exception (_ ("Exiting... "))
97 if global_options
.debug
:
98 progress ("debug: " + s
)
100 def system (cmd
, ignore_error
= 0):
101 return ly
.system (cmd
, ignore_error
=ignore_error
)
103 def strip_extension (f
, ext
):
104 (p
, e
) = os
.path
.splitext (f
)
111 allowed_durs
= (1, 2, 4, 8, 16, 32, 64, 128)
112 def __init__ (self
, clocks
):
115 self
.clocks
= duration_quant_clocks
116 (self
.dur
, self
.num
, self
.den
) = self
.dur_num_den (clocks
)
118 def dur_num_den (self
, clocks
):
119 for i
in range (len (allowed_tuplet_clocks
)):
120 if clocks
== allowed_tuplet_clocks
[i
]:
121 return global_options
.allowed_tuplets
[i
]
123 dur
= 0; num
= 1; den
= 1;
124 g
= gcd (clocks
, clocks_per_1
)
126 (dur
, num
) = (clocks_per_1
/ g
, clocks
/ g
)
127 if not dur
in self
.allowed_durs
:
128 dur
= 4; num
= clocks
; den
= clocks_per_4
129 return (dur
, num
, den
)
135 elif self
.num
== 3 and self
.dur
!= 1:
136 s
= '%d.' % (self
.dur
/ 2)
138 s
= '%d*%d' % (self
.dur
, self
.num
)
140 s
= '%d*%d/%d' % (self
.dur
, self
.num
, self
.den
)
142 global reference_note
143 if reference_note
: # debugging
144 reference_note
.duration
= self
148 def compare (self
, other
):
149 return self
.clocks
- other
.clocks
158 names
= (0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6)
159 alterations
= (0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0)
160 alteration_names
= ('eses', 'es', '', 'is' , 'isis')
161 def __init__ (self
, clocks
, pitch
, velocity
):
163 self
.velocity
= velocity
166 self
.duration
= Duration (clocks
)
167 (self
.octave
, self
.notename
, self
.alteration
) = self
.o_n_a ()
171 # minor scale: la-la (= + 5) '''
173 n
= self
.names
[(self
.pitch
) % 12]
174 a
= self
.alterations
[(self
.pitch
) % 12]
176 key
= global_options
.key
181 a
= - self
.alterations
[(self
.pitch
) % 12]
184 # By tradition, all scales now consist of a sequence
185 # of 7 notes each with a distinct name, from amongst
186 # a b c d e f g. But, minor scales have a wide
187 # second interval at the top - the 'leading note' is
188 # sharped. (Why? it just works that way! Anything
189 # else doesn't sound as good and isn't as flexible at
190 # saying things. In medieval times, scales only had 6
191 # notes to avoid this problem - the hexachords.)
193 # So, the d minor scale is d e f g a b-flat c-sharp d
194 # - using d-flat for the leading note would skip the
195 # name c and duplicate the name d. Why isn't c-sharp
196 # put in the key signature? Tradition. (It's also
197 # supposedly based on the Pythagorean theory of the
198 # cycle of fifths, but that really only applies to
199 # major scales...) Anyway, g minor is g a b-flat c d
200 # e-flat f-sharp g, and all the other flat minor keys
201 # end up with a natural leading note. And there you
204 # John Sankey <bf250@freenet.carleton.ca>
206 # Let's also do a-minor: a b c d e f gis a
210 o
= self
.pitch
/ 12 - 4
214 if (key
.sharps
== 0 and key
.flats
== 0
215 and n
== 5 and a
== -1):
218 elif key
.flats
== 1 and n
== 1 and a
== -1:
221 elif key
.flats
== 2 and n
== 4 and a
== -1:
224 elif key
.sharps
== 5 and n
== 4 and a
== 0:
227 elif key
.sharps
== 6 and n
== 1 and a
== 0:
230 elif key
.sharps
== 7 and n
== 5 and a
== 0:
234 if key
.flats
>= 6 and n
== 6 and a
== 0:
235 n
= 0; a
= -1; o
= o
+ 1
237 if key
.flats
>= 7 and n
== 2 and a
== 0:
241 if key
.sharps
>= 3 and n
== 3 and a
== 0:
244 if key
.sharps
>= 4 and n
== 0 and a
== 0:
245 n
= 6; a
= 1; o
= o
- 1
250 s
= chr ((self
.notename
+ 2) % 7 + ord ('a'))
251 return 'Note(%s %s)' % (s
, self
.duration
.dump ())
253 def dump (self
, dump_dur
=True):
254 global reference_note
255 s
= chr ((self
.notename
+ 2) % 7 + ord ('a'))
256 s
= s
+ self
.alteration_names
[self
.alteration
+ 2]
257 if global_options
.absolute_pitches
:
260 delta
= self
.pitch
- reference_note
.pitch
261 commas
= sign (delta
) * (abs (delta
) / 12)
263 * (self
.notename
- reference_note
.notename
) + 7)
265 or ((self
.notename
== reference_note
.notename
)
266 and (abs (delta
) > 4) and (abs (delta
) < 12))):
267 commas
= commas
+ sign (delta
)
272 s
= s
+ "," * -commas
275 and self
.duration
.compare (reference_note
.duration
))
276 or global_options
.explicit_durations
):
277 s
= s
+ self
.duration
.dump ()
279 reference_note
= self
286 def __init__ (self
, num
, den
):
291 def bar_clocks (self
):
292 return clocks_per_1
* self
.num
/ self
.den
295 return 'Time(%d/%d)' % (self
.num
, self
.den
)
300 return '\n ' + '\\time %d/%d ' % (self
.num
, self
.den
) + '\n '
303 def __init__ (self
, seconds_per_1
):
305 self
.seconds_per_1
= seconds_per_1
308 return 'Tempo(%d)' % self
.bpm ()
311 return 4 * 60 / self
.seconds_per_1
314 return '\n ' + '\\tempo 4 = %d ' % (self
.bpm ()) + '\n '
317 clefs
= ('"bass_8"', 'bass', 'violin', '"violin^8"')
318 def __init__ (self
, type):
322 return 'Clef(%s)' % self
.clefs
[self
.type]
325 return '\n \\clef %s\n ' % self
.clefs
[self
.type]
328 key_sharps
= ('c', 'g', 'd', 'a', 'e', 'b', 'fis')
329 key_flats
= ('BUG', 'f', 'bes', 'es', 'as', 'des', 'ges')
331 def __init__ (self
, sharps
, flats
, minor
):
338 global_options
.key
= self
341 if self
.sharps
and self
.flats
:
345 k
= (ord ('cfbeadg'[self
.flats
% 7]) - ord ('a') - 2 -2 * self
.minor
+ 7) % 7
347 k
= (ord ('cgdaebf'[self
.sharps
% 7]) - ord ('a') - 2 -2 * self
.minor
+ 7) % 7
350 name
= chr ((k
+ 2) % 7 + ord ('a'))
352 name
= chr ((k
+ 2) % 7 + ord ('a'))
354 # fis cis gis dis ais eis bis
355 sharps
= (2, 4, 6, 1, 3, 5, 7)
356 # bes es as des ges ces fes
357 flats
= (6, 4, 2, 7, 5, 3, 1)
360 if flats
[k
] <= self
.flats
:
363 if sharps
[k
] <= self
.sharps
:
367 name
= name
+ Note
.alteration_names
[a
+ 2]
375 return '\n\n ' + s
+ '\n '
383 'SEQUENCE_TRACK_NAME',
389 def __init__ (self
, type, text
):
395 # urg, we should be sure that we're in a lyrics staff
397 if self
.type == midi
.LYRIC
:
398 s
= '"%s"' % self
.text
399 d
= Duration (self
.clocks
)
400 if (global_options
.explicit_durations
401 or d
.compare (reference_note
.duration
)):
402 s
= s
+ Duration (self
.clocks
).dump ()
404 elif (self
.text
.strip ()
405 and self
.type == midi
.SEQUENCE_TRACK_NAME
406 and not self
.text
== 'control track'):
407 text
= self
.text
.replace ('(MIDI)', '').strip ()
409 s
= '\n \\set Staff.instrumentName = "%(text)s"\n ' % locals ()
410 elif self
.text
.strip ():
411 s
= '\n % [' + self
.text_types
[self
.type] + '] ' + self
.text
+ '\n '
415 return 'Text(%d=%s)' % (self
.type, self
.text
)
417 def get_voice (channel
, music
):
418 debug ('channel: ' + str (channel
) + '\n')
419 return unthread_notes (music
)
422 def __init__ (self
, number
):
426 def add (self
, event
):
427 self
.events
.append (event
)
428 def get_voice (self
):
430 self
.music
= self
.parse ()
431 return get_voice (self
.number
, self
.music
)
438 for e
in self
.events
:
441 if start_quant_clocks
:
442 t
= quantise_clocks (t
, start_quant_clocks
)
444 if (e
[1][0] == midi
.NOTE_OFF
445 or (e
[1][0] == midi
.NOTE_ON
and e
[1][2] == 0)):
446 debug ('%d: NOTE OFF: %s' % (t
, e
[1][1]))
448 debug (' ...treated as OFF')
449 end_note (pitches
, notes
, t
, e
[1][1])
451 elif e
[1][0] == midi
.NOTE_ON
:
452 if not pitches
.has_key (e
[1][1]):
453 debug ('%d: NOTE ON: %s' % (t
, e
[1][1]))
454 pitches
[e
[1][1]] = (t
, e
[1][2])
458 # all include ALL_NOTES_OFF
459 elif (e
[1][0] >= midi
.ALL_SOUND_OFF
460 and e
[1][0] <= midi
.POLY_MODE_ON
):
462 end_note (pitches
, notes
, t
, i
)
464 elif e
[1][0] == midi
.META_EVENT
:
465 if e
[1][1] == midi
.END_OF_TRACK
:
467 end_note (pitches
, notes
, t
, i
)
470 elif e
[1][1] == midi
.SET_TEMPO
:
471 (u0
, u1
, u2
) = map (ord, e
[1][2])
472 us_per_4
= u2
+ 256 * (u1
+ 256 * u0
)
473 seconds_per_1
= us_per_4
* 4 / 1e6
474 music
.append ((t
, Tempo (seconds_per_1
)))
475 elif e
[1][1] == midi
.TIME_SIGNATURE
:
476 (num
, dur
, clocks4
, count32
) = map (ord, e
[1][2])
478 music
.append ((t
, Time (num
, den
)))
479 elif e
[1][1] == midi
.KEY_SIGNATURE
:
480 (alterations
, minor
) = map (ord, e
[1][2])
483 if alterations
< 127:
486 flats
= 256 - alterations
488 k
= Key (sharps
, flats
, minor
)
489 if not t
and global_options
.key
:
490 # At t == 0, a set --key overrides us
491 k
= global_options
.key
492 music
.append ((t
, k
))
494 # ugh, must set key while parsing
495 # because Note init uses key
496 # Better do Note.calc () at dump time?
497 global_options
.key
= k
499 elif (e
[1][1] == midi
.LYRIC
500 or (global_options
.text_lyrics
501 and e
[1][1] == midi
.TEXT_EVENT
)):
502 self
.lyrics_p_
= True
504 last_lyric
.clocks
= t
- last_time
505 music
.append ((last_time
, last_lyric
))
507 last_lyric
= Text (midi
.LYRIC
, e
[1][2])
509 elif (e
[1][1] >= midi
.SEQUENCE_NUMBER
510 and e
[1][1] <= midi
.CUE_POINT
):
511 text
= Text (e
[1][1], e
[1][2])
512 music
.append ((t
, text
))
513 if (text
.type == midi
.SEQUENCE_TRACK_NAME
):
514 self
.name
= text
.text
516 if global_options
.verbose
:
517 sys
.stderr
.write ("SKIP: %s\n" % `e`
)
519 if global_options
.verbose
:
520 sys
.stderr
.write ("SKIP: %s\n" % `e`
)
523 # last_lyric.clocks = t - last_time
525 last_lyric
.clocks
= clocks_per_4
526 music
.append ((last_time
, last_lyric
))
531 if i
< len (music
) and notes
[0][0] >= music
[i
][0]:
534 music
.insert (i
, notes
[0])
538 class Track (Channel
):
540 Channel
.__init
__ (self
, None)
543 self
.lyrics_p_
= False
544 def _add (self
, event
):
545 self
.events
.append (event
)
546 def add (self
, event
, channel
=None):
550 self
.channels
[channel
] = self
.channels
.get (channel
, Channel (channel
))
551 self
.channels
[channel
].add (event
)
552 def get_voices (self
):
553 return ([self
.get_voice ()]
554 + [self
.channels
[k
].get_voice ()
555 for k
in sorted (self
.channels
.keys ())])
557 def create_track (events
):
561 if data
[0] > 0x7f and data
[0] < 0xf0:
562 channel
= data
[0] & 0x0f
563 e
= (e
[0], tuple ([data
[0] & 0xf0] + data
[1:]))
564 track
.add (e
, channel
)
569 def quantise_clocks (clocks
, quant
):
570 q
= int (clocks
/ quant
) * quant
572 for tquant
in allowed_tuplet_clocks
:
573 if int (clocks
/ tquant
) * tquant
== clocks
:
575 if 2 * (clocks
- q
) > quant
:
579 def end_note (pitches
, notes
, t
, e
):
581 (lt
, vel
) = pitches
[e
]
591 if duration_quant_clocks
:
592 d
= quantise_clocks (d
, duration_quant_clocks
)
594 d
= duration_quant_clocks
597 (lt
, Note (d
, e
, vel
)))
602 def unthread_notes (channel
):
611 if (e
[1].__class
__ == Note
612 and ((t
== start_busy_t
613 and e
[1].clocks
+ t
== end_busy_t
)
614 or t
>= end_busy_t
)):
617 end_busy_t
= t
+ e
[1].clocks
618 elif (e
[1].__class
__ == Time
619 or e
[1].__class
__ == Key
620 or e
[1].__class
__ == Text
621 or e
[1].__class
__ == Tempo
):
625 threads
.append (thread
)
640 def dump_skip (skip
, clocks
):
641 return skip
+ Duration (clocks
).dump () + ' '
650 if i
.__class
__ == Note
:
655 s
= s
+ dump (notes
[0])
656 elif len (notes
) > 1:
657 global reference_note
659 s
= s
+ notes
[0].dump (dump_dur
=False)
662 s
= s
+ i
.dump (dump_dur
=False)
665 s
= s
+ notes
[0].duration
.dump () + ' '
669 def dump_bar_line (last_bar_t
, t
, bar_count
):
671 bar_t
= time
.bar_clocks ()
672 if t
- last_bar_t
>= bar_t
:
673 bar_count
= bar_count
+ (t
- last_bar_t
) / bar_t
675 if t
- last_bar_t
== bar_t
:
676 s
= '\n | %% %(bar_count)d\n ' % locals ()
679 # urg, this will barf at meter changes
680 last_bar_t
= last_bar_t
+ (t
- last_bar_t
) / bar_t
* bar_t
682 return (s
, last_bar_t
, bar_count
)
685 def dump_voice (thread
, skip
):
686 global reference_note
, time
687 ref
= Note (0, 4*12, 0)
688 if not reference_note
:
691 ref
.duration
= reference_note
.duration
698 if last_e
and last_e
[0] == e
[0]:
702 chs
.append ((last_e
[0], ch
))
709 chs
.append ((last_e
[0], ch
))
719 i
= lines
[-1].rfind ('\n') + 1
720 if len (lines
[-1][i
:]) > LINE_BELL
:
725 if bar_max
and t
> time
.bar_clocks () * bar_max
:
726 d
= time
.bar_clocks () * bar_max
- last_t
727 lines
[-1] = lines
[-1] + dump_skip (skip
, d
)
729 errorport
.write ('BUG: time skew')
731 (s
, last_bar_t
, bar_count
) = dump_bar_line (last_bar_t
,
734 if bar_max
and bar_count
> bar_max
:
737 lines
[-1] = lines
[-1] + s
738 lines
[-1] = lines
[-1] + dump_chord (ch
[1])
742 if i
.clocks
> clocks
:
747 (s
, last_bar_t
, bar_count
) = dump_bar_line (last_bar_t
,
749 lines
[-1] = lines
[-1] + s
751 return '\n '.join (lines
) + '\n'
753 def number2ascii (i
):
758 s
= '%c' % (m
+ ord ('A')) + s
762 def get_track_name (i
):
763 return 'track' + number2ascii (i
)
765 def get_channel_name (i
):
766 return 'channel' + number2ascii (i
)
768 def get_voice_name (i
, zero_too_p
=False):
770 return 'voice' + number2ascii (i
)
773 def lst_append (lst
, x
):
777 def get_voice_layout (average_pitch
):
779 for i
in range (len (average_pitch
)):
780 d
[average_pitch
[i
]] = lst_append (d
.get (average_pitch
[i
], []), i
)
781 s
= list (reversed (sorted (average_pitch
)))
782 non_empty
= len (filter (lambda x
: x
, s
))
783 names
= ['One', 'Two']
785 names
= ['One', 'Three', 'Four', 'Two']
786 layout
= map (lambda x
: '', range (len (average_pitch
)))
787 for i
, n
in zip (s
, names
):
796 def dump_track (track
, n
):
798 track_name
= get_track_name (n
)
800 average_pitch
= track_average_pitch (track
)
801 voices
= len (filter (lambda x
: x
, average_pitch
[1:]))
802 clef
= get_best_clef (average_pitch
[0])
806 for channel
in track
:
808 channel_name
= get_channel_name (c
)
810 for voice
in channel
:
811 voice_name
= get_voice_name (v
)
812 voice_id
= track_name
+ channel_name
+ voice_name
813 item
= voice_first_item (voice
)
815 if item
and item
.__class
__ == Note
:
817 if global_options
.skip
:
819 s
+= '%(voice_id)s = ' % locals ()
820 if not global_options
.absolute_pitches
:
822 elif item
and item
.__class
__ == Text
:
824 s
+= '%(voice_id)s = \\lyricmode ' % locals ()
827 s
+= '%(voice_id)s = ' % locals ()
829 if not n
and not vv
and global_options
.key
:
830 s
+= global_options
.key
.dump ()
831 if average_pitch
[vv
+1] and voices
> 1:
832 s
+= ' \\voice' + get_voice_layout (average_pitch
[1:])[vv
] + '\n'
833 s
+= ' ' + dump_voice (voice
, skip
)
838 s
+= '%(track_name)s = <<\n' % locals ()
841 s
+= clef
.dump () + '\n'
845 for channel
in track
:
847 channel_name
= get_channel_name (c
)
849 for voice
in channel
:
850 voice_context_name
= get_voice_name (vv
, zero_too_p
=True)
851 voice_name
= get_voice_name (v
)
854 voice_id
= track_name
+ channel_name
+ voice_name
855 item
= voice_first_item (voice
)
857 if item
and item
.__class
__ == Text
:
859 s
+= ' \\context %(context)s = %(voice_context_name)s \\%(voice_id)s\n' % locals ()
863 def voice_first_item (voice
):
865 if (event
[1].__class
__ == Note
866 or (event
[1].__class
__ == Text
867 and event
[1].type == midi
.LYRIC
)):
871 def channel_first_item (channel
):
872 for voice
in channel
:
873 first
= voice_first_item (voice
)
878 def track_first_item (track
):
879 for channel
in track
:
880 first
= channel_first_item (channel
)
885 def track_average_pitch (track
):
889 for channel
in track
:
890 for voice
in channel
:
894 if event
[1].__class
__ == Note
:
897 p
[v
] += event
[1].pitch
906 def get_best_clef (average_pitch
):
908 if average_pitch
<= 3*12:
910 elif average_pitch
<= 5*12:
912 elif average_pitch
>= 7*12:
917 def __init__ (self
, track
):
918 self
.voices
= track
.get_voices ()
920 return dump_track (self
.voices
, i
)
922 def convert_midi (in_file
, out_file
):
923 global clocks_per_1
, clocks_per_4
, key
924 global start_quant_clocks
925 global duration_quant_clocks
926 global allowed_tuplet_clocks
929 str = open (in_file
, 'rb').read ()
930 clocks_max
= bar_max
* clocks_per_1
* 2
931 midi_dump
= midi
.parse (str, clocks_max
)
933 clocks_per_1
= midi_dump
[0][1]
934 clocks_per_4
= clocks_per_1
/ 4
937 if global_options
.start_quant
:
938 start_quant_clocks
= clocks_per_1
/ global_options
.start_quant
940 if global_options
.duration_quant
:
941 duration_quant_clocks
= clocks_per_1
/ global_options
.duration_quant
943 allowed_tuplet_clocks
= []
944 for (dur
, num
, den
) in global_options
.allowed_tuplets
:
945 allowed_tuplet_clocks
.append (clocks_per_1
/ dur
* num
/ den
)
947 if global_options
.verbose
:
948 print 'allowed tuplet clocks:', allowed_tuplet_clocks
950 tracks
= [create_track (t
) for t
in midi_dump
[1]]
951 # urg, parse all global track events, such as Key first
952 # this fixes key in different voice/staff problem
958 voices
= t
.get_voices ()
959 if ((t
.name
and prev
and prev
.name
)
960 and t
.name
.split (':')[0] == prev
.name
.split (':')[0]):
961 # staves[-1].voices += voices
962 # all global track events first
963 staves
[-1].voices
= ([staves
[-1].voices
[0]]
965 + staves
[-1].voices
[1:]
968 staves
.append (Staff (t
))
971 tag
= '%% Lily was here -- automatically converted by %s from %s' % ( program_name
, in_file
)
983 \remove "Note_heads_engraver"
984 \consists "Completion_heads_engraver"
985 \remove "Rest_engraver"
986 \consists "Completion_rest_engraver"
991 for i
in global_options
.include_header
:
992 s
+= '\n%% included from %(i)s\n' % locals ()
993 s
+= open (i
).read ()
998 for i
, t
in enumerate (staves
):
1001 s
+= '\n\\score {\n <<\n'
1004 for i
, staff
in enumerate (staves
):
1005 track_name
= get_track_name (i
)
1006 item
= track_first_item (staff
.voices
)
1007 staff_name
= track_name
1009 if not i
and not item
and len (staves
) > 1:
1011 staff_name
= get_track_name (1)
1013 elif (item
and item
.__class
__ == Note
):
1015 elif item
and item
.__class
__ == Text
:
1018 s
+= ' \\context %(context)s=%(staff_name)s \\%(track_name)s\n' % locals ()
1026 progress (_ ("%s output to `%s'...") % ('LY', out_file
))
1031 handle
= open (out_file
, 'w')
1037 def get_option_parser ():
1038 p
= ly
.get_option_parser (usage
=_ ("%s [OPTION]... FILE") % 'midi2ly',
1039 description
=_ ("Convert %s to LilyPond input.\n") % 'MIDI',
1040 add_help_option
=False)
1042 p
.add_option ('-a', '--absolute-pitches',
1043 action
='store_true',
1044 help=_ ('print absolute pitches'))
1045 p
.add_option ('-d', '--duration-quant',
1047 help=_ ('quantise note durations on DUR'))
1048 p
.add_option ('-D', '--debug',
1049 action
='store_true',
1050 help=_ ('debug printing'))
1051 p
.add_option ('-e', '--explicit-durations',
1052 action
='store_true',
1053 help=_ ('print explicit durations'))
1054 p
.add_option('-h', '--help',
1056 help=_ ('show this help and exit'))
1057 p
.add_option('-i', '--include-header',
1058 help=_ ('prepend FILE to output'),
1062 p
.add_option('-k', '--key', help=_ ('set key: ALT=+sharps|-flats; MINOR=1'),
1063 metavar
=_ ('ALT[:MINOR]'),
1065 p
.add_option ('-o', '--output', help=_ ('write output to FILE'),
1068 p
.add_option ('-p', '--preview', help=_ ('preview of first 4 bars'),
1069 action
='store_true')
1070 p
.add_option ('-s', '--start-quant',help= _ ('quantise note starts on DUR'),
1072 p
.add_option ('-S', '--skip',
1073 action
= "store_true",
1074 help =_ ("use s instead of r for rests"))
1075 p
.add_option ('-t', '--allow-tuplet',
1076 metavar
=_ ('DUR*NUM/DEN'),
1078 dest
='allowed_tuplets',
1079 help=_ ('allow tuplet durations DUR*NUM/DEN'),
1081 p
.add_option ('-V', '--verbose', help=_ ('be verbose'),
1084 p
.version
= 'midi2ly (LilyPond) @TOPLEVEL_VERSION@'
1085 p
.add_option ('--version',
1087 help=_ ('show version number and exit'))
1088 p
.add_option ('-w', '--warranty', help=_ ('show warranty and copyright'),
1089 action
='store_true',
1091 p
.add_option ('-x', '--text-lyrics', help=_ ('treat every text as a lyric'),
1092 action
='store_true')
1094 p
.add_option_group (ly
.display_encode (_ ('Examples')),
1096 $ midi2ly --key=-2:1 --duration-quant=32 --allow-tuplet=4*2/3 --allow-tuplet=2*4/3 foo.midi
1098 p
.add_option_group ('',
1100 _ ('Report bugs via %s')
1101 % 'http://post.gmane.org/post.php'
1102 '?group=gmane.comp.gnu.lilypond.bugs') + '\n')
1108 opt_parser
= get_option_parser ()
1109 (options
, args
) = opt_parser
.parse_args ()
1111 if options
.warranty
:
1115 if not args
or args
[0] == '-':
1116 opt_parser
.print_help ()
1117 ly
.stderr_write ('\n%s: %s %s\n' % (program_name
, _ ('error: '),
1118 _ ('no files specified on command line.')))
1121 if options
.duration_quant
:
1122 options
.duration_quant
= int (options
.duration_quant
)
1125 (alterations
, minor
) = map (int, (options
.key
+ ':0').split (':'))[0:2]
1128 if alterations
>= 0:
1129 sharps
= alterations
1131 flats
= - alterations
1132 options
.key
= Key (sharps
, flats
, minor
)
1134 if options
.start_quant
:
1135 options
.start_quant
= int (options
.start_quant
)
1141 options
.allowed_tuplets
= [map (int, a
.replace ('/','*').split ('*'))
1142 for a
in options
.allowed_tuplets
]
1145 sys
.stderr
.write ('Allowed tuplets: %s\n' % `options
.allowed_tuplets`
)
1147 global global_options
1148 global_options
= options
1153 files
= do_options ()
1155 exts
= ['.midi', '.mid', '.MID']
1159 g
= strip_extension (g
, e
)
1160 if not os
.path
.exists (f
):
1163 if os
.path
.exists (n
):
1167 if not global_options
.output
:
1169 outbase
= os
.path
.basename (g
)
1170 o
= outbase
+ '-midi.ly'
1171 elif (global_options
.output
[-1] == os
.sep
1172 or os
.path
.isdir (global_options
.output
)):
1173 outdir
= global_options
.output
1174 outbase
= os
.path
.basename (g
)
1175 o
= os
.path
.join (outdir
, outbase
+ '-midi.ly')
1177 o
= global_options
.output
1178 (outdir
, outbase
) = os
.path
.split (o
)
1180 if outdir
and outdir
!= '.' and not os
.path
.exists (outdir
):
1181 os
.mkdir (outdir
, 0777)
1185 if __name__
== '__main__':