9 from rational
import Rational
11 # Store previously converted pitch for \relative conversion as a global state variable
13 relative_pitches
= False
16 ly
.stderr_write ((_ ("warning: %s") % str) + "\n")
19 def escape_instrument_string (input_string
):
20 retstring
= string
.replace (input_string
, "\"", "\\\"")
21 if re
.match ('.*[\r\n]+.*', retstring
):
22 rx
= re
.compile (r
'[\n\r]+')
23 strings
= rx
.split (retstring
)
24 retstring
= "\\markup { \\column { "
26 retstring
+= "\\line {\"" + s
+ "\"} "
29 retstring
= "\"" + retstring
+ "\""
32 class Output_stack_element
:
34 self
.factor
= Rational (1)
36 o
= Output_stack_element()
37 o
.factor
= self
.factor
42 """A class that takes care of formatting (eg.: indenting) a
43 Music expression as a .ly file.
46 ## TODO: support for \relative.
52 self
._file
= sys
.stdout
54 self
._output
_state
_stack
= [Output_stack_element()]
55 self
._skipspace
= False
56 self
._last
_duration
= None
58 def set_file (self
, file):
61 def dump_version (self
):
63 self
.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
66 def get_indent (self
):
67 return self
._nesting
* self
._indent
70 last
= self
._output
_state
_stack
[-1]
71 self
._output
_state
_stack
.append (last
.copy())
73 def add_factor (self
, factor
):
75 self
._output
_state
_stack
[-1].factor
*= factor
78 del self
._output
_state
_stack
[-1]
79 if not self
._output
_state
_stack
:
82 def duration_factor (self
):
83 return self
._output
_state
_stack
[-1].factor
85 def print_verbatim (self
, str):
88 def unformatted_output (self
, str):
89 # don't indent on \< and indent only once on <<
90 self
._nesting
+= ( str.count ('<')
91 - str.count ('\<') - str.count ('<<')
93 self
._nesting
-= ( str.count ('>') - str.count ('\>') - str.count ('>>')
94 - str.count ('->') - str.count ('_>')
97 self
.print_verbatim (str)
99 def print_duration_string (self
, str):
100 if self
._last
_duration
== str:
103 self
.unformatted_output (str)
105 def add_word (self
, str):
106 if (len (str) + 1 + len (self
._line
) > self
._line
_len
):
108 self
._skipspace
= True
110 if not self
._skipspace
:
112 self
.unformatted_output (str)
113 self
._skipspace
= False
116 self
._file
.write (self
._line
+ '\n')
117 self
._line
= ' ' * self
._indent
* self
._nesting
118 self
._skipspace
= True
120 def skipspace (self
):
121 self
._skipspace
= True
123 def __call__(self
, arg
):
126 def dump (self
, str):
128 self
._skipspace
= False
129 self
.unformatted_output (str)
131 words
= string
.split (str)
144 self
.duration_log
= 0
146 self
.factor
= Rational (1)
148 def lisp_expression (self
):
149 return '(ly:make-duration %d %d %d %d)' % (self
.duration_log
,
151 self
.factor
.numerator (),
152 self
.factor
.denominator ())
155 def ly_expression (self
, factor
= None, scheme_mode
= False):
159 if self
.duration_log
< 0:
161 longer_dict
= {-1: "breve", -2: "longa"}
163 longer_dict
= {-1: "\\breve", -2: "\\longa"}
164 str = longer_dict
.get (self
.duration_log
, "1")
166 str = '%d' % (1 << self
.duration_log
)
169 if factor
<> Rational (1,1):
170 if factor
.denominator () <> 1:
171 str += '*%d/%d' % (factor
.numerator (), factor
.denominator ())
173 str += '*%d' % factor
.numerator ()
177 def print_ly (self
, outputter
):
178 str = self
.ly_expression (self
.factor
/ outputter
.duration_factor ())
179 outputter
.print_duration_string (str)
182 return self
.ly_expression()
187 d
.duration_log
= self
.duration_log
188 d
.factor
= self
.factor
191 def get_length (self
):
192 dot_fact
= Rational( (1 << (1 + self
.dots
))-1,
195 log
= abs (self
.duration_log
)
197 if self
.duration_log
< 0:
198 base
= Rational (dur
)
200 base
= Rational (1, dur
)
202 return base
* dot_fact
* self
.factor
205 # Implement the different note names for the various languages
206 def pitch_generic (pitch
, notenames
, accidentals
):
207 str = notenames
[pitch
.step
]
208 if pitch
.alteration
< 0:
209 str += accidentals
[0] * (-pitch
.alteration
)
210 elif pitch
.alteration
> 0:
211 str += accidentals
[3] * (pitch
.alteration
)
214 def pitch_general (pitch
):
215 str = pitch_generic (pitch
, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
216 return str.replace ('aes', 'as').replace ('ees', 'es')
218 def pitch_nederlands (pitch
):
219 return pitch_general (pitch
)
221 def pitch_english (pitch
):
222 str = pitch_generic (pitch
, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
223 return str.replace ('aes', 'as').replace ('ees', 'es')
225 def pitch_deutsch (pitch
):
226 str = pitch_generic (pitch
, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
227 return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
229 def pitch_norsk (pitch
):
230 return pitch_deutsch (pitch
)
232 def pitch_svenska (pitch
):
233 str = pitch_generic (pitch
, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', '', '', 'iss'])
234 return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
236 def pitch_italiano (pitch
):
237 str = pitch_generic (pitch
, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
240 def pitch_catalan (pitch
):
241 return pitch_italiano (pitch
)
243 def pitch_espanol (pitch
):
244 str = pitch_generic (pitch
, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 's'])
247 def pitch_vlaams (pitch
):
248 str = pitch_generic (pitch
, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 'k'])
251 def set_pitch_language (language
):
252 global pitch_generating_function
254 "nederlands": pitch_nederlands
,
255 "english": pitch_english
,
256 "deutsch": pitch_deutsch
,
257 "norsk": pitch_norsk
,
258 "svenska": pitch_svenska
,
259 "italiano": pitch_italiano
,
260 "catalan": pitch_catalan
,
261 "espanol": pitch_espanol
,
262 "vlaams": pitch_vlaams
}
263 pitch_generating_function
= function_dict
.get (language
, pitch_general
)
265 # global variable to hold the formatting function.
266 pitch_generating_function
= pitch_general
276 return self
.ly_expression()
278 def transposed (self
, interval
):
280 c
.alteration
+= interval
.alteration
281 c
.step
+= interval
.step
282 c
.octave
+= interval
.octave
285 target_st
= self
.semitones() + interval
.semitones()
286 c
.alteration
+= target_st
- c
.semitones()
293 c
.octave
+= c
.step
/ 7
296 def lisp_expression (self
):
297 return '(ly:make-pitch %d %d %d)' % (self
.octave
,
303 p
.alteration
= self
.alteration
305 p
.octave
= self
.octave
309 return self
.step
+ self
.octave
*7
311 def semitones (self
):
312 return self
.octave
* 12 + [0,2,4,5,7,9,11][self
.step
] + self
.alteration
314 def ly_step_expression (self
):
315 return pitch_generating_function (self
)
317 def absolute_pitch (self
):
319 return "'" * (self
.octave
+ 1)
320 elif self
.octave
< -1:
321 return "," * (-self
.octave
- 1)
325 def relative_pitch (self
):
326 global previous_pitch
327 if not previous_pitch
:
328 previous_pitch
= self
329 return self
.absolute_pitch ()
330 previous_pitch_steps
= previous_pitch
.octave
* 7 + previous_pitch
.step
331 this_pitch_steps
= self
.octave
* 7 + self
.step
332 pitch_diff
= (this_pitch_steps
- previous_pitch_steps
)
333 previous_pitch
= self
335 return "'" * ((pitch_diff
+ 3) / 7)
336 elif pitch_diff
< -3:
337 return "," * ((-pitch_diff
+ 3) / 7)
341 def ly_expression (self
):
342 str = self
.ly_step_expression ()
344 str += self
.relative_pitch ()
346 str += self
.absolute_pitch ()
350 def print_ly (self
, outputter
):
351 outputter (self
.ly_expression())
356 self
.start
= Rational (0)
358 self
.identifier
= None
360 def get_length(self
):
363 def get_properties (self
):
366 def has_children (self
):
369 def get_index (self
):
371 return self
.parent
.elements
.index (self
)
375 return self
.__class
__.__name
__
377 def lisp_expression (self
):
380 props
= self
.get_properties ()
382 return "(make-music '%s %s)" % (name
, props
)
384 def set_start (self
, start
):
387 def find_first (self
, predicate
):
392 def print_comment (self
, printer
, text
= None):
403 lines
= string
.split (text
, '\n')
406 printer
.unformatted_output ('% ' + l
)
410 def print_with_identifier (self
, printer
):
412 printer ("\\%s" % self
.identifier
)
414 self
.print_ly (printer
)
416 def print_ly (self
, printer
):
417 printer (self
.ly_expression ())
419 class MusicWrapper (Music
):
423 def print_ly (self
, func
):
424 self
.element
.print_ly (func
)
426 class ModeChangingMusicWrapper (MusicWrapper
):
428 MusicWrapper
.__init
__ (self
)
429 self
.mode
= 'notemode'
431 def print_ly (self
, func
):
432 func ('\\%s' % self
.mode
)
433 MusicWrapper
.print_ly (self
, func
)
435 class RelativeMusic (MusicWrapper
):
437 MusicWrapper
.__init
__ (self
)
438 self
.basepitch
= None
440 def print_ly (self
, func
):
441 global previous_pitch
442 global relative_pitches
443 prev_relative_pitches
= relative_pitches
444 relative_pitches
= True
445 previous_pitch
= self
.basepitch
446 if not previous_pitch
:
447 previous_pitch
= Pitch ()
448 func ('\\relative %s%s' % (pitch_generating_function (previous_pitch
),
449 previous_pitch
.absolute_pitch ()))
450 MusicWrapper
.print_ly (self
, func
)
451 relative_pitches
= prev_relative_pitches
453 class TimeScaledMusic (MusicWrapper
):
454 def print_ly (self
, func
):
455 func ('\\times %d/%d ' %
456 (self
.numerator
, self
.denominator
))
457 func
.add_factor (Rational (self
.numerator
, self
.denominator
))
458 MusicWrapper
.print_ly (self
, func
)
461 class NestedMusic(Music
):
463 Music
.__init
__ (self
)
466 def append (self
, what
):
468 self
.elements
.append (what
)
470 def has_children (self
):
473 def insert_around (self
, succ
, elt
, dir):
474 assert elt
.parent
== None
475 assert succ
== None or succ
in self
.elements
480 idx
= self
.elements
.index (succ
)
487 idx
= len (self
.elements
)
489 self
.elements
.insert (idx
, elt
)
492 def get_properties (self
):
493 return ("'elements (list %s)"
494 % string
.join (map (lambda x
: x
.lisp_expression(),
497 def get_subset_properties (self
, predicate
):
498 return ("'elements (list %s)"
499 % string
.join (map (lambda x
: x
.lisp_expression(),
500 filter ( predicate
, self
.elements
))))
501 def get_neighbor (self
, music
, dir):
502 assert music
.parent
== self
503 idx
= self
.elements
.index (music
)
505 idx
= min (idx
, len (self
.elements
) -1)
508 return self
.elements
[idx
]
510 def delete_element (self
, element
):
511 assert element
in self
.elements
513 self
.elements
.remove (element
)
514 element
.parent
= None
516 def set_start (self
, start
):
518 for e
in self
.elements
:
521 def find_first (self
, predicate
):
522 r
= Music
.find_first (self
, predicate
)
526 for e
in self
.elements
:
527 r
= e
.find_first (predicate
)
532 class SequentialMusic (NestedMusic
):
533 def get_last_event_chord (self
):
535 at
= len( self
.elements
) - 1
537 not isinstance (self
.elements
[at
], ChordEvent
) and
538 not isinstance (self
.elements
[at
], BarLine
)):
541 if (at
>= 0 and isinstance (self
.elements
[at
], ChordEvent
)):
542 value
= self
.elements
[at
]
545 def print_ly (self
, printer
, newline
= True):
548 self
.print_comment (printer
)
552 for e
in self
.elements
:
559 def lisp_sub_expression (self
, pred
):
563 props
= self
.get_subset_properties (pred
)
565 return "(make-music '%s %s)" % (name
, props
)
567 def set_start (self
, start
):
568 for e
in self
.elements
:
570 start
+= e
.get_length()
574 self
.repeat_type
= "volta"
575 self
.repeat_count
= 2
578 def set_music (self
, music
):
579 if isinstance (music
, Music
):
581 elif isinstance (music
, list):
582 self
.music
= SequentialMusic ()
583 self
.music
.elements
= music
585 warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
586 {'music':music
, 'repeat':self
})
587 def add_ending (self
, music
):
588 self
.endings
.append (music
)
589 def print_ly (self
, printer
):
590 printer
.dump ('\\repeat %s %s' % (self
.repeat_type
, self
.repeat_count
))
592 self
.music
.print_ly (printer
)
594 warning (_ ("encountered repeat without body"))
597 printer
.dump ('\\alternative {')
598 for e
in self
.endings
:
605 self
.lyrics_syllables
= []
607 def print_ly (self
, printer
):
608 printer
.dump ("\lyricmode {")
609 for l
in self
.lyrics_syllables
:
610 printer
.dump ( "%s " % l
)
613 def ly_expression (self
):
614 lstr
= "\lyricmode {\n "
615 for l
in self
.lyrics_syllables
:
623 self
.header_fields
= {}
624 def set_field (self
, field
, value
):
625 self
.header_fields
[field
] = value
627 def print_ly (self
, printer
):
628 printer
.dump ("\header {")
630 for (k
,v
) in self
.header_fields
.items ():
632 printer
.dump ('%s = %s' % (k
,v
))
641 self
.global_staff_size
= -1
644 self
.page_height
= -1
647 self
.bottom_margin
= -1
648 self
.left_margin
= -1
649 self
.right_margin
= -1
650 self
.system_left_margin
= -1
651 self
.system_right_margin
= -1
652 self
.system_distance
= -1
653 self
.top_system_distance
= -1
655 def print_length_field (self
, printer
, field
, value
):
657 printer
.dump ("%s = %s\\cm" % (field
, value
))
659 def print_ly (self
, printer
):
660 if self
.global_staff_size
> 0:
661 printer
.dump ('#(set-global-staff-size %s)' % self
.global_staff_size
)
663 printer
.dump ('\\paper {')
665 self
.print_length_field (printer
, "paper-width", self
.page_width
)
666 self
.print_length_field (printer
, "paper-height", self
.page_height
)
667 self
.print_length_field (printer
, "top-margin", self
.top_margin
)
668 self
.print_length_field (printer
, "botton-margin", self
.bottom_margin
)
669 self
.print_length_field (printer
, "left-margin", self
.left_margin
)
670 # TODO: maybe set line-width instead of right-margin?
671 self
.print_length_field (printer
, "right-margin", self
.right_margin
)
672 # TODO: What's the corresponding setting for system_left_margin and
673 # system_right_margin in Lilypond?
674 self
.print_length_field (printer
, "between-system-space", self
.system_distance
)
675 self
.print_length_field (printer
, "page-top-space", self
.top_system_distance
)
682 self
.context_dict
= {}
683 def add_context (self
, context
):
684 if not self
.context_dict
.has_key (context
):
685 self
.context_dict
[context
] = []
686 def set_context_item (self
, context
, item
):
687 self
.add_context (context
)
688 if not item
in self
.context_dict
[context
]:
689 self
.context_dict
[context
].append (item
)
690 def print_ly (self
, printer
):
691 if self
.context_dict
.items ():
692 printer
.dump ('\\layout {')
694 for (context
, defs
) in self
.context_dict
.items ():
695 printer
.dump ('\\context { \\%s' % context
)
706 class ChordEvent (NestedMusic
):
708 NestedMusic
.__init
__ (self
)
709 self
.after_grace_elements
= None
710 self
.grace_elements
= None
711 self
.grace_type
= None
712 def append_grace (self
, element
):
714 if not self
.grace_elements
:
715 self
.grace_elements
= SequentialMusic ()
716 self
.grace_elements
.append (element
)
717 def append_after_grace (self
, element
):
719 if not self
.after_grace_elements
:
720 self
.after_grace_elements
= SequentialMusic ()
721 self
.after_grace_elements
.append (element
)
723 def has_elements (self
):
724 return [e
for e
in self
.elements
if
725 isinstance (e
, NoteEvent
) or isinstance (e
, RestEvent
)] != []
728 def get_length (self
):
730 for e
in self
.elements
:
731 l
= max(l
, e
.get_length())
734 def get_duration (self
):
735 note_events
= [e
for e
in self
.elements
if
736 isinstance (e
, NoteEvent
) or isinstance (e
, RestEvent
)]
738 return note_events
[0].duration
742 def print_ly (self
, printer
):
743 note_events
= [e
for e
in self
.elements
if
744 isinstance (e
, NoteEvent
)]
746 rest_events
= [e
for e
in self
.elements
if
747 isinstance (e
, RhythmicEvent
)
748 and not isinstance (e
, NoteEvent
)]
750 other_events
= [e
for e
in self
.elements
if
751 not isinstance (e
, RhythmicEvent
)]
753 if self
.after_grace_elements
:
754 printer ('\\afterGrace {')
756 if self
.grace_elements
and self
.elements
:
758 printer ('\\%s' % self
.grace_type
)
761 # don't print newlines after the { and } braces
762 self
.grace_elements
.print_ly (printer
, False)
763 elif self
.grace_elements
: # no self.elements!
764 warning (_ ("Grace note with no following music: %s") % self
.grace_elements
)
766 printer ('\\%s' % self
.grace_type
)
769 self
.grace_elements
.print_ly (printer
, False)
772 # Print all overrides and other settings needed by the
773 # articulations/ornaments before the note
774 for e
in other_events
:
775 e
.print_before_note (printer
)
778 rest_events
[0].print_ly (printer
)
779 elif len (note_events
) == 1:
780 note_events
[0].print_ly (printer
)
782 global previous_pitch
785 for x
in note_events
:
786 pitches
.append (x
.pitch
.ly_expression ())
788 basepitch
= previous_pitch
789 printer ('<%s>' % string
.join (pitches
))
790 previous_pitch
= basepitch
791 duration
= self
.get_duration ()
793 duration
.print_ly (printer
)
797 for e
in other_events
:
800 for e
in other_events
:
801 e
.print_after_note (printer
)
803 if self
.after_grace_elements
:
805 self
.after_grace_elements
.print_ly (printer
, False)
807 self
.print_comment (printer
)
809 class Partial (Music
):
811 Music
.__init
__ (self
)
813 def print_ly (self
, printer
):
815 printer
.dump ("\\partial %s" % self
.partial
.ly_expression ())
817 class BarLine (Music
):
819 Music
.__init
__ (self
)
823 def print_ly (self
, printer
):
824 bar_symbol
= { 'regular': "|", 'dotted': ":", 'dashed': ":",
825 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
826 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
827 'short': "'", 'none': "" }.get (self
.type, None)
828 if bar_symbol
<> None:
829 printer
.dump ('\\bar "%s"' % bar_symbol
)
833 if self
.bar_number
> 0 and (self
.bar_number
% 10) == 0:
834 printer
.dump ("\\barNumberCheck #%d " % self
.bar_number
)
835 elif self
.bar_number
> 0:
836 printer
.print_verbatim (' %% %d' % self
.bar_number
)
839 def ly_expression (self
):
844 # strings to print before the note to which an event is attached.
845 # Ignored for notes etc.
846 self
.before_note
= None
847 self
.after_note
= None
848 # print something before the note to which an event is attached, e.g. overrides
849 def print_before_note (self
, printer
):
851 printer
.dump (self
.before_note
)
852 # print something after the note to which an event is attached, e.g. resetting
853 def print_after_note (self
, printer
):
855 printer
.dump (self
.after_note
)
858 class SpanEvent (Event
):
860 Event
.__init
__ (self
)
861 self
.span_direction
= 0 # start/stop
862 self
.line_type
= 'solid'
863 self
.span_type
= 0 # e.g. cres/decrescendo, ottava up/down
864 self
.size
= 0 # size of e.g. ocrave shift
865 def wait_for_note (self
):
867 def get_properties(self
):
868 return "'span-direction %d" % self
.span_direction
869 def set_span_type (self
, type):
870 self
.span_type
= type
872 class SlurEvent (SpanEvent
):
873 def print_before_note (self
, printer
):
874 command
= {'dotted': '\\slurDotted',
875 'dashed' : '\\slurDashed'}.get (self
.line_type
, '')
876 if command
and self
.span_direction
== -1:
877 printer
.dump (command
)
878 def print_after_note (self
, printer
):
879 # reset non-solid slur types!
880 command
= {'dotted': '\\slurSolid',
881 'dashed' : '\\slurSolid'}.get (self
.line_type
, '')
882 if command
and self
.span_direction
== -1:
883 printer
.dump (command
)
884 def ly_expression (self
):
885 return {-1: '(', 1:')'}.get (self
.span_direction
, '')
887 class BeamEvent (SpanEvent
):
888 def ly_expression (self
):
889 return {-1: '[', 1:']'}.get (self
.span_direction
, '')
891 class PedalEvent (SpanEvent
):
892 def ly_expression (self
):
893 return {-1: '\\sustainOn',
894 0:'\\sustainOff\\sustainOn',
895 1:'\\sustainOff'}.get (self
.span_direction
, '')
897 class TextSpannerEvent (SpanEvent
):
898 def ly_expression (self
):
899 return {-1: '\\startTextSpan',
900 1:'\\stopTextSpan'}.get (self
.span_direction
, '')
902 class BracketSpannerEvent (SpanEvent
):
903 # Ligature brackets use prefix-notation!!!
904 def print_before_note (self
, printer
):
905 if self
.span_direction
== -1:
907 # the the bracket after the last note
908 def print_after_note (self
, printer
):
909 if self
.span_direction
== 1:
911 # we're printing everything in print_(before|after)_note...
912 def ly_expression (self
):
916 class OctaveShiftEvent (SpanEvent
):
917 def wait_for_note (self
):
919 def set_span_type (self
, type):
920 self
.span_type
= {'up': 1, 'down': -1}.get (type, 0)
921 def ly_octave_shift_indicator (self
):
922 # convert 8/15 to lilypond indicators (+-1/+-2)
923 value
= {8: 1, 15: 2}.get (self
.size
, 0)
924 # negative values go up!
925 value
*= -1*self
.span_type
927 def ly_expression (self
):
928 dir = self
.ly_octave_shift_indicator ()
931 value
= '\ottava #%s' % dir
934 1: '\ottava #0'}.get (self
.span_direction
, '')
936 class TrillSpanEvent (SpanEvent
):
937 def ly_expression (self
):
938 return {-1: '\\startTrillSpan',
939 0: '', # no need to write out anything for type='continue'
940 1:'\\stopTrillSpan'}.get (self
.span_direction
, '')
942 class GlissandoEvent (SpanEvent
):
943 def print_before_note (self
, printer
):
944 if self
.span_direction
== -1:
946 "dashed" : "dashed-line",
947 "dotted" : "dotted-line",
949 }. get (self
.line_type
, None)
951 printer
.dump ("\once \override Glissando #'style = #'%s" % style
)
952 def ly_expression (self
):
953 return {-1: '\\glissando',
954 1:''}.get (self
.span_direction
, '')
956 class ArpeggioEvent(Event
):
958 Event
.__init
__ (self
)
960 self
.non_arpeggiate
= False
961 def wait_for_note (self
):
963 def print_before_note (self
, printer
):
964 if self
.non_arpeggiate
:
965 printer
.dump ("\\arpeggioBracket")
967 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self
.direction
, '')
970 def print_after_note (self
, printer
):
971 if self
.non_arpeggiate
or self
.direction
:
972 printer
.dump ("\\arpeggioNormal")
973 def ly_expression (self
):
974 return ('\\arpeggio')
977 class TieEvent(Event
):
978 def ly_expression (self
):
982 class HairpinEvent (SpanEvent
):
983 def set_span_type (self
, type):
984 self
.span_type
= {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
985 def hairpin_to_ly (self
):
986 if self
.span_direction
== 1:
989 return {1: '\<', -1: '\>'}.get (self
.span_type
, '')
991 def ly_expression (self
):
992 return self
.hairpin_to_ly ()
994 def print_ly (self
, printer
):
995 val
= self
.hairpin_to_ly ()
1001 class DynamicsEvent (Event
):
1002 def __init__ (self
):
1003 Event
.__init
__ (self
)
1005 def wait_for_note (self
):
1007 def ly_expression (self
):
1009 return '\%s' % self
.type
1013 def print_ly (self
, printer
):
1015 printer
.dump ("\\%s" % self
.type)
1017 class MarkEvent (Event
):
1018 def __init__ (self
, text
="\\default"):
1019 Event
.__init
__ (self
)
1021 def wait_for_note (self
):
1023 def ly_contents (self
):
1025 return '%s' % self
.mark
1028 def ly_expression (self
):
1029 return '\\mark %s' % self
.ly_contents ()
1031 class MusicGlyphMarkEvent (MarkEvent
):
1032 def ly_contents (self
):
1034 return '\\markup { \\musicglyph #"scripts.%s" }' % self
.mark
1039 class TextEvent (Event
):
1040 def __init__ (self
):
1041 Event
.__init
__ (self
)
1043 self
.force_direction
= None
1045 def wait_for_note (self
):
1048 def direction_mod (self
):
1049 return { 1: '^', -1: '_', 0: '-' }.get (self
.force_direction
, '-')
1051 def ly_expression (self
):
1052 base_string
= '%s\"%s\"'
1054 base_string
= '%s\markup{ ' + self
.markup
+ ' {%s} }'
1055 return base_string
% (self
.direction_mod (), self
.text
)
1057 class ArticulationEvent (Event
):
1058 def __init__ (self
):
1059 Event
.__init
__ (self
)
1061 self
.force_direction
= None
1062 def wait_for_note (self
):
1065 def direction_mod (self
):
1066 return { 1: '^', -1: '_', 0: '-' }.get (self
.force_direction
, '')
1068 def ly_expression (self
):
1069 return '%s\\%s' % (self
.direction_mod (), self
.type)
1071 class ShortArticulationEvent (ArticulationEvent
):
1072 def direction_mod (self
):
1074 return { 1: '^', -1: '_', 0: '-' }.get (self
.force_direction
, '-')
1075 def ly_expression (self
):
1077 return '%s%s' % (self
.direction_mod (), self
.type)
1081 class NoDirectionArticulationEvent (ArticulationEvent
):
1082 def ly_expression (self
):
1084 return '\\%s' % self
.type
1088 class MarkupEvent (ShortArticulationEvent
):
1089 def __init__ (self
):
1090 ArticulationEvent
.__init
__ (self
)
1091 self
.contents
= None
1092 def ly_expression (self
):
1094 return "%s\\markup { %s }" % (self
.direction_mod (), self
.contents
)
1098 class FretEvent (MarkupEvent
):
1099 def __init__ (self
):
1100 MarkupEvent
.__init
__ (self
)
1101 self
.force_direction
= 1
1106 def ly_expression (self
):
1108 if self
.strings
<> 6:
1109 val
+= "w:%s;" % self
.strings
1111 val
+= "h:%s;" % self
.frets
1112 if self
.barre
and len (self
.barre
) >= 3:
1113 val
+= "c:%s-%s-%s;" % (self
.barre
[0], self
.barre
[1], self
.barre
[2])
1114 have_fingering
= False
1115 for i
in self
.elements
:
1117 val
+= "%s-%s" % (i
[0], i
[1])
1119 have_fingering
= True
1125 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self
.direction_mod (), val
)
1130 def __init__ (self
):
1134 return self
.ly_expression()
1135 def ly_expression (self
):
1136 return pitch_generating_function (self
)
1138 class ChordModification
:
1139 def __init__ (self
):
1143 def ly_expression (self
):
1145 val
= {1: ".", -1: "^" }.get (self
.type, "")
1146 val
+= "%s" % self
.step
1147 val
+= {1: "+", -1: "-"}.get (self
.alteration
, "")
1152 class ChordNameEvent (Event
):
1153 def __init__ (self
):
1154 Event
.__init
__ (self
)
1157 self
.duration
= None
1158 self
.modifications
= []
1160 def add_modification (self
, mod
):
1161 self
.modifications
.append (mod
)
1162 def ly_expression (self
):
1165 value
= self
.root
.ly_expression ()
1167 value
+= self
.duration
.ly_expression ()
1171 # First print all additions/changes, and only afterwards all subtractions
1172 for m
in self
.modifications
:
1174 value
+= m
.ly_expression ()
1175 for m
in self
.modifications
:
1177 value
+= m
.ly_expression ()
1179 value
+= "/+%s" % self
.bass
.ly_expression ()
1183 class TremoloEvent (ArticulationEvent
):
1184 def __init__ (self
):
1185 Event
.__init
__ (self
)
1188 def ly_expression (self
):
1190 if self
.bars
and self
.bars
> 0:
1191 str += ':%s' % (2 ** (2 + string
.atoi (self
.bars
)))
1194 class BendEvent (ArticulationEvent
):
1195 def __init__ (self
):
1196 Event
.__init
__ (self
)
1198 def ly_expression (self
):
1200 return "-\\bendAfter #%s" % self
.alter
1204 class RhythmicEvent(Event
):
1205 def __init__ (self
):
1206 Event
.__init
__ (self
)
1207 self
.duration
= Duration()
1209 def get_length (self
):
1210 return self
.duration
.get_length()
1212 def get_properties (self
):
1213 return ("'duration %s"
1214 % self
.duration
.lisp_expression ())
1216 class RestEvent (RhythmicEvent
):
1217 def __init__ (self
):
1218 RhythmicEvent
.__init
__ (self
)
1220 def ly_expression (self
):
1222 return "%s%s\\rest" % (self
.pitch
.ly_expression (), self
.duration
.ly_expression ())
1224 return 'r%s' % self
.duration
.ly_expression ()
1226 def print_ly (self
, printer
):
1228 self
.pitch
.print_ly (printer
)
1229 self
.duration
.print_ly (printer
)
1233 self
.duration
.print_ly (printer
)
1235 class SkipEvent (RhythmicEvent
):
1236 def ly_expression (self
):
1237 return 's%s' % self
.duration
.ly_expression ()
1239 class NoteEvent(RhythmicEvent
):
1240 def __init__ (self
):
1241 RhythmicEvent
.__init
__ (self
)
1243 self
.drum_type
= None
1244 self
.cautionary
= False
1245 self
.forced_accidental
= False
1247 def get_properties (self
):
1248 str = RhythmicEvent
.get_properties (self
)
1251 str += self
.pitch
.lisp_expression ()
1252 elif self
.drum_type
:
1253 str += "'drum-type '%s" % self
.drum_type
1257 def pitch_mods (self
):
1260 excl_question
+= '?'
1261 if self
.forced_accidental
:
1262 excl_question
+= '!'
1264 return excl_question
1266 def ly_expression (self
):
1268 return '%s%s%s' % (self
.pitch
.ly_expression (),
1270 self
.duration
.ly_expression ())
1271 elif self
.drum_type
:
1272 return '%s%s' (self
.drum_type
,
1273 self
.duration
.ly_expression ())
1275 def print_ly (self
, printer
):
1277 self
.pitch
.print_ly (printer
)
1278 printer (self
.pitch_mods ())
1280 printer (self
.drum_type
)
1282 self
.duration
.print_ly (printer
)
1284 class KeySignatureChange (Music
):
1285 def __init__ (self
):
1286 Music
.__init
__ (self
)
1288 self
.tonic
= Pitch()
1291 def ly_expression (self
):
1292 return '\\key %s \\%s' % (self
.tonic
.ly_step_expression (),
1295 def lisp_expression (self
):
1296 pairs
= ['(%d . %d)' % (i
, self
.scale
[i
]) for i
in range (0,7)]
1297 scale_str
= ("'(%s)" % string
.join (pairs
))
1299 return """ (make-music 'KeyChangeEvent
1300 'pitch-alist %s) """ % scale_str
1302 class TimeSignatureChange (Music
):
1303 def __init__ (self
):
1304 Music
.__init
__ (self
)
1305 self
.fraction
= (4,4)
1306 def ly_expression (self
):
1307 return '\\time %d/%d ' % self
.fraction
1309 class ClefChange (Music
):
1310 def __init__ (self
):
1311 Music
.__init
__ (self
)
1316 def octave_modifier (self
):
1317 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self
.octave
, '')
1318 def clef_name (self
):
1319 return {('G', 2): "treble",
1321 ('C', 1): "soprano",
1322 ('C', 2): "mezzosoprano",
1325 ('C', 5): "baritone",
1326 ('F', 3): "varbaritone",
1328 ('F', 5): "subbass",
1329 ("percussion", 2): "percussion",
1330 ("TAB", 5): "tab"}.get ((self
.type, self
.position
), None)
1331 def ly_expression (self
):
1332 return '\\clef "%s%s"' % (self
.clef_name (), self
.octave_modifier ())
1335 "G": ("clefs.G", -2, -6),
1336 "C": ("clefs.C", 0, 0),
1337 "F": ("clefs.F", 2, 6),
1340 def lisp_expression (self
):
1342 (glyph
, pos
, c0
) = self
.clef_dict
[self
.type]
1346 (make-music 'SequentialMusic
1349 (make-property-set 'clefGlyph "%s") 'Staff)
1351 (make-property-set 'clefPosition %d) 'Staff)
1353 (make-property-set 'middleCPosition %d) 'Staff)))
1354 """ % (glyph
, pos
, c0
)
1358 class StaffChange (Music
):
1359 def __init__ (self
, staff
):
1360 Music
.__init
__ (self
)
1362 def ly_expression (self
):
1364 return "\\change Staff=\"%s\"" % self
.staff
1369 class TempoMark (Music
):
1370 def __init__ (self
):
1371 Music
.__init
__ (self
)
1372 self
.baseduration
= None
1373 self
.newduration
= None
1375 self
.parentheses
= False
1376 def set_base_duration (self
, dur
):
1377 self
.baseduration
= dur
1378 def set_new_duration (self
, dur
):
1379 self
.newduration
= dur
1380 def set_beats_per_minute (self
, beats
):
1382 def set_parentheses (self
, parentheses
):
1383 self
.parentheses
= parentheses
1384 def wait_for_note (self
):
1386 def duration_to_markup (self
, dur
):
1388 # Generate the markup to print the note, use scheme mode for
1389 # ly_expression to get longa and not \longa (which causes an error)
1390 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur
.ly_expression(None, True)
1393 def tempo_markup_template (self
):
1394 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1395 def ly_expression (self
):
1397 if not self
.baseduration
:
1400 if self
.parentheses
:
1401 res
+= "\\tempo \"\" %s=%s" % (self
.baseduration
.ly_expression(), self
.beats
)
1403 res
+= "\\tempo %s=%s" % (self
.baseduration
.ly_expression(), self
.beats
)
1404 elif self
.newduration
:
1405 dm
= self
.duration_to_markup (self
.baseduration
)
1406 ndm
= self
.duration_to_markup (self
.newduration
)
1407 if self
.parentheses
:
1408 contents
= "\"(\" %s = %s \")\"" % (dm
, ndm
)
1410 contents
= " %s = %s " % (dm
, ndm
)
1411 res
+= self
.tempo_markup_template() % contents
1416 class FiguredBassNote (Music
):
1417 def __init__ (self
):
1418 Music
.__init
__ (self
)
1422 def set_prefix (self
, prefix
):
1423 self
.prefix
= prefix
1424 def set_suffix (self
, suffix
):
1425 self
.prefix
= suffix
1426 def set_number (self
, number
):
1427 self
.number
= number
1428 def ly_expression (self
):
1441 class FiguredBassEvent (NestedMusic
):
1442 def __init__ (self
):
1443 NestedMusic
.__init
__ (self
)
1444 self
.duration
= None
1445 self
.real_duration
= 0
1446 self
.parentheses
= False
1448 def set_duration (self
, dur
):
1450 def set_parentheses (self
, par
):
1451 self
.parentheses
= par
1452 def set_real_duration (self
, dur
):
1453 self
.real_duration
= dur
1455 def print_ly (self
, printer
):
1456 figured_bass_events
= [e
for e
in self
.elements
if
1457 isinstance (e
, FiguredBassNote
)]
1458 if figured_bass_events
:
1460 for x
in figured_bass_events
:
1461 notes
.append (x
.ly_expression ())
1462 contents
= string
.join (notes
)
1463 if self
.parentheses
:
1464 contents
= '[%s]' % contents
1465 printer ('<%s>' % contents
)
1466 self
.duration
.print_ly (printer
)
1469 class MultiMeasureRest(Music
):
1471 def lisp_expression (self
):
1474 'MultiMeasureRestMusicGroup
1476 (list (make-music (quote BarCheck))
1481 'MultiMeasureRestEvent
1484 (make-music (quote BarCheck))))
1485 """ % self
.duration
.lisp_expression ()
1487 def ly_expression (self
):
1488 return 'R%s' % self
.duration
.ly_expression ()
1492 def __init__ (self
, command
= "StaffGroup"):
1493 self
.stafftype
= command
1495 self
.instrument_name
= None
1496 self
.short_instrument_name
= None
1500 self
.is_group
= True
1501 # part_information is a list with entries of the form
1502 # [staffid, voicelist]
1503 # where voicelist is a list with entries of the form
1504 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1505 self
.part_information
= None
1507 def append_staff (self
, staff
):
1508 self
.children
.append (staff
)
1510 def set_part_information (self
, part_name
, staves_info
):
1511 if part_name
== self
.id:
1512 self
.part_information
= staves_info
1514 for c
in self
.children
:
1515 c
.set_part_information (part_name
, staves_info
)
1517 def print_ly_contents (self
, printer
):
1518 for c
in self
.children
:
1520 c
.print_ly (printer
)
1521 def print_ly_overrides (self
, printer
):
1523 needs_with |
= self
.spanbar
== "no"
1524 needs_with |
= self
.instrument_name
!= None
1525 needs_with |
= self
.short_instrument_name
!= None
1526 needs_with |
= (self
.symbol
!= None) and (self
.symbol
!= "bracket")
1528 printer
.dump ("\\with {")
1529 if self
.instrument_name
or self
.short_instrument_name
:
1530 printer
.dump ("\\consists \"Instrument_name_engraver\"")
1531 if self
.spanbar
== "no":
1532 printer
.dump ("\\override SpanBar #'transparent = ##t")
1533 brack
= {"brace": "SystemStartBrace",
1535 "line": "SystemStartSquare"}.get (self
.symbol
, None)
1537 printer
.dump ("systemStartDelimiter = #'%s" % brack
)
1540 def print_ly (self
, printer
):
1542 printer
.dump ("\\new %s" % self
.stafftype
)
1543 self
.print_ly_overrides (printer
)
1546 if self
.stafftype
and self
.instrument_name
:
1547 printer
.dump ("\\set %s.instrumentName = %s" % (self
.stafftype
,
1548 escape_instrument_string (self
.instrument_name
)))
1550 if self
.stafftype
and self
.short_instrument_name
:
1551 printer
.dump ("\\set %s.shortInstrumentName = %s" % (self
.stafftype
,
1552 escape_instrument_string (self
.short_instrument_name
)))
1554 self
.print_ly_contents (printer
)
1560 class Staff (StaffGroup
):
1561 def __init__ (self
, command
= "Staff"):
1562 StaffGroup
.__init
__ (self
, command
)
1563 self
.is_group
= False
1565 self
.voice_command
= "Voice"
1566 self
.substafftype
= None
1568 def print_ly_overrides (self
, printer
):
1571 def print_ly_contents (self
, printer
):
1572 if not self
.id or not self
.part_information
:
1574 sub_staff_type
= self
.substafftype
1575 if not sub_staff_type
:
1576 sub_staff_type
= self
.stafftype
1578 for [staff_id
, voices
] in self
.part_information
:
1579 # Chord names need to come before the staff itself!
1580 for [v
, lyrics
, figuredbass
, chordnames
] in voices
:
1582 printer ('\context ChordNames = "%s" \\%s' % (chordnames
, chordnames
))
1584 # now comes the real staff definition:
1586 printer ('\\context %s = "%s" << ' % (sub_staff_type
, staff_id
))
1588 printer ('\\context %s << ' % sub_staff_type
)
1591 nr_voices
= len (voices
)
1592 for [v
, lyrics
, figuredbass
, chordnames
] in voices
:
1594 voice_count_text
= ''
1596 voice_count_text
= {1: ' \\voiceOne', 2: ' \\voiceTwo',
1597 3: ' \\voiceThree'}.get (n
, ' \\voiceFour')
1598 printer ('\\context %s = "%s" {%s \\%s }' % (self
.voice_command
, v
, voice_count_text
, v
))
1602 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v
,l
))
1605 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass
, figuredbass
))
1608 def print_ly (self
, printer
):
1609 if self
.part_information
and len (self
.part_information
) > 1:
1610 self
.stafftype
= "PianoStaff"
1611 self
.substafftype
= "Staff"
1612 StaffGroup
.print_ly (self
, printer
)
1614 class TabStaff (Staff
):
1615 def __init__ (self
, command
= "TabStaff"):
1616 Staff
.__init
__ (self
, command
)
1617 self
.string_tunings
= []
1618 self
.tablature_format
= None
1619 self
.voice_command
= "TabVoice"
1620 def print_ly_overrides (self
, printer
):
1621 if self
.string_tunings
or self
.tablature_format
:
1622 printer
.dump ("\\with {")
1623 if self
.string_tunings
:
1624 printer
.dump ("stringTunings = #'(")
1625 for i
in self
.string_tunings
:
1626 printer
.dump ("%s" % i
.semitones ())
1628 if self
.tablature_format
:
1629 printer
.dump ("tablatureFormat = #%s" % self
.tablature_format
)
1633 class DrumStaff (Staff
):
1634 def __init__ (self
, command
= "DrumStaff"):
1635 Staff
.__init
__ (self
, command
)
1636 self
.drum_style_table
= None
1637 self
.voice_command
= "DrumVoice"
1638 def print_ly_overrides (self
, printer
):
1639 if self
.drum_style_table
:
1640 printer
.dump ("\with {")
1641 printer
.dump ("drumStyleTable = #%s" % self
.drum_style_table
)
1644 class RhythmicStaff (Staff
):
1645 def __init__ (self
, command
= "RhythmicStaff"):
1646 Staff
.__init
__ (self
, command
)
1649 def __init__ (self
):
1650 self
.contents
= None
1651 self
.create_midi
= False
1653 def set_contents (self
, contents
):
1654 self
.contents
= contents
1656 def set_part_information (self
, part_id
, staves_info
):
1658 self
.contents
.set_part_information (part_id
, staves_info
)
1660 def print_ly (self
, printer
):
1661 printer
.dump ("\\score {");
1664 self
.contents
.print_ly (printer
);
1665 printer
.dump ("\\layout {}");
1667 if not self
.create_midi
:
1668 printer
.dump ("% To create MIDI output, uncomment the following line:");
1670 printer
.dump ("% ");
1671 printer
.dump ("\\midi {}");
1679 bflat
.alteration
= -1
1689 print bflat
.semitones()
1690 print bflat
.transposed (fifth
), bflat
.transposed (fifth
).transposed (fifth
)
1691 print bflat
.transposed (fifth
).transposed (fifth
).transposed (fifth
)
1693 print bflat
.semitones(), 'down'
1694 print bflat
.transposed (down
)
1695 print bflat
.transposed (down
).transposed (down
)
1696 print bflat
.transposed (down
).transposed (down
).transposed (down
)
1700 def test_printer ():
1708 m
= SequentialMusic()
1709 m
.append (make_note ())
1710 m
.append (make_note ())
1711 m
.append (make_note ())
1714 t
= TimeScaledMusic ()
1720 m
= SequentialMusic ()
1721 m
.append (make_tup ())
1722 m
.append (make_tup ())
1723 m
.append (make_tup ())
1725 printer
= Output_printer()
1726 m
.print_ly (printer
)
1730 m
= SequentialMusic()
1734 n
.duration
.duration_log
= l
1736 evc
.insert_around (None, n
, 0)
1737 m
.insert_around (None, evc
, 0)
1741 n
.duration
.duration_log
= l
1743 evc
.insert_around (None, n
, 0)
1744 m
.insert_around (None, evc
, 0)
1748 n
.duration
.duration_log
= l
1750 evc
.insert_around (None, n
, 0)
1751 m
.insert_around (None, evc
, 0)
1755 m
.insert_around (None, evc
, 0)
1760 tonic
.alteration
= -2
1761 n
= KeySignatureChange()
1762 n
.tonic
=tonic
.copy()
1763 n
.scale
= [0, 0, -2, 0, 0,-2,-2]
1765 evc
.insert_around (None, n
, 0)
1766 m
.insert_around (None, evc
, 0)
1771 if __name__
== '__main__':
1777 expr
.set_start (Rational (0))
1778 print expr
.ly_expression()
1779 start
= Rational (0,4)
1780 stop
= Rational (4,2)
1781 def sub(x
, start
=start
, stop
=stop
):
1782 ok
= x
.start
>= start
and x
.start
+x
.get_length() <= stop
1785 print expr
.lisp_sub_expression(sub
)