X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=python%2Fmusicexp.py;h=f6b47c3c93582af7471c13da23b38e7eec70ae1d;hb=14bd7e660f59c1ce1373424a877a70ec576a93d3;hp=d53815b03c11788feb67662fb4aba38e92704bfb;hpb=e28fc62d28b63167f2506f91b0df3eb319adef40;p=lilypond.git diff --git a/python/musicexp.py b/python/musicexp.py index d53815b03c..f6b47c3c93 100644 --- a/python/musicexp.py +++ b/python/musicexp.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- import inspect import sys import string @@ -12,16 +13,13 @@ from rational import Rational previous_pitch = None relative_pitches = False -def warning (str): - ly.stderr_write ((_ ("warning: %s") % str) + "\n") - def escape_instrument_string (input_string): retstring = string.replace (input_string, "\"", "\\\"") if re.match ('.*[\r\n]+.*', retstring): rx = re.compile (r'[\n\r]+') strings = rx.split (retstring) - retstring = "\\markup { \\column { " + retstring = "\\markup { \\center-column { " for s in strings: retstring += "\\line {\"" + s + "\"} " retstring += "} }" @@ -41,9 +39,9 @@ class Output_printer: """A class that takes care of formatting (eg.: indenting) a Music expression as a .ly file. - + """ - + def __init__ (self): self._line = '' self._indent = 4 @@ -56,19 +54,19 @@ class Output_printer: def set_file (self, file): self._file = file - + def dump_version (self): self.newline () self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"') self.newline () - + def get_indent (self): return self._nesting * self._indent - + def override (self): last = self._output_state_stack[-1] self._output_state_stack.append (last.copy()) - + def add_factor (self, factor): self.override() self._output_state_stack[-1].factor *= factor @@ -86,21 +84,21 @@ class Output_printer: def unformatted_output (self, str): # don't indent on \< and indent only once on << - self._nesting += ( str.count ('<') - - str.count ('\<') - str.count ('<<') + self._nesting += ( str.count ('<') + - str.count ('\<') - str.count ('<<') + str.count ('{') ) self._nesting -= ( str.count ('>') - str.count ('\>') - str.count ('>>') - str.count ('->') - str.count ('_>') - str.count ('^>') + str.count ('}') ) self.print_verbatim (str) - + def print_duration_string (self, str): if self._last_duration == str: return - + self.unformatted_output (str) - + def add_word (self, str): if (len (str) + 1 + len (self._line) > self._line_len): self.newline() @@ -110,7 +108,7 @@ class Output_printer: self._line += ' ' self.unformatted_output (str) self._skipspace = False - + def newline (self): self._file.write (self._line + '\n') self._line = ' ' * self._indent * self._nesting @@ -118,10 +116,10 @@ class Output_printer: def skipspace (self): self._skipspace = True - + def __call__(self, arg): self.dump (arg) - + def dump (self, str): if self._skipspace: self._skipspace = False @@ -143,7 +141,7 @@ class Duration: self.duration_log = 0 self.dots = 0 self.factor = Rational (1) - + def lisp_expression (self): return '(ly:make-duration %d %d %d %d)' % (self.duration_log, self.dots, @@ -172,14 +170,14 @@ class Duration: str += '*%d' % factor.numerator () return str - + def print_ly (self, outputter): str = self.ly_expression (self.factor / outputter.duration_factor ()) outputter.print_duration_string (str) - + def __repr__(self): return self.ly_expression() - + def copy (self): d = Duration () d.dots = self.dots @@ -200,6 +198,17 @@ class Duration: return base * dot_fact * self.factor +# implement the midi command line option '-m' and '--midi' +# if TRUE add midi-block to .ly file (see below) +def set_create_midi (option): + global midi_option + midi_option = option + +def get_create_midi (): + try: + return midi_option + except: + return False # Implement the different note names for the various languages def pitch_generic (pitch, notenames, accidentals): @@ -212,12 +221,12 @@ def pitch_generic (pitch, notenames, accidentals): # Handle remaining fraction to pitch.alteration (for microtones) if (halftones != pitch.alteration): if None in accidentals[1:3]: - warning (_ ("Language does not support microtones contained in the piece")) + ly.warning (_ ("Language does not support microtones contained in the piece")) else: try: str += {-0.5: accidentals[1], 0.5: accidentals[2]}[pitch.alteration-halftones] except KeyError: - warning (_ ("Language does not support microtones contained in the piece")) + ly.warning (_ ("Language does not support microtones contained in the piece")) return str def pitch_general (pitch): @@ -249,6 +258,10 @@ def pitch_italiano (pitch): def pitch_catalan (pitch): return pitch_italiano (pitch) +def pitch_francais (pitch): + str = pitch_generic (pitch, ['do', 'ré', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd']) + return str + def pitch_espanol (pitch): str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', None, None, 's']) return str @@ -266,8 +279,10 @@ def set_pitch_language (language): "norsk": pitch_norsk, "svenska": pitch_svenska, "italiano": pitch_italiano, + "français": pitch_francais, "catalan": pitch_catalan, "espanol": pitch_espanol, + "español": pitch_espanol, "vlaams": pitch_vlaams} pitch_generating_function = function_dict.get (language, pitch_general) @@ -281,7 +296,7 @@ class Pitch: self.step = 0 self.octave = 0 self._force_absolute_pitch = False - + def __repr__(self): return self.ly_expression() @@ -291,7 +306,7 @@ class Pitch: c.step += interval.step c.octave += interval.octave c.normalize () - + target_st = self.semitones() + interval.semitones() c.alteration += target_st - c.semitones() return c @@ -312,7 +327,7 @@ class Pitch: p = Pitch () p.alteration = self.alteration p.step = self.step - p.octave = self.octave + p.octave = self.octave return p def steps (self): @@ -320,8 +335,8 @@ class Pitch: def semitones (self): return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration - - def ly_step_expression (self): + + def ly_step_expression (self): return pitch_generating_function (self) def absolute_pitch (self): @@ -356,26 +371,26 @@ class Pitch: str += self.absolute_pitch () return str - + def print_ly (self, outputter): outputter (self.ly_expression()) - + class Music: def __init__ (self): self.parent = None self.start = Rational (0) self.comment = '' self.identifier = None - + def get_length(self): return Rational (0) - + def get_properties (self): return '' - + def has_children (self): return False - + def get_index (self): if self.parent: return self.parent.elements.index (self) @@ -383,12 +398,12 @@ class Music: return None def name (self): return self.__class__.__name__ - + def lisp_expression (self): name = self.name() props = self.get_properties () - + return "(make-music '%s %s)" % (name, props) def set_start (self, start): @@ -405,20 +420,20 @@ class Music: if not text: return - + if text == '\n': printer.newline () return - + lines = string.split (text, '\n') for l in lines: if l: printer.unformatted_output ('% ' + l) printer.newline () - + def print_with_identifier (self, printer): - if self.identifier: + if self.identifier: printer ("\\%s" % self.identifier) else: self.print_ly (printer) @@ -455,7 +470,7 @@ class RelativeMusic (MusicWrapper): previous_pitch = self.basepitch if not previous_pitch: previous_pitch = Pitch () - func ('\\relative %s%s' % (pitch_generating_function (previous_pitch), + func ('\\relative %s%s' % (pitch_generating_function (previous_pitch), previous_pitch.absolute_pitch ())) MusicWrapper.print_ly (self, func) relative_pitches = prev_relative_pitches @@ -476,15 +491,15 @@ class TimeScaledMusic (MusicWrapper): def print_ly (self, func): if self.display_bracket == None: - func ("\\once \\override TupletBracket #'stencil = ##f") + func ("\\once \\omit TupletBracket") func.newline () elif self.display_bracket == "curved": - warning (_ ("Tuplet brackets of curved shape are not correctly implemented")) - func ("\\once \\override TupletBracket #'stencil = #ly:slur::print") + ly.warning (_ ("Tuplet brackets of curved shape are not correctly implemented")) + func ("\\once \\override TupletBracket.stencil = #ly:slur::print") func.newline () - base_number_function = {None: "#f", - "actual": "tuplet-number::calc-denominator-text", + base_number_function = {None: "#f", + "actual": "tuplet-number::calc-denominator-text", "both": "tuplet-number::calc-fraction-text"}.get (self.display_number, None) # If we have non-standard numerator/denominator, use our custom function if self.display_number == "actual" and self.display_denominator: @@ -504,23 +519,35 @@ class TimeScaledMusic (MusicWrapper): if self.display_type == "actual" and self.normal_type: # Obtain the note duration in scheme-mode, i.e. \longa as \\longa base_duration = self.normal_type.ly_expression (None, True) - func ("\\once \\override TupletNumber #'text = #(tuplet-number::append-note-wrapper %s \"%s\")" % + func ("\\once \\override TupletNumber.text = #(tuplet-number::append-note-wrapper %s \"%s\")" % (base_number_function, base_duration)) func.newline () elif self.display_type == "both": # TODO: Implement this using actual_type and normal_type! - warning (_ ("Tuplet brackets displaying both note durations are not implemented, using default")) if self.display_number == None: - func ("\\once \\override TupletNumber #'stencil = ##f") + func ("\\once \\omit TupletNumber") func.newline () elif self.display_number == "both": - func ("\\once \\override TupletNumber #'text = #%s" % base_number_function) - func.newline () + den_duration = self.normal_type.ly_expression (None, True) + # If we don't have an actual type set, use the normal duration! + if self.actual_type: + num_duration = self.actual_type.ly_expression (None, True) + else: + num_duration = den_duration + if (self.display_denominator or self.display_numerator): + func ("\\once \\override TupletNumber.text = #(tuplet-number::non-default-fraction-with-notes %s \"%s\" %s \"%s\")" % + (self.display_denominator, den_duration, + self.display_numerator, num_duration)) + func.newline () + else: + func ("\\once \\override TupletNumber.text = #(tuplet-number::fraction-with-notes \"%s\" \"%s\")" % + (den_duration, num_duration)) + func.newline () else: if self.display_number == None: - func ("\\once \\override TupletNumber #'stencil = ##f") + func ("\\once \\omit TupletNumber") func.newline () elif self.display_number == "both": - func ("\\once \\override TupletNumber #'text = #%s" % base_number_function) + func ("\\once \\override TupletNumber.text = #%s" % base_number_function) func.newline () func ('\\times %d/%d ' % @@ -537,7 +564,7 @@ class NestedMusic(Music): def append (self, what): if what: self.elements.append (what) - + def has_children (self): return self.elements @@ -545,7 +572,7 @@ class NestedMusic(Music): assert elt.parent == None assert succ == None or succ in self.elements - + idx = 0 if succ: idx = self.elements.index (succ) @@ -559,7 +586,7 @@ class NestedMusic(Music): self.elements.insert (idx, elt) elt.parent = self - + def get_properties (self): return ("'elements (list %s)" % string.join (map (lambda x: x.lisp_expression(), @@ -580,10 +607,10 @@ class NestedMusic(Music): def delete_element (self, element): assert element in self.elements - + self.elements.remove (element) element.parent = None - + def set_start (self, start): self.start = start for e in self.elements: @@ -593,13 +620,13 @@ class NestedMusic(Music): r = Music.find_first (self, predicate) if r: return r - + for e in self.elements: r = e.find_first (predicate) if r: return r return None - + class SequentialMusic (NestedMusic): def get_last_event_chord (self): value = None @@ -626,15 +653,15 @@ class SequentialMusic (NestedMusic): printer ('}') if newline: printer.newline() - + def lisp_sub_expression (self, pred): name = self.name() props = self.get_subset_properties (pred) - + return "(make-music '%s %s)" % (name, props) - + def set_start (self, start): for e in self.elements: e.set_start (start) @@ -653,7 +680,7 @@ class RepeatedMusic: self.music = SequentialMusic () self.music.elements = music else: - warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \ + ly.warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \ {'music':music, 'repeat':self}) def add_ending (self, music): self.endings.append (music) @@ -662,7 +689,7 @@ class RepeatedMusic: if self.music: self.music.print_ly (printer) else: - warning (_ ("encountered repeat without body")) + ly.warning (_ ("encountered repeat without body")) printer.dump ('{}') if self.endings: printer.dump ('\\alternative {') @@ -736,12 +763,12 @@ class Paper: self.print_length_field (printer, "paper-width", self.page_width) self.print_length_field (printer, "paper-height", self.page_height) self.print_length_field (printer, "top-margin", self.top_margin) - self.print_length_field (printer, "botton-margin", self.bottom_margin) + self.print_length_field (printer, "bottom-margin", self.bottom_margin) self.print_length_field (printer, "left-margin", self.left_margin) # TODO: maybe set line-width instead of right-margin? self.print_length_field (printer, "right-margin", self.right_margin) # TODO: What's the corresponding setting for system_left_margin and - # system_right_margin in Lilypond? + # system_right_margin in LilyPond? self.print_length_field (printer, "between-system-space", self.system_distance) self.print_length_field (printer, "page-top-space", self.top_system_distance) @@ -817,7 +844,7 @@ class ChordEvent (NestedMusic): rest_events = [e for e in self.elements if isinstance (e, RhythmicEvent) and not isinstance (e, NoteEvent)] - + other_events = [e for e in self.elements if not isinstance (e, RhythmicEvent)] @@ -832,7 +859,7 @@ class ChordEvent (NestedMusic): # don't print newlines after the { and } braces self.grace_elements.print_ly (printer, False) elif self.grace_elements: # no self.elements! - warning (_ ("Grace note with no following music: %s") % self.grace_elements) + ly.warning (_ ("Grace note with no following music: %s") % self.grace_elements) if self.grace_type: printer ('\\%s' % self.grace_type) else: @@ -840,7 +867,7 @@ class ChordEvent (NestedMusic): self.grace_elements.print_ly (printer, False) printer ('{}') - # Print all overrides and other settings needed by the + # Print all overrides and other settings needed by the # articulations/ornaments before the note for e in other_events: e.print_before_note (printer) @@ -864,7 +891,7 @@ class ChordEvent (NestedMusic): duration.print_ly (printer) else: pass - + for e in other_events: e.print_ly (printer) @@ -876,7 +903,7 @@ class ChordEvent (NestedMusic): self.after_grace_elements.print_ly (printer, False) self.print_comment (printer) - + class Partial (Music): def __init__ (self): Music.__init__ (self) @@ -890,9 +917,9 @@ class BarLine (Music): Music.__init__ (self) self.bar_number = 0 self.type = None - + def print_ly (self, printer): - bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":", + bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': "dashed", 'heavy': "|", 'light-light': "||", 'light-heavy': "|.", 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'", 'short': "'", 'none': "" }.get (self.type, None) @@ -942,13 +969,13 @@ class SpanEvent (Event): class SlurEvent (SpanEvent): def print_before_note (self, printer): - command = {'dotted': '\\slurDotted', + command = {'dotted': '\\slurDotted', 'dashed' : '\\slurDashed'}.get (self.line_type, '') if command and self.span_direction == -1: printer.dump (command) def print_after_note (self, printer): # reset non-solid slur types! - command = {'dotted': '\\slurSolid', + command = {'dotted': '\\slurSolid', 'dashed' : '\\slurSolid'}.get (self.line_type, '') if command and self.span_direction == -1: printer.dump (command) @@ -975,7 +1002,7 @@ class BracketSpannerEvent (SpanEvent): def print_before_note (self, printer): if self.span_direction == -1: printer.dump ('\[') - # the the bracket after the last note + # the bracket after the last note def print_after_note (self, printer): if self.span_direction == 1: printer.dump ('\]') @@ -991,7 +1018,11 @@ class OctaveShiftEvent (SpanEvent): self.span_type = {'up': 1, 'down': -1}.get (type, 0) def ly_octave_shift_indicator (self): # convert 8/15 to lilypond indicators (+-1/+-2) - value = {8: 1, 15: 2}.get (self.size, 0) + try: + value = {8: 1, 15: 2}[self.size] + except KeyError: + ly.warning (_ ("Invalid octave shift size found: %s. Using no shift.") % self.size) + value = 0 # negative values go up! value *= -1*self.span_type return value @@ -1000,7 +1031,7 @@ class OctaveShiftEvent (SpanEvent): value = '' if dir: value = '\ottava #%s' % dir - return { + return { -1: value, 1: '\ottava #0'}.get (self.span_direction, '') @@ -1016,10 +1047,10 @@ class GlissandoEvent (SpanEvent): style= { "dashed" : "dashed-line", "dotted" : "dotted-line", - "wavy" : "zigzag" + "wavy" : "zigzag" }. get (self.line_type, None) if style: - printer.dump ("\once \override Glissando #'style = #'%s" % style) + printer.dump ("\\once \\override Glissando.style = #'%s" % style) def ly_expression (self): return {-1: '\\glissando', 1:''}.get (self.span_direction, '') @@ -1058,10 +1089,10 @@ class HairpinEvent (SpanEvent): return '\!' else: return {1: '\<', -1: '\>'}.get (self.span_type, '') - + def ly_expression (self): return self.hairpin_to_ly () - + def print_ly (self, printer): val = self.hairpin_to_ly () if val: @@ -1226,12 +1257,12 @@ class NotestyleEvent (Event): self.filled = None def pre_chord_ly (self): if self.style: - return "\\once \\override NoteHead #'style = #%s" % self.style + return "\\once \\override NoteHead.style = #%s" % self.style else: return '' def pre_note_ly (self, is_chord_element): if self.style and is_chord_element: - return "\\tweak #'style #%s" % self.style + return "\\tweak style #%s" % self.style else: return '' def ly_expression (self): @@ -1244,7 +1275,7 @@ class ChordPitch: self.step = 0 def __repr__(self): return self.ly_expression() - def ly_expression (self): + def ly_expression (self): return pitch_generating_function (self) class ChordModification: @@ -1337,11 +1368,11 @@ class RhythmicEvent(Event): def get_length (self): return self.duration.get_length() - + def get_properties (self): return ("'duration %s" % self.duration.lisp_expression ()) - + class RestEvent (RhythmicEvent): def __init__ (self): RhythmicEvent.__init__ (self) @@ -1353,7 +1384,7 @@ class RestEvent (RhythmicEvent): return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ()) else: return 'r%s' % self.duration.ly_expression () - + def print_ly (self, printer): for ev in self.associated_events: ev.print_ly (printer) @@ -1367,7 +1398,7 @@ class RestEvent (RhythmicEvent): class SkipEvent (RhythmicEvent): def ly_expression (self): - return 's%s' % self.duration.ly_expression () + return 's%s' % self.duration.ly_expression () class NoteEvent(RhythmicEvent): def __init__ (self): @@ -1379,14 +1410,14 @@ class NoteEvent(RhythmicEvent): def get_properties (self): str = RhythmicEvent.get_properties (self) - + if self.pitch: str += self.pitch.lisp_expression () elif self.drum_type: str += "'drum-type '%s" % self.drum_type return str - + def pitch_mods (self): excl_question = '' if self.cautionary: @@ -1448,7 +1479,7 @@ class KeySignatureChange (Music): try: accidental = alter_dict[a[1]] except KeyError: - warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1]) + ly.warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1]) return '' if len (a) == 2: return "( %s . %s )" % (a[0], accidental) @@ -1464,12 +1495,7 @@ class KeySignatureChange (Music): elif self.non_standard_alterations: alterations = [self.format_non_standard_alteration (a) for a in self.non_standard_alterations] - # TODO: Check if the alterations should really be given in reverse - # order of if that's just a bug in Lilypond. If it's a bug, - # fix it and remove the following call, otherwise add a - # proper comment here! - alterations.reverse () - return "\\set Staff.keySignature = #`(%s)" % string.join (alterations, " ") + return "\\set Staff.keyAlterations = #`(%s)" % string.join (alterations, " ") else: return '' @@ -1478,26 +1504,35 @@ class TimeSignatureChange (Music): Music.__init__ (self) self.fractions = [4,4] self.style = None + def format_fraction (self, frac): + if isinstance (frac, list): + l = [self.format_fraction (f) for f in frac] + return "(" + string.join (l, " ") + ")" + else: + return "%s" % frac + def ly_expression (self): st = '' - # Print out the style if we have ome, but the '() should only be - # forced for 2/2 or 4/4, since in all other cases we'll get numeric + # Print out the style if we have ome, but the '() should only be + # forced for 2/2 or 4/4, since in all other cases we'll get numeric # signatures anyway despite the default 'C signature style! is_common_signature = self.fractions in ([2,2], [4,4], [4,2]) if self.style: - if (self.style != "'()") or is_common_signature: - st = "\\once \\override Staff.TimeSignature #'style = #%s " % self.style + if self.style == "common": + st = "\\defaultTimeSignature" + elif (self.style != "'()"): + st = "\\once \\override Staff.TimeSignature.style = #%s " % self.style + elif (self.style != "'()") or is_common_signature: + st = "\\numericTimeSignature" # Easy case: self.fractions = [n,d] => normal \time n/d call: if len (self.fractions) == 2 and isinstance (self.fractions[0], int): return st + '\\time %d/%d ' % tuple (self.fractions) - elif self.fractions and not isinstance (self.fractions[0], list): - # TODO: Implement non-standard time-signatures - return st + '' + elif self.fractions: + return st + "\\compoundMeter #'%s" % self.format_fraction (self.fractions) else: - # TODO: Implement non-standard time-signatures return st + '' - + class ClefChange (Music): def __init__ (self): Music.__init__ (self) @@ -1519,6 +1554,8 @@ class ClefChange (Music): ('F', 4): "bass", ('F', 5): "subbass", ("percussion", 2): "percussion", + # Workaround: MuseScore uses PERC instead of percussion + ("PERC", 2): "percussion", ("TAB", 5): "tab"}.get ((self.type, self.position), None) def ly_expression (self): return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ()) @@ -1528,7 +1565,7 @@ class ClefChange (Music): "C": ("clefs.C", 0, 0), "F": ("clefs.F", 2, 6), } - + def lisp_expression (self): try: (glyph, pos, c0) = self.clef_dict[self.type] @@ -1564,6 +1601,26 @@ class StaffChange (Music): else: return '' +class SetEvent (Music): + def __init__ (self, contextprop, value): + Music.__init__ (self) + self.context_prop = contextprop + self.value = value + def ly_expression (self): + if self.value: + return "\\set %s = %s" % (self.context_prop, self.value) + else: + return '' + +class StaffLinesEvent (Music): + def __init__ (self, lines): + Music.__init__ (self) + self.lines = lines + def ly_expression (self): + if (self.lines > 0): + return "\\stopStaff \\override Staff.StaffSymbol.line-count = #%s \\startStaff" % self.lines + else: + return "\\stopStaff \\revert Staff.StaffSymbol.line-count \\startStaff" class TempoMark (Music): def __init__ (self): @@ -1584,7 +1641,7 @@ class TempoMark (Music): return False def duration_to_markup (self, dur): if dur: - # Generate the markup to print the note, use scheme mode for + # Generate the markup to print the note, use scheme mode for # ly_expression to get longa and not \longa (which causes an error) return "\\general-align #Y #DOWN \\smaller \\note #\"%s\" #UP" % dur.ly_expression(None, True) else: @@ -1687,6 +1744,14 @@ class MultiMeasureRest(Music): return 'R%s' % self.duration.ly_expression () +class Break (Music): + def __init__ (self, tp="break"): + Music.__init__ (self) + self.type = tp + def print_ly (self, printer): + if self.type: + printer.dump ("\\%s" % self.type) + class StaffGroup: def __init__ (self, command = "StaffGroup"): self.stafftype = command @@ -1697,6 +1762,7 @@ class StaffGroup: self.spanbar = None self.children = [] self.is_group = True + self.context_modifications = [] # part_information is a list with entries of the form # [staffid, voicelist] # where voicelist is a list with entries of the form @@ -1713,37 +1779,59 @@ class StaffGroup: for c in self.children: c.set_part_information (part_name, staves_info) + def add_context_modification (self, modification): + self.context_modifications.append (modification) + def print_ly_contents (self, printer): for c in self.children: if c: c.print_ly (printer) - def print_ly_overrides (self, printer): + def needs_with (self): needs_with = False needs_with |= self.spanbar == "no" needs_with |= self.instrument_name != None needs_with |= self.short_instrument_name != None needs_with |= (self.symbol != None) and (self.symbol != "bracket") + return needs_with + def print_ly_context_mods (self, printer): + if self.instrument_name or self.short_instrument_name: + printer.dump ("\\consists \"Instrument_name_engraver\"") + if self.spanbar == "no": + printer.dump ("\\hide SpanBar") + brack = {"brace": "SystemStartBrace", + "none": "SystemStartBar", + "line": "SystemStartSquare"}.get (self.symbol, None) + if brack: + printer.dump ("systemStartDelimiter = #'%s" % brack) + + def print_ly_overrides (self, printer): + needs_with = self.needs_with () | (len (self.context_modifications) > 0); if needs_with: printer.dump ("\\with {") - if self.instrument_name or self.short_instrument_name: - printer.dump ("\\consists \"Instrument_name_engraver\"") - if self.spanbar == "no": - printer.dump ("\\override SpanBar #'transparent = ##t") - brack = {"brace": "SystemStartBrace", - "none": "f", - "line": "SystemStartSquare"}.get (self.symbol, None) - if brack: - printer.dump ("systemStartDelimiter = #'%s" % brack) + self.print_ly_context_mods (printer) + for m in self.context_modifications: + printer.dump (m) printer.dump ("}") + def print_ly_chords (self,printer): + try: + for [staff_id, voices] in self.part_information: + for [v, lyrics, figuredbass, chordnames] in voices: + if chordnames: + printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames)) + printer.newline () + except TypeError: + return + def print_ly (self, printer): + self.print_ly_chords (printer) if self.stafftype: printer.dump ("\\new %s" % self.stafftype) self.print_ly_overrides (printer) printer.dump ("<<") printer.newline () if self.stafftype and self.instrument_name: - printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype, + printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype, escape_instrument_string (self.instrument_name))) printer.newline () if self.stafftype and self.short_instrument_name: @@ -1764,7 +1852,9 @@ class Staff (StaffGroup): self.voice_command = "Voice" self.substafftype = None - def print_ly_overrides (self, printer): + def needs_with (self): + return False + def print_ly_context_mods (self, printer): pass def print_ly_contents (self, printer): @@ -1775,12 +1865,6 @@ class Staff (StaffGroup): sub_staff_type = self.stafftype for [staff_id, voices] in self.part_information: - # Chord names need to come before the staff itself! - for [v, lyrics, figuredbass, chordnames] in voices: - if chordnames: - printer ('\context ChordNames = "%s" \\%s' % (chordnames, chordnames)) - - # now comes the real staff definition: if staff_id: printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id)) else: @@ -1820,9 +1904,9 @@ class TabStaff (Staff): if self.string_tunings or self.tablature_format: printer.dump ("\\with {") if self.string_tunings: - printer.dump ("stringTunings = #'(") + printer.dump ("stringTunings = #`(") for i in self.string_tunings: - printer.dump ("%s" % i.semitones ()) + printer.dump (",%s" % i.lisp_expression ()) printer.dump (")") if self.tablature_format: printer.dump ("tablatureFormat = #%s" % self.tablature_format) @@ -1843,7 +1927,7 @@ class DrumStaff (Staff): class RhythmicStaff (Staff): def __init__ (self, command = "RhythmicStaff"): Staff.__init__ (self, command) - + class Score: def __init__ (self): self.contents = None @@ -1851,12 +1935,13 @@ class Score: def set_contents (self, contents): self.contents = contents - + def set_part_information (self, part_id, staves_info): if self.contents: self.contents.set_part_information (part_id, staves_info) def print_ly (self, printer): + self.create_midi = get_create_midi () printer.dump ("\\score {"); printer.newline () if self.contents: @@ -1883,8 +1968,8 @@ def test_pitch (): down = Pitch () down.step = -4 down.normalize () - - + + print bflat.semitones() print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth) print bflat.transposed (fifth).transposed (fifth).transposed (fifth) @@ -1909,7 +1994,7 @@ def test_printer (): m.append (make_note ()) m.append (make_note ()) - + t = TimeScaledMusic () t.numerator = 2 t.denominator = 3 @@ -1920,14 +2005,14 @@ def test_printer (): m.append (make_tup ()) m.append (make_tup ()) m.append (make_tup ()) - + printer = Output_printer() m.print_ly (printer) printer.newline () - + def test_expr (): m = SequentialMusic() - l = 2 + l = 2 evc = ChordEvent() n = NoteEvent() n.duration.duration_log = l @@ -1945,7 +2030,7 @@ def test_expr (): evc = ChordEvent() n = NoteEvent() n.duration.duration_log = l - n.pitch.step = 2 + n.pitch.step = 2 evc.insert_around (None, n, 0) m.insert_around (None, evc, 0) @@ -1960,7 +2045,7 @@ def test_expr (): n = KeySignatureChange() n.tonic=tonic.copy() n.scale = [0, 0, -2, 0, 0,-2,-2] - + evc.insert_around (None, n, 0) m.insert_around (None, evc, 0) @@ -1971,7 +2056,7 @@ if __name__ == '__main__': test_printer () raise 'bla' test_pitch() - + expr = test_expr() expr.set_start (Rational (0)) print expr.ly_expression() @@ -1980,6 +2065,6 @@ if __name__ == '__main__': def sub(x, start=start, stop=stop): ok = x.start >= start and x.start +x.get_length() <= stop return ok - + print expr.lisp_sub_expression(sub)