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
.grace_elements
= None
710 self
.grace_type
= None
711 def append_grace (self
, element
):
713 if not self
.grace_elements
:
714 self
.grace_elements
= SequentialMusic ()
715 self
.grace_elements
.append (element
)
717 def get_length (self
):
719 for e
in self
.elements
:
720 l
= max(l
, e
.get_length())
723 def get_duration (self
):
724 note_events
= [e
for e
in self
.elements
if
725 isinstance (e
, NoteEvent
) or isinstance (e
, RestEvent
)]
727 return note_events
[0].duration
731 def print_ly (self
, printer
):
732 note_events
= [e
for e
in self
.elements
if
733 isinstance (e
, NoteEvent
)]
735 rest_events
= [e
for e
in self
.elements
if
736 isinstance (e
, RhythmicEvent
)
737 and not isinstance (e
, NoteEvent
)]
739 other_events
= [e
for e
in self
.elements
if
740 not isinstance (e
, RhythmicEvent
)]
742 if self
.grace_elements
and self
.elements
:
744 printer ('\\%s' % self
.grace_type
)
747 # don't print newlines after the { and } braces
748 self
.grace_elements
.print_ly (printer
, False)
749 # Print all overrides and other settings needed by the
750 # articulations/ornaments before the note
751 for e
in other_events
:
752 e
.print_before_note (printer
)
755 rest_events
[0].print_ly (printer
)
756 elif len (note_events
) == 1:
757 note_events
[0].print_ly (printer
)
759 global previous_pitch
762 for x
in note_events
:
763 pitches
.append (x
.pitch
.ly_expression ())
765 basepitch
= previous_pitch
766 printer ('<%s>' % string
.join (pitches
))
767 previous_pitch
= basepitch
768 duration
= self
.get_duration ()
770 duration
.print_ly (printer
)
774 for e
in other_events
:
777 for e
in other_events
:
778 e
.print_after_note (printer
)
780 self
.print_comment (printer
)
782 class Partial (Music
):
784 Music
.__init
__ (self
)
786 def print_ly (self
, printer
):
788 printer
.dump ("\\partial %s" % self
.partial
.ly_expression ())
790 class BarLine (Music
):
792 Music
.__init
__ (self
)
796 def print_ly (self
, printer
):
797 bar_symbol
= { 'regular': "|", 'dotted': ":", 'dashed': ":",
798 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
799 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
800 'short': "'", 'none': "" }.get (self
.type, None)
801 if bar_symbol
<> None:
802 printer
.dump ('\\bar "%s"' % bar_symbol
)
806 if self
.bar_number
> 0 and (self
.bar_number
% 10) == 0:
807 printer
.dump ("\\barNumberCheck #%d " % self
.bar_number
)
809 printer
.print_verbatim (' %% %d' % self
.bar_number
)
812 def ly_expression (self
):
817 # strings to print before the note to which an event is attached.
818 # Ignored for notes etc.
819 self
.before_note
= None
820 self
.after_note
= None
821 # print something before the note to which an event is attached, e.g. overrides
822 def print_before_note (self
, printer
):
824 printer
.dump (self
.before_note
)
825 # print something after the note to which an event is attached, e.g. resetting
826 def print_after_note (self
, printer
):
828 printer
.dump (self
.after_note
)
831 class SpanEvent (Event
):
833 Event
.__init
__ (self
)
834 self
.span_direction
= 0 # start/stop
835 self
.line_type
= 'solid'
836 self
.span_type
= 0 # e.g. cres/decrescendo, ottava up/down
837 self
.size
= 0 # size of e.g. ocrave shift
838 def wait_for_note (self
):
840 def get_properties(self
):
841 return "'span-direction %d" % self
.span_direction
842 def set_span_type (self
, type):
843 self
.span_type
= type
845 class SlurEvent (SpanEvent
):
846 def print_before_note (self
, printer
):
847 command
= {'dotted': '\\slurDotted',
848 'dashed' : '\\slurDashed'}.get (self
.line_type
, '')
849 if command
and self
.span_direction
== -1:
850 printer
.dump (command
)
851 def print_after_note (self
, printer
):
852 # reset non-solid slur types!
853 command
= {'dotted': '\\slurSolid',
854 'dashed' : '\\slurSolid'}.get (self
.line_type
, '')
855 if command
and self
.span_direction
== -1:
856 printer
.dump (command
)
857 def ly_expression (self
):
858 return {-1: '(', 1:')'}.get (self
.span_direction
, '')
860 class BeamEvent (SpanEvent
):
861 def ly_expression (self
):
862 return {-1: '[', 1:']'}.get (self
.span_direction
, '')
864 class PedalEvent (SpanEvent
):
865 def ly_expression (self
):
866 return {-1: '\\sustainOn',
867 0:'\\sustainOff\\sustainOn',
868 1:'\\sustainOff'}.get (self
.span_direction
, '')
870 class TextSpannerEvent (SpanEvent
):
871 def ly_expression (self
):
872 return {-1: '\\startTextSpan',
873 1:'\\stopTextSpan'}.get (self
.span_direction
, '')
875 class BracketSpannerEvent (SpanEvent
):
876 # Ligature brackets use prefix-notation!!!
877 def print_before_note (self
, printer
):
878 if self
.span_direction
== -1:
880 # the the bracket after the last note
881 def print_after_note (self
, printer
):
882 if self
.span_direction
== 1:
884 # we're printing everything in print_(before|after)_note...
885 def ly_expression (self
):
889 class OctaveShiftEvent (SpanEvent
):
890 def wait_for_note (self
):
892 def set_span_type (self
, type):
893 self
.span_type
= {'up': 1, 'down': -1}.get (type, 0)
894 def ly_octave_shift_indicator (self
):
895 # convert 8/15 to lilypond indicators (+-1/+-2)
896 value
= {8: 1, 15: 2}.get (self
.size
, 0)
897 # negative values go up!
898 value
*= -1*self
.span_type
900 def ly_expression (self
):
901 dir = self
.ly_octave_shift_indicator ()
904 value
= '\ottava #%s' % dir
907 1: '\ottava #0'}.get (self
.span_direction
, '')
909 class TrillSpanEvent (SpanEvent
):
910 def ly_expression (self
):
911 return {-1: '\\startTrillSpan',
912 0: '', # no need to write out anything for type='continue'
913 1:'\\stopTrillSpan'}.get (self
.span_direction
, '')
915 class GlissandoEvent (SpanEvent
):
916 def print_before_note (self
, printer
):
917 if self
.span_direction
== -1:
919 "dashed" : "dashed-line",
920 "dotted" : "dotted-line",
922 }. get (self
.line_type
, None)
924 printer
.dump ("\once \override Glissando #'style = #'%s" % style
)
925 def ly_expression (self
):
926 return {-1: '\\glissando',
927 1:''}.get (self
.span_direction
, '')
929 class ArpeggioEvent(Event
):
931 Event
.__init
__ (self
)
933 self
.non_arpeggiate
= False
934 def wait_for_note (self
):
936 def print_before_note (self
, printer
):
937 if self
.non_arpeggiate
:
938 printer
.dump ("\\arpeggioBracket")
940 dir = { -1: "\\arpeggioArrowDown", 1: "\\arpeggioArrowUp" }.get (self
.direction
, '')
943 def print_after_note (self
, printer
):
944 if self
.non_arpeggiate
or self
.direction
:
945 printer
.dump ("\\arpeggioNormal")
946 def ly_expression (self
):
947 return ('\\arpeggio')
950 class TieEvent(Event
):
951 def ly_expression (self
):
955 class HairpinEvent (SpanEvent
):
956 def set_span_type (self
, type):
957 self
.span_type
= {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
958 def hairpin_to_ly (self
):
959 if self
.span_direction
== 1:
962 return {1: '\<', -1: '\>'}.get (self
.span_type
, '')
964 def ly_expression (self
):
965 return self
.hairpin_to_ly ()
967 def print_ly (self
, printer
):
968 val
= self
.hairpin_to_ly ()
974 class DynamicsEvent (Event
):
976 Event
.__init
__ (self
)
978 def wait_for_note (self
):
980 def ly_expression (self
):
982 return '\%s' % self
.type
986 def print_ly (self
, printer
):
988 printer
.dump ("\\%s" % self
.type)
990 class MarkEvent (Event
):
991 def __init__ (self
, text
="\\default"):
992 Event
.__init
__ (self
)
994 def wait_for_note (self
):
996 def ly_contents (self
):
998 return '%s' % self
.mark
1001 def ly_expression (self
):
1002 return '\\mark %s' % self
.ly_contents ()
1004 class MusicGlyphMarkEvent (MarkEvent
):
1005 def ly_contents (self
):
1007 return '\\markup { \\musicglyph #"scripts.%s" }' % self
.mark
1012 class TextEvent (Event
):
1013 def __init__ (self
):
1014 Event
.__init
__ (self
)
1016 self
.force_direction
= None
1018 def wait_for_note (self
):
1021 def direction_mod (self
):
1022 return { 1: '^', -1: '_', 0: '-' }.get (self
.force_direction
, '-')
1024 def ly_expression (self
):
1025 base_string
= '%s\"%s\"'
1027 base_string
= '%s\markup{ ' + self
.markup
+ ' {%s} }'
1028 return base_string
% (self
.direction_mod (), self
.text
)
1030 class ArticulationEvent (Event
):
1031 def __init__ (self
):
1032 Event
.__init
__ (self
)
1034 self
.force_direction
= None
1035 def wait_for_note (self
):
1038 def direction_mod (self
):
1039 return { 1: '^', -1: '_', 0: '-' }.get (self
.force_direction
, '')
1041 def ly_expression (self
):
1042 return '%s\\%s' % (self
.direction_mod (), self
.type)
1044 class ShortArticulationEvent (ArticulationEvent
):
1045 def direction_mod (self
):
1047 return { 1: '^', -1: '_', 0: '-' }.get (self
.force_direction
, '-')
1048 def ly_expression (self
):
1050 return '%s%s' % (self
.direction_mod (), self
.type)
1054 class NoDirectionArticulationEvent (ArticulationEvent
):
1055 def ly_expression (self
):
1057 return '\\%s' % self
.type
1061 class MarkupEvent (ShortArticulationEvent
):
1062 def __init__ (self
):
1063 ArticulationEvent
.__init
__ (self
)
1064 self
.contents
= None
1065 def ly_expression (self
):
1067 return "%s\\markup { %s }" % (self
.direction_mod (), self
.contents
)
1071 class FretEvent (MarkupEvent
):
1072 def __init__ (self
):
1073 MarkupEvent
.__init
__ (self
)
1074 self
.force_direction
= 1
1079 def ly_expression (self
):
1081 if self
.strings
<> 6:
1082 val
+= "w:%s;" % self
.strings
1084 val
+= "h:%s;" % self
.frets
1085 if self
.barre
and len (self
.barre
) >= 3:
1086 val
+= "c:%s-%s-%s;" % (self
.barre
[0], self
.barre
[1], self
.barre
[2])
1087 have_fingering
= False
1088 for i
in self
.elements
:
1090 val
+= "%s-%s" % (i
[0], i
[1])
1092 have_fingering
= True
1098 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self
.direction_mod (), val
)
1103 def __init__ (self
):
1107 return self
.ly_expression()
1108 def ly_expression (self
):
1109 return pitch_generating_function (self
)
1111 class ChordModification
:
1112 def __init__ (self
):
1116 def ly_expression (self
):
1118 val
= {1: ".", -1: "^" }.get (self
.type, "")
1119 val
+= "%s" % self
.step
1120 val
+= {1: "+", -1: "-"}.get (self
.alteration
, "")
1125 class ChordNameEvent (Event
):
1126 def __init__ (self
):
1127 Event
.__init
__ (self
)
1130 self
.duration
= None
1131 self
.modifications
= []
1133 def add_modification (self
, mod
):
1134 self
.modifications
.append (mod
)
1135 def ly_expression (self
):
1138 value
= self
.root
.ly_expression ()
1140 value
+= self
.duration
.ly_expression ()
1144 # First print all additions/changes, and only afterwards all subtractions
1145 for m
in self
.modifications
:
1147 value
+= m
.ly_expression ()
1148 for m
in self
.modifications
:
1150 value
+= m
.ly_expression ()
1152 value
+= "/+%s" % self
.bass
.ly_expression ()
1156 class TremoloEvent (ArticulationEvent
):
1157 def __init__ (self
):
1158 Event
.__init
__ (self
)
1161 def ly_expression (self
):
1163 if self
.bars
and self
.bars
> 0:
1164 str += ':%s' % (2 ** (2 + string
.atoi (self
.bars
)))
1167 class BendEvent (ArticulationEvent
):
1168 def __init__ (self
):
1169 Event
.__init
__ (self
)
1171 def ly_expression (self
):
1173 return "-\\bendAfter #%s" % self
.alter
1177 class RhythmicEvent(Event
):
1178 def __init__ (self
):
1179 Event
.__init
__ (self
)
1180 self
.duration
= Duration()
1182 def get_length (self
):
1183 return self
.duration
.get_length()
1185 def get_properties (self
):
1186 return ("'duration %s"
1187 % self
.duration
.lisp_expression ())
1189 class RestEvent (RhythmicEvent
):
1190 def __init__ (self
):
1191 RhythmicEvent
.__init
__ (self
)
1193 def ly_expression (self
):
1195 return "%s%s\\rest" % (self
.pitch
.ly_expression (), self
.duration
.ly_expression ())
1197 return 'r%s' % self
.duration
.ly_expression ()
1199 def print_ly (self
, printer
):
1201 self
.pitch
.print_ly (printer
)
1202 self
.duration
.print_ly (printer
)
1206 self
.duration
.print_ly (printer
)
1208 class SkipEvent (RhythmicEvent
):
1209 def ly_expression (self
):
1210 return 's%s' % self
.duration
.ly_expression ()
1212 class NoteEvent(RhythmicEvent
):
1213 def __init__ (self
):
1214 RhythmicEvent
.__init
__ (self
)
1216 self
.drum_type
= None
1217 self
.cautionary
= False
1218 self
.forced_accidental
= False
1220 def get_properties (self
):
1221 str = RhythmicEvent
.get_properties (self
)
1224 str += self
.pitch
.lisp_expression ()
1225 elif self
.drum_type
:
1226 str += "'drum-type '%s" % self
.drum_type
1230 def pitch_mods (self
):
1233 excl_question
+= '?'
1234 if self
.forced_accidental
:
1235 excl_question
+= '!'
1237 return excl_question
1239 def ly_expression (self
):
1241 return '%s%s%s' % (self
.pitch
.ly_expression (),
1243 self
.duration
.ly_expression ())
1244 elif self
.drum_type
:
1245 return '%s%s' (self
.drum_type
,
1246 self
.duration
.ly_expression ())
1248 def print_ly (self
, printer
):
1250 self
.pitch
.print_ly (printer
)
1251 printer (self
.pitch_mods ())
1253 printer (self
.drum_type
)
1255 self
.duration
.print_ly (printer
)
1257 class KeySignatureChange (Music
):
1258 def __init__ (self
):
1259 Music
.__init
__ (self
)
1261 self
.tonic
= Pitch()
1264 def ly_expression (self
):
1265 return '\\key %s \\%s' % (self
.tonic
.ly_step_expression (),
1268 def lisp_expression (self
):
1269 pairs
= ['(%d . %d)' % (i
, self
.scale
[i
]) for i
in range (0,7)]
1270 scale_str
= ("'(%s)" % string
.join (pairs
))
1272 return """ (make-music 'KeyChangeEvent
1273 'pitch-alist %s) """ % scale_str
1275 class TimeSignatureChange (Music
):
1276 def __init__ (self
):
1277 Music
.__init
__ (self
)
1278 self
.fraction
= (4,4)
1279 def ly_expression (self
):
1280 return '\\time %d/%d ' % self
.fraction
1282 class ClefChange (Music
):
1283 def __init__ (self
):
1284 Music
.__init
__ (self
)
1289 def octave_modifier (self
):
1290 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self
.octave
, '')
1291 def clef_name (self
):
1292 return {('G', 2): "treble",
1294 ('C', 1): "soprano",
1295 ('C', 2): "mezzosoprano",
1298 ('C', 5): "baritone",
1299 ('F', 3): "varbaritone",
1301 ('F', 5): "subbass",
1302 ("percussion", 2): "percussion",
1303 ("TAB", 5): "tab"}.get ((self
.type, self
.position
), None)
1304 def ly_expression (self
):
1305 return '\\clef "%s%s"' % (self
.clef_name (), self
.octave_modifier ())
1308 "G": ("clefs.G", -2, -6),
1309 "C": ("clefs.C", 0, 0),
1310 "F": ("clefs.F", 2, 6),
1313 def lisp_expression (self
):
1315 (glyph
, pos
, c0
) = self
.clef_dict
[self
.type]
1319 (make-music 'SequentialMusic
1322 (make-property-set 'clefGlyph "%s") 'Staff)
1324 (make-property-set 'clefPosition %d) 'Staff)
1326 (make-property-set 'middleCPosition %d) 'Staff)))
1327 """ % (glyph
, pos
, c0
)
1331 class StaffChange (Music
):
1332 def __init__ (self
, staff
):
1333 Music
.__init
__ (self
)
1335 def ly_expression (self
):
1337 return "\\change Staff=\"%s\"" % self
.staff
1342 class TempoMark (Music
):
1343 def __init__ (self
):
1344 Music
.__init
__ (self
)
1345 self
.baseduration
= None
1346 self
.newduration
= None
1348 self
.parentheses
= False
1349 def set_base_duration (self
, dur
):
1350 self
.baseduration
= dur
1351 def set_new_duration (self
, dur
):
1352 self
.newduration
= dur
1353 def set_beats_per_minute (self
, beats
):
1355 def set_parentheses (self
, parentheses
):
1356 self
.parentheses
= parentheses
1357 def wait_for_note (self
):
1359 def duration_to_markup (self
, dur
):
1361 # Generate the markup to print the note, use scheme mode for
1362 # ly_expression to get longa and not \longa (which causes an error)
1363 return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur
.ly_expression(None, True)
1366 def tempo_markup_template (self
):
1367 return "\\mark\\markup { \\fontsize #-2 \\line { %s } }"
1368 def ly_expression (self
):
1370 if not self
.baseduration
:
1373 if self
.parentheses
:
1374 res
+= "\\tempo \"\" %s=%s" % (self
.baseduration
.ly_expression(), self
.beats
)
1376 res
+= "\\tempo %s=%s" % (self
.baseduration
.ly_expression(), self
.beats
)
1377 elif self
.newduration
:
1378 dm
= self
.duration_to_markup (self
.baseduration
)
1379 ndm
= self
.duration_to_markup (self
.newduration
)
1380 if self
.parentheses
:
1381 contents
= "\"(\" %s = %s \")\"" % (dm
, ndm
)
1383 contents
= " %s = %s " % (dm
, ndm
)
1384 res
+= self
.tempo_markup_template() % contents
1389 class FiguredBassNote (Music
):
1390 def __init__ (self
):
1391 Music
.__init
__ (self
)
1395 def set_prefix (self
, prefix
):
1396 self
.prefix
= prefix
1397 def set_suffix (self
, suffix
):
1398 self
.prefix
= suffix
1399 def set_number (self
, number
):
1400 self
.number
= number
1401 def ly_expression (self
):
1414 class FiguredBassEvent (NestedMusic
):
1415 def __init__ (self
):
1416 NestedMusic
.__init
__ (self
)
1417 self
.duration
= None
1418 self
.real_duration
= 0
1419 self
.parentheses
= False
1421 def set_duration (self
, dur
):
1423 def set_parentheses (self
, par
):
1424 self
.parentheses
= par
1425 def set_real_duration (self
, dur
):
1426 self
.real_duration
= dur
1428 def print_ly (self
, printer
):
1429 figured_bass_events
= [e
for e
in self
.elements
if
1430 isinstance (e
, FiguredBassNote
)]
1431 if figured_bass_events
:
1433 for x
in figured_bass_events
:
1434 notes
.append (x
.ly_expression ())
1435 contents
= string
.join (notes
)
1436 if self
.parentheses
:
1437 contents
= '[%s]' % contents
1438 printer ('<%s>' % contents
)
1439 self
.duration
.print_ly (printer
)
1442 class MultiMeasureRest(Music
):
1444 def lisp_expression (self
):
1447 'MultiMeasureRestMusicGroup
1449 (list (make-music (quote BarCheck))
1454 'MultiMeasureRestEvent
1457 (make-music (quote BarCheck))))
1458 """ % self
.duration
.lisp_expression ()
1460 def ly_expression (self
):
1461 return 'R%s' % self
.duration
.ly_expression ()
1465 def __init__ (self
, command
= "StaffGroup"):
1466 self
.stafftype
= command
1468 self
.instrument_name
= None
1469 self
.short_instrument_name
= None
1473 self
.is_group
= True
1474 # part_information is a list with entries of the form
1475 # [staffid, voicelist]
1476 # where voicelist is a list with entries of the form
1477 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1478 self
.part_information
= None
1480 def append_staff (self
, staff
):
1481 self
.children
.append (staff
)
1483 def set_part_information (self
, part_name
, staves_info
):
1484 if part_name
== self
.id:
1485 self
.part_information
= staves_info
1487 for c
in self
.children
:
1488 c
.set_part_information (part_name
, staves_info
)
1490 def print_ly_contents (self
, printer
):
1491 for c
in self
.children
:
1493 c
.print_ly (printer
)
1494 def print_ly_overrides (self
, printer
):
1496 needs_with |
= self
.spanbar
== "no"
1497 needs_with |
= self
.instrument_name
!= None
1498 needs_with |
= self
.short_instrument_name
!= None
1499 needs_with |
= (self
.symbol
!= None) and (self
.symbol
!= "bracket")
1501 printer
.dump ("\\with {")
1502 if self
.instrument_name
or self
.short_instrument_name
:
1503 printer
.dump ("\\consists \"Instrument_name_engraver\"")
1504 if self
.spanbar
== "no":
1505 printer
.dump ("\\override SpanBar #'transparent = ##t")
1506 brack
= {"brace": "SystemStartBrace",
1508 "line": "SystemStartSquare"}.get (self
.symbol
, None)
1510 printer
.dump ("systemStartDelimiter = #'%s" % brack
)
1513 def print_ly (self
, printer
):
1515 printer
.dump ("\\new %s" % self
.stafftype
)
1516 self
.print_ly_overrides (printer
)
1519 if self
.stafftype
and self
.instrument_name
:
1520 printer
.dump ("\\set %s.instrumentName = %s" % (self
.stafftype
,
1521 escape_instrument_string (self
.instrument_name
)))
1523 if self
.stafftype
and self
.short_instrument_name
:
1524 printer
.dump ("\\set %s.shortInstrumentName = %s" % (self
.stafftype
,
1525 escape_instrument_string (self
.short_instrument_name
)))
1527 self
.print_ly_contents (printer
)
1533 class Staff (StaffGroup
):
1534 def __init__ (self
, command
= "Staff"):
1535 StaffGroup
.__init
__ (self
, command
)
1536 self
.is_group
= False
1538 self
.voice_command
= "Voice"
1539 self
.substafftype
= None
1541 def print_ly_overrides (self
, printer
):
1544 def print_ly_contents (self
, printer
):
1545 if not self
.id or not self
.part_information
:
1547 sub_staff_type
= self
.substafftype
1548 if not sub_staff_type
:
1549 sub_staff_type
= self
.stafftype
1551 for [staff_id
, voices
] in self
.part_information
:
1552 # Chord names need to come before the staff itself!
1553 for [v
, lyrics
, figuredbass
, chordnames
] in voices
:
1555 printer ('\context ChordNames = "%s" \\%s' % (chordnames
, chordnames
))
1557 # now comes the real staff definition:
1559 printer ('\\context %s = "%s" << ' % (sub_staff_type
, staff_id
))
1561 printer ('\\context %s << ' % sub_staff_type
)
1564 nr_voices
= len (voices
)
1565 for [v
, lyrics
, figuredbass
, chordnames
] in voices
:
1567 voice_count_text
= ''
1569 voice_count_text
= {1: ' \\voiceOne', 2: ' \\voiceTwo',
1570 3: ' \\voiceThree'}.get (n
, ' \\voiceFour')
1571 printer ('\\context %s = "%s" {%s \\%s }' % (self
.voice_command
, v
, voice_count_text
, v
))
1575 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v
,l
))
1578 printer ('\context FiguredBass = "%s" \\%s' % (figuredbass
, figuredbass
))
1581 def print_ly (self
, printer
):
1582 if self
.part_information
and len (self
.part_information
) > 1:
1583 self
.stafftype
= "PianoStaff"
1584 self
.substafftype
= "Staff"
1585 StaffGroup
.print_ly (self
, printer
)
1587 class TabStaff (Staff
):
1588 def __init__ (self
, command
= "TabStaff"):
1589 Staff
.__init
__ (self
, command
)
1590 self
.string_tunings
= []
1591 self
.tablature_format
= None
1592 self
.voice_command
= "TabVoice"
1593 def print_ly_overrides (self
, printer
):
1594 if self
.string_tunings
or self
.tablature_format
:
1595 printer
.dump ("\\with {")
1596 if self
.string_tunings
:
1597 printer
.dump ("stringTunings = #'(")
1598 for i
in self
.string_tunings
:
1599 printer
.dump ("%s" % i
.semitones ())
1601 if self
.tablature_format
:
1602 printer
.dump ("tablatureFormat = #%s" % self
.tablature_format
)
1606 class DrumStaff (Staff
):
1607 def __init__ (self
, command
= "DrumStaff"):
1608 Staff
.__init
__ (self
, command
)
1609 self
.drum_style_table
= None
1610 self
.voice_command
= "DrumVoice"
1611 def print_ly_overrides (self
, printer
):
1612 if self
.drum_style_table
:
1613 printer
.dump ("\with {")
1614 printer
.dump ("drumStyleTable = #%s" % self
.drum_style_table
)
1617 class RhythmicStaff (Staff
):
1618 def __init__ (self
, command
= "RhythmicStaff"):
1619 Staff
.__init
__ (self
, command
)
1624 bflat
.alteration
= -1
1634 print bflat
.semitones()
1635 print bflat
.transposed (fifth
), bflat
.transposed (fifth
).transposed (fifth
)
1636 print bflat
.transposed (fifth
).transposed (fifth
).transposed (fifth
)
1638 print bflat
.semitones(), 'down'
1639 print bflat
.transposed (down
)
1640 print bflat
.transposed (down
).transposed (down
)
1641 print bflat
.transposed (down
).transposed (down
).transposed (down
)
1645 def test_printer ():
1653 m
= SequentialMusic()
1654 m
.append (make_note ())
1655 m
.append (make_note ())
1656 m
.append (make_note ())
1659 t
= TimeScaledMusic ()
1665 m
= SequentialMusic ()
1666 m
.append (make_tup ())
1667 m
.append (make_tup ())
1668 m
.append (make_tup ())
1670 printer
= Output_printer()
1671 m
.print_ly (printer
)
1675 m
= SequentialMusic()
1679 n
.duration
.duration_log
= l
1681 evc
.insert_around (None, n
, 0)
1682 m
.insert_around (None, evc
, 0)
1686 n
.duration
.duration_log
= l
1688 evc
.insert_around (None, n
, 0)
1689 m
.insert_around (None, evc
, 0)
1693 n
.duration
.duration_log
= l
1695 evc
.insert_around (None, n
, 0)
1696 m
.insert_around (None, evc
, 0)
1700 m
.insert_around (None, evc
, 0)
1705 tonic
.alteration
= -2
1706 n
= KeySignatureChange()
1707 n
.tonic
=tonic
.copy()
1708 n
.scale
= [0, 0, -2, 0, 0,-2,-2]
1710 evc
.insert_around (None, n
, 0)
1711 m
.insert_around (None, evc
, 0)
1716 if __name__
== '__main__':
1722 expr
.set_start (Rational (0))
1723 print expr
.ly_expression()
1724 start
= Rational (0,4)
1725 stop
= Rational (4,2)
1726 def sub(x
, start
=start
, stop
=stop
):
1727 ok
= x
.start
>= start
and x
.start
+x
.get_length() <= stop
1730 print expr
.lisp_sub_expression(sub
)