else
-$(INSTALL) -d $(DESTDIR)$(package_infodir)
-install-info --remove --info-dir=$(infodir) $(outdir)/lilypond.info
+ -install-info --remove --info-dir=$(infodir) $(outdir)/lilypond-program.info
install-info --info-dir=$(infodir) $(outdir)/lilypond.info
(cd $(package_infodir) && ln -sf $(webdir)/Documentation/user/*png .)
endif
def ly_expression (self):
return '~'
+
+class HairpinEvent (Event):
+ def __init__ (self, type):
+ self.type = type
+ def hairpin_to_ly (self):
+ val = ''
+ tp = { 0: '\!', 1: '\<', -1: '\>' }.get (self.type)
+ if tp:
+ val += tp
+ return val
+
+ def ly_expression (self):
+ return self.hairpin_to_ly ()
+ def print_ly (self, printer):
+ val = self.hairpin_to_ly ()
+ if val:
+ printer.dump (val)
+
+
+
+class DynamicsEvent (Event):
+ def __init__ (self):
+ self.type = None
+ self.available_commands = [ "ppppp", "pppp", "ppp", "pp", "p",
+ "mp", "mf",
+ "f", "ff", "fff", "ffff",
+ "fp", "sf", "sff", "sp", "spp", "sfz", "rfz" ];
+ def ly_expression (self):
+ if self.type == None:
+ return;
+ elif self.type in self.available_commands:
+ return '\%s' % self.type
+ else:
+ return '\markup{ \dynamic %s }' % self.type
+
+ def print_ly (self, printer):
+ if self.type == None:
+ return
+ elif self.type in self.available_commands:
+ printer.dump ("\\%s" % self.type)
+ else:
+ printer.dump ("\\markup{ \\dynamic %s }" % self.type)
+
+
+class ArticulationEvent (Event):
+ def __init__ (self):
+ self.type = None
+ self.force_direction = None
+
+ def direction_mod (self):
+ dirstr = { 1: '^', -1: '_', 0: '-' }.get (self.force_direction)
+ if dirstr:
+ return dirstr
+ else:
+ return ''
+
+ def ly_expression (self):
+ return '%s\\%s' % (self.direction_mod (), self.type)
+
+
+class TremoloEvent (Event):
+ def __init__ (self):
+ self.bars = 0;
+
+ def ly_expression (self):
+ str=''
+ if self.bars > 0:
+ str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
+ return str
+
+
class RhythmicEvent(Event):
def __init__ (self):
Event.__init__ (self)
p = p.get_parent ()
def get_typed_children (self, klass):
- return [c for c in self._children if isinstance(c, klass)]
+ if not klass:
+ return []
+ else:
+ return [c for c in self._children if isinstance(c, klass)]
def get_named_children (self, nm):
- return self.get_typed_children (class_dict[nm])
+ return self.get_typed_children (class_dict.get (nm))
def get_named_child (self, nm):
return self.get_maybe_exist_named_child (nm)
for n in elements:
voice_id = n.get_maybe_exist_typed_child (class_dict['voice'])
- if not (voice_id or isinstance (n, Attributes)):
+ # TODO: If the first element of a voice is a dynamics entry,
+ # then voice_id is not yet set! Thus it will currently be ignored
+ if not (voice_id or isinstance (n, Attributes) or isinstance (n, Direction) ):
continue
if isinstance (n, Attributes) and not start_attr:
start_attr = n
continue
- if isinstance (n, Attributes):
+ if isinstance (n, Attributes) or isinstance (n, Direction):
for v in voices.values ():
v.add_element (n)
continue
class Instrument (Music_xml_node):
pass
+class Fermata (Music_xml_node):
+ pass
+class Dynamics (Music_xml_node):
+ pass
+class Articulations (Music_xml_node):
+ pass
+class Accent (Music_xml_node):
+ pass
+class Staccato (Music_xml_node):
+ pass
+class Tenuto (Music_xml_node):
+ pass
+class Tremolo (Music_xml_node):
+ pass
+class Technical (Music_xml_node):
+ pass
+class Ornaments (Music_xml_node):
+ pass
+
+
+class Direction (Music_xml_node):
+ pass
+class DirType (Music_xml_node):
+ pass
+class Wedge (Music_xml_node):
+ pass
+
+
## need this, not all classes are instantiated
## for every input file.
class_dict = {
'type': Type,
'part-list': Part_list,
'staff': Staff,
+ 'fermata': Fermata,
+ 'articulations': Articulations,
+ 'accent': Accent,
+ 'staccato': Staccato,
+ 'tenuto': Tenuto,
+ 'tremolo': Tremolo,
+ 'technical': Technical,
+ 'ornaments': Ornaments,
+ 'direction': Direction,
+ 'direction-type': DirType,
+ 'dynamics': Dynamics,
+ 'wedge': Wedge
}
def name2class_name (name):
(ly:add-interface
'accidental-suggestion-interface
- "An accidental, printed as a suggestion (typically: vertically over a note)"
- '())
+ "An accidental, printed as a suggestion (typically: vertically over a
+note)."
+ '())
(ly:add-interface
'bass-figure-interface
- "A bass figure text"
+ "A bass figure text."
'(implicit))
+(ly:add-interface
+ 'bass-figure-alignment-interface
+ "Align a bass figure."
+ '())
+
(ly:add-interface
'bend-after-interface
"A doit or drop."
'(thickness delta-position))
-(ly:add-interface
- 'bass-figure-alignment-interface
- ""
- '())
-
(ly:add-interface
'dynamic-interface
- "Any kind of loudness sign"
- '())
+ "Any kind of loudness sign."
+ '())
(ly:add-interface
'dynamic-line-spanner-interface
- "Dynamic line spanner"
- '(avoid-slur))
+ "Dynamic line spanner."
+ '(avoid-slur))
(ly:add-interface
'dynamic-text-spanner-interface
- "Dynamic text spanner"
- '(text))
+ "Dynamic text spanner."
+ '(text))
(ly:add-interface
'finger-interface
- "A fingering instruction"
+ "A fingering instruction."
'())
(ly:add-interface
'fret-diagram-interface
- "A fret diagram"
-
+ "A fret diagram."
'(align-dir barre-type dot-color dot-radius finger-code fret-count
label-dir number-type size string-count xo-font-magnification
mute-string open-string orientation string-fret-finger-combinations
(ly:add-interface
'key-cancellation-interface
- "A key cancellation"
- '())
-
-(ly:add-interface
- 'ligature-interface
- "A ligature"
- '())
-
-(ly:add-interface
- 'key-cancellation-interface
- "A key cancellation"
+ "A key cancellation."
'())
(ly:add-interface
'ligature-bracket-interface
- "A bracket indicating a ligature in the original edition"
+ "A bracket indicating a ligature in the original edition."
'(width thickness height))
-
(ly:add-interface
- 'lyric-syllable-interface
- "A single piece of lyrics"
+ 'ligature-interface
+ "A ligature."
'())
(ly:add-interface
"Any object that is related to lyrics."
'())
+(ly:add-interface
+ 'lyric-syllable-interface
+ "A single piece of lyrics."
+ '())
+
(ly:add-interface
'mark-interface
- "A rehearsal mark"
+ "A rehearsal mark."
'())
(ly:add-interface
'metronome-mark-interface
- "A metronome mark"
+ "A metronome mark."
'())
(ly:add-interface
'(bound-padding))
(ly:add-interface
-'note-name-interface
- "Note name"
+ 'note-name-interface
+ "Note names."
'(style))
(ly:add-interface
(ly:add-interface
'parentheses-interface
- "Parentheses for other objects"
+ "Parentheses for other objects."
'(padding stencils))
(ly:add-interface
'piano-pedal-interface
- "A piano pedal sign"
+ "A piano pedal sign."
'())
(ly:add-interface
'piano-pedal-script-interface
- "A piano pedal sign, fixed size"
+ "A piano pedal sign, fixed size."
'())
(ly:add-interface
'pitched-trill-interface
- "A note head to indicate trill pitches"
- '(accidental-grob))
-
-(ly:add-interface
- 'trill-pitch-accidental-interface
- "An accidental for trill pitch"
- '()
- )
-
-(ly:add-interface
- 'trill-spanner-interface
- "An accidental for trill pitch"
- '())
+ "A note head to indicate trill pitches."
+ '(accidental-grob))
(ly:add-interface
'rhythmic-grob-interface
- "Any object with a duration. Used to determine which grobs are
+ "Any object with a duration. Used to determine which grobs are
interesting enough to maintain a hara-kiri staff."
'())
-
(ly:add-interface
'spacing-options-interface
- "Supports setting of spacing variables"
+ "Supports setting of spacing variables."
'(spacing-increment shortest-duration-space))
(ly:add-interface
'stanza-number-interface
- "A stanza number, to be put in from of a lyrics line"
+ "A stanza number, to be put in from of a lyrics line."
'())
(ly:add-interface
'string-number-interface
- "A string number instruction"
+ "A string number instruction."
'())
(ly:add-interface
'stroke-finger-interface
- "A right hand finger instruction"
+ "A right hand finger instruction."
'(digit-names))
(ly:add-interface
;;; todo: this is not typesetting info. Move to interpretation.
(ly:add-interface
'tablature-interface
- "An interface for any notes set in a tablature staff"
+ "An interface for any notes set in a tablature staff."
+ '())
+
+(ly:add-interface
+ 'trill-spanner-interface
+ "A trill spanner."
+ '())
+
+(ly:add-interface
+ 'trill-pitch-accidental-interface
+ "An accidental for trill pitch."
'())
(ly:add-interface
'unbreakable-spanner-interface
- "A spanner that should not be broken across line breaks. Override
-with @code{breakable=##t}. "
-
+ "A spanner that should not be broken across line breaks. Override
+with @code{breakable=##t}."
'(breakable))
(ly:add-interface
'vertically-spaceable-interface
- "Objects that should be kept at constant vertical distances. Typically:
+ "Objects that should be kept at constant vertical distances. Typically:
@internalsref{VerticalAxisGroup} objects of @internalsref{Staff} contexts."
'())
makes it print only if there is no beam associated with this tuplet
bracket.")
(break-align-anchor ,number? "Grobs aligned to this break-align
-grob will have their X-offsets shifted by this number. In barlines,
+grob will have their X-offsets shifted by this number. In barlines,
for example, this is used to position grobs relative to the (visual)
center of the barline.")
(break-align-anchor-alignment ,number? "Read by
(break-align-symbol ,symbol? "This key is used for aligning and
spacing breakable items.")
(break-align-symbols ,list? "A list of symbols that determine
-which break-aligned grobs to align this to. If the grob selected by
+which break-aligned grobs to align this to. If the grob selected by
the first symbol in the list is invisible due to break-visibility,
we will align to the next grob (and so on).")
(break-align-orders ,vector? "Defines the order in which
(dot-count ,integer? "The number of dots.")
(dot-radius ,number? "Radius of dots.")
(duration-log ,integer? "The 2-log of the note head duration,
-i.e. @code{0} = whole note, @code{1} = half note, etc.")
+i.e., @code{0} = whole note, @code{1} = half note, etc.")
(eccentricity ,number? "How asymmetrical to make a slur.
Positive means move the center to the right.")
include @code{upright}, @code{italic}, @code{caps}.")
(font-size ,number? "The font size, compared to the @q{normal}
size. @code{0}@tie{}is style-sheet's normal size, @code{-1} is
-smaller, @code{+1} is bigger. Each step of@tie{}1 is approximately
+smaller, @code{+1} is bigger. Each step of@tie{}1 is approximately
12% larger, 6@tie{}steps are exactly a factor@tie{}2 larger.
Fractional values are allowed.")
(force-hshift ,number? "This specifies a manual shift for notes
normal notation for some types of polyphonic music.
@code{merge-differently-dotted} only applies to opposing stem
-directions (i.e. voice 1 &@tie{}2).")
+directions (i.e., voice 1 &@tie{}2).")
(merge-differently-headed ,boolean? "Merge note heads in
collisions, even if they have different note heads. The
smaller of the two heads is rendered invisible. This is used in
@internalsref{note-collision-interface}.
@code{merge-differently-headed} only applies to opposing stem
-directions (i.e. voice 1 &@tie{}2).")
+directions (i.e., voice 1 &@tie{}2).")
(minimum-X-extent ,number-pair? "Minimum size of an object in
X@tie{}dimension, measured in @code{staff-space} units.")
(minimum-Y-extent ,number-pair? "See @code{minimum-X-extent}.")
@code{minimum-space} or @code{extra-space}.")
(space-to-barline ,boolean? "If set, the distance between a note
and the following non-musical column will be measured to the barline
-instead of to the beginning of the non-musical column. If there is a
+instead of to the beginning of the non-musical column. If there is a
clef change followed by a barline, for example, this means that we will
try to space the non-musical column as though the clef is not there.")
(spacing-increment ,number? "Add this much space for a doubled
-duration. Typically, the width of a note head. See also
+duration. Typically, the width of a note head. See also
@internalsref{spacing-spanner-interface}.")
(springs-and-rods ,boolean? "Dummy variable for triggering
spacing routines.")
(begin-of-line-visible ,boolean? "Used for marking @code{ChordNames}
that should only show changes.")
- (cause ,scheme? "Any kind of causation objects (i.e. music, or perhaps
+ (cause ,scheme? "Any kind of causation objects (i.e., music, or perhaps
translator) that was the cause for this grob.")
(circled-tip ,boolean? "Put a circle at start/end of hairpins (al/del
niente).")
(interface-doc-string (cdr interface) '())
"\n\n"
"This grob interface is used in the following graphical objects: "
-
(human-listify
(map ref-ify
(sort
(map symbol->string
(hashq-ref iface->grob-table (car interface) '()))
- string<?)))))))
+ string<?)))
+ "."))))
(define (grob-alist->texi alist)
(let* ((uprops (filter (lambda (x) (not (object-property x 'backend-internal)))
'key': musicxml_key_to_lily
}
for (k, func) in attr_dispatch.items ():
- childs = attrs.get_named_children (k)
+ children = attrs.get_named_children (k)
## ugh: you get clefs spread over staves for piano
- if childs:
+ if children:
elts.append (func (attrs))
return elts
return ev
+def musicxml_direction_to_indicator (direction):
+ val = { "above": 1, "upright": 1, "below": -1, "downright": -1 }.get (direction)
+ if val:
+ return val
+ else:
+ return ''
+
+def musicxml_fermata_to_lily_event (mxl_event):
+ ev = musicexp.ArticulationEvent ()
+ ev.type = "fermata"
+ if hasattr (mxl_event, 'type'):
+ dir = musicxml_direction_to_indicator (mxl_event.type)
+ if dir:
+ ev.force_direction = dir
+ return ev
+
+def musicxml_tremolo_to_lily_event(mxl_event):
+ if mxl_event.get_name () != "tremolo":
+ return
+ ev = musicexp.TremoloEvent ()
+ ev.bars = mxl_event.get_text ()
+ return ev
+
+# TODO: Some translations are missing!
+articulations_dict = {
+ ##### ORNAMENTS
+ "trill-mark": "trill",
+ "turn": "turn",
+ #"delayed-turn": "?",
+ "inverted-turn": "reverseturn",
+ #"shake": "?",
+ #"wavy-line": "?",
+ "mordent": "mordent",
+ #"inverted-mordent": "?",
+ #"schleifer": "?"
+ ##### TECHNICALS
+ "up-bow": "upbow",
+ "down-bow": "downbow",
+ #"harmonic": "",
+ #"open-string": "",
+ #"thumb-position": "",
+ #"fingering": "",
+ #"pluck": "",
+ #"double-tongue": "",
+ #"triple-tongue": "",
+ #"stopped": "",
+ #"snap-pizzicato": "",
+ #"fret": "",
+ #"string": "",
+ #"hammer-on": "",
+ #"pull-off": "",
+ #"bend": "",
+ #"tap": "",
+ #"heel": "",
+ #"toe": "",
+ #"fingernails": ""
+ ##### ARTICULATIONS
+ "accent": "accent",
+ "strong-accent": "marcato",
+ "staccato": "staccato",
+ "tenuto": "tenuto",
+ #"detached-legato": "",
+ "staccatissimo": "staccatissimo",
+ #"spiccato": "",
+ #"scoop": "",
+ #"plop": "",
+ #"doit": "",
+ #"falloff": "",
+ "breath-mark": "breathe",
+ #"caesura": "caesura",
+ #"stress": "",
+ #"unstress": ""
+}
+
+def musicxml_articulation_to_lily_event(mxl_event):
+ ev = musicexp.ArticulationEvent ()
+ tp = articulations_dict.get (mxl_event.get_name ())
+ if not tp:
+ return
+
+ ev.type = tp
+
+ # Some articulations use the type attribute, other the placement...
+ dir = None
+ if hasattr (mxl_event, 'type'):
+ dir = musicxml_direction_to_indicator (mxl_event.type)
+ if hasattr (mxl_event, 'placement'):
+ dir = musicxml_direction_to_indicator (mxl_event.placement)
+ if dir:
+ ev.force_direction = dir
+ return ev
+
+
+def musicxml_direction_to_lily( n ):
+ # TODO: Handle the <staff> element!
+ res = []
+ dirtype = n.get_maybe_exist_typed_child (musicxml.DirType)
+ if not dirtype:
+ return res
+
+ for entry in dirtype.get_all_children ():
+ if entry.get_name () == "dynamics":
+ for dynentry in entry.get_all_children ():
+ dynamics_available = ( "p", "pp", "ppp", "pppp", "ppppp", "pppppp",
+ "f", "ff", "fff", "ffff", "fffff", "ffffff",
+ "mp", "mf", "sf", "sfp", "sfpp", "fp",
+ "rf", "rfz", "sfz", "sffz", "fz" )
+ if not dynentry.get_name() in dynamics_available:
+ continue
+ event = musicexp.DynamicsEvent ()
+ event.type = dynentry.get_name ()
+ res.append (event)
+
+ if entry.get_name() == "wedge":
+ if hasattr (entry, 'type'):
+ wedgetype = entry.type;
+ wedgetypeval = {"crescendo" : 1, "decrescendo" : -1,
+ "diminuendo" : -1, "stop" : 0 }.get (wedgetype)
+ if wedgetypeval != None:
+ event = musicexp.HairpinEvent (wedgetypeval)
+ res.append (event)
+
+ return res
+
instrument_drumtype_dict = {
'Acoustic Snare Drum': 'acousticsnare',
'Side Stick': 'sidestick',
'Open Triangle': 'opentriangle',
'Mute Triangle': 'mutetriangle',
- 'Tambourine': 'tambourine',
-
+ 'Tambourine': 'tambourine'
}
def musicxml_note_to_lily_main_event (n):
class LilyPondVoiceBuilder:
def __init__ (self):
self.elements = []
+ self.pending_dynamics = []
self.end_moment = Rational (0)
self.begin_moment = Rational (0)
self.pending_multibar = Rational (0)
self.begin_moment = self.end_moment
self.end_moment = self.begin_moment + duration
+ # Insert all pending dynamics right after the note/rest:
+ if duration > Rational (0):
+ for d in self.pending_dynamics:
+ self.elements.append (d)
+ self.pending_dynamics = []
+
+ def add_dynamics (self, dynamic):
+ # store the dynamic item(s) until we encounter the next note/rest:
+ self.pending_dynamics.append (dynamic)
+
def add_bar_check (self, number):
b = musicexp.BarCheck ()
b.bar_number = number
if n.get_name () == 'forward':
continue
+ if isinstance (n, musicxml.Direction):
+ for a in musicxml_direction_to_lily (n):
+ voice_builder.add_dynamics (a)
+ continue
+
if not n.get_maybe_exist_named_child ('chord'):
try:
voice_builder.jumpto (n._when)
notations = n.get_maybe_exist_typed_child (musicxml.Notations)
tuplet_event = None
span_events = []
+
+ # The <notation> element can have the following children (+ means implemented, ~ partially, - not):
+ # +tied | +slur | +tuplet | glissando | slide |
+ # ornaments | technical | articulations | dynamics |
+ # +fermata | arpeggiate | non-arpeggiate |
+ # accidental-mark | other-notation
if notations:
if notations.get_tuplet():
tuplet_event = notations.get_tuplet()
mxl_tie = notations.get_tie ()
if mxl_tie and mxl_tie.type == 'start':
ev_chord.append (musicexp.TieEvent ())
+
+ fermatas = notations.get_named_children ('fermata')
+ for a in fermatas:
+ ev = musicxml_fermata_to_lily_event (a);
+ if ev:
+ ev_chord.append (ev)
+
+ # Articulations can contain the following child elements:
+ # accent | strong-accent | staccato | tenuto |
+ # detached-legato | staccatissimo | spiccato |
+ # scoop | plop | doit | falloff | breath-mark |
+ # caesura | stress | unstress
+ # Technical can contain the following child elements:
+ # up-bow | down-bow | harmonic | open-string |
+ # thumb-position | fingering | pluck | double-tongue |
+ # triple-tongue | stopped | snap-pizzicato | fret |
+ # string | hammer-on | pull-off | bend | tap | heel |
+ # toe | fingernails | other-technical
+ # Ornaments can contain the following child elements:
+ # trill-mark | turn | delayed-turn | inverted-turn |
+ # shake | wavy-line | mordent | inverted-mordent |
+ # schleifer | tremolo | other-ornament, accidental-mark
+ ornaments = notations.get_named_children ('ornaments')
+ for a in ornaments:
+ for ch in a.get_named_children ('tremolo'):
+ ev = musicxml_tremolo_to_lily_event (ch)
+ if ev:
+ ev_chord.append (ev)
+
+ ornaments += notations.get_named_children ('articulations')
+ ornaments += notations.get_named_children ('technical')
+
+ for a in ornaments:
+ for ch in a.get_all_children ():
+ ev = musicxml_articulation_to_lily_event (ch)
+ if ev:
+ ev_chord.append (ev)
+
+ dynamics = notations.get_named_children ('dynamics')
+ for a in dynamics:
+ for ch in a.get_all_children ():
+ ev = musicxml_dynamics_to_lily_event (ch)
+ if ev:
+ ev_chord.append (ev)
mxl_beams = [b for b in n.get_named_children ('beam')
if (b.get_type () in ('begin', 'end')
def musicxml_id_to_lily (id):
- digits = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
- 'nine', 'ten']
+ digits = ['Zero', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight',
+ 'Nine', 'Ten']
for dig in digits:
- d = digits.index (dig) + 1
- dig = dig[0].upper() + dig[1:]
+ d = digits.index (dig)
id = re.sub ('%d' % d, dig, id)
id = re.sub ('[^a-zA-Z]', 'X', id)
str = "Part%sVoice%s" % (part.id, name)
return musicxml_id_to_lily (str)
-def print_voice_definitions (printer, voices):
+def print_voice_definitions (printer, part_list, voices):
+ part_dict={}
for (part, nv_dict) in voices.items():
-
+ part_dict[part.id] = (part, nv_dict)
+
+ for part in part_list:
+ (part, nv_dict) = part_dict[part.id]
for (name, (voice, mxlvoice)) in nv_dict.items ():
k = music_xml_voice_name_to_lily_name (part, name)
printer.dump ('%s = ' % k)
printer.set_file (open (defs_ly_name, 'w'))
print_ly_preamble (printer, filename)
- print_voice_definitions (printer, voices)
+ print_voice_definitions (printer, part_list, voices)
printer.close ()