or their equivalents with cautionary accidentals.
@item
-The music function @code{\\unfoldRepeats} can now take an
+The music function @code{\unfoldRepeats} can now take an
optional argument-list specifying which type(s) of repeated music
should be unfolded. Possible entries are @code{percent}, @code{tremolo},
@code{volta}.
@node Configuring git-cl
@unnumberedsubsec Configuring @code{git-cl}
-@subsubheading Set up login accounts
-
Because @code{git-cl} updates two separate websites (Google's Rietveld
Code Review Tool and LilyPond's issue tracker) you @emph{must} have a
valid user account (login and password) for both sites.
+@subsubheading Set up a login account for Rietveld Code Review Tool
+
@noindent
-For the Rietveld Code Review Tool you will need a Google account. Note
-that a Google account does not require that you have or use a @q{Google}
-email address. You can use @emph{any} email address for your Google
-account. Just select the option @qq{I prefer to use my current email
-address} when you sign up.
+For the Rietveld Code Review Tool you will need a Google account but
+this does @emph{not} require @q{Google} email address; i.e. @emph{any}
+email address for your Google account can be used. Just select the
+option @qq{I prefer to use my current email address} when you sign up
+with Google.
+
+@warning{In order for @code{git-cl} to work correctly with this Google
+account, your Google Account Settings must have the
+@q{Access for less secure apps} set to @q{Allowed} -- this is normally
+the default setting.}
-@warning{In order for @code{git-cl} to work, your Google Account
-Settings must have the @q{Access for less secure apps} set to
-@q{Allowed}. This is normally the default setting.}
+@subsubheading Set up a login account for LilyPond's Issue Tracker
+
+@noindent
+Please register a user account at
+@code{https://sourceforge.net/user/registration} preferably using the
+same email address that you want to use LilyPond Developer mailing list
+login.
@noindent
-For the LilyPond issue tracker, please request a user account by sending
-an email to the LilyPond Developer's mailing list
-(@code{lilypond-devel@@gnu.org}), preferably using the same email
-address that you want to use for your user login.
+Once you have created this Sourceforge user account, send an email to
+the LilyPond Developer's mailing list (@code{lilypond-devel@@gnu.org})
+asking for write access to the issue tracker along with your Sourceforce
+@emph{Username} (not email address) and someone will then be able to set
+this up for you.
@subsubheading Authorizing git-cl for the LilyPond issue tracker
* Finding the cause of a regression::
* Memory and coverage tests::
* MusicXML tests::
-* Grand Regression Test Checking::
@end menu
@uref{http://lilypond.org/doc/latest/input/regression/musicxml/collated-files}
@end example
-
-@node Grand Regression Test Checking
-@section Grand Regression Test Checking
-
-@subheading What is this all about?
-
-Regression tests (usually abbreviated "regtests") is a collection
-of @file{.ly} files used to check whether LilyPond is working correctly.
-Example: before version 2.15.12 breve noteheads had incorrect width,
-which resulted in collisions with other objects. After the issue was fixed,
-a small @file{.ly} file demonstrating the problem was added to the regression
-tests as a proof that the fix works. If someone will accidentally break
-breve width again, we will notice this in the output of that regression test.
-
-@subheading How can I help?
-
-We ask you to help us by checking one or two regtests from time to time.
-You don't need programming skills to do this, not even LilyPond skills -
-just basic music notation knowledge; checking one regtest takes less than
-a minute. Simply go here:
-
-@example
-@uref{http://www.philholmes.net/lilypond/regtests/}
-@end example
-
-@subheading Some tips on checking regtests
-
-@subsubheading Description text
-
-The description should be clear even for a music beginner.
-If there are any special terms used in the description,
-they all should be explained in our @rglosnamed{Top, Music Glossary}
-or @rinternalsnamed{Top, Internals Reference}.
-Vague descriptions (like "behaves well", "looks reasonable") shouldn't be used.
-
-@ignore
-this may be useful for advanced regtest checking
-@subsubheading Is regtest straightforward and systematic?
-
-Unfortunately some regtests are written poorly. A good regtest should be
-straightforward: it should be obvious what it checks and how. Also, it
-usually shouldn't check everything at once. For example it's a bad idea to test
-accidental placement by constucting one huge chord with many suspended notes
-and loads of accidentals. It's better to divide such problem into a series
-of clearly separated cases.
-@end ignore
but occasionally it can be tricky. If the wrong context
is specified, no error message is produced, but the expected
action will not take place. For example, the
-@code{instrumentName} clearly lives in the @code{Staff} context, since
-it is the staff that is to be named.
-In this example the first staff is labeled, but not the second,
-because we omitted the context name.
+@code{clefGlyph} clearly lives in the @code{Staff} context, since
+it is the staff's clef glyph that is to be changed.
+In this example the first staff's clef is printed correctly, but not the
+second -- which prints the default treble clef instead of the
+expected bass (or F) clef -- because we omitted the context name.
@lilypond[quote,verbatim,ragged-right]
<<
\new Staff \relative {
- \set Staff.instrumentName = #"Soprano"
+ \set Staff.clefGlyph = "clefs.C"
c''2 c
}
\new Staff \relative {
- \set instrumentName = #"Alto" % Wrong!
+ \set clefGlyph = "clefs.F" % Wrong!
d'2 d
}
>>
@end lilypond
Remember the default context name is @code{Voice}, so the second
-@code{\set} command set the property @code{instrumentName} in the
-@code{Voice} context to @qq{Alto}, but as LilyPond does not look
+@code{\set} command set the property @code{clefGlyph} in the
+@code{Voice} context to @code{clefs.F}, but as LilyPond does not look
for any such property in the @code{Voice} context, no
further action took place. This is not an error, and no error
message is logged in the log file.
Internals Reference: see @rinternals{Tunable context properties}, or
@rinternals{Contexts}.
-The @code{instrumentName} property will take effect only
+The @code{clefGlyph} property will take effect only
if it is set in the @code{Staff} context, but
some properties can be set in more than one context.
For example, the property @code{extraNatural} is by
\score {
<< % combine ChoirStaff and PianoStaff in parallel
\new ChoirStaff <<
- \new Staff = "sopranos" <<
- \set Staff.instrumentName = #"Soprano"
+ \new Staff = "sopranos"
+ \with { instrumentName = #"Soprano" }
+ <<
\new Voice = "sopranos" {
\global
\sopranoMusic
\new Lyrics \lyricsto "sopranos" {
\sopranoWords
}
- \new Staff = "altos" <<
- \set Staff.instrumentName = #"Alto"
+ \new Staff = "altos"
+ \with { instrumentName = #"Alto" }
+ <<
\new Voice = "altos" {
\global
\altoMusic
}
>>
- \new Lyrics \lyricsto "altos" { \altoWords }
- \new Staff = "tenors" <<
- \set Staff.instrumentName = #"Tenor"
+ \new Lyrics \lyricsto "altos" {
+ \altoWords
+ }
+ \new Staff = "tenors"
+ \with { instrumentName = #"Tenor" }
+ <<
\new Voice = "tenors" {
\global
\tenorMusic
}
>>
- \new Lyrics \lyricsto "tenors" { \tenorWords }
- \new Staff = "basses" <<
- \set Staff.instrumentName = #"Bass"
+ \new Lyrics \lyricsto "tenors" {
+ \tenorWords
+ }
+ \new Staff = "basses"
+ \with { instrumentName = #"Bass" }
+ <<
\new Voice = "basses" {
\global
\bassMusic
\bassWords
}
>> % end ChoirStaff
- \new PianoStaff <<
- \set PianoStaff.instrumentName = #"Piano"
+ \new PianoStaff \with { instrumentName = #"Piano" }
+ <<
\new Staff = "upper" \upper
\new Staff = "lower" \lower
>>
@example
\new ChoirStaff <<
- \new Staff = "sopranos" <<
- \set Staff.instrumentName = #"Soprano"
+ \new Staff = "sopranos"
+ \with @{ instrumentName = #"Soprano" @}
+ <<
\new Voice = "sopranos" @{
\global
\sopranoMusic
\new Lyrics \lyricsto "sopranos" @{
\sopranoWords
@}
- \new Staff = "altos" <<
- \set Staff.instrumentName = #"Alto"
+ \new Staff = "altos"
+ \with @{ instrumentName = #"Alto" @}
+ <<
\new Voice = "altos" @{
\global
\altoMusic
\new Lyrics \lyricsto "altos" @{
\altoWords
@}
- \new Staff = "tenors" <<
- \set Staff.instrumentName = #"Tenor"
+ \new Staff = "tenors"
+ \with @{ instrumentName = #"Tenor" @}
+ <<
\new Voice = "tenors" @{
\global
\tenorMusic
\new Lyrics \lyricsto "tenors" @{
\tenorWords
@}
- \new Staff = "basses" <<
- \set Staff.instrumentName = #"Bass"
+ \new Staff = "basses"
+ \with @{ instrumentName = #"Bass" @}
+ <<
\new Voice = "basses" @{
\global
\bassMusic
@q{Solo piano} template:
@example
-\new PianoStaff <<
- \set PianoStaff.instrumentName = #"Piano "
+\new PianoStaff \with @{ instrumentName = #"Piano " @}
+<<
\new Staff = "upper" \upper
\new Staff = "lower" \lower
>>
@}
>> % end ChoirStaff
- \new PianoStaff <<
- \set PianoStaff.instrumentName = #"Piano"
+ \new PianoStaff \with @{ instrumentName = #"Piano" @}
+ <<
\new Staff = "upper" \upper
\new Staff = "lower" \lower
>>
\score {
<< % combine ChoirStaff and PianoStaff in parallel
\new ChoirStaff <<
- \new Staff = "sopranos" <<
- \set Staff.instrumentName = #"Soprano"
+ \new Staff = "sopranos"
+ \with { instrumentName = #"Soprano" }
+ <<
\new Voice = "sopranos" {
\global
\sopranoMusic
\new Lyrics \lyricsto "sopranos" {
\sopranoWords
}
- \new Staff = "altos" <<
- \set Staff.instrumentName = #"Alto"
+ \new Staff = "altos"
+ \with { instrumentName = #"Alto" }
+ <<
\new Voice = "altos" {
\global
\altoMusic
\new Lyrics \lyricsto "altos" {
\altoWords
}
- \new Staff = "tenors" <<
- \set Staff.instrumentName = #"Tenor"
+ \new Staff = "tenors"
+ \with { instrumentName = #"Tenor" }
+ <<
\new Voice = "tenors" {
\global
\tenorMusic
\new Lyrics \lyricsto "tenors" {
\tenorWords
}
- \new Staff = "basses" <<
- \set Staff.instrumentName = #"Bass"
+ \new Staff = "basses"
+ \with { instrumentName = #"Bass" }
+ <<
\new Voice = "basses" {
\global
\bassMusic
}
>> % end ChoirStaff
- \new PianoStaff <<
- \set PianoStaff.instrumentName = #"Piano "
+ \new PianoStaff
+ \with { instrumentName = #"Piano " }
+ <<
\new Staff = "upper" \upper
\new Staff = "lower" \lower
>>
my $reldir = "";
$reldir = "../" unless $bigpage;
if ($have_index_entries) {
- $Texi2HTML::THISDOC{'CSS_LINES'} .= "<script language=\"JavaScript\" src=\"${reldir}lily_search.js\"></script>\n";
+ $Texi2HTML::THISDOC{'CSS_LINES'} .= "<script language=\"JavaScript\" type=\"text/javascript\" src=\"${reldir}lily_search.js\"></script>\n";
}
}
* The override command::
* The tweak command::
* set versus override::
+* The offset command::
* Modifying alists::
@end menu
@code{\overrideProperty} for a specific override.
+@node The offset command
+@subsection The @code{\offset} command
+
+@funindex \offset
+@cindex offsetting
+@cindex defaults, offsetting
+
+While it is possible to set grob properties to new values with the
+@code{\override}, @code{\tweak}, and @code{\overrideProperty} commands,
+it is often more convenient to modify such properties relative to a
+default value. The @code{\offset} command is available for this
+purpose.
+
+The syntax for @code{\offset} is
+
+@example
+[-]\offset @var{property} @var{offsets} @var{item}
+@end example
+
+The command works by adding the contents of @var{offsets} to the
+default setting of the property @var{property} of the grob indicated by
+@var{item}.
+
+Depending on the formulation of the command, @code{\offset} may act
+as either a @code{\tweak} or @code{\override}. The variations in
+usage are discussed after consideration is given to grob properties
+that may be used with @code{\offset}.
+
+@subsubsubheading{Properties which may be offset}
+
+Many, but not all, grob properties may be offset. If @var{property}
+cannot be offset, the object will remain unchanged and a warning will
+be issued. In such cases, @code{\override} or @code{\tweak} should be
+used to modify the object instead.
+
+One can work by trial and error and let the warnings be the guide to
+what may or may not be offset. A more systematic approach is possible,
+however.
+
+The following criteria determine whether a property can be modified with
+@code{\offset}:
+
+@itemize
+
+@item
+The property has a @q{default setting} in the grob's description. Such
+properties are listed for each grob in @rinternals{All layout objects}.
+(They are also found in @file{scm/define-grobs.scm}.)
+
+@item
+The property takes a numerical value. Numerical values include
+@code{number}, list of @code{number}s, @code{number-pair}, and
+@code{number-pair-list}. The pages at @rinternals{All layout objects}
+list the type of data characteristic to each property. It is immaterial
+whether the default setting is a function.
+
+@item
+The property cannot be a @q{subproperty}---a property residing within
+another property.
+
+@item
+Properties set to infinite values cannot be offset. There is no
+sensible way to offset positive and negative infinity.
+@end itemize
+
+The following examples consider several grob properties against the
+criteria outlined above.
+
+@itemize
+
+@item Properties that may be offset
+
+@table @asis
+
+@item @code{Hairpin.height}
+
+This property is not a subproperty, and it is listed at
+@rinternals{Hairpin}. For a value, it takes @q{dimension, in staff
+space} set to @code{0.6666}---clearly a non-infinite @code{number}.
+
+@item @code{Arpeggio.positions}
+
+The page @rinternals{Arpeggio} lists a @code{positions} property which
+accepts a @q{pair of numbers}. It defaults to
+@code{ly:arpeggio::positions}---a callback which will be evaluated
+during the typesetting phase to yield a pair of numbers for any given
+@code{Arpeggio} object.
+
+@end table
+
+@item Properties that may not be offset
+
+@table @asis
+
+@item @code{Hairpin.color}
+
+There is no listing for @code{color} at @rinternals{Hairpin}.
+
+@item @code{Hairpin.circled-tip}
+
+The listing for @code{Hairpin.circled-tip} at @rinternals{Hairpin} shows
+that it takes a @code{boolean} value. Booleans are non-numerical.
+
+@item @code{Stem.details.lengths}
+
+Though listed at @rinternals{Stem} and defaulting to a list of
+@code{number}s, this is a @q{subproperty}. There is currently no
+support for @q{nested properties}.
+
+@end table
+
+@end itemize
+
+@subsubsubheading{@bs{}offset as an override}
+
+If @var{item} is a grob name like @code{Arpeggio} or
+@code{Staff.OttavaBracket}, the result is an @code{\override} of the
+specified grob-type.
+
+@example
+\offset @var{property} @var{offsets} [@var{context}.]@var{GrobName}
+@end example
+
+Note that the leading hyphen is @emph{never} used with the @q{override}
+form, just as it is never used with the @code{\override} command itself.
+
+The following example uses the @q{override} form to lengthen the
+default arpeggios shown in the first measure to cover the extent of
+the chords more fully. The arpeggios are stretched by a half
+staff-space to top and bottom. Also shown is the same operation done on
+the first chord with an ordinary override of the @code{positions}
+property. This method is not at all expressive of the task of
+@q{stretching by a half staff-space}, as the endpoints must be specified
+with absolute rather than relative coordinates. Furthermore, individual
+overrides would be needed for the other chords, as they vary in size and
+position.
+
+@lilypond[quote,verbatim]
+arpeggioMusic = {
+ <c' e' g'>\arpeggio <a' c'' e''>\arpeggio
+ <d' f' a' c''>\arpeggio <c' e' g' b' d'' f'' a''>\arpeggio
+}
+
+{
+ \arpeggioMusic
+ \bar "||"
+ \offset positions #'(-0.5 . 0.5) Arpeggio
+ \arpeggioMusic
+ \bar "||"
+ \once \override Arpeggio.positions = #'(-3.5 . -0.5)
+ <c' e' g'>1\arpeggio
+ \bar "||"
+}
+@end lilypond
+
+In its @q{override} usage, @code{\offset} may be prefaced with
+@code{\once} or @code{\temporary} and reverted using @code{\revert} with
+@var{property}. This follows from the fact that @code{\offset} actually
+creates an @code{\override} of @var{property}.
+
+@lilypond[quote,verbatim]
+music = { c'8\< d' e' f'\! }
+
+{
+ \music
+ \offset height 1 Hairpin
+ \music
+ \music
+ \revert Hairpin.height
+ \music
+ \bar "||"
+ \once \offset height 1 Hairpin
+ \music \music
+ \bar "||"
+ \override Hairpin.height = 0.2
+ \music
+ \temporary \offset height 2 Hairpin
+ \music
+ \music
+ \revert Hairpin.height
+ \music
+ \bar "||"
+}
+@end lilypond
+
+Also like @code{\override}, the @q{override} form of @code{\offset} may
+be used with @code{\undo} and @code{\single}.
+
+@lilypond[quote,verbatim]
+longStem = \offset length 6 Stem
+
+{
+ \longStem c'4 c''' c' c''
+ \bar "||"
+ \undo \longStem c'4 c''' c' c''
+ \bar "||"
+ \single \longStem c'4 c''' c' c''
+ \bar "||"
+}
+@end lilypond
+
+@subsubsubheading{@bs{}offset as a tweak}
+
+If @var{item} is a music expression such as @code{(} or
+@code{\arpeggio}, the result is the same music expression with a tweak
+applied.
+
+@example
+[-]\offset [@var{GrobName}.]@var{property} @var{offsets} @var{music-expression}
+@end example
+
+The syntax of @code{\offset} in its @q{tweak} form is analogous to the
+@code{\tweak} command itself, both in ordering and in the presence or
+absence of the leading hyphen.
+
+The following example uses the @q{tweak} form to adjust the vertical
+position of the @code{BreathingSign} object. Compare this with the
+ordinary @code{\tweak} command also demonstrated. The syntax is
+equivalent; however, the output of @code{\tweak} is less intuitive,
+since @code{BreathingSign.Y-offset} is calculated from the middle
+staff-line. It is not necessary to know how @code{Y-offset} is
+calculated when using @code{\offset}.
+
+@lilypond[quote,verbatim]
+{
+ c''4
+ \breathe
+ c''4
+ \offset Y-offset 2 \breathe
+ c''2
+ \tweak Y-offset 3 \breathe
+}
+@end lilypond
+
+In the previous example, the tweaked objects were created directly from
+the user input: the @code{\breathe} command was an explicit instruction
+to return a @code{BreathingSign} object. Since the focus of the command
+was unambiguous, there was no need to specify the object's name. When
+an object is @emph{indirectly} created, however, it is necessary to
+include the grob's name. This is the same as for the @code{\tweak}
+command.
+
+In the following example, the @code{Beam} object is lowered two
+staff-spaces by applying @code{\offset} to the @code{positions}
+property.
+
+The first application of @code{\offset} requires that the grob's name
+be included, because nothing in the input explicitly creates the
+beam. In the second application, the beam is created manually with the
+music expression @code{[}; therefore, the grob's name is not needed.
+(Also illustrated is a shorthand: a single @code{number} will be applied
+to both members of a @code{number-pair}.)
+
+@lilypond[quote,verbatim]
+{
+ c''8 g'' e'' d''
+ \offset Beam.positions #'(-2 . -2)
+ c''8 g'' e'' d''
+ c''8 g'' e'' d''
+ c''8-\offset positions #-2 [ g'' e'' d'']
+}
+@end lilypond
+
+@subsubsubheading{@bs{}offset with broken spanners}
+
+Independently modifying segments of a spanner extending over a line
+break or breaks is also possible. In this case, @var{offsets}
+takes a list of values of the property's required data type.
+
+The @code{\offset} command used in this manner is similar to the
+@code{\alterBroken} command. (See @ref{Modifying broken spanners}.)
+In contrast with @code{\alterBroken}, however, the values given to
+@code{\offset} are relative, not absolute.
+
+The following example displaces the @q{broken} @code{OttavaBracket}
+object through its @code{staff-padding} property. Since the property
+takes a @code{number}, @var{offsets} is provided with a list of
+@code{number}s to account for the two segments created by the line
+break. The slur piece on the first line is effectively untouched since
+@code{0} is added to its default value. The segment on the second
+line is raised two staff-spaces from its default height. The default
+height happens to be @code{2}, though it is not necesssary to know this.
+
+@lilypond[quote,verbatim]
+{
+ \offset staff-padding #'(0 3) Staff.OttavaBracket
+ \ottava #1
+ c'''2 c'''
+ \break
+ c'''2 c'''
+}
+@end lilypond
+
+The following example mimics the effect of the @code{\shape} command by
+offsetting the @code{control-points} property of the @code{Slur} object.
+Here, @var{offsets} is a list of @code{number-pair-list}s, one for each
+slur segment. This example achieves a result identical to the
+corresponding illustration at @ref{Modifying shapes}.
+
+@lilypond[quote,verbatim]
+{
+ c'4-\offset control-points #'(
+ ((0 . 0) (0 . 0) (0 . 0) (0 . 1))
+ ((0.5 . 1.5) (1 . 0) (0 . 0) (0 . -1.5))
+ ) ( f'4 g' c''
+ \break
+ d'4 c'' f' c')
+}
+@end lilypond
+
+
@node Modifying alists
@subsection Modifying alists
color returned defaults to black.
@lilypond[verbatim,quote]
-\relative c'' {
- \override Staff.StaffSymbol.color = #(x11-color 'SlateBlue2)
- \set Staff.instrumentName = \markup {
- \with-color #(x11-color 'navy) "Clarinet"
+\new Staff \with {
+ instrumentName = \markup {
+ \with-color #(x11-color 'red) "Clarinet"
+ }
}
-
+ \relative c'' {
+ \override Staff.StaffSymbol.color = #(x11-color 'SlateBlue2)
gis8 a
\override Beam.color = #(x11-color "medium turquoise")
gis a
@code{rgb-color}.
@lilypond[verbatim,quote]
+\new Staff \with {
+ instrumentName = \markup {
+ \with-color #(x11-color 'red) "Clarinet"
+ }
+ }
\relative c'' {
\override Staff.StaffSymbol.color = #(x11-color 'SlateBlue2)
- \set Staff.instrumentName = \markup {
- \with-color #(x11-color 'navy) "Clarinet"
- }
-
\override Stem.color = #(rgb-color 0 0 0)
gis8 a
\override Stem.color = #(rgb-color 1 1 1)
A tambourine, entered with @q{tamb}:
-@lilypond[quote,verbatim]
+@lilypond[verbatim,quote]
#(define mydrums '((tambourine default #t 0)))
-tambustaff = {
- \override Staff.StaffSymbol.line-positions = #'( 0 )
- \override Staff.BarLine.bar-extent = #'(-1.5 . 1.5)
- \set DrumStaff.instrumentName = #"Tambourine"
-}
+\new DrumStaff \with { instrumentName = #"Tambourine" }
-\new DrumStaff {
- \tambustaff
+\drummode {
\set DrumStaff.drumStyleTable = #(alist->hash-table mydrums)
+ \override Staff.StaffSymbol.line-positions = #'( 0 )
+ \override Staff.BarLine.bar-extent = #'(-1.5 . 1.5)
- \drummode {
- \time 6/8
- tamb8. 16 8 8 8 8 |
- tamb4. 8 8 8 |
- % the trick with the scaled duration and the shorter rest
- % is neccessary for the correct ending of the trill-span!
- tamb2.*5/6 \startTrillSpan s8 \stopTrillSpan |
- }
+ \time 6/8
+ tamb8. 16 8 8 8 8 |
+ tamb4. 8 8 8 |
+ % the trick with the scaled duration and the shorter rest
+ % is neccessary for the correct ending of the trill-span!
+ tamb2.*5/6 \startTrillSpan s8 \stopTrillSpan |
}
@end lilypond
@lilypond[quote,verbatim]
#(define mydrums '((tamtam default #t 0)))
-tamtamstaff = {
- \override Staff.StaffSymbol.line-positions = #'( 0 )
- \override Staff.BarLine.bar-extent = #'(-1.5 . 1.5)
- \set DrumStaff.instrumentName = #"Tamtam"
-}
+\new DrumStaff \with { instrumentName = #"Tamtam" }
-\new DrumStaff {
- \tamtamstaff
- \set DrumStaff.drumStyleTable = #(alist->hash-table mydrums)
+\drummode {
+\set DrumStaff.drumStyleTable = #(alist->hash-table mydrums)
+\override Staff.StaffSymbol.line-positions = #'( 0 )
+\override Staff.BarLine.bar-extent = #'(-1.5 . 1.5)
- \drummode {
- tt 1 \pp \laissezVibrer
- }
+ tt 1 \pp \laissezVibrer
}
@end lilypond
#(define mydrums '((ridebell default #t 3)
(cowbell default #t -2)))
-bellstaff = {
- \override DrumStaff.StaffSymbol.line-positions = #'(-2 3)
+\new DrumStaff \with { instrumentName = #"Different Bells" }
+
+\drummode {
\set DrumStaff.drumStyleTable = #(alist->hash-table mydrums)
+ \override DrumStaff.StaffSymbol.line-positions = #'(-2 3)
\override Staff.BarLine.bar-extent = #'(-1.5 . 1.5)
- \set DrumStaff.instrumentName = #"Different Bells"
-}
-\new DrumStaff {
- \bellstaff
- \drummode {
- \time 2/4
- rb8 8 cb8 16 rb16-> ~ |
- 16 8 16 cb8 8 |
- }
+ \time 2/4
+ rb8 8 cb8 16 rb16-> ~ |
+ 16 8 16 cb8 8 |
}
@end lilypond
\score {
\new StaffGroup <<
- \new DrumStaff {
- \set DrumStaff.instrumentName = \markup {
+ \new DrumStaff \with {
+ instrumentName = \markup {
\column {
"Tambourine"
"et"
"caisse claire s. timbre"
}
}
- \set DrumStaff.drumStyleTable = #(alist->hash-table mydrums)
- \drumsA
- }
-
- \new DrumStaff {
- \set DrumStaff.instrumentName = #"Grosse Caisse"
- \set DrumStaff.drumStyleTable = #(alist->hash-table mydrums)
- \drumsB }
+ drumStyleTable = #(alist->hash-table mydrums)
+ }
+ \drumsA
+ \new DrumStaff \with {
+ instrumentName = #"Grosse Caisse"
+ drumStyleTable = #(alist->hash-table mydrums)
+ }
+ \drumsB
>>
}
@end lilypond
@lilypond[verbatim,quote]
\new GrandStaff <<
- \new Staff = "violin" {
- \relative c'' {
- \set Staff.instrumentName = #"Vln"
- \set Staff.midiInstrument = #"violin"
- % not strictly necessary, but a good reminder
- \transposition c'
-
- \key c \major
- g4( c8) r c r c4
- }
+ \new Staff = "violin" \with {
+ instrumentName = #"Vln"
+ midiInstrument = #"violin"
}
- \new Staff = "clarinet" {
- \relative c'' {
- \set Staff.instrumentName = \markup { Cl (B\flat) }
- \set Staff.midiInstrument = #"clarinet"
- \transposition bes
-
- \key d \major
- a4( d8) r d r d4
- }
+ \relative c'' {
+ % not strictly necessary, but a good reminder
+ \transposition c'
+ \key c \major
+ g4( c8) r c r c4
+ }
+ \new Staff = "clarinet" \with {
+ instrumentName = \markup { Cl (B\flat) }
+ midiInstrument = #"clarinet"
+ }
+ \relative c'' {
+ \transposition bes
+ \key d \major
+ a4( d8) r d r d4
}
>>
@end lilypond
details, see @ref{Instrument names}.
@lilypond[verbatim,quote]
-\new PianoStaff <<
- \set PianoStaff.instrumentName = #"Piano"
+\new PianoStaff \with { instrumentName = #"Piano" }
+<<
\new Staff \relative { c''1 c }
\new Staff \relative { \clef bass c1 c }
>>
@lilypond[verbatim,quote,ragged-right]
prepPiccolo = <>^\markup \italic { muta in Piccolo }
+prepFlute = <>^\markup \italic { muta in Flauto }
+
setPiccolo = {
- \set Staff.instrumentName = #"Piccolo"
- \set Staff.shortInstrumentName = #"Picc."
- \set Staff.midiInstrument = #"piccolo"
<>^\markup \bold { Piccolo }
\transposition c''
}
-prepFlute = <>^\markup \italic { muta in Flauto }
-
setFlute = {
- \set Staff.instrumentName = #"Flute"
- \set Staff.shortInstrumentName = #"Flt."
- \set Staff.midiInstrument = #"flute"
<>^\markup \bold { Flute }
\transposition c'
}
\new Staff \with {
instrumentName = #"Flute"
shortInstrumentName = #"Flt."
- midiInstrument = #"flute"
}
\relative {
g'1 g g g \break
g1 g \prepPiccolo R R \break
+ \set Staff.instrumentName = #"Piccolo"
+ \set Staff.shortInstrumentName = #"Picc."
\setPiccolo
g1 g g g \break
g1 g \prepFlute R R \break
+ \set Staff.instrumentName = #"Flute"
+ \set Staff.shortInstrumentName = #"Flt."
\setFlute
g1 g g g
}
--- /dev/null
+\version "2.19.22"
+
+\header {
+ lsrtags = "pitches, scheme-language, workaround"
+
+ texidoc = "
+This example uses some Scheme code to enforce enharmonic modifications
+for notes in order to have the minimum number of accidentals. In this
+case, the following rules apply:
+
+Double accidentals should be removed
+
+
+B sharp -> C
+
+
+E sharp -> F
+
+
+C flat -> B
+
+
+F flat -> E
+
+
+In this manner, the most natural enharmonic notes are chosen.
+
+"
+ doctitle = "Transposing pitches with minimum accidentals (\"Smart\" transpose)"
+}
+#(define (naturalize-pitch p)
+ (let ((o (ly:pitch-octave p))
+ (a (* 4 (ly:pitch-alteration p)))
+ ;; alteration, a, in quarter tone steps,
+ ;; for historical reasons
+ (n (ly:pitch-notename p)))
+ (cond
+ ((and (> a 1) (or (eqv? n 6) (eqv? n 2)))
+ (set! a (- a 2))
+ (set! n (+ n 1)))
+ ((and (< a -1) (or (eqv? n 0) (eqv? n 3)))
+ (set! a (+ a 2))
+ (set! n (- n 1))))
+ (cond
+ ((> a 2) (set! a (- a 4)) (set! n (+ n 1)))
+ ((< a -2) (set! a (+ a 4)) (set! n (- n 1))))
+ (if (< n 0) (begin (set! o (- o 1)) (set! n (+ n 7))))
+ (if (> n 6) (begin (set! o (+ o 1)) (set! n (- n 7))))
+ (ly:make-pitch o n (/ a 4))))
+
+#(define (naturalize music)
+ (let ((es (ly:music-property music 'elements))
+ (e (ly:music-property music 'element))
+ (p (ly:music-property music 'pitch)))
+ (if (pair? es)
+ (ly:music-set-property!
+ music 'elements
+ (map naturalize es)))
+ (if (ly:music? e)
+ (ly:music-set-property!
+ music 'element
+ (naturalize e)))
+ (if (ly:pitch? p)
+ (begin
+ (set! p (naturalize-pitch p))
+ (ly:music-set-property! music 'pitch p)))
+ music))
+
+naturalizeMusic =
+#(define-music-function (m)
+ (ly:music?)
+ (naturalize m))
+
+music = \relative c' { c4 d e g }
+
+\score {
+ \new Staff {
+ \transpose c ais { \music }
+ \naturalizeMusic \transpose c ais { \music }
+ \transpose c deses { \music }
+ \naturalizeMusic \transpose c deses { \music }
+ }
+ \layout { }
+}
-%% DO NOT EDIT this file manually; it is automatically
-%% generated from LSR http://lsr.di.unimi.it
-%% Make any changes in LSR itself, or in Documentation/snippets/new/ ,
-%% and then run scripts/auxiliar/makelsr.py
-%%
-%% This file is in the public domain.
+% DO NOT EDIT this file manually; it is automatically
+% generated from Documentation/snippets/new
+% Make any changes in Documentation/snippets/new/
+% and then run scripts/auxiliar/makelsr.py
+%
+% This file is in the public domain.
+%% Note: this file works from version 2.19.22
\version "2.19.22"
\header {
;; for historical reasons
(n (ly:pitch-notename p)))
(cond
- ((and (> a 1) (or (eq? n 6) (eq? n 2)))
+ ((and (> a 1) (or (eqv? n 6) (eqv? n 2)))
(set! a (- a 2))
(set! n (+ n 1)))
- ((and (< a -1) (or (eq? n 0) (eq? n 3)))
+ ((and (< a -1) (or (eqv? n 0) (eqv? n 3)))
(set! a (+ a 2))
(set! n (- n 1))))
(cond
@divClass{column-center-top}
@subheading What is Google Summer of Code?
-@uref{https://developers.google.com/open-source/gsoc/, GSoC} is a global
-program that offers students stipends to write code for free software
-and open source projects during the summer. It is an excellent
+@uref{https://summerofcode.withgoogle.com/, GSoC} is a global program
+that offers students stipends to write code for free software and open
+source projects during the summer. For three months students work to
+complete a given task as part of the project's community and under the
+guidance of experienced mentors. The program is an excellent
opportunity for students to gain experience with real-world software
development and make a contribution that benefits everyone. It brings
new contributors to LilyPond and enables students who are already
involved to become more involved. LilyPond participates in GSoC as part
of the @uref{http://www.gnu.org/, GNU project}.
-We have had GSoC participants in 2012, 2015 and 2016 and encourage students
-to apply for future summers.
+@strong{Note:} The accepted mentoring organizations will be announced on
+February 27, so only then we will officially know that we can
+participate in this year's program.
-If you have questions or would like to apply, send us an email on our
-developer mailing list (see @ref{Contact}).
+We have had GSoC participants in 2012, 2015 and 2016 and encourage
+students to apply for future summers.
+
+If you are interested to apply for the program with LilyPond as a
+project, please read the information below and don't hesitate to write
+us on our developer mailing list (see @ref{Contact}). The student
+application window is March 20 to April 3, 2017, but we strongly
+encourage you to get in touch with our community ahead of that.
@divEnd
@divClass{column-center-middle-color2}
@subheading Project Ideas List
-Below is a list of suggested projects for GSoC or for anyone who is
-interested in helping to improve LilyPond. (Last updated: November 2016)
-
-Mentor availability varies from project to project and from year to year.
-Send us an email on our developer mailing list (see @ref{Contact}), and
-we will help you find a mentor for a project that fits your interests
-and skills.
-
-If you have ideas for a GSoC project that is not listed below you can
-send us an email as well. There are a number of areas where LilyPond
-could be improved, and our development team is always willing to help
-those who would like to tackle a project like those listed below.
+Below is a list of GSoC project ideas (last update: January 2017), but
+if you have other ideas for a project you may complete within the three
+months of the program you're welcome to make a suggestion on our
+developer mailing list (see @ref{Contact}). There are a number of areas
+where LilyPond could be improved, and our development team is always
+willing to help those who would like to tackle a project similar to
+those listed below. As mentor availability varies from project to
+project and from year to year it is wise to get in touch with us as
+early as possible.
A full list of all the current open issues can be found
@uref{http://sourceforge.net/p/testlilyissues/issues/, here}.
@divEnd
@divClass{column-center-middle-color3}
-@subheading Grace notes
-
-Fix problems with synchronization of grace notes. Grace notes can
-interfere with LilyPond's timing and cause odd effects, especially when
-multiple staffs are used where some have grace notes and others don't.
-This is one of the longest-standing and one of the more embarrassing
-@uref{https://sourceforge.net/p/testlilyissues/issues/34/,bugs} in
-LilyPond.
+@subheading Contemporary Notation
+
+LilyPond is very good at creating non-standard notation. Having to
+@emph{code} every graphical element instead of simply @emph{drawing}
+it may seem cumbersome but is in fact a strong asset. New notational
+functionality can be provided with consistent appearance, automatic
+layout and a natural syntactic interface.
+
+Within the @uref{https://github.com/openlilylib/oll-core, openLilyLib}
+library system the student will create a fundamental infrastructure
+and building blocks to make creating contemporary notation easier.
+Additionally (at least) @emph{one} concrete package is developed to
+cover specific contemporary notation, such as for example the style
+of a given composer, extended playing techniques for a specific
+instrument or a certain category of effects.
@strong{Difficulty:} medium
-@strong{Requirements:} C++, MIDI
-@strong{Recommended:} familiarity with LilyPond internals
-@strong{Potential Mentors:} Mike Solomon (not available for GSoC 2016),
-Carl Sorensen
+@strong{Requirements:} Scheme (interaction with LilyPond internals),
+contemporary notation techniques
+@strong{Recommended:} sense of building hierarchical frameworks
+@strong{Mentors:} @strong{NN,} Urs Liska
@divEnd
@divClass{column-center-middle-color3}
-@subheading Improve default beam positioning
-
-For regular, cross-staff, broken and kneed beams. Beaming should depend
-on context and neighbor notes (see section 2.2 of
-@uref{http://imslp.org/wiki/Repository_of_Music-Notation_Mistakes_%28Coulon%2C_Jean-Pierre%29,
-this book}). If possible also reduce beaming-computation time.
+@subheading Automated testing and documentation for openLilyLib
+
+@uref{https://github.com/openlilylib, openLilyLib} is an extension
+framework for LilyPond code providing a “snippets” repository and a
+suite of integrated packages such as for example page layout tools or
+scholarly annotations. It is very powerful and promising, but to really
+get off the ground two features are missing: automated testing and
+documentation generation.
+
+Automated testing is necessary to ensure modifications to functionality
+don't break other functions within the library. There is already some
+Automated Testing of the “snippets” repository with Github's Travis
+server, but this has to be reconsidered and extended to cover the
+standalone packages too.
+
+In order to be usable for a wider range of LilyPond users on a “consumer
+level” openLilyLib needs proper documentation. This documentation has
+to be generated from the sources, so a system is needed that requires
+package authors to document the input files and provide additional usage
+examples, from which documentation is generated. Ideally but not
+necessarily this is implemented as a Git hook, i.e. automatically upon
+each update to the repository. We don't prescribe the tools and
+approaches to be used, but the most widely used language in the LilyPond
+domain is Python, so there would be some bias towards that.
+Alternatively a Scheme solution could be fine so generating the
+documentation would actually be triggered by “compiling” a certain
+LilyPond input file. In general it is advisable to make use of proven
+concepts and tools from other languages.
+
+The eventual output of the documentation should be a static HTML site
+that can be viewed locally and/or uploaded to a website. But it would
+be beneficial if the tool would first generate an intermediate
+representation (e.g. a JSON file with additional media files) from which
+a Single Page Application could retrieve content for display on
+openLilyLib's @uref{https://openlilylib.org, website}. Development of
+such a SPA @emph{can} be part of the GSoC project, but is optional.
@strong{Difficulty:} medium
-@strong{Requirements:} C++, experience with writing heuristics
-@strong{Recommended knowledge:} aesthetic sense
-@strong{Potential Mentors:} Mike Solomon (not available for GSoC 2016),
-Carl Sorensen
-
-@divEnd
-
-@divClass{column-center-middle-color3}
-@subheading Help improve compilation behavior
-
-Automatic code analysis tools, like valgrind memory leak detection or
-callgrind code profilers, provide valuable information about possible
-flaws in our C++ code. Cleaning up warnings would allow us to automate
-the rejection of any patch which introduced extra warnings.
-
-@strong{Difficulty:} medium
-@strong{Requirements:} C++
-@strong{Potential Mentors:} Reinhold Kainhofer (not available for GSoC
-2016), Joe Neeman
+@strong{Requirements:} Python or Scheme, static website generator(s) or
+(Node.js based) dynamic web application technology. Continuous
+Integration (can be learned during the bonding period)
+@strong{Mentors:} Urs Liska, Matteo Ceccarello
@divEnd
@strong{Difficulty:} medium
@strong{Requirements:} MusicXML, Python, Scheme, basic LilyPond knowledge
-@strong{Potential Mentors:} Reinhold Kainhofer, Mike Solomon (both not
-available for GSoC 2016)
+@strong{Recommended:} Familiarity with other scorewriters (for cross-testing)
+@strong{Mentor:} Jan-Peter Voigt
+
-Familiarity with other scorewriters (for cross-testing) would also help.
@divEnd
-@divClass{column-center-middle-color3}
-@subheading Improve slurs and ties
+@divClass{column-center-middle-color2}
+@subheading Information for Applicants/Participants
-The engraving quality of slurs and ties is often unsatisfactory. Ties
-@q{broken} by clef or staff changes are not handled well. The project
-could include collecting and sorting examples of bad output, deciding on
-the intended output and writing code to improve them.
+In order to have a satisfying experience with GSoC applicants are
+strongly advised to thoroughly read the following recommendations. Some
+of these are relevant for the application process, others for the time
+within the project.
-@strong{Difficulty:} hard
-@strong{Requirements:} C++, experience with writing heuristics
-@strong{Recommended knowledge:} LilyPond knowledge, aesthetic sense
-@strong{Potential Mentors:} Mike Solomon, Janek Warchoł (both not available for
-GSoC 2016)
+@itemize
-@divEnd
+@item
+Read all applicable information on the program's website, particularly
+the
+@uref{https://developers.google.com/open-source/gsoc/resources/manual,
+students' manual}. Make sure you fulfil all of Google's prerequisites
+and are willing to join the program as a full-time commitment over the
+coding period of three months.
+
+@item
+Please get in touch with us as soon as possible if you are interested in
+applying with a project. Mentor availability may change without notice,
+project proposals may need fine-tuning, and many other reasons might
+require us to reject or ignore an application that hasn't been discussed
+before.
+
+@item
+We do not know in advance how many “slots” we will have available for
+projects, so please be aware that you may find yourself in competition
+with other applicants or not. Interested or even enthusiastic response
+from our mentors is no guarantee of eventually being accepted, and
+@emph{not} being accepted does not necessarily indicate a negative
+evaluation of your application. If we have to decide between different
+applicants there may be various aspects to consider.
+
+@item
+Integration in the LilyPond community is a fundamental part of GSoC, and
+we expect our students to make substantial efforts to become community
+members. Within the @emph{bonding period} we expect you to write a blog
+post about your project (either on @uref{http://lilypondblog.org, Scores
+of Beauty} or on any other blog) and to be active on our mailing lists,
+introducing yourself but also communicating about unrelated tasks. This
+goes beyond the mere setting up of a working environment and
+familiarizing yourself with the relevant code, but we think it is
+crucial for the GSoC project to be mutually satisfying.
+@item
+If you are accepted to the program you will have one mentor explicitly
+assigned to your project. With this mentor you will have to agree upon
+a communication strategy, be it emails, chatrooms, issue trackers or
+voice/video chats. Regular communication is absolutely crucial for the
+success of a GSoC project so you are stricly required to keep talking to
+your mentor. But keep in mind that your mentor has explicitly taken
+over the responsibility for your project, and while unlike you he isn't
+paid for this activity you are still entitled to get regular attention
+from him.
+
+@item
+In order to get support from your mentor you have to give him a chance
+to follow your progress and efforts. Therefore it is important to
+regularly commit your changes to the versioning repository you are
+working on. Don't hesitate making unfinished code available because you
+are afraid of criticism, and don't suppress questions because you think
+they might be considered stupid. But ideally your code should at any
+time be accompanied by compatible testing code. Your mentor may not be
+able to properly assess your code by only @emph{reading} it without the
+opportunity to apply it in a real example.
+
+@end itemize
+
+There is a list of inactive projects in the @ref{Attic}. We list
+projects there that are still considered valuable but for which there
+are currently no mentors available.
+
+@divEnd
@node Authors
@unnumberedsec Authors
@miscLink{CHANGES-0.0,v0.0}
@divEnd
+
+@divClass{column-center-middle-color2}
+@subheading Unused Google Summer of Code project suggestions
+
+The following list describes GSoC projects that had been proposed
+in recent years and which are still considered valuable but for
+which we currently don't have mentors available.
+
+@divEnd
+
+@divClass{column-center-middle-color3}
+@subheading Improve slurs and ties
+
+The engraving quality of slurs and ties is often unsatisfactory. Ties
+@q{broken} by clef or staff changes are not handled well. The project
+could include collecting and sorting examples of bad output, deciding on
+the intended output and writing code to improve them.
+
+@strong{Difficulty:} hard
+@strong{Requirements:} C++, experience with writing heuristics
+@strong{Recommended knowledge:} LilyPond knowledge, aesthetic sense
+
+
+@divEnd
+
+@divClass{column-center-middle-color3}
+@subheading Grace notes
+
+Fix problems with synchronization of grace notes. Grace notes can
+interfere with LilyPond's timing and cause odd effects, especially when
+multiple staffs are used where some have grace notes and others don't.
+This is one of the longest-standing and one of the more embarrassing
+@uref{https://sourceforge.net/p/testlilyissues/issues/34/,bugs} in
+LilyPond.
+
+@strong{Difficulty:} medium
+@strong{Requirements:} C++, MIDI
+@strong{Recommended:} familiarity with LilyPond internals
+
+@divEnd
+
+@divClass{column-center-middle-color3}
+@subheading Improve default beam positioning
+
+For regular, cross-staff, broken and kneed beams. Beaming should depend
+on context and neighbor notes (see section 2.2 of
+@uref{http://imslp.org/wiki/Repository_of_Music-Notation_Mistakes_%28Coulon%2C_Jean-Pierre%29,
+this book}). If possible also reduce beaming-computation time.
+
+@strong{Difficulty:} medium
+@strong{Requirements:} C++, experience with writing heuristics
+@strong{Recommended knowledge:} aesthetic sense
+
+@divEnd
+
+@divClass{column-center-middle-color3}
+@subheading Help improve compilation behavior
+
+Automatic code analysis tools, like valgrind memory leak detection or
+callgrind code profilers, provide valuable information about possible
+flaws in our C++ code. Cleaning up warnings would allow us to automate
+the rejection of any patch which introduced extra warnings.
+
+@strong{Difficulty:} medium
+@strong{Requirements:} C++
+
+@divEnd
@c used for news about the upcoming release; see CG on Release Work
@newsItem
-@subheading LilyPond 2.19.54 released @emph{January 4, 2017}
+@subheading LilyPond 2.19.55 released @emph{February 12, 2017}
We are happy to announce the release of LilyPond
-2.19.54. This release includes a number of enhancements, and contains some
+2.19.55. This release includes a number of enhancements, and contains some
work in progress. You will have access to the very latest features, but
some may be incomplete, and you may encounter bugs and crashes. If you
require a stable version of LilyPond, we recommend using the 2.18
@ifclear web_version
@c no anchor links, just link to News page
-@ref{News, LilyPond 2.19.54 released - @emph{January 4, 2017}}
+@ref{News, LilyPond 2.19.55 released - @emph{February 12, 2017}}
@ref{News, Two LilyPond projects in Google Summer of Code 2016 - @emph{April 23, 2016}}
@ifset web_version
@c anchor links, link to individual news items by their <a> tag
-@uref{news.html#LilyPond-2_002e19_002e54-released-January-4_002c-2017,
- LilyPond 2.19.54 released - @emph{January 4, 2017}}
+@uref{news.html#LilyPond-2_002e19_002e55-released-February-12_002c-2017,
+ LilyPond 2.19.55 released - @emph{February 12, 2017}}
@uref{news.html#Two-LilyPond-projects-in-Google-Summer-of-Code-2016-April-23_002c-2016,
Two LilyPond projects in Google Summer of Code 2016 - @emph{April 23, 2016}}
* don't duplicate entries from news-front.itexi
@end ignore
+@newsItem
+@subheading LilyPond 2.19.54 released @emph{January 4, 2017}
+
+We are happy to announce the release of LilyPond
+2.19.54. This release includes a number of enhancements, and contains some
+work in progress. You will have access to the very latest features, but
+some may be incomplete, and you may encounter bugs and crashes. If you
+require a stable version of LilyPond, we recommend using the 2.18
+version.
+
+@newsEnd
+
@newsItem
@subheading LilyPond 2.19.53 released @emph{December 17, 2016}
PACKAGE_NAME=LilyPond
MAJOR_VERSION=2
MINOR_VERSION=19
-PATCH_LEVEL=55
+PATCH_LEVEL=56
MY_PATCH_LEVEL=
VERSION_STABLE=2.18.2
-VERSION_DEVEL=2.19.54
+VERSION_DEVEL=2.19.55
<<
\new Voice = "one" \relative {
c''4\melisma
- c4 r c\melismaEnd c
+ c4 r c\melismaEnd c1
+ c4 \melisma
+ c4 r c\melismaEnd c1
+ c4 \melisma
+ c4 r c\melismaEnd c1
}
\new Lyrics \lyricsto "one" {
+ Test __ "default"
\set extendersOverRests = ##t
-
- Test __ end
+ test __ \markup \typewriter "#t"
+ \set extendersOverRests = ##f
+ test __ \markup \typewriter "#f"
}
>>
(ly:spanner-set-bound! spanner RIGHT item)))
#(define (axis-offset-symbol axis)
- (if (eq? axis X) 'X-offset 'Y-offset))
+ (if (eqv? axis X) 'X-offset 'Y-offset))
#(define (set-axis! grob axis)
(if (not (number? (ly:grob-property grob 'side-axis)))
(set! (ly:grob-property grob 'side-axis) axis)
(ly:grob-chain-callback
grob
- (if (eq? axis X)
+ (if (eqv? axis X)
ly:side-position-interface::x-aligned-side
side-position-interface::y-aligned-side)
(axis-offset-symbol axis)))))
in grobs should always store ly_deep_copy ()s of those.
*/
-Accidental_engraver::Accidental_engraver ()
+Accidental_engraver::Accidental_engraver (Context *c)
+ : Engraver (c)
{
accidental_placement_ = 0;
last_keysig_ = SCM_EOL;
*/
for (vsize i = 0; i < left_objects_.size (); i++)
{
- if (scm_is_eq (left_objects_[i]->get_property ("side-axis"), scm_from_int (X_AXIS)))
+ if (ly_is_equal (left_objects_[i]->get_property ("side-axis"), scm_from_int (X_AXIS)))
Side_position_interface::add_support (left_objects_[i], a);
}
Accidental_engraver::process_music ()
{
SCM sig = get_property ("keyAlterations");
- if (last_keysig_ != sig)
+ if (!scm_is_eq (last_keysig_, sig))
update_local_key_signature (sig);
}
is_typeset_ = false;
}
-Ambitus_engraver::Ambitus_engraver ()
+Ambitus_engraver::Ambitus_engraver (Context *c)
+ : Engraver (c)
{
ambitus_ = 0;
heads_.set (0, 0);
Stream_event *arpeggio_event_;
};
-Arpeggio_engraver::Arpeggio_engraver ()
+Arpeggio_engraver::Arpeggio_engraver (Context *c)
+ : Engraver (c)
{
arpeggio_ = 0;
arpeggio_event_ = 0;
}
}
-Auto_beam_engraver::Auto_beam_engraver ()
+Auto_beam_engraver::Auto_beam_engraver (Context *c)
+ : Engraver (c)
{
forbid_ = 0;
process_acknowledged_count_ = 0;
virtual bool test_moment (Direction, Moment, Moment);
};
-Grace_auto_beam_engraver::Grace_auto_beam_engraver ()
+Grace_auto_beam_engraver::Grace_auto_beam_engraver (Context *c)
+ : Auto_beam_engraver (c)
{
last_grace_start_.main_part_.set_infinite (-1);
// grace_part_ is zero -> test_moment is false, last_grace_position_
};
-Axis_group_engraver::Axis_group_engraver ()
+Axis_group_engraver::Axis_group_engraver (Context *c)
+ : Engraver (c)
{
staffline_ = 0;
interesting_ = SCM_EOL;
vector<Grob *> current_elts;
current_elts.push_back (elements[i]);
while (i + 1 < elements.size ()
- && scm_is_eq (elements[i + 1]->get_property ("outside-staff-priority"), priority))
+ && ly_is_equal (elements[i + 1]->get_property ("outside-staff-priority"), priority))
{
if (!to_boolean (elements[i + 1]->get_property ("cross-staff")))
current_elts.push_back (elements[i + 1]);
events_.clear ();
}
-Balloon_engraver::Balloon_engraver ()
+Balloon_engraver::Balloon_engraver (Context *c)
+ : Engraver (c)
{
}
vector<Spanner *> spanners_;
};
-Bar_engraver::Bar_engraver ()
+Bar_engraver::Bar_engraver (Context *c)
+ : Engraver (c)
{
bar_ = 0;
}
}
}
-Bar_number_engraver::Bar_number_engraver ()
+Bar_number_engraver::Bar_number_engraver (Context *c)
+ : Engraver (c)
{
text_ = 0;
alternative_starting_bar_number_ = 0;
TRANSLATOR_DECLARATIONS (Beam_collision_engraver);
};
-Beam_collision_engraver::Beam_collision_engraver () {}
+Beam_collision_engraver::Beam_collision_engraver (Context *c)
+ : Engraver (c)
+{}
bool
Beam_collision_engraver::covered_grob_has_interface (Grob *covered_grob, Grob *beam)
return valid_start_point ();
}
-Beam_engraver::Beam_engraver ()
+Beam_engraver::Beam_engraver (Context *c)
+ : Engraver (c)
{
beam_ = 0;
finished_beam_ = 0;
virtual bool valid_end_point ();
};
-Grace_beam_engraver::Grace_beam_engraver ()
+Grace_beam_engraver::Grace_beam_engraver (Context *c)
+ : Beam_engraver (c)
{
}
bool beam_;
};
-Beam_performer::Beam_performer ()
+Beam_performer::Beam_performer (Context *c)
+ : Performer (c)
{
beam_ = false;
start_ev_ = 0;
now_mom ());
}
-Bend_engraver::Bend_engraver ()
+Bend_engraver::Bend_engraver (Context *c)
+ : Engraver (c)
{
fall_ = 0;
last_fall_ = 0;
{
LY_ASSERT_SMOB (Book, book, 1);
Book *b = unsmob<Book> (book);
- return b->header_ ? b->header_ : SCM_BOOL_F;
+ return ly_is_module (b->header_) ? b->header_ : SCM_BOOL_F;
}
LY_DEFINE (ly_book_set_header_x, "ly:book-set-header!",
left_edge_ = 0;
}
-Break_align_engraver::Break_align_engraver ()
+Break_align_engraver::Break_align_engraver (Context *c)
+ : Engraver (c)
{
column_alist_ = SCM_EOL;
left_edge_ = 0;
for (vsize i = writable_elts.size (); i--;)
{
Grob *g = writable_elts[i];
- if (g && sym == g->get_property ("break-align-symbol"))
+ if (g && scm_is_eq (sym, g->get_property ("break-align-symbol")))
{
new_elts.push_back (g);
writable_elts.erase (writable_elts.begin () + i);
SCM sym = scm_car (symbol_list);
for (vsize i = 0; i < elements.size (); i++)
{
- if (elements[i]->get_property ("break-align-symbol") == sym)
+ if (scm_is_eq (sym, elements[i]->get_property ("break-align-symbol")))
{
if (Item::break_visible (elements[i])
+ // TODO SCM: simplify syntax?
&& !elements[i]->extent (elements[i], X_AXIS).is_empty ())
{
break_aligned_grob = i;
Grob *breathing_sign_;
};
-Breathing_sign_engraver::Breathing_sign_engraver ()
+Breathing_sign_engraver::Breathing_sign_engraver (Context *c)
+ : Engraver (c)
{
breathing_sign_ = 0;
breathing_sign_event_ = 0;
{
}
-Chord_name_engraver::Chord_name_engraver ()
+Chord_name_engraver::Chord_name_engraver (Context *c)
+ : Engraver (c)
{
rest_event_ = 0;
}
void acknowledge_stem (Grob_info);
};
-Chord_tremolo_engraver::Chord_tremolo_engraver ()
+Chord_tremolo_engraver::Chord_tremolo_engraver (Context *c)
+ : Engraver (c)
{
beam_ = 0;
repeat_ = 0;
scm_gc_mark (prev_glyph_);
}
-Clef_engraver::Clef_engraver ()
+Clef_engraver::Clef_engraver (Context *c)
+ : Engraver (c)
{
clef_ = 0;
modifier_ = 0;
{
if (clef_)
{
- SCM vis = 0;
if (to_boolean (clef_->get_property ("non-default")))
- vis = get_property ("explicitClefVisibility");
+ {
+ SCM vis = get_property ("explicitClefVisibility");
- if (vis)
- clef_->set_property ("break-visibility", vis);
+ if (scm_is_vector (vis))
+ clef_->set_property ("break-visibility", vis);
+ }
clef_ = 0;
Spanner *finished_spanner_;
};
-Cluster_spanner_engraver::Cluster_spanner_engraver ()
+Cluster_spanner_engraver::Cluster_spanner_engraver (Context *c)
+ : Engraver (c)
{
spanner_ = 0;
finished_spanner_ = 0;
note_columns_.clear ();
}
-Collision_engraver::Collision_engraver ()
+Collision_engraver::Collision_engraver (Context *c)
+ : Engraver (c)
{
col_ = 0;
}
ly_bool2scm (note_events_.size ()));
}
-Completion_heads_engraver::Completion_heads_engraver ()
+Completion_heads_engraver::Completion_heads_engraver (Context *c)
+ : Engraver (c)
{
tie_column_ = 0;
}
ly_bool2scm (rest_events_.size ()));
}
-Completion_rest_engraver::Completion_rest_engraver ()
+Completion_rest_engraver::Completion_rest_engraver (Context *c)
+ : Engraver (c)
{
}
vector<Grob *> hairpins_hanging_out_;
};
-Concurrent_hairpin_engraver::Concurrent_hairpin_engraver ()
+Concurrent_hairpin_engraver::Concurrent_hairpin_engraver (Context *c)
+ : Engraver (c)
{
}
if (scm_is_eq (tag, ly_symbol2scm ("consists")))
l1 = scm_cons (arg, l1);
- else if (scm_is_eq (tag, ly_symbol2scm ("remove"))
- && (scm_is_pair (arg)
- || ly_is_procedure (arg)
- || get_translator (arg)))
- l1 = scm_delete_x (arg, l1);
+ else if (scm_is_eq (tag, ly_symbol2scm ("remove")))
+ l1 = scm_delq_x (arg, l1);
}
return l1;
virtual void acknowledge_audio_element (Audio_element_info info);
};
-Control_track_performer::Control_track_performer ()
+Control_track_performer::Control_track_performer (Context *c)
+ : Performer (c)
{
control_track_ = 0;
}
scm_gc_mark (prev_glyph_);
}
-Cue_clef_engraver::Cue_clef_engraver ()
+Cue_clef_engraver::Cue_clef_engraver (Context *c)
+ : Engraver (c)
{
clef_ = 0;
modifier_ = 0;
{
if (clef_)
{
- SCM vis = 0;
if (to_boolean (clef_->get_property ("non-default")))
- vis = get_property ("explicitCueClefVisibility");
+ {
+ SCM vis = get_property ("explicitCueClefVisibility");
- if (vis)
- clef_->set_property ("break-visibility", vis);
+ if (scm_is_vector (vis))
+ clef_->set_property ("break-visibility", vis);
+ }
clef_ = 0;
modifier_ = 0;
vector<Pitch> pitches_;
};
-Custos_engraver::Custos_engraver ()
+Custos_engraver::Custos_engraver (Context *c)
+ : Engraver (c)
{
custos_permitted_ = false;
}
""
);
-Default_bar_line_engraver::Default_bar_line_engraver ()
+Default_bar_line_engraver::Default_bar_line_engraver (Context *c)
+ : Engraver (c)
{
last_moment_.main_part_ = Rational (-1);
}
void stop_translation_timestep ();
};
-Dot_column_engraver::Dot_column_engraver ()
+Dot_column_engraver::Dot_column_engraver (Context *c)
+ : Engraver (c)
{
dotcol_ = 0;
}
TRANSLATOR_DECLARATIONS (Dots_engraver);
};
-Dots_engraver::Dots_engraver ()
+Dots_engraver::Dots_engraver (Context *c)
+ : Engraver (c)
{
}
void process_music ();
};
-Double_percent_repeat_engraver::Double_percent_repeat_engraver ()
+Double_percent_repeat_engraver::Double_percent_repeat_engraver (Context *c)
+ : Engraver (c)
{
percent_event_ = 0;
}
void stop_translation_timestep ();
};
-Drum_notes_engraver::Drum_notes_engraver ()
+Drum_notes_engraver::Drum_notes_engraver (Context *c)
+ : Engraver (c)
{
}
void
Drum_notes_engraver::process_music ()
{
- SCM tab = 0;
+ if (events_.empty ())
+ return;
+
+ SCM tab = get_property ("drumStyleTable");
for (vsize i = 0; i < events_.size (); i++)
{
- if (!tab)
- tab = get_property ("drumStyleTable");
-
Stream_event *ev = events_[i];
Item *note = make_item ("NoteHead", ev->self_scm ());
vector<Stream_event *> note_evs_;
};
-Drum_note_performer::Drum_note_performer ()
+Drum_note_performer::Drum_note_performer (Context *c)
+ : Performer (c)
{
}
set<Spanner *> running_;
};
-Dynamic_align_engraver::Dynamic_align_engraver ()
+Dynamic_align_engraver::Dynamic_align_engraver (Context *c)
+ : Engraver (c)
{
line_ = 0;
ended_line_ = 0;
bool end_new_spanner_;
};
-Dynamic_engraver::Dynamic_engraver ()
+Dynamic_engraver::Dynamic_engraver (Context *c)
+ : Engraver (c)
{
script_event_ = 0;
current_span_event_ = 0;
State state_;
};
-Dynamic_performer::Dynamic_performer ()
- : script_event_ (0),
+Dynamic_performer::Dynamic_performer (Context *c)
+ : Performer (c),
+ script_event_ (0),
next_grow_dir_ (CENTER),
depart_dir_ (CENTER),
state_ (STATE_INITIAL)
announce_end_grob (make_grob_info (e, cause));
}
-Engraver::Engraver ()
+Engraver::Engraver (Context *c)
+ : Translator (c)
{
}
void typeset_all ();
};
-Episema_engraver::Episema_engraver ()
+Episema_engraver::Episema_engraver (Context *c)
+ : Engraver (c)
{
finished_ = 0;
current_event_ = 0;
void process_music ();
};
-Extender_engraver::Extender_engraver ()
+Extender_engraver::Extender_engraver (Context *c)
+ : Engraver (c)
{
extender_ = 0;
pending_extender_ = 0;
else
{
if (pending_extender_
- && !get_property ("extendersOverRests"))
+ && !to_boolean (get_property ("extendersOverRests")))
{
completize_extender (pending_extender_);
pending_extender_ = 0;
void process_music ();
};
-Figured_bass_engraver::Figured_bass_engraver ()
+Figured_bass_engraver::Figured_bass_engraver (Context *c)
+ : Engraver (c)
{
alignment_ = 0;
continuation_ = false;
void stop_translation_timestep ();
};
-Figured_bass_position_engraver::Figured_bass_position_engraver ()
+Figured_bass_position_engraver::Figured_bass_position_engraver (Context *c)
+ : Engraver (c)
{
positioner_ = 0;
bass_figure_alignment_ = 0;
void stop_translation_timestep ();
};
-Fingering_column_engraver::Fingering_column_engraver ()
+Fingering_column_engraver::Fingering_column_engraver (Context *c)
+ : Engraver (c)
{
for (LEFT_and_RIGHT (d))
fingering_columns_[d] = 0;
events_.clear ();
}
-Fingering_engraver::Fingering_engraver ()
+Fingering_engraver::Fingering_engraver (Context *c)
+ : Engraver (c)
{
}
private:
};
-Font_size_engraver::Font_size_engraver ()
+Font_size_engraver::Font_size_engraver (Context *c)
+ : Engraver (c)
{
size = 0.0;
}
annotated_spanners_.clear ();
}
-Footnote_engraver::Footnote_engraver ()
+Footnote_engraver::Footnote_engraver (Context *c)
+ : Engraver (c)
{
}
void start_translation_timestep ();
};
-Forbid_line_break_engraver::Forbid_line_break_engraver ()
+Forbid_line_break_engraver::Forbid_line_break_engraver (Context *c)
+ : Engraver (c)
{
}
scm_gc_mark (last_placements_);
}
-Fretboard_engraver::Fretboard_engraver ()
+Fretboard_engraver::Fretboard_engraver (Context *c)
+ : Engraver (c)
{
fret_board_ = 0;
last_placements_ = SCM_BOOL_F;
#include "music-function.hh"
#include "paper-score.hh"
#include "performance.hh"
+#include "protected-scm.hh"
#include "spanner.hh"
#include "stream-event.hh"
#include "unpure-pure-container.hh"
-static SCM doc_hash_table;
+static Protected_scm doc_hash_table;
void
ly_check_name (const string &cxx, const string &scm_name)
if (doc == "")
return;
- if (!doc_hash_table)
- doc_hash_table = scm_permanent_object (scm_c_make_hash_table (59));
+ if (!doc_hash_table.is_bound ())
+ doc_hash_table = scm_c_make_hash_table (59);
string s = string (" - ") + "LilyPond procedure: " + fname + " " + varlist
+ "\n" + doc;
vector<vsize> note_column_2;
};
-Glissando_engraver::Glissando_engraver ()
+Glissando_engraver::Glissando_engraver (Context *c)
+ : Engraver (c)
{
event_ = 0;
start_glissandi_ = false;
void grace_change (SCM);
};
-Grace_engraver::Grace_engraver ()
+Grace_engraver::Grace_engraver (Context *c)
+ : Engraver (c)
{
grace_settings_ = SCM_EOL;
last_moment_ = Moment (Rational (-1, 1));
void stop_translation_timestep ();
};
-Grace_spacing_engraver::Grace_spacing_engraver ()
+Grace_spacing_engraver::Grace_spacing_engraver (Context *c)
+ : Engraver (c)
{
grace_spacing_ = 0;
}
* engravers for Gregorian chant will be added in the future, such as
* Medicaea_ligature_engraver or Hufnagel_ligature_engraver.
*/
-Gregorian_ligature_engraver::Gregorian_ligature_engraver ()
+Gregorian_ligature_engraver::Gregorian_ligature_engraver (Context *c)
+ : Coherent_ligature_engraver (c)
{
pes_or_flexa_req_ = 0;
}
void stop_translation_timestep ();
};
-Grid_line_span_engraver::Grid_line_span_engraver ()
+Grid_line_span_engraver::Grid_line_span_engraver (Context *c)
+ : Engraver (c)
{
spanline_ = 0;
}
}
}
-Grid_point_engraver::Grid_point_engraver ()
+Grid_point_engraver::Grid_point_engraver (Context *c)
+ : Engraver (c)
{
}
#include "lily-guile.hh"
#include "std-string.hh"
+#include "protected-scm.hh"
-static SCM all_ifaces;
+static Protected_scm all_ifaces;
void
internal_add_interface (SCM a, SCM b, SCM c)
{
- if (!all_ifaces)
- {
- SCM tab = scm_c_make_hash_table (59);
- all_ifaces = tab;
- scm_permanent_object (tab);
- }
+ if (!all_ifaces.is_bound ())
+ all_ifaces = scm_c_make_hash_table (59);
SCM entry = scm_list_3 (a, b, c);
vector<Grob_pq_entry> started_now_;
};
-Grob_pq_engraver::Grob_pq_engraver ()
+Grob_pq_engraver::Grob_pq_engraver (Context *c)
+ : Engraver (c)
{
}
busy = scm_cdr (busy);
}
- if (start_busy != busy)
+ if (!scm_is_eq (start_busy, busy))
context ()->set_property ("busyGrobs", busy);
}
void listen_note_grouping (Stream_event *);
};
-Horizontal_bracket_engraver::Horizontal_bracket_engraver ()
+Horizontal_bracket_engraver::Horizontal_bracket_engraver (Context *c)
+ : Engraver (c)
{
pop_count_ = 0;
push_count_ = 0;
void process_music ();
};
-Hyphen_engraver::Hyphen_engraver ()
+Hyphen_engraver::Hyphen_engraver (Context *c)
+ : Engraver (c)
{
hyphen_ = 0;
finished_hyphen_ = 0;
class Coherent_ligature_engraver : public Ligature_engraver
{
public:
+ Coherent_ligature_engraver(Context *c)
+ : Ligature_engraver (c)
+ {}
// no TRANSLATOR_DECLARATIONS (Coherent_ligature_engraver) needed
// since this class is abstract
TRANSLATOR_INHERIT (Ligature_engraver);
*/
DECLARE_CLASSNAME (Engraver);
DECLARE_TRANSLATOR_CALLBACKS (Engraver);
- Engraver ();
+ Engraver (Context *);
};
#define make_item(x, cause) internal_make_item (ly_symbol2scm (x), cause, __FILE__, __LINE__, __FUNCTION__)
TRANSLATOR_INHERIT(Coherent_ligature_engraver);
DECLARE_TRANSLATOR_CALLBACKS (Gregorian_ligature_engraver);
protected:
- Gregorian_ligature_engraver ();
+ Gregorian_ligature_engraver (Context *);
void listen_pes_or_flexa (Stream_event *ev);
virtual void build_ligature (Spanner *ligature,
class Ligature_engraver : public Engraver
{
protected:
- Ligature_engraver ();
+ Ligature_engraver (Context *c);
void stop_translation_timestep ();
virtual void finalize ();
class Time_signature_performer;
class Timing_translator;
class Translator;
+class Translator_creator;
class Translator_group;
#endif /* LILY_PROTO_HH */
DECLARE_CLASSNAME (Performer);
friend class Performer_group;
Performer_group *get_daddy_performer () const;
+ Performer (Context *c)
+ : Translator (c)
+ { }
protected:
virtual void announce_element (Audio_element_info);
#include "lily-guile.hh"
-void note_property_access (SCM *table, SCM sym);
-extern SCM context_property_lookup_table;
-extern SCM grob_property_lookup_table;
-extern SCM prob_property_lookup_table;
+class Protected_scm;
+
+void note_property_access (Protected_scm *table, SCM sym);
+extern Protected_scm context_property_lookup_table;
+extern Protected_scm grob_property_lookup_table;
+extern Protected_scm prob_property_lookup_table;
extern bool profile_property_accesses;
#endif /* PROFILE_HH */
Protected_scm &operator = (Protected_scm const &);
operator const SCM & () const;
operator SCM & ();
+ bool is_bound () const; // SCM_UNBNDP balks at Protected_scm
};
#endif /* PROTECTED_SCM_HH */
{
public:
TRANSLATOR_FAMILY_DECLARATIONS (Scheme_engraver);
- Scheme_engraver (SCM definition);
+ Scheme_engraver (SCM definition, Context *c);
protected:
~Scheme_engraver ();
}
SCM init_acknowledgers (SCM alist);
- // For now no description. In future, something derived from the
- // definition might make sense.
- SCM translator_description () const { return SCM_EOL; }
bool must_be_last_;
};
bool is_empty () const;
bool is_empty (Axis) const;
Stencil in_color (Real r, Real g, Real b) const;
+ Stencil with_outline (Stencil const &ol) const;
static SCM skylines_from_stencil (SCM, Real, Axis);
};
#include "std-vector.hh"
#include "protected-scm.hh"
+// The Translator_creator class is only for translators defined in C.
+// Its elements are callable entities taking a context argument and
+// returning a corresponding translator.
+//
+// Other translator-creating entities may be alists and functions returning
+// such alists. Information for those, such as created grobs/properties
+// is attached via object properties.
+
+// Smob rather than Simple_smob since we want an entity for
+// property lookup.
+
+class Translator_creator : public Smob<Translator_creator>
+{
+ Translator_creator (Translator_creator const &); // don't define
+ Translator * (*allocate_)(Context *);
+ template <class T>
+ static Translator *allocate (Context *ctx);
+
+ Translator_creator (Translator * (*allocate)(Context *))
+ : allocate_(allocate)
+ {
+ smobify_self ();
+ }
+public:
+ // This is stupid, but constructors cannot have explicit template
+ // argument lists.
+ template <class T>
+ static Translator_creator *alloc()
+ {
+ return new Translator_creator(&allocate<T>);
+ }
+ SCM call (SCM ctx);
+ LY_DECLARE_SMOB_PROC (&Translator_creator::call, 1, 0, 0);
+};
+
+template <class T> Translator *
+Translator_creator::allocate (Context *ctx)
+{
+ return new T(ctx);
+}
+
#define TRANSLATOR_FAMILY_DECLARATIONS(NAME) \
public: \
- VIRTUAL_COPY_CONSTRUCTOR (Translator, NAME); \
+ DECLARE_CLASSNAME (NAME); \
virtual void fetch_precomputable_methods (SCM methods[]); \
DECLARE_TRANSLATOR_CALLBACKS (NAME); \
TRANSLATOR_INHERIT (Translator); \
public: \
TRANSLATOR_FAMILY_DECLARATIONS (NAME); \
static Drul_array<Protected_scm> acknowledge_static_array_drul_; \
- static SCM static_description_; \
static Protected_scm listener_list_; \
static SCM static_get_acknowledger (SCM sym, Direction start_end); \
virtual SCM get_acknowledger (SCM sym, Direction start_end) \
return static_get_acknowledger (sym, start_end); \
} \
public: \
- NAME (); \
+ NAME (Context *); \
static void boot (); \
- virtual SCM static_translator_description () const; \
- virtual SCM translator_description () const; \
+ static SCM static_translator_description (); \
virtual SCM get_listener_list () const \
{ \
return listener_list_; \
SCM mark_smob () const;
static const char * const type_p_name_;
virtual ~Translator ();
-private:
- void init ();
-public:
Context *context () const { return daddy_context_; }
- Translator ();
- Translator (Translator const &);
+protected:
+ Translator (Context *);
+private:
+ Translator (Translator const &); // not copyable
+public:
SCM internal_get_property (SCM symbol) const;
Global_context *get_global_context () const;
DECLARE_CLASSNAME (Translator);
- virtual Translator *clone () const = 0;
+
virtual void fetch_precomputable_methods (SCM methods[]) = 0;
virtual SCM get_listener_list () const = 0;
- virtual SCM translator_description () const = 0;
virtual SCM get_acknowledger (SCM sym, Direction start_end) = 0;
protected: // should be private.
virtual void derived_mark () const;
static SCM event_class_symbol (const char *ev_class);
- SCM static_translator_description (const char *grobs,
- const char *desc,
- SCM listener_list,
- const char *read,
- const char *write) const;
+ static SCM
+ static_translator_description (const char *grobs,
+ const char *desc,
+ SCM listener_list,
+ const char *read,
+ const char *write);
friend class Translator_group;
};
-void add_translator (Translator *trans);
-
-Translator *get_translator (SCM s);
-
SCM
generic_get_acknowledger (SCM sym, SCM ack_hash);
+void add_translator_creator (SCM creator, SCM name, SCM description);
+
+SCM get_translator_creator (SCM s);
Moment get_event_length (Stream_event *s, Moment now);
Moment get_event_length (Stream_event *s);
A macro to automate administration of translators.
*/
#define ADD_THIS_TRANSLATOR(T) \
- SCM T::static_description_ = SCM_EOL; \
static void _ ## T ## _adder () \
{ \
T::boot (); \
- T *t = new T; \
- T::static_description_ = \
- scm_permanent_object (t->static_translator_description ()); \
- add_translator (t); \
- } \
- SCM T::translator_description () const \
- { \
- return static_description_; \
+ add_translator_creator (Translator_creator::alloc<T>()->unprotect (), \
+ scm_from_ascii_symbol (#T), \
+ T::static_translator_description ()); \
} \
ADD_GLOBAL_CTOR (_ ## T ## _adder); \
/* end define */
-#define DEFINE_TRANSLATOR_LISTENER_LIST(T) \
- Protected_scm T::listener_list_ (SCM_EOL)
+#define DEFINE_TRANSLATOR_LISTENER_LIST(T) \
+ Protected_scm T::listener_list_ (SCM_EOL); \
+ /* end define */
#define DEFINE_ACKNOWLEDGERS(classname) \
Drul_array<Protected_scm> classname::acknowledge_static_array_drul_; \
} \
/* end define */
-#define DEFINE_TRANSLATOR_DOC(classname, desc, grobs, read, write) \
+#define DEFINE_TRANSLATOR_DOC(classname, desc, grobs, read, write) \
SCM \
- classname::static_translator_description () const \
+ classname::static_translator_description () \
{ \
return Translator::static_translator_description (grobs, desc, listener_list_, read, write); \
}
{ \
ptrs[START_TRANSLATION_TIMESTEP] = \
method_finder <&T::start_translation_timestep> (); \
- \
- ptrs[STOP_TRANSLATION_TIMESTEP] = \
+ \
+ ptrs[STOP_TRANSLATION_TIMESTEP] = \
method_finder <&T::stop_translation_timestep> (); \
\
- ptrs[PROCESS_MUSIC] = \
+ ptrs[PROCESS_MUSIC] = \
method_finder <&T::process_music> (); \
- \
- ptrs[PROCESS_ACKNOWLEDGED] = \
+ \
+ ptrs[PROCESS_ACKNOWLEDGED] = \
method_finder <&T::process_acknowledged> (); \
}
/*
Implement the method cl::listen_##m, and make it listen to stream
events of class m.
+
+ At macro call time, neither creator instances (which are anonymous
+ and only accessible via the translator registry) nor translator
+ instances exist, so the only named place where we can store it is in
+ a static member of the translator class.
*/
#define ADD_LISTENER_FOR(cl, m, ev) \
listener_list_ = scm_acons \
scm_gc_mark (short_text_);
}
-Instrument_name_engraver::Instrument_name_engraver ()
+Instrument_name_engraver::Instrument_name_engraver (Context *c)
+ : Engraver (c)
{
text_spanner_ = 0;
scm_gc_mark (cue_name_);
}
-Instrument_switch_engraver::Instrument_switch_engraver ()
+Instrument_switch_engraver::Instrument_switch_engraver (Context *c)
+ : Engraver (c)
{
cue_name_ = SCM_EOL;
text_ = 0;
virtual void finalize ();
};
-Keep_alive_together_engraver::Keep_alive_together_engraver ()
+Keep_alive_together_engraver::Keep_alive_together_engraver (Context *c)
+ : Engraver (c)
{
}
{
}
-Key_engraver::Key_engraver ()
+Key_engraver::Key_engraver (Context *c)
+ : Engraver (c)
{
key_event_ = 0;
item_ = 0;
Key_engraver::process_music ()
{
if (key_event_
- || get_property ("lastKeyAlterations") != get_property ("keyAlterations"))
+ || !scm_is_eq (get_property ("lastKeyAlterations"),
+ get_property ("keyAlterations")))
create_key (false);
}
Audio_key *audio_;
};
-Key_performer::Key_performer ()
+Key_performer::Key_performer (Context *c)
+ : Performer (c)
{
key_ev_ = 0;
audio_ = 0;
void fold_up_primitives (vector<Grob_info> const &primitives, Real padding, Real &min_length);
};
-Kievan_ligature_engraver::Kievan_ligature_engraver ()
+Kievan_ligature_engraver::Kievan_ligature_engraver (Context *c)
+ : Coherent_ligature_engraver (c)
{
}
TRANSLATOR_DECLARATIONS (Laissez_vibrer_engraver);
};
-Laissez_vibrer_engraver::Laissez_vibrer_engraver ()
+Laissez_vibrer_engraver::Laissez_vibrer_engraver (Context *c)
+ : Engraver (c)
{
event_ = 0;
lv_column_ = 0;
void stop_translation_timestep ();
};
-Ledger_line_engraver::Ledger_line_engraver ()
+Ledger_line_engraver::Ledger_line_engraver (Context *c)
+ : Engraver (c)
{
span_ = 0;
}
ASSIGN_EVENT_ONCE (events_drul_[d], ev);
}
-Ligature_bracket_engraver::Ligature_bracket_engraver ()
+Ligature_bracket_engraver::Ligature_bracket_engraver (Context *c)
+ : Engraver (c)
{
ligature_ = 0;
finished_ligature_ = 0;
* would require to have a single, complicated Ligature_engraver that
* consists of all the code... This needs further thoughts.
*/
-Ligature_engraver::Ligature_engraver ()
+Ligature_engraver::Ligature_engraver (Context *c)
+ : Engraver (c)
{
ligature_ = 0;
finished_ligature_ = 0;
Context *get_voice_context ();
};
-Lyric_engraver::Lyric_engraver ()
+Lyric_engraver::Lyric_engraver (Context *c)
+ : Engraver (c)
{
text_ = 0;
last_text_ = 0;
Audio_text *audio_;
};
-Lyric_performer::Lyric_performer ()
+Lyric_performer::Lyric_performer (Context *c)
+ : Performer (c)
{
audio_ = 0;
}
void acknowledge_break_alignment (Grob_info);
};
-Mark_engraver::Mark_engraver ()
+Mark_engraver::Mark_engraver (Context *c)
+ : Engraver (c)
{
text_ = 0;
final_text_ = 0;
}
}
-Measure_grouping_engraver::Measure_grouping_engraver ()
+Measure_grouping_engraver::Measure_grouping_engraver (Context *c)
+ : Engraver (c)
{
grouping_ = 0;
}
void process_music ();
};
-Melody_engraver::Melody_engraver ()
+Melody_engraver::Melody_engraver (Context *c)
+ : Engraver (c)
{
stem_ = 0;
melody_item_ = 0;
Real &min_length);
};
-Mensural_ligature_engraver::Mensural_ligature_engraver ()
+Mensural_ligature_engraver::Mensural_ligature_engraver (Context *c)
+ : Coherent_ligature_engraver (c)
{
brew_ligature_primitive_proc
= Mensural_ligature::brew_ligature_primitive_proc;
void listen_tempo_change (Stream_event *);
};
-Metronome_mark_engraver::Metronome_mark_engraver ()
+Metronome_mark_engraver::Metronome_mark_engraver (Context *c)
+ : Engraver (c)
{
text_ = 0;
support_ = 0;
};
};
-Midi_control_change_performer::Midi_control_change_performer ()
+Midi_control_change_performer::Midi_control_change_performer (Context *c)
+ : Performer (c)
{
}
bool first_time_;
};
-Multi_measure_rest_engraver::Multi_measure_rest_engraver ()
- : rest_ev_ (0),
+Multi_measure_rest_engraver::Multi_measure_rest_engraver (Context *c)
+ : Engraver (c),
+ rest_ev_ (0),
mmrest_ (0),
start_measure_ (0),
last_command_item_ (0),
Grob *last = 0;
for (vsize i = 0; i < text_.size (); i++)
{
- if (scm_is_eq (dir, text_[i]->get_property ("direction")))
+ if (ly_is_equal (dir, text_[i]->get_property ("direction")))
{
if (last)
Side_position_interface::add_support (text_[i], last);
&& scm_is_pair (val))
new_val = ly_transpose_key_alist (val, delta.smobbed_copy ());
- if (val != new_val)
+ if (!scm_is_eq (val, new_val))
scm_set_cdr_x (entry, new_val);
}
}
articulations_.clear ();
}
-New_fingering_engraver::New_fingering_engraver ()
+New_fingering_engraver::New_fingering_engraver (Context *c)
+ : Engraver (c)
{
stem_ = 0;
}
Grob *last_head_;
};
-Note_head_line_engraver::Note_head_line_engraver ()
+Note_head_line_engraver::Note_head_line_engraver (Context *c)
+ : Engraver (c)
{
line_ = 0;
follow_ = false;
void stop_translation_timestep ();
};
-Note_heads_engraver::Note_heads_engraver ()
+Note_heads_engraver::Note_heads_engraver (Context *c)
+ : Engraver (c)
{
}
events_.clear ();
}
-Note_name_engraver::Note_name_engraver ()
+Note_name_engraver::Note_name_engraver (Context *c)
+ : Engraver (c)
{
}
""
);
-Note_performer::Note_performer ()
+Note_performer::Note_performer (Context *c)
+ : Performer (c)
{
}
scm_gc_mark (i->first->self_scm ());
}
-Note_spacing_engraver::Note_spacing_engraver ()
+Note_spacing_engraver::Note_spacing_engraver (Context *c)
+ : Engraver (c)
{
spacing_ = 0;
last_spacing_ = 0;
scm_gc_mark (last_ottavation_);
}
-Ottava_spanner_engraver::Ottava_spanner_engraver ()
+Ottava_spanner_engraver::Ottava_spanner_engraver (Context *c)
+ : Engraver (c)
{
finished_ = 0;
span_ = 0;
Ottava_spanner_engraver::process_music ()
{
SCM ott = get_property ("ottavation");
- if (ott != last_ottavation_)
+ if (!scm_is_eq (ott, last_ottavation_))
{
finished_ = span_;
span_ = 0;
props_.clear ();
}
-Output_property_engraver::Output_property_engraver ()
+Output_property_engraver::Output_property_engraver (Context *c)
+ : Engraver (c)
{
}
SCM lines = scm_caar (s);
SCM config = scm_cdar (s);
- bool bookpart_last_page = (s == systems_configs_fncounts);
+ bool bookpart_last_page = scm_is_eq (s, systems_configs_fncounts);
SCM page = draw_page (lines, config, page_num, bookpart_last_page);
/* collect labels */
SCM page_num_scm = scm_from_int (page_num);
bool last = (j == cols.size () - 1);
bool break_point = is_break && is_break (cols[j]);
- bool chunk_end = cols[j]->get_property ("page-break-permission") == force_sym;
+ bool chunk_end = scm_is_eq (cols[j]->get_property ("page-break-permission"), force_sym);
Break_position cur_pos = Break_position (i,
line_breaker_columns.size (),
cols[j],
for (SCM s = systems; scm_is_pair (s); s = scm_cdr (s))
{
- bool first = (s == systems);
+ bool first = scm_is_eq (s, systems);
if (Grob *g = unsmob<Grob> (scm_car (s)))
{
void finalize ();
};
-Page_turn_engraver::Page_turn_engraver ()
+Page_turn_engraver::Page_turn_engraver (Context *c)
+ : Engraver (c)
{
repeat_begin_ = Moment (-1);
repeat_begin_rest_length_ = 0;
SCM footnotes = get_footnotes (unsmob<Stencil> (t)->expr ());
ps->set_property ("footnotes", footnotes);
ps->set_property ("is-title", SCM_BOOL_T);
- if (list == texts)
+ if (scm_is_eq (list, texts))
first = ps;
else
{
#include "translator.icc"
-Paper_column_engraver::Paper_column_engraver ()
+Paper_column_engraver::Paper_column_engraver (Context *c)
+ : Engraver (c)
{
last_moment_.main_part_ = Rational (-1, 1);
command_column_ = 0;
extract_grob_set (me, "elements", elts);
for (vsize i = 0; i < elts.size (); i++)
{
- if (elts[i]->get_property ("break-align-symbol") == align_sym
+ if (scm_is_eq (align_sym, elts[i]->get_property ("break-align-symbol"))
+ // TODO SCM: there must be a simpler way to put this.
&& !elts[i]->extent (elts[i], X_AXIS).is_empty ())
{
align = elts[i];
void acknowledge_grob (Grob_info);
};
-Parenthesis_engraver::Parenthesis_engraver ()
+Parenthesis_engraver::Parenthesis_engraver (Context *c)
+ : Engraver (c)
{
}
| context_def_mod embedded_scm
{
if (!scm_is_string ($2)
- && ly_symbol2scm ("consists") != $1
- && ly_symbol2scm ("remove") != $1)
+ && !scm_is_eq ($1, ly_symbol2scm ("consists"))
+ && !scm_is_eq ($1, ly_symbol2scm ("remove")))
{
$$ = SCM_EOL;
parser->parser_error (@1, _ ("only \\consists and \\remove take non-string argument."));
note_found_ = true;
}
-Part_combine_engraver::Part_combine_engraver ()
+Part_combine_engraver::Part_combine_engraver (Context *c)
+ : Engraver (c)
{
text_ = 0;
new_event_ = 0;
void process_music ();
};
-Percent_repeat_engraver::Percent_repeat_engraver ()
+Percent_repeat_engraver::Percent_repeat_engraver (Context *c)
+ : Engraver (c)
{
percent_ = 0;
percent_counter_ = 0;
return "phrasing slur";
}
-Phrasing_slur_engraver::Phrasing_slur_engraver ()
+Phrasing_slur_engraver::Phrasing_slur_engraver (Context *c)
+ : Slur_engraver (c)
{
}
Spanner *make_line_spanner (Pedal_type t, SCM);
};
-Piano_pedal_align_engraver::Piano_pedal_align_engraver ()
+Piano_pedal_align_engraver::Piano_pedal_align_engraver (Context *c)
+ : Engraver (c)
{
}
ADD_SCM_INIT_FUNC (Piano_pedal_engraver_init_pedal_types_, init_pedal_types);
-Piano_pedal_engraver::Piano_pedal_engraver ()
+Piano_pedal_engraver::Piano_pedal_engraver (Context *c)
+ : Engraver (c)
{
}
Pedal_info info_alist_[NUM_PEDAL_TYPES];
};
-Piano_pedal_performer::Piano_pedal_performer ()
+Piano_pedal_performer::Piano_pedal_performer (Context *c)
+ : Performer (c)
{
}
i.grob ()->set_property ("staff-position", newpos);
}
-Pitch_squash_engraver::Pitch_squash_engraver ()
+Pitch_squash_engraver::Pitch_squash_engraver (Context *c)
+ : Engraver (c)
{
}
void make_trill (Stream_event *);
};
-Pitched_trill_engraver::Pitched_trill_engraver ()
+Pitched_trill_engraver::Pitched_trill_engraver (Context *c)
+ : Engraver (c)
{
trill_head_ = 0;
trill_group_ = 0;
"Is @var{obj} the specified prob-type?")
{
Prob *prob = unsmob<Prob> (obj);
- return scm_from_bool (prob && prob->type () == type);
+ return scm_from_bool (prob && scm_is_eq (prob->type (), type));
}
LY_DEFINE (ly_make_prob, "ly:make-prob",
*/
#include "profile.hh"
+#include "protected-scm.hh"
-void note_property_access (SCM *table, SCM sym);
-
-SCM context_property_lookup_table;
-SCM grob_property_lookup_table;
-SCM prob_property_lookup_table;
+Protected_scm context_property_lookup_table;
+Protected_scm grob_property_lookup_table;
+Protected_scm prob_property_lookup_table;
LY_DEFINE (ly_property_lookup_stats, "ly:property-lookup-stats",
1, 0, 0, (SCM sym),
" @var{sym}. Choices are @code{prob}, @code{grob}, and"
" @code{context}.")
{
- if (scm_is_eq (sym, ly_symbol2scm ("context")))
- return context_property_lookup_table ? context_property_lookup_table
- : scm_c_make_hash_table (1);
- if (scm_is_eq (sym, ly_symbol2scm ("prob")))
- return prob_property_lookup_table ? prob_property_lookup_table
- : scm_c_make_hash_table (1);
- if (scm_is_eq (sym, ly_symbol2scm ("grob")))
- return grob_property_lookup_table ? grob_property_lookup_table
- : scm_c_make_hash_table (1);
+ if (context_property_lookup_table.is_bound ()
+ && scm_is_eq (sym, ly_symbol2scm ("context")))
+ return context_property_lookup_table;
+ if (prob_property_lookup_table.is_bound ()
+ && scm_is_eq (sym, ly_symbol2scm ("prob")))
+ return prob_property_lookup_table;
+ if (grob_property_lookup_table.is_bound ()
+ && scm_is_eq (sym, ly_symbol2scm ("grob")))
+ return grob_property_lookup_table;
return scm_c_make_hash_table (1);
}
void
-note_property_access (SCM *table, SCM sym)
+note_property_access (Protected_scm *table, SCM sym)
{
/*
Statistics: which properties are looked up?
*/
- if (!*table)
- *table = scm_permanent_object (scm_c_make_hash_table (259));
+ if (!table->is_bound ())
+ *table = scm_c_make_hash_table (259);
SCM hashhandle = scm_hashq_get_handle (*table, sym);
if (scm_is_false (hashhandle))
#include "string-convert.hh"
#include "warn.hh"
#include "lily-imports.hh"
+#include "protected-scm.hh"
bool debug_skylines;
bool debug_property_callbacks;
bool do_internal_type_checking_global;
bool strict_infinity_checking = false;
-static SCM option_hash;
+static Protected_scm option_hash;
void
internal_set_option (SCM var,
"Add a program option @var{sym}. @var{val} is the default"
" value and @var{description} is a string description.")
{
- if (!option_hash)
- option_hash = scm_permanent_object (scm_c_make_hash_table (11));
+ if (!option_hash.is_bound ())
+ option_hash = scm_c_make_hash_table (11);
LY_ASSERT_TYPE (ly_is_symbol, sym, 1);
LY_ASSERT_TYPE (scm_is_string, description, 3);
return *SCM_CARLOC (object_);
}
+
+bool
+Protected_scm::is_bound () const
+{
+ if (SCM_CONSP (object_))
+ return !SCM_UNBNDP (SCM_CAR (object_));
+ return !SCM_UNBNDP (object_);
+}
void finalize ();
};
-Pure_from_neighbor_engraver::Pure_from_neighbor_engraver ()
+Pure_from_neighbor_engraver::Pure_from_neighbor_engraver (Context *c)
+ : Engraver (c)
{
}
context ()->set_property ("repeatCommands", SCM_EOL);
}
-Repeat_acknowledge_engraver::Repeat_acknowledge_engraver ()
+Repeat_acknowledge_engraver::Repeat_acknowledge_engraver (Context *c)
+ : Engraver (c)
{
}
TRANSLATOR_DECLARATIONS (Repeat_tie_engraver);
};
-Repeat_tie_engraver::Repeat_tie_engraver ()
+Repeat_tie_engraver::Repeat_tie_engraver (Context *c)
+ : Engraver (c)
{
event_ = 0;
semi_tie_column_ = 0;
TRANSLATOR_DECLARATIONS (Rest_collision_engraver);
};
-Rest_collision_engraver::Rest_collision_engraver ()
+Rest_collision_engraver::Rest_collision_engraver (Context *c)
+ : Engraver (c)
{
rest_collision_ = 0;
}
/*
Should merge with Note_head_engraver
*/
-Rest_engraver::Rest_engraver ()
+Rest_engraver::Rest_engraver (Context *c)
+ : Engraver (c)
{
rest_event_ = 0;
rest_ = 0;
void stop_translation_timestep ();
};
-Rhythmic_column_engraver::Rhythmic_column_engraver ()
+Rhythmic_column_engraver::Rhythmic_column_engraver (Context *c)
+ : Engraver (c)
{
stem_ = 0;
ptrs[i] = precomputable_methods_[i];
}
-Scheme_engraver::Scheme_engraver (SCM definition)
+Scheme_engraver::Scheme_engraver (SCM definition, Context *c)
+ : Engraver (c)
{
precomputable_methods_[START_TRANSLATION_TIMESTEP]
= callable (ly_symbol2scm ("start-translation-timestep"), definition);
void stop_translation_timestep ();
};
-Script_column_engraver::Script_column_engraver ()
+Script_column_engraver::Script_column_engraver (Context *c)
+ : Engraver (c)
{
script_column_ = 0;
}
{
affect_all_grobs.push_back (sc);
}
- else if (sc->get_property_data ("Y-offset")
- != Side_position_interface::y_aligned_side_proc)
+ else if (!scm_is_eq (sc->get_property_data ("Y-offset"),
+ Side_position_interface::y_aligned_side_proc))
{
head_scripts_map[sc->get_parent (Y_AXIS)].push_back (sc);
}
/*
Don't want to consider scripts horizontally next to notes.
*/
- if (sc->get_property_data ("X-offset")
- != Side_position_interface::x_aligned_side_proc)
+ if (!scm_is_eq (sc->get_property_data ("X-offset"),
+ Side_position_interface::x_aligned_side_proc))
staff_sided.push_back (sc);
}
TRANSLATOR_DECLARATIONS (Script_engraver);
};
-Script_engraver::Script_engraver ()
+Script_engraver::Script_engraver (Context *c)
+ : Engraver (c)
{
}
void stop_translation_timestep ();
};
-Script_row_engraver::Script_row_engraver ()
+Script_row_engraver::Script_row_engraver (Context *c)
+ : Engraver (c)
{
script_row_ = 0;
}
TRANSLATOR_DECLARATIONS (Separating_line_group_engraver);
};
-Separating_line_group_engraver::Separating_line_group_engraver ()
+Separating_line_group_engraver::Separating_line_group_engraver (Context *c)
+ : Engraver (c)
{
}
force[b * breaks.size () + c] = infinity_f;
break;
}
- if (end < cols.size () && cols[end].break_permission_ == force_break)
+ if (end < cols.size () && scm_is_eq (cols[end].break_permission_, force_break))
break;
}
}
void process_music ();
};
-Slash_repeat_engraver::Slash_repeat_engraver ()
+Slash_repeat_engraver::Slash_repeat_engraver (Context *c)
+ : Engraver (c)
{
slash_ = 0;
}
return "slur";
}
-Slur_engraver::Slur_engraver ()
+Slur_engraver::Slur_engraver (Context *c)
+ : Engraver (c)
{
}
bool slur_;
};
-Slur_performer::Slur_performer ()
+Slur_performer::Slur_performer (Context *c)
+ : Performer (c)
{
slur_ = false;
start_ev_ = 0;
void stop_spanner ();
};
-Spacing_engraver::Spacing_engraver ()
+Spacing_engraver::Spacing_engraver (Context *c)
+ : Engraver (c)
{
spacing_ = 0;
start_section_ = 0;
vector<Grob *> note_columns_;
};
-Span_arpeggio_engraver::Span_arpeggio_engraver ()
+Span_arpeggio_engraver::Span_arpeggio_engraver (Context *c)
+ : Engraver (c)
{
span_arpeggio_ = 0;
}
void process_acknowledged ();
};
-Span_bar_engraver::Span_bar_engraver ()
+Span_bar_engraver::Span_bar_engraver (Context *c)
+ : Engraver (c)
{
spanbar_ = 0;
make_spanbar_ = false;
virtual void derived_mark () const;
};
-Span_bar_stub_engraver::Span_bar_stub_engraver ()
+Span_bar_stub_engraver::Span_bar_stub_engraver (Context *c)
+ : Engraver (c)
{
axis_groups_ = SCM_EOL;
}
running_spanners_.push_back (gi.spanner ());
}
-Spanner_break_forbid_engraver::Spanner_break_forbid_engraver ()
+Spanner_break_forbid_engraver::Spanner_break_forbid_engraver (Context *c)
+ : Engraver (c)
{
}
Real total_width = 0.0;
vector<Real> span_data;
- if (!orig->is_broken ())
- span_data.push_back (orig->spanner_length ());
- else
- for (vsize i = 0; i < orig->broken_intos_.size (); i++)
- span_data.push_back (orig->broken_intos_[i]->spanner_length ());
+ for (vsize i = 0; i < orig->broken_intos_.size (); i++)
+ span_data.push_back (orig->broken_intos_[i]->spanner_length ());
vector<Interval> unnormalized_endpoints;
SCM
Spring::equal_p (SCM a, SCM b)
{
- return a == b ? SCM_BOOL_T : SCM_BOOL_F;
+ // TODO SCM: This could be made simpler.
+ return scm_is_eq (a, b) ? SCM_BOOL_T : SCM_BOOL_F;
}
LY_DEFINE (ly_make_spring, "ly:make-spring",
void acknowledge_end_staff_symbol (Grob_info);
};
-Staff_collecting_engraver::Staff_collecting_engraver ()
+Staff_collecting_engraver::Staff_collecting_engraver (Context *c)
+ : Engraver (c)
{
}
/* write */
"");
-Staff_performer::Staff_performer ()
- : channel_ (-1),
+Staff_performer::Staff_performer (Context *c)
+ : Performer (c),
+ channel_ (-1),
instrument_ (0),
instrument_name_ (0),
name_ (0),
}
}
-Staff_symbol_engraver::Staff_symbol_engraver ()
+Staff_symbol_engraver::Staff_symbol_engraver (Context *c)
+ : Engraver (c)
{
finished_span_ = 0;
first_start_ = true;
void stop_translation_timestep ();
};
-Stanza_number_align_engraver::Stanza_number_align_engraver ()
+Stanza_number_align_engraver::Stanza_number_align_engraver (Context *c)
+ : Engraver (c)
{
}
all aligned.
*/
-Stanza_number_engraver::Stanza_number_engraver ()
+Stanza_number_engraver::Stanza_number_engraver (Context *c)
+ : Engraver (c)
{
text_ = 0;
last_stanza_ = SCM_EOL;
SCM stanza = get_property ("stanza");
if (Text_interface::is_markup (stanza)
- && stanza != last_stanza_)
+ && !scm_is_eq (stanza, last_stanza_))
{
last_stanza_ = stanza;
void kill_unused_flags ();
};
-Stem_engraver::Stem_engraver ()
+Stem_engraver::Stem_engraver (Context *c)
+ : Engraver (c)
{
tremolo_ev_ = 0;
stem_ = 0;
*/
#include "stencil.hh"
+#include "protected-scm.hh"
-static SCM heads;
+static Protected_scm heads (SCM_EOL);
void register_stencil_head (SCM symbol)
{
- if (!heads)
- heads = scm_permanent_object (scm_cons (SCM_EOL, SCM_EOL));
-
scm_set_object_property_x (symbol, ly_symbol2scm ("stencil-head?"), SCM_BOOL_T);
- scm_set_cdr_x (heads, scm_cons (symbol, scm_cdr (heads)));
+ heads = scm_cons (symbol, heads);
}
bool
SCM
all_stencil_heads ()
{
- return scm_cdr (heads);
+ return heads;
}
-
vector<Transform_matrix_and_expression>
stencil_traverser (PangoMatrix trans, SCM expr)
{
- if (scm_is_null (expr))
- return vector<Transform_matrix_and_expression> ();
- else if (scm_is_eq (expr, ly_string2scm ("")))
+ if (scm_is_null (expr)
+ || (scm_is_string (expr) && scm_is_true (scm_string_null_p (expr))))
return vector<Transform_matrix_and_expression> ();
else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("combine-stencil")))
{
return stencil_traverser (trans, scm_cadr (expr));
else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("output-attributes")))
return stencil_traverser (trans, scm_caddr (expr));
+ else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("with-outline")))
+ return stencil_traverser (trans, scm_cadr (expr));
else
{
vector<Transform_matrix_and_expression> out;
return;
}
+ else if (scm_is_eq (head, ly_symbol2scm ("with-outline")))
+ {
+ expr = scm_caddr (expr);
+ }
else
{
(*func) (func_arg,
q->scale (scm_to_double (x), scm_to_double (y));
return new_s;
}
+
+LY_DEFINE (ly_stencil_outline, "ly:stencil-outline",
+ 2, 0, 0, (SCM stil, SCM outline),
+ "Return a stencil with the stencil expression (inking)"
+ " of stencil @var{stil} but with outline and dimensions"
+ " from stencil @var{outline}.")
+{
+ Stencil s = *LY_ASSERT_SMOB (Stencil, stil, 1);
+ Stencil o = *LY_ASSERT_SMOB (Stencil, outline, 2);
+ return s.with_outline (o).smobbed_copy ();
+}
s.translate (z);
return s;
}
+
+Stencil
+Stencil::with_outline (Stencil const &ol) const
+{
+ Stencil new_stencil (ol.extent_box (),
+ scm_list_3 (ly_symbol2scm ("with-outline"),
+ ol.expr (),
+ expr ()));
+ return new_stencil;
+}
virtual void finalize ();
};
-System_start_delimiter_engraver::System_start_delimiter_engraver ()
+System_start_delimiter_engraver::System_start_delimiter_engraver (Context *c)
+ : Engraver (c)
{
nesting_ = 0;
}
void stop_translation_timestep ();
};
-Tab_note_heads_engraver::Tab_note_heads_engraver ()
+Tab_note_heads_engraver::Tab_note_heads_engraver (Context *c)
+ : Engraver (c)
{
}
gi.grob ()->set_property ("line-count", scm_from_int (k));
}
-Tab_staff_symbol_engraver::Tab_staff_symbol_engraver ()
+Tab_staff_symbol_engraver::Tab_staff_symbol_engraver (Context *c)
+ : Engraver (c)
{
}
void stop_translation_timestep ();
};
-Tab_tie_follow_engraver::Tab_tie_follow_engraver ()
+Tab_tie_follow_engraver::Tab_tie_follow_engraver (Context *c)
+ : Engraver (c)
{
}
scm_gc_mark (last_tempo_);
}
-Tempo_performer::Tempo_performer ()
+Tempo_performer::Tempo_performer (Context *c)
+ : Performer (c)
{
last_tempo_ = SCM_EOL;
audio_ = 0;
scripts_.clear ();
}
-Text_engraver::Text_engraver ()
+Text_engraver::Text_engraver (Context *c)
+ : Engraver (c)
{
}
void typeset_all ();
};
-Text_spanner_engraver::Text_spanner_engraver ()
+Text_spanner_engraver::Text_spanner_engraver (Context *c)
+ : Engraver (c)
{
finished_ = 0;
current_event_ = 0;
TRANSLATOR_DECLARATIONS (Tie_engraver);
};
-Tie_engraver::Tie_engraver ()
+Tie_engraver::Tie_engraver (Context *c)
+ : Engraver (c)
{
event_ = 0;
tie_column_ = 0;
TRANSLATOR_DECLARATIONS (Tie_performer);
};
-Tie_performer::Tie_performer ()
+Tie_performer::Tie_performer (Context *c)
+ : Performer (c)
{
event_ = 0;
}
scm_gc_mark (time_cause_);
}
-Time_signature_engraver::Time_signature_engraver ()
+Time_signature_engraver::Time_signature_engraver (Context *c)
+ : Engraver (c)
{
time_signature_ = 0;
time_cause_ = SCM_EOL;
return;
SCM fr = get_property ("timeSignatureFraction");
- if (last_time_fraction_ != fr
- && scm_is_pair (fr))
+ if (!scm_is_eq (last_time_fraction_, fr) && scm_is_pair (fr))
{
time_signature_ = make_item ("TimeSignature", time_cause_);
time_signature_->set_property ("fraction", fr);
scm_gc_mark (prev_fraction_);
}
-Time_signature_performer::Time_signature_performer ()
+Time_signature_performer::Time_signature_performer (Context *c)
+ : Performer (c)
{
prev_fraction_ = SCM_BOOL_F;
audio_ = 0;
return Rational (1);
}
-Timing_translator::Timing_translator ()
+Timing_translator::Timing_translator (Context *c)
+ : Translator (c)
{
}
along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "context.hh"
#include "translator.hh"
-
+#include "lily-imports.hh"
#include "international.hh"
#include "scm-hash.hh"
#include "warn.hh"
#include "protected-scm.hh"
-/*
- should delete these after exit.
-*/
+SCM
+Translator_creator::call (SCM ctx)
+{
+ return (allocate_ (LY_ASSERT_SMOB (Context, ctx, 1)))->unprotect ();
+}
Protected_scm global_translator_dict;
+Protected_scm global_translator_dict_rev;
LY_DEFINE (get_all_translators, "ly:get-all-translators", 0, 0, 0, (),
"Return a list of all translator objects that may be"
}
void
-add_translator (Translator *t)
+add_translator_creator (SCM creator, SCM name, SCM description)
{
Scheme_hash_table *dict = unsmob<Scheme_hash_table> (global_translator_dict);
if (!dict)
{
global_translator_dict = Scheme_hash_table::make_smob ();
+ global_translator_dict_rev =
+ scm_make_weak_key_hash_table (scm_from_int (119));
dict = unsmob<Scheme_hash_table> (global_translator_dict);
}
+ dict->set (name, creator);
+ scm_hashq_set_x (global_translator_dict_rev, creator, scm_cons (name, description));
+}
- SCM k = ly_symbol2scm (t->class_name ());
- dict->set (k, t->unprotect ());
+LY_DEFINE (ly_translator_name, "ly:translator-name",
+ 1, 0, 0, (SCM creator),
+ "Return the type name of the translator definition @var{creator}."
+ " The name is a symbol.")
+{
+ SCM res = global_translator_dict_rev.is_bound ()
+ ? scm_hashq_ref (global_translator_dict_rev, creator, SCM_BOOL_F)
+ : SCM_BOOL_F;
+ SCM_ASSERT_TYPE (scm_is_pair (res),
+ creator, SCM_ARG1, __FUNCTION__, "translator definition");
+ return scm_car (res);
+}
+
+LY_DEFINE (ly_translator_description, "ly:translator-description",
+ 1, 0, 0, (SCM creator),
+ "Return an alist of properties of translator definition @var{creator}.")
+{
+ SCM res = global_translator_dict_rev.is_bound ()
+ ? scm_hashq_ref (global_translator_dict_rev, creator, SCM_BOOL_F)
+ : SCM_BOOL_F;
+ SCM_ASSERT_TYPE (scm_is_pair (res),
+ creator, SCM_ARG1, __FUNCTION__, "translator definition");
+ return scm_cdr (res);
+}
+
+LY_DEFINE (ly_register_translator, "ly:register-translator",
+ 2, 1, 0, (SCM creator, SCM name, SCM description),
+ "Register a translator @var{creator} (usually a descriptive"
+ " alist or a function/closure returning one when given a"
+ " context argument) with the given symbol @var{name} and"
+ " the given @var{description} alist.")
+{
+ SCM_ASSERT_TYPE (ly_is_procedure (creator) || scm_is_pair (creator),
+ creator, SCM_ARG1, __FUNCTION__, "translator creator");
+ LY_ASSERT_TYPE (ly_is_symbol, name, 2);
+ if (SCM_UNBNDP (description))
+ description = SCM_EOL;
+ else
+ LY_ASSERT_TYPE (ly_is_list, description, 3);
+ add_translator_creator (creator, name, description);
+ return SCM_UNSPECIFIED;
}
-Translator *
-get_translator (SCM sym)
+SCM
+get_translator_creator (SCM sym)
{
SCM v = SCM_BOOL_F;
Scheme_hash_table *dict = unsmob<Scheme_hash_table> (global_translator_dict);
if (scm_is_false (v))
{
warning (_f ("unknown translator: `%s'", ly_symbol2string (sym).c_str ()));
- return 0;
}
- return unsmob<Translator> (v);
+ return v;
}
for (SCM s = trans_names; scm_is_pair (s); s = scm_cdr (s))
{
- SCM definition = scm_car (s);
- bool is_scheme = false;
-
- Translator *type = 0;
- if (ly_is_symbol (definition))
- type = get_translator (definition);
- else if (ly_is_pair (definition))
- {
- is_scheme = true;
- }
- else if (ly_is_procedure (definition))
+ SCM trans = scm_car (s);
+
+ if (ly_is_symbol (trans))
+ trans = get_translator_creator (trans);
+ if (ly_is_procedure (trans))
+ trans = scm_call_1 (trans, cs);
+ if (ly_cheap_is_list (trans))
+ trans = (new Scheme_engraver (trans, new_context))->unprotect ();
+ Translator *instance = unsmob<Translator> (trans);
+ if (!instance)
{
- // `definition' is a procedure, which takes the context as
- // an argument and evaluates to an a-list scheme engraver
- // definition.
- definition = scm_call_1 (definition, cs);
- is_scheme = true;
+ warning (_f ("cannot find: `%s'", ly_scm_write_string (trans).c_str ()));
+ continue;
}
- if (!is_scheme && !type)
- warning (_f ("cannot find: `%s'", ly_symbol2string (scm_car (s)).c_str ()));
- else
+ if (instance->must_be_last ())
{
- Translator *instance = is_scheme ? new Scheme_engraver (definition)
- : type->clone ();
-
- SCM str = instance->self_scm ();
-
- if (instance->must_be_last ())
- {
- SCM cons = scm_cons (str, SCM_EOL);
- if (scm_is_pair (trans_list))
- scm_set_cdr_x (scm_last_pair (trans_list), cons);
- else
- trans_list = cons;
- }
+ SCM cons = scm_cons (trans, SCM_EOL);
+ if (scm_is_pair (trans_list))
+ scm_set_cdr_x (scm_last_pair (trans_list), cons);
else
- trans_list = scm_cons (str, trans_list);
-
- instance->daddy_context_ = new_context;
- instance->unprotect ();
+ trans_list = cons;
}
+ else
+ trans_list = scm_cons (trans, trans_list);
+
}
/* Filter unwanted translator types. Required to make
#include "translator-group.hh"
#include "moment.hh"
-LY_DEFINE (ly_translator_name, "ly:translator-name",
- 1, 0, 0, (SCM trans),
- "Return the type name of the translator object @var{trans}."
- " The name is a symbol.")
-{
- LY_ASSERT_SMOB (Translator, trans, 1);
- Translator *tr = unsmob<Translator> (trans);
- char const *nm = tr->class_name ();
- return ly_symbol2scm (nm);
-}
-
-LY_DEFINE (ly_translator_description, "ly:translator-description",
- 1, 0, 0, (SCM me),
- "Return an alist of properties of translator @var{me}.")
-{
- LY_ASSERT_SMOB (Translator, me, 1);
- Translator *tr = unsmob<Translator> (me);
- return tr->translator_description ();
-}
-
LY_DEFINE (ly_translator_context, "ly:translator-context",
1, 0, 0, (SCM trans),
"Return the context of the translator object @var{trans}.")
{
}
-void
-Translator::init ()
-{
- daddy_context_ = 0;
- smobify_self ();
-}
-
void
Translator::process_music ()
{
{
}
-Translator::Translator ()
+Translator::Translator (Context *c)
+ : daddy_context_ (c)
{
- init ();
-}
-
-Translator::Translator (Translator const &)
- : Smob<Translator> ()
-{
- init ();
+ smobify_self ();
}
Moment
const char *desc,
SCM listener_list,
const char *read,
- const char *write) const
+ const char *write)
{
SCM static_properties = SCM_EOL;
void typeset_all ();
};
-Trill_spanner_engraver::Trill_spanner_engraver ()
+Trill_spanner_engraver::Trill_spanner_engraver (Context *c)
+ : Engraver (c)
{
finished_ = 0;
current_event_ = 0;
}
}
-Tuplet_engraver::Tuplet_engraver ()
+Tuplet_engraver::Tuplet_engraver (Context *c)
+ : Engraver (c)
{
}
void acknowledge_grob (Grob_info);
};
-Tweak_engraver::Tweak_engraver ()
+Tweak_engraver::Tweak_engraver (Context *c)
+ : Engraver (c)
{
}
vector<Grob_info> const &primitives);
};
-Vaticana_ligature_engraver::Vaticana_ligature_engraver ()
+Vaticana_ligature_engraver::Vaticana_ligature_engraver (Context *c)
+ : Gregorian_ligature_engraver (c)
{
brew_ligature_primitive_proc
= Vaticana_ligature::brew_ligature_primitive_proc;
""
);
-Vertical_align_engraver::Vertical_align_engraver ()
+Vertical_align_engraver::Vertical_align_engraver (Context *c)
+ : Engraver (c)
{
valign_ = 0;
id_to_group_hashtab_ = SCM_EOL;
scm_gc_mark (start_string_);
}
-Volta_engraver::Volta_engraver ()
+Volta_engraver::Volta_engraver (Context *c)
+ : Engraver (c)
{
start_string_ = SCM_EOL;
volta_bracket_ = 0;
%}
-\version "2.19.54" % necessary for upgrading to future LilyPond versions.
+\version "2.19.55" % necessary for upgrading to future LilyPond versions.
\header{
title = "A scale in LilyPond"
%}
-\version "2.19.54" % necessary for upgrading to future LilyPond versions.
+\version "2.19.55" % necessary for upgrading to future LilyPond versions.
\header{
title = "A scale in LilyPond"
#(define (ac:up note)
(let* ((pitch (ly:music-property note 'pitch))
(notename (ly:pitch-notename pitch))
- (new-notename (if (eq? notename 6) 0 (+ 1 notename)))
+ (new-notename (if (eqv? notename 6) 0 (+ 1 notename)))
(alterations (ly:music-property ac:current-key 'pitch-alist))
(new-alteration (cdr (assq new-notename alterations)))
- (new-octave (if (eq? new-notename 0) (+ 1 (ly:pitch-octave pitch))
+ (new-octave (if (eqv? new-notename 0) (+ 1 (ly:pitch-octave pitch))
(ly:pitch-octave pitch)))
)
(set! (ly:music-property note 'pitch)(ly:make-pitch new-octave new-notename new-alteration))))
#(define (ac:down note)
(begin (let* ((pitch (ly:music-property note 'pitch))
(notename (ly:pitch-notename pitch))
- (new-notename (if (eq? notename 0) 6 (- notename 1)))
+ (new-notename (if (eqv? notename 0) 6 (- notename 1)))
(alterations (ly:music-property ac:current-key 'pitch-alist))
(new-alteration (cdr (assq new-notename alterations)))
- (new-octave (if (eq? new-notename 6) (- (ly:pitch-octave pitch) 1)
+ (new-octave (if (eqv? new-notename 6) (- (ly:pitch-octave pitch) 1)
(ly:pitch-octave pitch)))
)
(set! (ly:music-property note 'pitch)(ly:make-pitch new-octave new-notename new-alteration))))
((SlurEvent)
(let ((direction (ly:music-property e 'span-direction)))
- (set! ac:inSlur (eq? direction -1))
- (set! at-end-of-slur (eq? direction 1))
+ (set! ac:inSlur (eqv? direction -1))
+ (set! at-end-of-slur (eqv? direction 1))
(loop factor newelements tail actions)))
((TrillSpanEvent)
(let ((direction (ly:music-property e 'span-direction)))
- (set! ac:inTrill (eq? direction -1))
+ (set! ac:inTrill (eqv? direction -1))
(if ac:inTrill
(loop factor newelements tail (cons 'trill actions))
(loop factor (cons e newelements) tail actions))))
((PhrasingSlurEvent)
(let ((direction (ly:music-property e 'span-direction)))
- (set! ac:inPhrasingSlur (eq? direction -1))
+ (set! ac:inPhrasingSlur (eqv? direction -1))
(loop factor newelements tail actions)))
(else (loop factor (cons e newelements) tail actions))))))))
(len (ly:duration-log ac:currentDuration))
(dots (ly:duration-dot-count ac:currentDuration)))
- (if (not (eq? num denom))
+ (if (not (eqv? num denom))
(make-sequential-music
(list (ac:to128 music)
(make-music 'EventChord 'elements
(grace-orig-len (ly:music-length grace))
(main-orig-len (ly:music-length main))
(numerator (ly:moment-main-numerator maindur))
- (factor (if (eq? (remainder numerator 3) 0)
+ (factor (if (eqv? (remainder numerator 3) 0)
(ly:make-moment 1/3) (ly:make-moment 1/2))))
(ly:music-compress grace
(ly:moment-mul factor (ly:moment-div main-orig-len grace-orig-len)))
form of a spanner event, @var{property} may also have the form
@samp{Grob.property} for specifying a directed tweak.")
(if (ly:music? item)
- (if (eq? (ly:music-property item 'span-direction) START)
+ (if (or (eqv? (ly:music-property item 'span-direction) START)
+ (music-is-of-type? item 'tie-event))
(tweak property (value-for-spanner-piece arg) item)
(begin
(ly:music-warning item (_ "not a spanner"))
#, fuzzy
msgid ""
msgstr ""
-"Project-Id-Version: lilypond 2.19.54\n"
+"Project-Id-Version: lilypond 2.19.55\n"
"Report-Msgid-Bugs-To: http://post.gmane.org/post.php?group=gmane.comp.gnu."
"lilypond.bugs\n"
-"POT-Creation-Date: 2017-01-03 14:31+0000\n"
+"POT-Creation-Date: 2017-02-12 12:08+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
msgid "Encountered unprocessed marker %s\n"
msgstr ""
-#: abc2ly.py:1389 convert-ly.py:85 lilypond-book.py:122 midi2ly.py:1052
+#: abc2ly.py:1389 convert-ly.py:85 lilypond-book.py:122 midi2ly.py:1061
#, python-format
msgid "%s [OPTION]... FILE"
msgstr ""
msgstr ""
#: abc2ly.py:1398 convert-ly.py:92 etf2ly.py:1208 lilypond-book.py:231
-#: midi2ly.py:1103 musicxml2ly.py:2774 main.cc:184
+#: midi2ly.py:1112 musicxml2ly.py:2774 main.cc:184
msgid "show version number and exit"
msgstr ""
#: abc2ly.py:1401 convert-ly.py:96 etf2ly.py:1204 lilypond-book.py:140
-#: midi2ly.py:1070 musicxml2ly.py:2755 main.cc:163
+#: midi2ly.py:1079 musicxml2ly.py:2755 main.cc:163
msgid "show this help and exit"
msgstr ""
-#: abc2ly.py:1404 etf2ly.py:1209 midi2ly.py:1079
+#: abc2ly.py:1404 etf2ly.py:1209 midi2ly.py:1088
msgid "write output to FILE"
msgstr ""
#. or if there is a LilyPond users list or forum in your language
#. "Report bugs in English via %s or in YOUR_LANG via URI"
#: abc2ly.py:1416 convert-ly.py:157 etf2ly.py:1218 lilypond-book.py:258
-#: midi2ly.py:1115 musicxml2ly.py:2917 main.cc:318
+#: midi2ly.py:1124 musicxml2ly.py:2917 main.cc:318
#, c-format, python-format
msgid "Report bugs via %s"
msgstr ""
msgid "make a numbered backup [default: filename.ext~]"
msgstr ""
-#: convert-ly.py:152 etf2ly.py:1212 lilypond-book.py:234 midi2ly.py:1104
+#: convert-ly.py:152 etf2ly.py:1212 lilypond-book.py:234 midi2ly.py:1113
#: main.cc:186
msgid "show warranty and copyright"
msgstr ""
"file.\n"
msgstr ""
-#: etf2ly.py:1210 midi2ly.py:1075 midi2ly.py:1080 musicxml2ly.py:2867
+#: etf2ly.py:1210 midi2ly.py:1084 midi2ly.py:1089 musicxml2ly.py:2867
#: main.cc:169 main.cc:181
msgid "FILE"
msgstr ""
msgid "write snippet output files with the same base name as their source file"
msgstr ""
-#: lilypond-book.py:223 midi2ly.py:1098 musicxml2ly.py:2780
+#: lilypond-book.py:223 midi2ly.py:1107 musicxml2ly.py:2780
msgid "be verbose"
msgstr ""
msgid "warning: "
msgstr ""
-#: midi2ly.py:92 midi2ly.py:1132
+#: midi2ly.py:92 midi2ly.py:1141
msgid "error: "
msgstr ""
msgid "Exiting... "
msgstr ""
-#: midi2ly.py:840
+#: midi2ly.py:849
msgid "found more than 5 voices on a staff, expect bad output"
msgstr ""
-#: midi2ly.py:1040
+#: midi2ly.py:1049
#, python-format
msgid "%s output to `%s'..."
msgstr ""
-#: midi2ly.py:1053
+#: midi2ly.py:1062
#, python-format
msgid "Convert %s to LilyPond input.\n"
msgstr ""
-#: midi2ly.py:1058
+#: midi2ly.py:1067
msgid "print absolute pitches"
msgstr ""
-#: midi2ly.py:1060 midi2ly.py:1088
+#: midi2ly.py:1069 midi2ly.py:1097
msgid "DUR"
msgstr ""
-#: midi2ly.py:1061
+#: midi2ly.py:1070
msgid "quantise note durations on DUR"
msgstr ""
-#: midi2ly.py:1064
+#: midi2ly.py:1073
msgid "debug printing"
msgstr ""
-#: midi2ly.py:1067
+#: midi2ly.py:1076
msgid "print explicit durations"
msgstr ""
-#: midi2ly.py:1072
+#: midi2ly.py:1081
msgid "prepend FILE to output"
msgstr ""
-#: midi2ly.py:1076
+#: midi2ly.py:1085
msgid "set key: ALT=+sharps|-flats; MINOR=1"
msgstr ""
-#: midi2ly.py:1077
+#: midi2ly.py:1086
msgid "ALT[:MINOR]"
msgstr ""
-#: midi2ly.py:1082
+#: midi2ly.py:1091
msgid "preview of first 4 bars"
msgstr ""
-#: midi2ly.py:1086
+#: midi2ly.py:1095
msgid "suppress progress messages and warnings about excess voices"
msgstr ""
-#: midi2ly.py:1087
+#: midi2ly.py:1096
msgid "quantise note starts on DUR"
msgstr ""
-#: midi2ly.py:1091
+#: midi2ly.py:1100
msgid "use s instead of r for rests"
msgstr ""
-#: midi2ly.py:1093
+#: midi2ly.py:1102
msgid "DUR*NUM/DEN"
msgstr ""
-#: midi2ly.py:1096
+#: midi2ly.py:1105
msgid "allow tuplet durations DUR*NUM/DEN"
msgstr ""
-#: midi2ly.py:1106
+#: midi2ly.py:1115
msgid "treat every text as a lyric"
msgstr ""
-#: midi2ly.py:1109
+#: midi2ly.py:1118
msgid "Examples"
msgstr ""
-#: midi2ly.py:1133
+#: midi2ly.py:1142
msgid "no files specified on command line."
msgstr ""
msgid "suppressed warning: %s"
msgstr ""
-#: accidental-engraver.cc:180
+#: accidental-engraver.cc:181
#, c-format
msgid "accidental typesetting list must begin with context-name: %s"
msgstr ""
-#: accidental-engraver.cc:207
+#: accidental-engraver.cc:208
#, c-format
msgid "procedure or context-name expected for accidental rule, found %s"
msgstr ""
"asked to compute volume at +%f for dynamic span of duration %f starting at %s"
msgstr ""
-#: axis-group-engraver.cc:154
+#: axis-group-engraver.cc:155
msgid "Axis_group_engraver: vertical group already has a parent"
msgstr ""
-#: axis-group-engraver.cc:155
+#: axis-group-engraver.cc:156
msgid "are there two Axis_group_engravers?"
msgstr ""
-#: axis-group-engraver.cc:156
+#: axis-group-engraver.cc:157
msgid "removing this vertical group"
msgstr ""
msgid "barcheck failed at: %s"
msgstr ""
-#: beam-engraver.cc:147
+#: beam-engraver.cc:148
msgid "already have a beam"
msgstr ""
-#: beam-engraver.cc:234
+#: beam-engraver.cc:235
msgid "unterminated beam"
msgstr ""
-#: beam-engraver.cc:281 chord-tremolo-engraver.cc:148
+#: beam-engraver.cc:282 chord-tremolo-engraver.cc:149
msgid "stem must have Rhythmic structure"
msgstr ""
-#: beam-engraver.cc:292
+#: beam-engraver.cc:293
msgid "stem does not fit in beam"
msgstr ""
-#: beam-engraver.cc:293
+#: beam-engraver.cc:294
msgid "beam was started here"
msgstr ""
msgid "none of these in my family"
msgstr ""
-#: chord-tremolo-engraver.cc:87
+#: chord-tremolo-engraver.cc:88
msgid "No tremolo to end"
msgstr ""
-#: chord-tremolo-engraver.cc:108
+#: chord-tremolo-engraver.cc:109
msgid "unterminated chord tremolo"
msgstr ""
msgid "dot `%s' not found"
msgstr ""
-#: dynamic-engraver.cc:166
+#: dynamic-engraver.cc:167
#, c-format
msgid ""
"unknown crescendo style: %s\n"
"defaulting to hairpin."
msgstr ""
-#: dynamic-engraver.cc:231 slur-engraver.cc:185
+#: dynamic-engraver.cc:232 slur-engraver.cc:186
#, c-format
msgid "unterminated %s"
msgstr ""
-#: episema-engraver.cc:74
+#: episema-engraver.cc:75
msgid "already have an episema"
msgstr ""
-#: episema-engraver.cc:87
+#: episema-engraver.cc:88
msgid "cannot find start of episema"
msgstr ""
-#: episema-engraver.cc:136
+#: episema-engraver.cc:137
msgid "unterminated episema"
msgstr ""
-#: extender-engraver.cc:167 extender-engraver.cc:176
+#: extender-engraver.cc:168 extender-engraver.cc:177
msgid "unterminated extender"
msgstr ""
msgid "Building font database..."
msgstr ""
-#: footnote-engraver.cc:87
+#: footnote-engraver.cc:88
msgid "Must be footnote-event."
msgstr ""
msgid "g_spawn_sync failed (%d): %s: %s"
msgstr ""
-#: glissando-engraver.cc:157
+#: glissando-engraver.cc:158
msgid "unterminated glissando"
msgstr ""
msgid "elapsed time: %.2f seconds"
msgstr ""
-#: gregorian-ligature-engraver.cc:70
+#: gregorian-ligature-engraver.cc:71
#, c-format
msgid "\\%s ignored"
msgstr ""
-#: gregorian-ligature-engraver.cc:75
+#: gregorian-ligature-engraver.cc:76
#, c-format
msgid "implied \\%s added"
msgstr ""
#. ligature may not start with 2nd head of pes or flexa
-#: gregorian-ligature-engraver.cc:224
+#: gregorian-ligature-engraver.cc:225
msgid "cannot apply `\\~' on first head of ligature"
msgstr ""
#. (pitch == prev_pitch)
-#: gregorian-ligature-engraver.cc:236
+#: gregorian-ligature-engraver.cc:237
msgid "cannot apply `\\~' on heads with identical pitch"
msgstr ""
msgid "Asking for broken bound padding at a non-broken bound."
msgstr ""
-#: hairpin.cc:257
+#: hairpin.cc:264
msgid "decrescendo too small"
msgstr ""
-#: horizontal-bracket-engraver.cc:61
+#: horizontal-bracket-engraver.cc:62
msgid "do not have that many brackets"
msgstr ""
-#: horizontal-bracket-engraver.cc:70
+#: horizontal-bracket-engraver.cc:71
msgid "conflicting note group events"
msgstr ""
-#: hyphen-engraver.cc:103
+#: hyphen-engraver.cc:104
msgid "removing unterminated hyphen"
msgstr ""
-#: hyphen-engraver.cc:117
+#: hyphen-engraver.cc:118
msgid "unterminated hyphen; removing"
msgstr ""
msgid "position unknown"
msgstr ""
-#: keep-alive-together-engraver.cc:93
+#: keep-alive-together-engraver.cc:94
#, c-format
msgid "unknown remove-layer value `%s'"
msgstr ""
-#: key-engraver.cc:197
+#: key-engraver.cc:199
msgid "Incomplete keyAlterationOrder for key signature"
msgstr ""
msgid "alteration not found"
msgstr ""
-#: ligature-bracket-engraver.cc:71 ligature-engraver.cc:109
+#: ligature-bracket-engraver.cc:72 ligature-engraver.cc:110
msgid "cannot find start of ligature"
msgstr ""
-#: ligature-bracket-engraver.cc:84 ligature-engraver.cc:136
+#: ligature-bracket-engraver.cc:85 ligature-engraver.cc:137
msgid "already have a ligature"
msgstr ""
-#: ligature-engraver.cc:114
+#: ligature-engraver.cc:115
msgid "no right bound"
msgstr ""
-#: ligature-engraver.cc:145
+#: ligature-engraver.cc:146
msgid "no left bound"
msgstr ""
-#: ligature-engraver.cc:189
+#: ligature-engraver.cc:190
msgid "unterminated ligature"
msgstr ""
-#: ligature-engraver.cc:216
+#: ligature-engraver.cc:217
msgid "ignoring rest: ligature may not contain rest"
msgstr ""
-#: ligature-engraver.cc:217
+#: ligature-engraver.cc:218
msgid "ligature was started here"
msgstr ""
msgstr ""
#. FIXME: constant error message.
-#: mark-engraver.cc:149
+#: mark-engraver.cc:150
msgid "rehearsalMark must have integer value"
msgstr ""
-#: mark-engraver.cc:155
+#: mark-engraver.cc:156
msgid "mark label must be a markup object"
msgstr ""
-#: mensural-ligature-engraver.cc:93
+#: mensural-ligature-engraver.cc:94
msgid "ligature with less than 2 heads -> skipping"
msgstr ""
-#: mensural-ligature-engraver.cc:120
+#: mensural-ligature-engraver.cc:121
msgid "cannot determine pitch of ligature primitive -> skipping"
msgstr ""
-#: mensural-ligature-engraver.cc:134
+#: mensural-ligature-engraver.cc:135
msgid "single note ligature - skipping"
msgstr ""
-#: mensural-ligature-engraver.cc:145
+#: mensural-ligature-engraver.cc:146
msgid "prime interval within ligature -> skipping"
msgstr ""
-#: mensural-ligature-engraver.cc:156
+#: mensural-ligature-engraver.cc:157
msgid "mensural ligature: duration none of Mx, L, B, S -> skipping"
msgstr ""
-#: mensural-ligature-engraver.cc:199
+#: mensural-ligature-engraver.cc:200
msgid "semibrevis must be followed by another one -> skipping"
msgstr ""
-#: mensural-ligature-engraver.cc:209
+#: mensural-ligature-engraver.cc:210
msgid ""
"semibreves can only appear at the beginning of a ligature,\n"
"and there may be only zero or two of them"
msgstr ""
-#: mensural-ligature-engraver.cc:229
+#: mensural-ligature-engraver.cc:230
msgid ""
"invalid ligatura ending:\n"
"when the last note is a descending brevis,\n"
"or the ligatura must be LB or SSB"
msgstr ""
-#: mensural-ligature-engraver.cc:389
+#: mensural-ligature-engraver.cc:390
msgid "unexpected case fall-through"
msgstr ""
"usable-duration-logs must be a non-empty list. Falling back to whole rests."
msgstr ""
-#: music.cc:154
+#: music.cc:153
#, c-format
msgid "octave check failed; expected \"%s\", found: \"%s\""
msgstr ""
msgid "none of note heads `%s' or `%s' found"
msgstr ""
-#: note-heads-engraver.cc:75
+#: note-heads-engraver.cc:76
msgid "NoteEvent without pitch"
msgstr ""
msgid "Replace font name from %s to %s."
msgstr ""
-#: open-type-font.cc:321
+#: open-type-font.cc:320
#, c-format
msgid "FT_Get_Glyph_Name () Freetype error: %s"
msgstr ""
-#: open-type-font.cc:469 pango-font.cc:261
+#: open-type-font.cc:468 pango-font.cc:260
#, c-format
msgid "FT_Get_Glyph_Name () error: %s"
msgstr ""
msgid "\tprevious break: %d"
msgstr ""
-#: pango-font.cc:250
+#: pango-font.cc:249
#, c-format
msgid "no glyph for character U+%0X in font `%s'"
msgstr ""
-#: pango-font.cc:277
+#: pango-font.cc:276
#, c-format
msgid ""
"Glyph has no name, but font supports glyph naming.\n"
"Skipping glyph U+%0X, file %s"
msgstr ""
-#: pango-font.cc:327
+#: pango-font.cc:326
#, c-format
msgid "no PostScript font name for font `%s'"
msgstr ""
-#: pango-font.cc:377
+#: pango-font.cc:376
msgid "FreeType face has no PostScript font name"
msgstr ""
msgid "program option -dpreview not supported by backend `%s'"
msgstr ""
-#: paper-column-engraver.cc:273
+#: paper-column-engraver.cc:274
msgid ""
"forced break was overridden by some other event, should you be using bar "
"checks?"
msgid "Conversion of string `%s' to UTF-16be failed: %s"
msgstr ""
-#: percent-repeat-engraver.cc:147
+#: percent-repeat-engraver.cc:148
msgid "unterminated percent repeat"
msgstr ""
msgid "Segment type of the Type 1 (PFB) font is unknown."
msgstr ""
-#: piano-pedal-engraver.cc:276
+#: piano-pedal-engraver.cc:277
#, c-format
msgid "expect 3 strings for piano pedals, found: %ld"
msgstr ""
-#: piano-pedal-engraver.cc:291 piano-pedal-engraver.cc:302
-#: piano-pedal-performer.cc:104
+#: piano-pedal-engraver.cc:292 piano-pedal-engraver.cc:303
+#: piano-pedal-performer.cc:105
#, c-format
msgid "cannot find start of piano pedal: `%s'"
msgstr ""
-#: piano-pedal-engraver.cc:337
+#: piano-pedal-engraver.cc:338
#, c-format
msgid "cannot find start of piano pedal bracket: `%s'"
msgstr ""
-#: program-option-scheme.cc:223
+#: program-option-scheme.cc:224
#, c-format
msgid "no such internal option: %s"
msgstr ""
msgstr ""
#. FIXME:
-#: script-engraver.cc:114
+#: script-engraver.cc:115
msgid "do not know how to interpret articulation:"
msgstr ""
-#: script-engraver.cc:115
+#: script-engraver.cc:116
msgid " scheme encoding: "
msgstr ""
msgid "direction must not be CENTER in ly:skyline-pair::skyline"
msgstr ""
-#: slur-engraver.cc:121
+#: slur-engraver.cc:122
#, c-format
msgid "direction of %s invalid: %d"
msgstr ""
#. We already have an old slur, so give a warning
#. and completely ignore the new slur.
-#: slur-engraver.cc:238
+#: slur-engraver.cc:239
#, c-format
msgid "already have %s"
msgstr ""
-#: slur-engraver.cc:255
+#: slur-engraver.cc:256
#, c-format
msgid "%s without a cause"
msgstr ""
-#: slur-engraver.cc:320
+#: slur-engraver.cc:321
#, c-format
msgid "cannot end %s"
msgstr ""
msgid "expected to read %d characters, got %d"
msgstr ""
-#: staff-performer.cc:273
+#: staff-performer.cc:274
msgid "MIDI channel wrapped around"
msgstr ""
-#: staff-performer.cc:274
+#: staff-performer.cc:275
msgid "remapping modulo 16"
msgstr ""
-#: stem-engraver.cc:100
+#: stem-engraver.cc:101
msgid "tremolo duration is too long"
msgstr ""
-#: stem-engraver.cc:152
+#: stem-engraver.cc:153
#, c-format
msgid "adding note head to incompatible stem (type = %d/%d)"
msgstr ""
-#: stem-engraver.cc:155
+#: stem-engraver.cc:156
msgid "maybe input should specify polyphonic voices"
msgstr ""
msgid "Markup depth exceeds maximal value of %d; Markup: %s"
msgstr ""
-#: text-spanner-engraver.cc:71
+#: text-spanner-engraver.cc:72
msgid "cannot find start of text spanner"
msgstr ""
-#: text-spanner-engraver.cc:84
+#: text-spanner-engraver.cc:85
msgid "already have a text spanner"
msgstr ""
-#: text-spanner-engraver.cc:131
+#: text-spanner-engraver.cc:132
msgid "unterminated text spanner"
msgstr ""
-#: tie-engraver.cc:120
+#: tie-engraver.cc:121
msgid "unterminated tie"
msgstr ""
-#: tie-engraver.cc:376
+#: tie-engraver.cc:377
msgid "lonely tie"
msgstr ""
msgid "strange time signature found: %d/%d"
msgstr ""
-#: translator-ctors.cc:70
+#: translator-ctors.cc:118
#, c-format
msgid "unknown translator: `%s'"
msgstr ""
msgid "fatal error. Couldn't find type: %s"
msgstr ""
-#: translator-group.cc:185
+#: translator-group.cc:176
#, c-format
msgid "cannot find: `%s'"
msgstr ""
-#: translator.cc:305
+#: translator.cc:293
#, c-format
msgid "Two simultaneous %s events, junking this one"
msgstr ""
-#: translator.cc:306
+#: translator.cc:294
#, c-format
msgid "Previous %s event here"
msgstr ""
msgid "No tuplet to end"
msgstr ""
-#: vaticana-ligature-engraver.cc:384
+#: vaticana-ligature-engraver.cc:385
#, c-format
msgid ""
"ignored prefix(es) `%s' of this head according to restrictions of the "
"selected ligature style"
msgstr ""
-#: vaticana-ligature-engraver.cc:450
+#: vaticana-ligature-engraver.cc:451
msgid ""
"Ambiguous use of dots in ligature: there are multiple dotted notes with the "
"same pitch. The ligature should be split."
msgstr ""
-#: vaticana-ligature-engraver.cc:508
+#: vaticana-ligature-engraver.cc:509
msgid ""
"This ligature has a dotted head followed by a non-dotted head. The ligature "
"should be split after the last dotted head before this head."
msgstr ""
-#: vaticana-ligature-engraver.cc:720
+#: vaticana-ligature-engraver.cc:721
#, c-format
msgid "Vaticana_ligature_engraver: setting `spacing-increment = %f': ptr =%ul"
msgstr ""
msgid "ascending vaticana style flexa"
msgstr ""
-#: vertical-align-engraver.cc:100
+#: vertical-align-engraver.cc:101
msgid "Ignoring Vertical_align_engraver in VerticalAxisGroup"
msgstr ""
#. fixme: be more verbose.
-#: volta-engraver.cc:110
+#: volta-engraver.cc:111
msgid "cannot end volta spanner"
msgstr ""
-#: volta-engraver.cc:120
+#: volta-engraver.cc:121
msgid "already have a volta spanner, ending that one prematurely"
msgstr ""
-#: volta-engraver.cc:124
+#: volta-engraver.cc:125
msgid "also already have an ended spanner"
msgstr ""
-#: volta-engraver.cc:125
+#: volta-engraver.cc:126
msgid "giving up"
msgstr ""
msgid "no systems found in \\score markup, does it have a \\layout block?"
msgstr ""
-#: define-markup-commands.scm:3122
+#: define-markup-commands.scm:3127
#, scheme-format
msgid "Cannot find glyph ~a"
msgstr ""
-#: define-markup-commands.scm:3598
+#: define-markup-commands.scm:3603
#, scheme-format
msgid "no brace found for point size ~S "
msgstr ""
-#: define-markup-commands.scm:3599
+#: define-markup-commands.scm:3604
#, scheme-format
msgid "defaulting to ~S pt"
msgstr ""
-#: define-markup-commands.scm:3858
+#: define-markup-commands.scm:3863
#, scheme-format
msgid "not a valid duration string: ~a"
msgstr ""
-#: define-markup-commands.scm:4071
+#: define-markup-commands.scm:4076
#, scheme-format
msgid "not a valid duration string: ~a - ignoring"
msgstr ""
msgid "cannot find description for property ~S (~S)"
msgstr ""
-#: flag-styles.scm:154
+#: flag-styles.scm:156
#, scheme-format
msgid "flag stroke `~a' or `~a' not found"
msgstr ""
SUBDIRS=auxiliar
-STEPMAKE_TEMPLATES=c python-module install-out po
+STEPMAKE_TEMPLATES=python-module install-out po
include $(depth)/make/stepmake.make
INSTALLATION_OUT_DIR1=$(local_lilypond_datadir)/python
INSTALLATION_OUT_FILES1=$(OUT_PY_MODULES) $(OUT_PYC_MODULES)
-$(outdir)/midi.lo: $(outdir)/config.hh
-
default: $(outdir)/relocate-preamble.py
$(outdir)/relocate-preamble.py: $(depth)/VERSION
+++ /dev/null
-/*
- This file is part of LilyPond, the GNU music typesetter.
-
- Copyright (C) 2001--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
- Jan Nieuwenhuizen <janneke@gnu.org>
-
-
- LilyPond is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- LilyPond is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/*
-
-python
-import midi
-s = open ("s.midi").read ()
-midi.parse_track (s)
-midi.parse (s)
-
-
-returns a MIDI file as the tuple
-
- ((format, division), TRACKLIST)
-
-each track is an EVENTLIST, where EVENT is
-
- (time, (type, ARG1, [ARG2]))
-
-*/
-
-#include <Python.h>
-
-char *
-compat_itoa (int i)
-{
- static char buffer[9];
- snprintf (buffer, 8, "%d", i);
- return buffer;
-}
-
-/* PyMIDINIT_FUNC isn't defined in Python < 2.3 */
-#ifndef PyMODINIT_FUNC
-# if defined(__cplusplus)
-# define PyMODINIT_FUNC extern "C" void
-# else /* __cplusplus */
-# define PyMODINIT_FUNC void
-# endif /* __cplusplus */
-#endif
-
-#if 0
-int x = 0;
-int *track = &x;
-#define urg_debug_print(f, args...) fprintf (stderr, "%s:%d: track: %p: " f, __FUNCTION__, __LINE__, *track, ##args)
-#define debug_print(f, args...) fprintf (stderr, f, ##args)
-#else
-#define debug_print(f, args...)
-#endif
-
-static PyObject *Midi_error;
-static PyObject *Midi_warning;
-
-static PyObject *
-midi_error (char const *func, char *s, char *t)
-{
- char *dest = (char*) malloc (sizeof (char)
- * (strlen (func) + strlen (s) + strlen (t) + 1));
- strcpy (dest, func);
- strcat (dest, s);
- strcat (dest, t);
- PyErr_SetString (Midi_error, dest);
- free (dest);
-
- return 0;
-}
-
-static PyObject *
-midi_warning (char const *s)
-{
- PyErr_SetString (Midi_warning, s);
- return 0;
-}
-
-
-typedef struct message {
- unsigned char msg;
- char * description;
-} message_t;
-
-message_t channelVoiceMessages[] = {
- {0x80, "NOTE_OFF"},
- {0x90, "NOTE_ON"},
- {0xA0, "POLYPHONIC_KEY_PRESSURE"},
- {0xB0, "CONTROLLER_CHANGE"},
- {0xC0, "PROGRAM_CHANGE"},
- {0xD0, "CHANNEL_KEY_PRESSURE"},
- {0xE0, "PITCH_BEND"},
- {0,0}
-};
-
-message_t channelModeMessages[] = {
- {0x78, "ALL_SOUND_OFF"},
- {0x79, "RESET_ALL_CONTROLLERS"},
- {0x7A, "LOCAL_CONTROL"},
- {0x7B, "ALL_NOTES_OFF"},
- {0x7C, "OMNI_MODE_OFF"},
- {0x7D, "OMNI_MODE_ON"},
- {0x7E, "MONO_MODE_ON"},
- {0x7F, "POLY_MODE_ON"},
- {0,0}
-};
-
-message_t metaEvents[] = {
- {0x00, "SEQUENCE_NUMBER"},
- {0x01, "TEXT_EVENT"},
- {0x02, "COPYRIGHT_NOTICE"},
- {0x03, "SEQUENCE_TRACK_NAME"},
- {0x04, "INSTRUMENT_NAME"},
- {0x05, "LYRIC"},
- {0x06, "MARKER"},
- {0x07, "CUE_POINT"},
- {0x20, "MIDI_CHANNEL_PREFIX"},
- {0x21, "MIDI_PORT"},
- {0x2F, "END_OF_TRACK"},
- {0x51, "SET_TEMPO"},
- {0x54, "SMTPE_OFFSET"},
- {0x58, "TIME_SIGNATURE"},
- {0x59, "KEY_SIGNATURE"},
- {0x7F, "SEQUENCER_SPECIFIC_META_EVENT"},
- {0xFF, "META_EVENT"},
- {0,0}
-};
-
-void
-add_constants (PyObject *dict)
-{
- message_t * p[] = {metaEvents, channelModeMessages, channelVoiceMessages ,0};
- int i,j;
- for ( j =0; p[j]; j++)
- for ( i = 0; p[j][i].description; i++)
- PyDict_SetItemString (dict, p[j][i].description, Py_BuildValue ("i", p[j][i].msg));
-}
-
-unsigned long int
-get_number (unsigned char ** str, unsigned char * end_str, int length)
-{
- /* # MIDI uses big-endian for everything */
- long sum = 0;
- int i = 0;
-
- for (; i < length &&
- ((*str) + i < end_str); i++)
- sum = (sum << 8) + (unsigned char) (*str)[i];
-
- *str += length;
- debug_print ("%ld:\n", sum);
- return sum;
-}
-
-unsigned long int
-get_variable_length_number (unsigned char **str, unsigned char * end_str)
-{
- long sum = 0;
-
- while (*str < end_str)
- {
- unsigned char x = **str;
- (*str) ++;
- sum = (sum << 7) + (x & 0x7F);
- if (!(x & 0x80))
- break;
- }
- debug_print ("%ld:\n", sum);
- return sum;
-}
-
-PyObject *
-read_one_byte (unsigned char **track, unsigned char *end,
- unsigned char x)
-{
- PyObject *pyev = Py_BuildValue ("(i)", x);
- debug_print ("%x:%s", x, "event\n");
-
- return pyev;
-}
-
-PyObject *
-read_two_bytes (unsigned char **track, unsigned char *end,
- unsigned char x)
-{
- PyObject *pyev = Py_BuildValue ("(ii)", x, (*track)[0]);
- *track += 1;
- debug_print ("%x:%s", x, "event\n");
- return pyev;
-}
-
-PyObject *
-read_three_bytes (unsigned char **track, unsigned char *end,
- unsigned char x)
-{
- PyObject *pyev = Py_BuildValue ("(iii)", x, (*track)[0],
- (*track)[1]);
-
- *track += 2;
- debug_print ("%x:%s", x, "event\n");
- return pyev;
-}
-
-PyObject *
-read_string (unsigned char **track, unsigned char *end)
-{
- unsigned long length = get_variable_length_number (track, end);
- if (length > end - *track)
- length = end - *track;
-
- *track += length;
- return Py_BuildValue ("s#", ((*track) -length), length);
-}
-
-typedef PyObject* (*Read_midi_event)
- (unsigned char **track, unsigned char *end,
- unsigned char x);
-
-
-static PyObject *
-read_f0_byte (unsigned char **track, unsigned char *end,
- unsigned char x)
-
-{
- debug_print ("%x:%s", x, "event\n");
- if (x == 0xff)
- {
- unsigned char z = (*track)[0 ];
- *track += 1;
- debug_print ("%x:%s", z, "f0-event\n");
-
- return Py_BuildValue ("(iiO)", x, z, read_string (track, end));
- }
-
- return Py_BuildValue ("(iO)", x, read_string (track, end));
-}
-
-Read_midi_event read_midi_event [16] =
-{
- read_one_byte, // 0
- read_one_byte, // 10
- read_one_byte, // 20
- read_one_byte, // 30
- read_one_byte, // 40
- read_one_byte, // 50
- read_one_byte, // 60 data entry.
- read_two_bytes, // 70 all notes off
- read_three_bytes, // 80 note off
- read_three_bytes, // 90 note on
- read_three_bytes, // a0 poly aftertouch
- read_three_bytes, // b0 control
- read_two_bytes, // c0 prog change
- read_two_bytes, // d0 ch aftertouch
- read_three_bytes, // e0 pitchwheel range
- read_f0_byte, // f0
-};
-
-
-static PyObject *
-read_event (unsigned char **track, unsigned char *end, PyObject *time,
- unsigned char *running_status)
-{
- int rsb_skip = ((**track & 0x80)) ? 1 :0;
-
- unsigned char x = (rsb_skip) ? (*track)[0]: *running_status;
-
- PyObject * bare_event = 0;
- debug_print ("%x:%s", x, "event\n");
- *running_status = x;
- *track += rsb_skip;
-
- // printf ("%x %x %d next %x\n", x, (*track)[0], rsb_skip, (*track)[1]);
- bare_event = (*read_midi_event[x >> 4]) (track, end, x);
- if (bare_event)
- return Py_BuildValue ("(OO)", time, bare_event);
- else
- return NULL;
-}
-
-static PyObject *
-midi_parse_track (unsigned char **track, unsigned char *track_end, int clocks_max)
-{
- unsigned int time = 0;
- unsigned long track_len, track_size;
- PyObject *pytrack = 0;
-
- debug_print ("%s", "\n");
-
- track_size = track_end - *track;
-
- debug_print ("%s", "\n");
- if (memcmp (*track, "MTrk", 4))
- {
- *track[4] = 0;
- return midi_error (__FUNCTION__, ": MTrk expected, got: ", *(char**)track);
- }
-
- *track += 4;
-
- track_len = get_number (track, *track + 4, 4);
-
- debug_print ("track_len: %lu\n", track_len);
- debug_print ("track_size: %lu\n", track_size);
- debug_print ("track begin: %p\n", track);
- debug_print ("track end: %p\n", track + track_len);
-
- if (track_len > track_size)
- return midi_error (__FUNCTION__, ": track length corrupt: ", compat_itoa (track_len));
-
- pytrack = PyList_New (0);
-
- if (*track + track_len < track_end)
- track_end = *track + track_len;
-
- {
- PyObject *pytime = PyInt_FromLong (0L);
- unsigned char running_status = 0;
-
- while (*track < track_end)
- {
- long dt = get_variable_length_number(track, track_end);
- PyObject *pyev = 0;
-
- time += dt;
- if (dt)
- pytime = PyInt_FromLong (time);
- if (clocks_max && time > clocks_max)
- break;
- pyev = read_event (track, track_end, pytime,
- &running_status);
- if (pyev)
- PyList_Append (pytrack, pyev);
- }
- }
-
- *track = track_end;
- return pytrack;
-}
-
-
-static PyObject *
-pymidi_parse_track (PyObject *self, PyObject *args)
-{
- unsigned char *track, *track_end;
- int track_size;
- int clocks_max;
-
- debug_print ("%s", "\n");
- if (!PyArg_ParseTuple (args, "s#|i", &track, &track_size, &clocks_max))
- return 0;
- debug_print ("clocks_max: %d\n", clocks_max);
-
- if (track_size < 0)
- return midi_error (__FUNCTION__, ": negative track size: ", compat_itoa (track_size));
-
- track_end = track + track_size;
-
- return midi_parse_track (&track, track_end, clocks_max);
-}
-
-static PyObject *
-midi_parse (unsigned char **midi,unsigned char *midi_end, int clocks_max)
-{
- PyObject *pymidi = 0;
- unsigned long header_len;
- unsigned format, tracks;
- int division;
- int i;
-
- debug_print ("%s", "\n");
-
- /* Header */
- header_len = get_number (midi, *midi + 4, 4);
-
- if (header_len < 6)
- return midi_error (__FUNCTION__, ": header too short: ", compat_itoa (header_len));
-
- format = get_number (midi, *midi + 2, 2);
- tracks = get_number (midi, *midi + 2, 2);
-
- if (tracks > 256)
- return midi_error (__FUNCTION__, ": too many tracks: ", compat_itoa (tracks));
-
- division = get_number (midi, *midi + 2, 2) * 4;
-
-
- /*
- if (division < 0)
- return midi_error (cannot handle non-metrical time");
- ;
- */
- *midi += header_len - 6;
-
- pymidi = PyList_New (0);
-
- /* Tracks */
- for (i = 0; i < tracks; i++)
- PyList_Append (pymidi, midi_parse_track (midi, midi_end, clocks_max));
-
- pymidi = Py_BuildValue ("(OO)", Py_BuildValue ("(ii)", format, division),
- pymidi);
- return pymidi;
-}
-
-static PyObject *
-pymidi_parse (PyObject *self, PyObject *args)
-{
- unsigned char *midi, *midi_end;
- unsigned long midi_size;
- int clocks_max;
-
- debug_print ("%s", "\n");
- if (!PyArg_ParseTuple (args, "s#|i", &midi, &midi_size, &clocks_max))
- return 0;
- debug_print ("clocks_max: %d\n", clocks_max);
-
- if (memcmp (midi, "MThd", 4))
- {
- midi[4] = 0;
- return midi_error (__FUNCTION__, ": MThd expected, got: ", (char*)midi);
- }
-
- midi += 4;
-
- midi_end = midi + midi_size;
-
- return midi_parse (&midi, midi_end, clocks_max);
-}
-
-static PyMethodDef MidiMethods[] =
-{
- {"parse", pymidi_parse, METH_VARARGS},
- {"parse_track", pymidi_parse_track, METH_VARARGS},
- {0, 0} /* Sentinel */
-};
-
-PyMODINIT_FUNC
-initmidi (void)
-{
- PyObject *m, *d;
- m = Py_InitModule ("midi", MidiMethods);
- d = PyModule_GetDict (m);
-
- Midi_error = PyString_FromString ("midi.error");
- PyDict_SetItemString (d, "error", Midi_error);
- add_constants (d);
- Midi_warning = PyString_FromString ("midi.warning");
- PyDict_SetItemString (d, "warning", Midi_warning);
-
- /*
- FIXME.
- */
- (void) midi_warning;
-}
-
--- /dev/null
+# This file is part of LilyPond, the GNU music typesetter.
+#
+# Copyright (C) 2001--2012 Han-Wen Nienhuys <hanwen@xs4all.nl>
+# Jan Nieuwenhuizen <janneke@gnu.org>
+#
+#
+# LilyPond is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# LilyPond is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
+
+# import midi
+# s = open ("s.midi").read ()
+# midi.parse_track (s)
+# midi.parse (s)
+#
+#
+# returns a MIDI file as the tuple
+#
+# ((format, division), TRACKLIST) # division (>0) = TPQN*4
+# # or (<0) TBD
+#
+# each track is an EVENTLIST, where EVENT is
+#
+# (time, (type, ARG1, [ARG2])) # time = cumulative delta time
+ # MIDI event:
+ # type = MIDI status+channel >= x80
+ # META-event = xFF:
+ # type = meta-event type <= x7F
+ # ARG1 = length
+ # ARG2 = data
+
+import array
+import struct
+
+class error (Exception): pass
+
+# class warning (Exception): pass
+
+def _add_constants ():
+ channelVoiceMessages = (
+ (0x80, "NOTE_OFF"),
+ (0x90, "NOTE_ON"),
+ (0xA0, "POLYPHONIC_KEY_PRESSURE"),
+ (0xB0, "CONTROLLER_CHANGE"),
+ (0xC0, "PROGRAM_CHANGE"),
+ (0xD0, "CHANNEL_KEY_PRESSURE"),
+ (0xE0, "PITCH_BEND"),
+ )
+ channelModeMessages = (
+ (0x78, "ALL_SOUND_OFF"),
+ (0x79, "RESET_ALL_CONTROLLERS"),
+ (0x7A, "LOCAL_CONTROL"),
+ (0x7B, "ALL_NOTES_OFF"),
+ (0x7C, "OMNI_MODE_OFF"),
+ (0x7D, "OMNI_MODE_ON"),
+ (0x7E, "MONO_MODE_ON"),
+ (0x7F, "POLY_MODE_ON"),
+ )
+ metaEvents = (
+ (0x00, "SEQUENCE_NUMBER"),
+ (0x01, "TEXT_EVENT"),
+ (0x02, "COPYRIGHT_NOTICE"),
+ (0x03, "SEQUENCE_TRACK_NAME"),
+ (0x04, "INSTRUMENT_NAME"),
+ (0x05, "LYRIC"), #renamed LYRIC_DISPLAY MIDI RP-26
+ (0x06, "MARKER"),
+ (0x07, "CUE_POINT"),
+ (0x08, "PROGRAM_NAME"), #added MIDI RP-19
+ (0X09, "DEVICE_NAME"), #added MIDI RP-19
+ (0x20, "MIDI_CHANNEL_PREFIX"),
+ (0x21, "MIDI_PORT"),
+ (0x2F, "END_OF_TRACK"),
+ (0x51, "SET_TEMPO"),
+ (0x54, "SMTPE_OFFSET"),
+ (0x58, "TIME_SIGNATURE"),
+ (0x59, "KEY_SIGNATURE"),
+ (0x60, "XMF_PATCH_TYPE_PREFIX"), #added MIDI RP-32
+ (0x7F, "SEQUENCER_SPECIFIC_META_EVENT"),
+ (0xFF, "META_EVENT"),
+ )
+ globals().update((desc, msg) for msg, desc in
+ channelVoiceMessages + channelModeMessages + metaEvents)
+
+_add_constants ()
+
+def _get_variable_length_number (nextbyte, getbyte):
+ sum = 0
+ while nextbyte >= 0x80:
+ sum = (sum + (nextbyte & 0x7F)) << 7
+ nextbyte = getbyte()
+ return sum + nextbyte
+
+def _first_command_is_repeat(status, nextbyte, getbyte):
+ raise error('the first midi command in the track is a repeat')
+
+def _read_two_bytes (status, nextbyte, getbyte):
+ return status, nextbyte
+
+def _read_three_bytes (status, nextbyte, getbyte):
+ return status, nextbyte, getbyte()
+
+def _read_string (nextbyte, getbyte):
+ length = _get_variable_length_number (nextbyte, getbyte)
+ return ''.join(chr(getbyte()) for i in xrange(length))
+
+def _read_f0_byte (status, nextbyte, getbyte):
+ if status == 0xff:
+ return status, nextbyte, _read_string(getbyte(), getbyte)
+ return status, _read_string(nextbyte, getbyte)
+
+_read_midi_event = (
+ _first_command_is_repeat, # 0
+ None, # 10
+ None, # 20
+ None, # 30
+ None, # 40
+ None, # 50
+ None, # 60 data entry???
+ None, # 70 all notes off???
+ _read_three_bytes, # 80 note off
+ _read_three_bytes, # 90 note on
+ _read_three_bytes, # a0 poly aftertouch
+ _read_three_bytes, # b0 control
+ _read_two_bytes, # c0 prog change
+ _read_two_bytes, # d0 ch aftertouch
+ _read_three_bytes, # e0 pitchwheel range
+ _read_f0_byte, # f0
+)
+
+def _parse_track_body (data, clocks_max):
+ # This seems to be the fastest way of getting bytes in order as integers.
+ dataiter = iter(array.array('B', data))
+ getbyte = dataiter.next
+
+ time = 0
+ status = 0
+ try:
+ for nextbyte in dataiter:
+ time += _get_variable_length_number (nextbyte, getbyte)
+ if clocks_max and time > clocks_max:
+ break
+ nextbyte = getbyte()
+ if nextbyte >= 0x80:
+ status = nextbyte
+ nextbyte = getbyte()
+ yield time, _read_midi_event[status >> 4] (status, nextbyte, getbyte)
+ except StopIteration:
+ # If the track ended just before the start of an event, the for loop
+ # will exit normally. If it ends anywhere else, we end up here.
+ print len(list(dataiter))
+ raise error('a track ended in the middle of a MIDI command')
+
+def _parse_hunk (data, pos, type, magic):
+ if data[pos:pos+4] != magic:
+ raise error ('expected %r, got %r' % (magic, data[pos:pos+4]))
+ try:
+ length, = struct.unpack ('>I', data[pos+4:pos+8])
+ except struct.error:
+ raise error ('the %s header is truncated (may be an incomplete download)' % type)
+ endpos = pos + 8 + length
+ data = data[pos+8:endpos]
+ if len(data) != length:
+ raise error('the %s is truncated (may be an incomplete download)' % type)
+ return data, endpos
+
+def _parse_tracks (midi, pos, num_tracks, clocks_max):
+ if num_tracks > 256:
+ raise error('too many tracks: %d' % num_tracks)
+ for i in xrange(num_tracks):
+ trackdata, pos = _parse_hunk (midi, pos, 'track', 'MTrk')
+ yield list (_parse_track_body (trackdata, clocks_max))
+ # if pos < len(midi):
+ # warn
+
+def parse_track (track, clocks_max=None):
+ track_body, end = _parse_hunk (track, 0, 'track', 'MTrk')
+ # if end < len(track):
+ # warn
+ return list (_parse_track_body (track_body, clocks_max))
+
+def parse (midi, clocks_max=None):
+ header, first_track_pos = _parse_hunk(midi, 0, 'file', 'MThd')
+ try:
+ format, num_tracks, division = struct.unpack ('>3H', header[:6])
+ except struct.error:
+ raise error('the file header is too short')
+# if division < 0:
+# raise error ('cannot handle non-metrical time')
+ tracks = list (_parse_tracks (midi, first_track_pos, num_tracks, clocks_max))
+ return (format, division*4), tracks
(interval-start extent)
Y))))
- (if (eq? dir LEFT)
+ (if (eqv? dir LEFT)
stencil
(ly:stencil-scale stencil -1 1))))
`(delay-stencil-evaluation ,(delay expr))
x y))))
+(define-markup-command (with-outline layout props outline arg)
+ (markup? markup?)
+ #:category other
+ "
+Print @var{arg} with the outline and dimensions of @var{outline}."
+ (ly:stencil-outline (interpret-markup layout props arg)
+ (interpret-markup layout props outline)))
+
(define-markup-command (with-dimensions-from layout props arg1 arg2)
(markup? markup?)
#:category other
}
}
@end lilypond"
- (let* ((m (interpret-markup layout props arg))
- (x (ly:stencil-extent m X))
- (y (ly:stencil-extent m Y)))
- (ly:make-stencil (list 'transparent-stencil (ly:stencil-expr m)) x y)))
+ (ly:stencil-outline empty-stencil (interpret-markup layout props arg)))
(define-markup-command (pad-to-box layout props x-ext y-ext arg)
(number-pair? number-pair? markup?)
scale-stencil
translate-stencil
transparent-stencil
+ with-outline
))
(for-each ly:register-stencil-expression
label-stencil
(stencil-coordinates
(* size fret-distance (1+ label-vertical-offset))
- (if (eq? label-dir LEFT)
+ (if (eqv? label-dir LEFT)
(- label-outside-diagram)
(+ (* size string-distance (1- string-count))
label-outside-diagram))))))
;; outer let to trigger suicide
(let ((sten (ly:hairpin::print grob)))
(if (grob::is-live? grob)
- (let* ((decresc? (eq? (ly:grob-property grob 'grow-direction) LEFT))
+ (let* ((decresc? (eqv? (ly:grob-property grob 'grow-direction) LEFT))
(thick (ly:grob-property grob 'thickness 0.1))
(thick (* thick (layout-line-thickness grob)))
(xex (ly:stencil-extent sten X))
(ly:grob-suicide! count-spanner)
(set! count-spanner '())
(ly:warning "measure count left unfinished")))))))
+
+(ly:register-translator
+ Measure_counter_engraver 'Measure_counter_engraver
+ '((grobs-created . (MeasureCounter))
+ (events-accepted . (measure-counter-event))
+ (properties-read . (currentCommandColumn
+ measurePosition
+ currentBarNumber))
+ (properties-written . ())
+ (description . "\
+This engraver numbers ranges of measures, which is useful in parts as an
+aid for counting repeated measures. There is no requirement that the
+affected measures be repeated, however. The user delimits the area to
+receive a count with @code{\\startMeasureCount} and
+@code{\\stopMeasureCount}.")))
+
+(ly:register-translator
+ Span_stem_engraver 'Span_stem_engraver
+ '((grobs-created . (Stem))
+ (events-accepted . ())
+ (properties-read . ())
+ (properties-written . ())
+ (description . "Connect cross-staff stems to the stems above in the system")))
(define-public (make-transparent-box-stencil xext yext)
"Make a transparent box."
- (ly:make-stencil
- (list 'transparent-stencil
- (ly:stencil-expr (make-filled-box-stencil xext yext)))
- xext yext))
+ (ly:stencil-outline empty-stencil (make-filled-box-stencil xext yext)))
(define-public (make-filled-box-stencil xext yext)
"Make a filled box."
((eq? head 'color) (interpret (caddr expr)))
((eq? head 'rotate-stencil) (interpret (caddr expr)))
((eq? head 'translate-stencil) (interpret (caddr expr)))
+ ;; for signatures, we indeed want the _outline_ rather than
+ ;; the expression interpreted. Right?
+ ((eq? head 'with-outline) (interpret (cadr expr)))
((eq? head 'combine-stencil)
(for-each interpret (cdr expr)))
(else
'INSTRUMENT_NAME',
'LYRIC',
'MARKER',
- 'CUE_POINT',)
+ 'CUE_POINT',
+ 'PROGRAM_NAME',
+ 'DEVICE_NAME', )
+
+ @staticmethod
+ def _text_only(chr):
+ if ((' ' <= chr <= '~') or chr in ['\n','\r']):
+ return chr
+ else:
+ return '~'
def __init__ (self, type, text):
self.clocks = 0
self.type = type
- self.text = text
+ self.text =''.join(map(self._text_only, text))
def dump (self):
# urg, we should be sure that we're in a lyrics staff