From: David Kastrup Date: Sun, 8 Dec 2013 14:23:14 +0000 (+0100) Subject: Merge branch 'translation' into 'master' X-Git-Tag: release/2.19.0-1~89 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=16a04d4a27ff185fd83125d965d48b534182d7d2;hp=88435714e762229ebe2715bcf6863eb89c1f8dff;p=lilypond.git Merge branch 'translation' into 'master' --- diff --git a/Documentation/changes.tely b/Documentation/changes.tely index 909d8e62d2..4ea92a7cb3 100644 --- a/Documentation/changes.tely +++ b/Documentation/changes.tely @@ -36,7 +36,7 @@ See user manual, \NAME\ @finalout @node Top -@top New features in 2.18 since 2.16 +@top New features in 2.20 since 2.18 @allowcodebreaks false @@ -62,425 +62,25 @@ which scares away people. @end ignore @item -Several articulations can be put into a single variable or -returned from an event function: +The PostScript functionality of stroke adjustment is no longer +applied automatically but left to the discretion of the PostScript +device (by default, Ghostscript uses it for resolutions up to +150dpi when generating raster images). When it is enabled, a more +complex drawing algorithm designed to benefit from stroke +adjustment is employed mostly for stems and bar lines. -@lilypond[verbatim,quote] -sempreStacc = -. ^\markup \italic sempre -\relative { c''4\sempreStacc c c c } -@end lilypond - -@item -The baseline of score markups is now taken from the reference -point (usually the middle of the staff) of the first bottom system -rather than the top of the bounding rectangle. The following -@lilypond[verbatim,quote] -\markup { - violin: \score { \new Staff { 1 } - \layout { indent=0 } } , - cello: \score { \new Staff { \clef "bass" } - \layout { indent=0 } } -} -@end lilypond -previously looked like -@lilypond[quote] -\markup { - violin: \general-align #Y #UP - \score { \new Staff { 1 } - \layout { indent=0 } } , - cello: \general-align #Y #UP - \score { \new Staff { \clef "bass" } - \layout { indent=0 } } -} -@end lilypond -without a reliable way to get both scores to line up. - -@item -LilyPond no longer automatically infers a @samp{\defaultchild} -context in a context definition with @samp{\accepts} clauses. Any -context definition without an explicit or inherited -@samp{\defaultchild} definition counts as a @samp{Bottom} context -and will be eligible for rhythmic events and overrides without -causing the implicit creation of other contexts. Be sure to -specify a @samp{\defaultchild} for non-@samp{Bottom} contexts when -defining them from scratch. - -@item -There is now extensive support for both discant and bass accordion -register symbols in the @samp{scm accreg} module, see -@ruser{Accordion Registers}. -@lilypond[verbatim,quote] -#(use-modules (scm accreg)) -\new PianoStaff -<< - \new Staff \relative - { \clef "treble" \discant "10" - r8 s32 f'[ bes f] s e[ a e] s d[ g d] s16 e32[ a] - \discant "121" - << { r16 r r } \\ - { d r a r bes r } >> | - 1 - } - \new Staff \relative - { \clef "treble" \freeBass "1" - r8 d'32 s16. c32 s16. bes32 s16. a32[ cis] s16 - \clef "bass" \stdBass "Master" - << { r16 ^"b" r ^"am" r ^"gm" | - 1^"a" } \\ - { d8_"D" c_"C" bes_"B" | a1_"A" } - >> - } ->> -@end lilypond - -@item -New commands @code{markLengthOn} and @code{markLengthOff} control -the allowance of horizontal space for tempo and rehearsal marks. - -@lilypond[quote,relative=2] -\markLengthOn -\compressFullBarRests -\tempo "Molto vivace" c2 c' -\mark\default -\tempo "Meno mosso" R1*16 -\mark\default -g,2 g -\bar "||" -\markLengthOff -\tempo "Molto vivace" c2 c' -\mark#1 -\tempo "Meno mosso" R1*16 -\mark\default -g,2 g -@end lilypond - -@item -Rehearsal marks at the beginning of a line are now placed to the right -of the clef and key signature by default. As in previous versions, the -@code{break-alignable-interface} controls the behavior. - -@lilypond[quote,relative=2] -\set Score.barNumberVisibility = #all-bar-numbers-visible -\set Timing.currentBarNumber = #72 -\bar"||" \time 3/4 \key e\major \mark#10 \tempo "Adagio" b2. -@end lilypond - -@item -Decimal numbers can now be written directly in music, -without a hash sign. Together with the previous change -in the way object properties are specified, the code to -change the length of stems has changed from this: -@example -\override Stem #'length = #5.6 -e' f' g' a' -@end example -to this: -@example -\override Stem.length = 5.6 -e' f' g' a' -@end example - -One has to write a digit on both sides of the dot -- values like -@code{4.} or @code{-.3} are not allowed. - -Decimal fractions are also not accepted in @code{\chordmode}. - -@item -A number of shorthands like @code{(}, @code{)}, @code{|}, -@code{[}, @code{]}, @code{~}, @code{\(}, @code{\)} and others can -now freely be redefined like normal commands. An example would be -@lilypond[verbatim,quote] -"\\{" = ( -"\\}" = ) -"(" = \melisma -")" = \melismaEnd - -\new Staff << - \relative c' { - c8 \{ d e f \} % slurred - g ( a b c ) % no slur, but with melisma - c,1 \bar "|." - } - \addlyrics { Li -- ly -- pond. } ->> -@end lilypond - -@item -The articulation shorthand for @code{\staccatissimo} has been -renamed from @code{-|} to@tie{}@code{-!}. - -@item -Tempo change ranges are now written as @code{\tempo 4 = 60 - 68} -rather than @code{\tempo 4 = 60 ~ 68}. - -@item -Grob @code{OctavateEight} was renamed to @code{ClefModifier}. -Related context properties were renamed from @code{xxxOctavationyyy} -to @code{xxxTranspositionyyy}. - -@item -There is a new @code{\absolute} command explicitly marking music -as being entered in absolute pitch. While this has been the -default previously, an explicit @code{\absolute} also prevents -reinterpretation when the passage is placed inside of -@code{\relative}: -@lilypond[verbatim,quote] -\relative c { c'4 \absolute { f'' g'' } c } -@end lilypond - -@item -When @code{\relative} is used without an explicit reference pitch, -the reference pitch now is the middle of the first octave, making -the first entered pitch indistinguishable from absolute pitch. -Previously, omitting the reference pitch would have lead to a -default of @code{c'}. Since that choice was somewhat arbitrary, -recommended usage was to always specify the reference pitch. - -@item -A new command @code{\single} can be used for converting a property -override into a tweak to be applied on a single music expression: - -@lilypond[quote,verbatim,relative=2] -1 -@end lilypond - -@item -Two ways of letting graphical objects not appear in the output are -overriding its @code{transparent} property with @code{#t} -(retaining the original spacing) or overriding its @code{stencil} -property with @code{#f} (not using any space at all). Those two -operations now have the shorthands @code{\hide} and @code{\omit}, -respectively. They can either be given a music expression to -tweak, or the name of a graphical object for which an override -should be created (for specifying both, use @code{\single} on the -override form): - -@lilypond[quote,verbatim] -\new Staff \with { \omit Clef } -\relative c'' 1 -@end lilypond - -@item -A new command @code{\temporary} can be applied to overrides in -order to not have them replace previous property settings. If a -@code{\revert} is applied to the same property subsequently, the -previous setting reappears: - -@lilypond[quote,verbatim,relative=2] -\override NoteHead.color = #red c4 -\override NoteHead.color = #green d -\revert NoteHead.color e2 -\override NoteHead.color = #red c4 -\temporary\override NoteHead.color = #green d -\revert NoteHead.color e -\revert NoteHead.color c -@end lilypond - -This is mainly useful for writing music functions that need to -have some property changed just for the duration of the function. - -@item -@code{\tag}, @code{\removeWithTag}, and @code{\keepWithTag} can -now accept a list of symbols rather than just a single symbol for -marking, removing, and keeping music with any of multiple tags. -This is particularly important for @code{\keepWithTag} since one -cannot achieve the same effect by using multiple consecutive -@code{\keepWithTag} commands. - -@item -The @samp{-d old-relative} option has been removed. Not actually -accessible from the command line any more, its remaining use was -for interpretating @code{\relative} in LilyPond files converted -automatically from version@tie{}1.8 or older. It is unclear how -much of this was actually still operative. - -@item -The meaning of @code{instrumentTransposition} has been reversed. -After -@example -\set instrumentTransposition = #@{ b #@} -@end example -a written @code{c'} now sounds like @code{b}. Previously, this -would have been the other way round. This and the following change -should make dealing with transposing instruments more -straightforward. - -@item -The music generated by @code{\set} and @code{\override} commands -is no longer affected by @code{\transpose}. The main consequence -is that @code{\transpose} will transpose audible/@/concert pitch and -printed pitch by the same amount even when the transposed music -contains @code{\transposition}. Previously, -@example -\transpose c' f' \transposition bes' -@end example -was equivalent to @code{\transposition f'}. Now it stays -equivalent to @code{\transposition bes'}. - -@item -When checking for collisions, LilyPond no longer treats objects as -rectangles. Instead, the actual shape of objects is approximated -using an integral-like approach. This generally results in more -even and snug positioning of objects and systems: - -@lilypond[relative=1] -#(ly:set-option 'debug-skylines #t) -\dynamicUp -c'4\f a4\f d\f( f) -a,4\< c c c\! -d4-.\downbow a4^"r'venu..." c \tempo "T1" e -@end lilypond - -Previously, the above snippet looked like this: - -@lilypond[relative=1] -#(ly:set-option 'debug-skylines #t) -\override Hairpin #'vertical-skylines = #'() -\override DynamicText #'vertical-skylines = #'() -\override TextScript #'vertical-skylines = #'() -\override Score.MetronomeMark #'vertical-skylines = #'() -\override Staff.Clef #'vertical-skylines = #'() -\dynamicUp -c'4\f a4\f d\f( f) -a,4\< c c c\! -d4-.\downbow a4^"r'venu..." c \tempo "T1" e -@end lilypond - -Affected objects include @code{Accidentals}, @code{Beams}, @code{Clefs}, -@code{Dynamics}, @code{FiguredBass}, @code{Flags}, @code{Glissandos}, -@code{Lyrics}, @code{MetronomeMarks}, @code{OttavaBrackets}, -@code{Pedals}, @code{RehearsalMarks}, @code{Rests}, @code{Scripts}, -@code{TextScripts}, @code{Ties}, @code{Tuplets} and @code{VoltaBrackets}. - -@item -Tuplets are now created with the @code{\tuplet} command, which -takes a fraction @code{@var{t}/@var{n}} to specify that @var{t} -notes are played in the time usually allowed for @var{n}. One -@code{\tuplet} command can create several tuplet groups if their -duration is typed after the fraction. -@lilypond[quote,verbatim,relative=2] -\tuplet 3/2 { c8 d e } \tuplet 3/2 { f e d } c2 -\tuplet 3/2 4 { c8 d e f e d } c2 -@end lilypond -The @code{\times} command with its inverted fraction order -@code{@var{n}/@var{t}} is still available. - -@item -Introducing two new markup-commands; @code{\draw-dashed-line} and -@code{\draw-dotted-line}. - -@noindent -The dashed-line extends to the whole length given by @var{dest}, if -@code{full-length} is set to @code{#t} (this is the default) without any -space at the beginning or end. @code{off} will then be altered to fit. -To insist on the given (or default) values of @code{on}, @code{off} use -@code{\override #'(full-length . #f)}. Manual settings for @code{on}, -@code{off} and @code{phase} are possible. - -@noindent -The dotted-line always extends to the whole length given by @var{dest}, -without any space at the beginning or end. Manual settings for -@code{off} are possible to get larger or smaller space between the dots. -The given (or default) value of @code{off} will be altered to fit the -line-length. - -@lilypond[verbatim,quote] -\markup { - \draw-dashed-line #'(5.1 . 2.3) - \override #'(on . 0.3) - \override #'(off . 0.5) - \draw-dashed-line #'(5.1 . 2.3) - \draw-dotted-line #'(5.1 . 2.3) - \override #'(thickness . 2) - \override #'(off . 0.2) - \draw-dotted-line #'(5.1 . 2.3) -} -@end lilypond - -@item -Starting with version@tie{}2.17.10, error messages or the -@code{textedit} @acronym{URI} used for point-and-click -functionality specify column numbers starting with@tie{}1 rather -than@tie{}0. The byte offset (also part of @code{textedit} -@acronym{URI}s) still starts at@tie{}0. - -@item -The @code{\clef} command supports optional transposition: -@lilypond[verbatim,quote,relative=1] -\clef "treble_(8)" -c2 c -\clef "bass^[15]" -c2 c -@end lilypond - -@item -The LilyPond syntax of dot-separated words @code{Voice.Accidental} -has been made interchangeable with @code{#'(Voice Accidental)}, a -Scheme list of symbols. As one result, code like -@example -\override Voice.TextSpanner #'(bound-details left text) = "rit." -@end example -is now equivalent to -@example -\override Voice.TextSpanner bound-details.left.text = "rit." -@end example -or even -@example -\override #'(Voice TextSpanner) bound-details.left.text = "rit." -@end example - -@item -Grob and grob property path no longer need to be specified as two -separate arguments to commands like @samp{\override} and -@code{\revert}, allowing for the syntax -@example -\override Voice.TextSpanner.bound-details.left.text = "rit." -@end example -Since complementary music functions like @samp{\overrideProperty} -cannot support forms with and without separating space at the same -time, using a single dotted path is now the preferred form. -Specifying grob path and grob property path separately, currently -still supported with @samp{\override} and @samp{\revert} for -compatibility reasons, is deprecated. - -@item -Due to words now being accepted as symbol function arguments, the -interfaces of @samp{\accidentalStyle}, @samp{\alterBroken}, -@samp{\footnote} and @samp{\tweak} had to be redesigned where -optional symbol arguments were involved. Please check the -respective music function documentation for details. - -@item -Several commands now accept symbol lists (conveniently entered as -dot-separated words) for various kinds of arguments. These -include @samp{\accidentalStyle}, @samp{\alterBroken}, -@samp{\footnote}, @samp{\hide}, @samp{\omit}, -@samp{\overrideProperty}, @samp{\shape}, and @samp{\tweak}. - -@item -The bar line user interface has changed. Bar glyphs now resemble the -appearance of the bar line, so a left repeat sign has to be coded -as @code{.|:}. The command @code{\defineBarLine} provides an easy way -to define additional bar line styles. - -@item -Accidentals in the key signature may be printed in octaves other -than their traditional positions, or in multiple octaves. -@lilypond[quote,relative=0] -\override Staff.KeySignature #'flat-positions = #'((-5 . 5)) -\override Staff.KeyCancellation #'flat-positions = #'((-5 . 5)) -\clef bass \key es \major es g bes d -\clef treble \bar "||" \key es \major es g bes d -\override Staff.KeySignature #'sharp-positions = #'(2) -\bar "||" \key d \major b fis b2 -@end lilypond +Stroke adjustment can be forced by specifying the command line +option @samp{-dstrokeadjust} to LilyPond. When generating +@code{PDF} files, this will usually result in markedly better +looking @code{PDF} previews but significantly larger file size. +Print quality at high resolutions will be unaffected. @end itemize @ifhtml For older news, go to +@uref{http://lilypond.org/doc/v2.18/Documentation/changes/}, @uref{http://lilypond.org/doc/v2.16/Documentation/changes/}, -@uref{http://lilypond.org/doc/v2.14/Documentation/changes/}, or @uref{../,go back} to the Documentation index. diff --git a/Documentation/included/note-head-style.ly b/Documentation/included/note-head-style.ly index a786978734..0d2cabfcda 100644 --- a/Documentation/included/note-head-style.ly +++ b/Documentation/included/note-head-style.ly @@ -1,4 +1,4 @@ -\version "2.17.6" +\version "2.19.0" \header { texidoc=" @@ -25,11 +25,11 @@ dimensions. pattern = << \new Voice { \override Stem.direction = #UP - e'4 e'2. e'1 e'\breve*1/2 e'\longa*1/4 \bar "||" + e'4 2. 1 \breve*1/2 \longa*1/4 \bar "||" } \new Voice { \override Stem.direction = #DOWN - a4 a2. a1 a\breve*1/2 a\longa*1/4 \bar "||" + a4 2. 1 \breve*1/2 \longa*1/4 \bar "||" } >> diff --git a/Documentation/ly-examples/orchestra.ly b/Documentation/ly-examples/orchestra.ly index 6b205af903..d784dfd6af 100644 --- a/Documentation/ly-examples/orchestra.ly +++ b/Documentation/ly-examples/orchestra.ly @@ -1,4 +1,4 @@ -\version "2.17.6" +\version "2.19.0" \header { tagline = ##f @@ -271,49 +271,49 @@ R2. | ees r r r4 r8 r4 r8 | } - trian = \relative c' { + trian = { \clef percussion \time 6/8 R2.*4 | \time 9/8 R1*9/8 | } - cym = \relative c' { + cym = { \clef percussion \time 6/8 R2.*4 | \time 9/8 R1*9/8 | } - tamt = \relative c' { + tamt = { \clef percussion \time 6/8 R2. | r4 r8 r c4\mf\<^"*" ~ | - c8\!\ff r r r4 r8 | R2. | + 8\!\ff r r r4 r8 | R2. | \time 9/8 R1*9/8 | } - tamb = \relative c' { + tamb = { \clef percussion \time 6/8 R2.*4 | \time 9/8 R1*9/8 | } - snare = \relative c' { + snare = { \clef percussion \time 6/8 R2.*4 | \time 9/8 - c8\pp c c c c c c c c | + c8\pp 8 8 8 8 8 8 8 8 | } - bsdrum = \relative c' { + bsdrum = { \clef percussion \time 6/8 - c2.:32\pp\< ~ | c: ~ | - c8\!\ff \offCr r r r4 r8 | R2. | + c2.:32\pp\< ~ | 2.: ~ | + 8\!\ff \offCr r r r4 r8 | R2. | \time 9/8 - c2.:32\pp ~ c4.: | + 2.:32\pp ~ 4.: | } harprh = \relative c'' { diff --git a/Documentation/notation/changing-defaults.itely b/Documentation/notation/changing-defaults.itely index 3dc39edd9b..cb8edf2c03 100644 --- a/Documentation/notation/changing-defaults.itely +++ b/Documentation/notation/changing-defaults.itely @@ -213,8 +213,9 @@ Handles clefs, bar lines, keys, accidentals. It can contain @strong{@emph{RhythmicStaff}} -Like @code{Staff} but for printing rhythms. Pitches are ignored; -the notes are printed on one line. +Like @code{Staff} but for printing rhythms. Pitches are ignored +when engraving; the notes are printed on one line. The MIDI +rendition retains pitches unchanged. @strong{@emph{TabStaff}} diff --git a/Documentation/notation/rhythms.itely b/Documentation/notation/rhythms.itely index f6842824a8..f935956922 100644 --- a/Documentation/notation/rhythms.itely +++ b/Documentation/notation/rhythms.itely @@ -7,7 +7,7 @@ Guide, node Updating translation committishes.. @end ignore -@c \version "2.17.30" +@c \version "2.19.0" @node Rhythms @section Rhythms @@ -93,6 +93,15 @@ note. a a a2 a a4 a a1 a @end lilypond +Durations occuring on their own within a music sequence will take +their pitches from the preceding note or chord. + +@lilypond[quote,verbatim,relative=2] +\time 8/1 +c \longa \breve 1 2 +4 8 16 32 64 128 128 +@end lilypond + @cindex notes, dotted @cindex dotted notes @cindex notes, double-dotted @@ -204,7 +213,7 @@ tuplets are triplets: 3@tie{}notes sound within the duration normally allowed for@tie{}2: @lilypond[quote,verbatim,relative=2] -a2 \tuplet 3/2 { b4 b b } +a2 \tuplet 3/2 { b4 4 4 } c4 c \tuplet 3/2 { b4 a g } @end lilypond @@ -425,6 +434,13 @@ should be tied to the following note, which must be at the same pitch. a2~ a4~ a16 r r8 @end lilypond +Ties can make use of the @q{last explicit pitch} interpretation of +isolated durations: + +@lilypond[quote,verbatim,relative=2] +a2 ~ 4 ~ 16 r r8 +@end lilypond + Ties are used either when the note crosses a bar line, or when dots cannot be used to denote the rhythm. Ties should also be used when note values cross larger subdivisions of the measure: @@ -450,7 +466,8 @@ created. Chords may be partially tied by placing the ties inside the chord. @lilypond[quote,verbatim,relative=1] -~ +2 ~ 2 +4~ @end lilypond @@ -1412,12 +1429,30 @@ So the first example above could be written: e8 | a4 c8 b c4 | @end lilypond -The property @code{measurePosition} contains a rational number, which -is usually positive and indicates how much of the measure has passed -at this point. The @code{\partial @var{duration}} command sets it to -a negative number, when it has a different meaning: it then says that -the current (first) bar will be @emph{preceded} by a bar 0 (the partial -bar) with a duration given by @var{duration}. +The property @code{measurePosition} contains a rational number, +which is usually positive and indicates how much of the measure +has passed at this point. @code{\partial @var{duration}} is +defined such that no numbered bar gets created: when used at the +beginning of a measure, @code{measurePosition} is set to a +negative number, implying that the current bar will be +@emph{preceded} by additional material. When used after a measure +has already started, however, it moves the requested distance +before the @emph{end} of the bar. + +@lilypond[quote,verbatim,relative=1] +\set Score.barNumberVisibility = #all-bar-numbers-visible +\override Score.BarNumber.break-visibility = + #end-of-line-invisible +\time 6/8 +\partial 8 +e8 | a4 c8 b[ c b] | +\partial 4 +r8 e,8 | a4 \bar "||" +\partial 4 +r8 e8 | a4 +c8 b[ c b] | +@end lilypond + @seealso Music Glossary: @@ -1432,19 +1467,6 @@ Snippets: Internal Reference: @rinternals{Timing_translator}. -@knownissues -The @code{\partial} command should be used only at the beginning of a -piece. If you use it after the beginning, warnings or problems may -occur, so use @code{\set Timing.measurePosition} instead. - -@lilypond[quote,verbatim,relative=1] -\time 6/8 -\partial 8 -e8 | a4 c8 b[ c b] | -\set Timing.measurePosition = #(ly:make-moment -1/4) -r8 e,8 | a4 c8 b[ c b] | -@end lilypond - @node Unmetered music @unnumberedsubsubsec Unmetered music @@ -1788,6 +1810,37 @@ inserts ties for notes. One of its uses is to debug complex scores: if the measures are not entirely filled, then the ties show exactly how much each measure is off. +The property @code{completionUnit} sets a preferred duration for +the split notes. + +@lilypond[quote,verbatim,relative=2] +\new Voice \with { + \remove "Note_heads_engraver" + \consists "Completion_heads_engraver" +} { + \time 9/8 g\breve. d4. \bar "||" + \set completionUnit = #(ly:make-moment 3 8) + g\breve. d4. +} +@end lilypond + +These engravers split notes with scaled duration, such as those in tuplets, +into notes with the same scale-factor as in the input note. + +@lilypond[quote,verbatim,relative=2] +\new Voice \with { + \remove "Note_heads_engraver" + \consists "Completion_heads_engraver" +} { + \time 2/4 r4 + \tuplet 3/2 {g4 a b} + \scaleDurations 2/3 {g a b} + g4*2/3 a b + \tuplet 3/2 {g4 a b} + r4 +} +@end lilypond + @seealso Music Glossary: @rglos{tie} @@ -1807,12 +1860,12 @@ Internals Reference: @rinternals{Forbid_line_break_engraver}. @knownissues -Not all durations (especially those containing tuplets) can be -represented exactly with normal notes and dots, but the -@code{Completion_heads_engraver} will not insert tuplets. - -The @code{Completion_heads_engraver} only affects notes; it does not -split rests. +For consistency with previous behavior, notes and rests with +duration longer than a measure, such as @code{c1*2}, are split into +notes without any scale factor, @code{@{ c1 c1 @}}. The property +@code{completionFactor} controls this behavior, and setting it to +@code{#f} cause split notes and rest to have the scale factor +of the input durations. @node Showing melody rhythms @@ -2015,6 +2068,7 @@ new beam starts. @funindex autoBeaming @funindex baseMoment @funindex beamExceptions +@funindex \beamExceptions @funindex beatStructure @funindex measureLength @funindex \time @@ -2156,42 +2210,24 @@ the time signature. Any exceptions to this default can be found in Special autobeaming rules (other than ending a beam on a beat) are defined in the @code{beamExceptions} property. +The value for @code{beamExceptions}, a somewhat complex Scheme +data structure, is easiest generated with the +@code{\beamExceptions} function. This function is given one or +more manually beamed measure-length rhythmic patterns (measures +have to be separated by a bar check@tie{}@code{|} since the +function has no other way to discern the measure length). Here is +a simple example: + @lilypond[quote,relative=2,verbatim] \time 3/16 \set Timing.beatStructure = #'(2 1) \set Timing.beamExceptions = - #'( ;start of alist - (end . ;entry for end of beams - ( ;start of alist of end points - ((1 . 32) . (2 2 2)) ;rule for 1/32 beams -- end each 1/16 - ))) %close all entries + \beamExceptions { 32[ 32] 32[ 32] 32[ 32] } c16 c c | \repeat unfold 6 { c32 } | @end lilypond -@code{beamExceptions} is an alist with a key of rule-type and a value -of beaming-rules. - -At this time the only available value of rule-type is -@code{'end} for beam ending. - -Beaming-rules is a scheme alist (or list of pairs) that indicates the -beam type and the grouping to be applied to beams containing notes with -a shortest duration of that beam type. - -@example -#'((beam-type1 . grouping-1) - (beam-type2 . grouping-2) - (beam-type3 . grouping-3)) -@end example - -Beam type is a scheme pair indicating the duration of the beam, -e.g., @code{(1 . 16)}. - -Grouping is a scheme list indicating the grouping to be applied to -the beam. The grouping is in units of the beam type. - -@warning{ A @code{beamExceptions} value must be @emph{complete} +@warning{A @code{beamExceptions} value must be @emph{complete} exceptions list. That is, every exception that should be applied must be included in the setting. It is not possible to add, remove, or change only one of the exceptions. While this may seem cumbersome, diff --git a/Documentation/notation/spacing.itely b/Documentation/notation/spacing.itely index a56101b0dc..834f234700 100644 --- a/Documentation/notation/spacing.itely +++ b/Documentation/notation/spacing.itely @@ -394,18 +394,16 @@ default value is scaled accordingly. @item ragged-bottom @funindex ragged-bottom -If set to true, systems will not spread vertically down the page. -This does not affect the last page. This should be set to true -for pieces that have only two or three systems per page, for -example orchestral scores. +If this is set to true, +systems will be set at their natural spacing, neither compressed +nor stretched vertically to fit the page. @item ragged-last-bottom @funindex ragged-last-bottom -If set to false, systems will spread vertically down the last -page. Pieces that amply fill two pages or more should have this -set to false. It also affects the last page of book parts, i.e. -parts of a book created with @code{\bookpart} blocks. +If this is set to false, then the last page, +and the last page in each section created with a @code{\bookpart} block, +will be vertically justified in the same way as the earlier pages. @end table @@ -1521,10 +1519,12 @@ The @code{\pageBreak} and @code{\noPageBreak} commands may also be inserted at top-level, between scores and top-level markups. There are also analogous settings to @code{ragged-right} and -@code{ragged-last} which have the same effect on vertical spacing: -@code{ragged-bottom} and @code{ragged-last-bottom}. If set to -@code{#t} the systems on all pages or just the last page -respectively will not be justified vertically. See +@code{ragged-last} which have the same effect on vertical spacing. +If @code{ragged-bottom} is set to @code{#t} the systems will not +be justified vertically. When @code{ragged-last-bottom} is set +to @code{#t}, as it is by default, empty space is allowed at the +bottom of the final page (or the final page in each +@code{\bookpart}). See @ref{Fixed vertical spacing paper variables,,Fixed vertical spacing @code{@bs{}paper} variables}. Page breaks are computed by the @code{page-breaking} function. LilyPond @@ -3107,11 +3107,14 @@ proportional notation settings and examine how these settings interact. We start with the following one-measure example, which uses classical spacing with ragged-right turned on. +@c The initial pitch is not necessary as long as RhythmicStaff is +@c not preceded by other material in the score, but we don't want +@c to explain that. @lilypond[quote,verbatim,ragged-right] \score { << \new RhythmicStaff { - c'2 c'16 c' c' c' \tuplet 5/4 { c'16 c' c' c' c' } + c2 16 16 16 16 \tuplet 5/4 { 16 16 16 16 16 } } >> } @@ -3136,7 +3139,7 @@ setting. \score { << \new RhythmicStaff { - c'2 c'16 c' c' c' \tuplet 5/4 { c'16 c' c' c' c' } + c2 16 16 16 16 \tuplet 5/4 { 16 16 16 16 16 } } >> \layout { @@ -3180,7 +3183,7 @@ larger reference durations space music tightly. \score { << \new RhythmicStaff { - c'2 c'16 c' c' c' \tuplet 5/4 { c'16 c' c' c' c' } + c2 16 16 16 16 \tuplet 5/4 { 16 16 16 16 16 } } >> \layout { @@ -3194,7 +3197,7 @@ larger reference durations space music tightly. \score { << \new RhythmicStaff { - c'2 c'16 c' c' c' \tuplet 5/4 { c'16 c' c' c' c' } + c2 16 16 16 16 \tuplet 5/4 { 16 16 16 16 16 } } >> \layout { @@ -3208,7 +3211,7 @@ larger reference durations space music tightly. \score { << \new RhythmicStaff { - c'2 c'16 c' c' c' \tuplet 5/4 { c'16 c' c' c' c' } + c2 16 16 16 16 \tuplet 5/4 { 16 16 16 16 16 } } >> \layout { @@ -3236,10 +3239,10 @@ tuplet. \score { << \new RhythmicStaff { - c'2 c'16 c' c' c' \tuplet 5/4 { c'16 c' c' c' c' } + c2 16 16 16 16 \tuplet 5/4 { 16 16 16 16 16 } } \new RhythmicStaff { - \tuplet 9/8 { c'8 c' c' c' c' c' c' c' c' } + \tuplet 9/8 { c8 8 8 8 8 8 8 8 8 } } >> } @@ -3254,10 +3257,10 @@ result. Setting @code{proportionalNotationDuration} fixes this. \score { << \new RhythmicStaff { - c'2 c'16 c' c' c' \tuplet 5/4 { c'16 c' c' c' c' } + c2 16 16 16 16 \tuplet 5/4 { 16 16 16 16 16 } } \new RhythmicStaff { - \tuplet 9/8 { c'8 c' c' c' c' c' c' c' c' } + \tuplet 9/8 { c8 8 8 8 8 8 8 8 8 } } >> \layout { @@ -3279,10 +3282,10 @@ turn on @code{uniform-stretching}, which is a property of \score { << \new RhythmicStaff { - c'2 c'16 c' c' c' \tuplet 5/4 { c'16 c' c' c' c' } + c2 16 16 16 16 \tuplet 5/4 { 16 16 16 16 16 } } \new RhythmicStaff { - \tuplet 9/8 { c'8 c' c' c' c' c' c' c' c' } + \tuplet 9/8 { c8 8 8 8 8 8 8 8 8 } } >> \layout { @@ -3378,13 +3381,13 @@ property of @code{SpacingSpanner}. Compare the two scores below: @lilypond[quote,verbatim,ragged-right] \new Staff { \set Score.proportionalNotationDuration = #(ly:make-moment 1/16) - c''8 c'' c'' \clef alto d' d'2 + c''8 8 8 \clef alto d'2 2 } \new Staff { \set Score.proportionalNotationDuration = #(ly:make-moment 1/16) \override Score.SpacingSpanner.strict-note-spacing = ##t - c''8 c'' c'' \clef alto d' d'2 + c''8 8 8 \clef alto d'2 2 } @end lilypond diff --git a/Documentation/snippets/adding-timing-marks-to-long-glissandi.ly b/Documentation/snippets/adding-timing-marks-to-long-glissandi.ly index 6189d3f64b..0cbcfeb719 100644 --- a/Documentation/snippets/adding-timing-marks-to-long-glissandi.ly +++ b/Documentation/snippets/adding-timing-marks-to-long-glissandi.ly @@ -4,7 +4,7 @@ % and then run scripts/auxiliar/makelsr.py % % This file is in the public domain. -%% Note: this file works from version 2.17.6 +%% Note: this file works from version 2.17.30 \version "2.17.30" \header { diff --git a/Documentation/snippets/ancient-notation-template----modern-transcription-of-gregorian-music.ly b/Documentation/snippets/ancient-notation-template----modern-transcription-of-gregorian-music.ly index 92c4092291..fbab93e75f 100644 --- a/Documentation/snippets/ancient-notation-template----modern-transcription-of-gregorian-music.ly +++ b/Documentation/snippets/ancient-notation-template----modern-transcription-of-gregorian-music.ly @@ -4,7 +4,7 @@ % and then run scripts/auxiliar/makelsr.py % % This file is in the public domain. -%% Note: this file works from version 2.17.20 +%% Note: this file works from version 2.17.30 \version "2.17.30" \header { diff --git a/Documentation/snippets/changing-the-tuplet-number.ly b/Documentation/snippets/changing-the-tuplet-number.ly index c69fc05c6b..e0257869b7 100644 --- a/Documentation/snippets/changing-the-tuplet-number.ly +++ b/Documentation/snippets/changing-the-tuplet-number.ly @@ -4,7 +4,7 @@ % and then run scripts/auxiliar/makelsr.py % % This file is in the public domain. -%% Note: this file works from version 2.17.11 +%% Note: this file works from version 2.17.30 \version "2.17.30" \header { diff --git a/Documentation/snippets/flat-flags-and-beam-nibs.ly b/Documentation/snippets/flat-flags-and-beam-nibs.ly index 9657cfe775..96a6bcc153 100644 --- a/Documentation/snippets/flat-flags-and-beam-nibs.ly +++ b/Documentation/snippets/flat-flags-and-beam-nibs.ly @@ -1,10 +1,11 @@ -%% DO NOT EDIT this file manually; it is automatically -%% generated from LSR http://lsr.dsi.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. -\version "2.16.0" +% 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.0 +\version "2.19.0" \header { lsrtags = "contemporary-notation, rhythms" @@ -47,7 +48,7 @@ carry both a left- and right-pointing flat flag. Do this with paired (Note that @code{\\set stemLeftBeamCount} is always equivalent to @code{\\once \\set}. In other words, the beam count settings are not @qq{sticky}, so the pair of flat flags attached to the lone -@code{c'16[]} in the last example have nothing to do with the +@code{16[]} in the last example have nothing to do with the @code{\\set} two notes prior.) @@ -69,25 +70,25 @@ carry both a left- and right-pointing flat flag. Do this with paired \new RhythmicStaff { r8. \set stemRightBeamCount = #0 - c16[] + 16[] } % Example 3 \new RhythmicStaff { - c16 c + 16 16 \set stemRightBeamCount = #2 - c16 r r + 16 r r \set stemLeftBeamCount = #2 - c16 c c + 16 16 16 } % Example 4 \new RhythmicStaff { - c16 c + 16 16 \set stemRightBeamCount = #2 - c16 r - c16[] + 16 r16 + 16[] r16 \set stemLeftBeamCount = #2 - c16 c + 16 16 } >> } diff --git a/Documentation/snippets/fretted-headword.ly b/Documentation/snippets/fretted-headword.ly index 43f92c152f..6b8f910d87 100644 --- a/Documentation/snippets/fretted-headword.ly +++ b/Documentation/snippets/fretted-headword.ly @@ -4,7 +4,7 @@ % and then run scripts/auxiliar/makelsr.py % % This file is in the public domain. -%% Note: this file works from version 2.17.11 +%% Note: this file works from version 2.17.30 % INSPIRATIONAL HEADER FOR LILYPOND DOCUMENTATION fretted-strings % % Passage from Johann Kaspar Mertz "Opern Revue, Op. 8, no. 17" % % on melodies from Bellini's "Norma" % diff --git a/Documentation/snippets/guitar-slides.ly b/Documentation/snippets/guitar-slides.ly index 205edecfda..e2e2b802f2 100644 --- a/Documentation/snippets/guitar-slides.ly +++ b/Documentation/snippets/guitar-slides.ly @@ -4,7 +4,7 @@ % and then run scripts/auxiliar/makelsr.py % % This file is in the public domain. -%% Note: this file works from version 2.17.20 +%% Note: this file works from version 2.17.30 \version "2.17.30" \header { diff --git a/Documentation/snippets/incipit.ly b/Documentation/snippets/incipit.ly index 1a4328a58f..b078cc0f53 100644 --- a/Documentation/snippets/incipit.ly +++ b/Documentation/snippets/incipit.ly @@ -4,7 +4,7 @@ % and then run scripts/auxiliar/makelsr.py % % This file is in the public domain. -%% Note: this file works from version 2.17.10 +%% Note: this file works from version 2.17.30 \version "2.17.30" \header { @@ -21,10 +21,7 @@ incipit = #(define-music-function (parser location incipit-music) (ly:music?) #{ \once \override Staff.InstrumentName.self-alignment-X = #RIGHT - \once \override Staff.InstrumentName.self-alignment-Y = #UP - \once \override Staff.InstrumentName.Y-offset = - #(lambda (grob) - (+ 4 (system-start-text::calc-y-offset grob))) + \once \override Staff.InstrumentName.self-alignment-Y = ##f \once \override Staff.InstrumentName.padding = #0.3 \once \override Staff.InstrumentName.stencil = #(lambda (grob) @@ -35,7 +32,6 @@ incipit = { { \context MensuralStaff \with { instrumentName = #instrument-name - \override VerticalAxisGroup.Y-extent = #'(-4 . 4) } $incipit-music } \layout { $(ly:grob-layout grob) diff --git a/Documentation/snippets/jazz-combo-template.ly b/Documentation/snippets/jazz-combo-template.ly index 89cec8be71..4f0570da2c 100644 --- a/Documentation/snippets/jazz-combo-template.ly +++ b/Documentation/snippets/jazz-combo-template.ly @@ -4,7 +4,7 @@ % and then run scripts/auxiliar/makelsr.py % % This file is in the public domain. -%% Note: this file works from version 2.17.20 +%% Note: this file works from version 2.17.30 \version "2.17.30" \header { diff --git a/Documentation/snippets/making-an-object-invisible-with-the-transparent-property.ly b/Documentation/snippets/making-an-object-invisible-with-the-transparent-property.ly index 572e39ca50..c7ad7b10a5 100644 --- a/Documentation/snippets/making-an-object-invisible-with-the-transparent-property.ly +++ b/Documentation/snippets/making-an-object-invisible-with-the-transparent-property.ly @@ -4,7 +4,7 @@ % and then run scripts/auxiliar/makelsr.py % % This file is in the public domain. -%% Note: this file works from version 2.17.6 +%% Note: this file works from version 2.17.30 \version "2.17.30" \header { diff --git a/Documentation/snippets/making-glissandi-breakable.ly b/Documentation/snippets/making-glissandi-breakable.ly index fd7b1e92c1..16799a19cf 100644 --- a/Documentation/snippets/making-glissandi-breakable.ly +++ b/Documentation/snippets/making-glissandi-breakable.ly @@ -4,7 +4,7 @@ % and then run scripts/auxiliar/makelsr.py % % This file is in the public domain. -%% Note: this file works from version 2.17.6 +%% Note: this file works from version 2.17.30 \version "2.17.30" \header { diff --git a/Documentation/snippets/modifying-tuplet-bracket-length.ly b/Documentation/snippets/modifying-tuplet-bracket-length.ly index bde66e6168..f19f6bc318 100644 --- a/Documentation/snippets/modifying-tuplet-bracket-length.ly +++ b/Documentation/snippets/modifying-tuplet-bracket-length.ly @@ -1,10 +1,11 @@ -%% DO NOT EDIT this file manually; it is automatically -%% generated from LSR http://lsr.dsi.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. -\version "2.17.11" +% 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.0 +\version "2.19.0" \header { lsrtags = "really-simple, rhythms" @@ -30,11 +31,11 @@ modify what material they cover. % ...to cover all items up to the next note \set tupletFullLengthNote = ##t \time 2/4 - \tuplet 3/2 { c4 c c } + \tuplet 3/2 { c4 4 4 } % ...or to cover just whitespace \set tupletFullLengthNote = ##f \time 4/4 - \tuplet 5/4 { c4 c1 } + \tuplet 5/4 { 4 1 } \time 3/4 - c2. + 2. } diff --git a/Documentation/snippets/new/flat-flags-and-beam-nibs.ly b/Documentation/snippets/new/flat-flags-and-beam-nibs.ly new file mode 100644 index 0000000000..754394be7a --- /dev/null +++ b/Documentation/snippets/new/flat-flags-and-beam-nibs.ly @@ -0,0 +1,86 @@ +\version "2.19.0" + +\header { + lsrtags = "contemporary-notation, rhythms" + + texidoc = " + Flat flags on lone notes and beam nibs at the ends of beamed figures +are both possible with a combination of @code{stemLeftBeamCount}, +@code{stemRightBeamCount} and paired @code{[]} beam indicators. + + + + +For right-pointing flat flags on lone notes, use paired @code{[]} beam +indicators and set @code{stemLeftBeamCount} to zero (see Example 1). + + + + +For left-pointing flat flags, set @code{stemRightBeamCount} instead +(Example 2). + + + + +For right-pointing nibs at the end of a run of beamed notes, set +@code{stemRightBeamCount} to a positive value. And for left-pointing +nibs at the start of a run of beamed notes, set +@code{stemLeftBeamCount} instead (Example 3). + + + + +Sometimes it may make sense for a lone note surrounded by rests to +carry both a left- and right-pointing flat flag. Do this with paired +@code{[]} beam indicators alone (Example 4). + + + + +(Note that @code{\\set stemLeftBeamCount} is always equivalent to +@code{\\once \\set}. In other words, the beam count settings are not +@qq{sticky}, so the pair of flat flags attached to the lone +@code{16[]} in the last example have nothing to do with the +@code{\\set} two notes prior.) + + + + +" + doctitle = "Flat flags and beam nibs" +} +\score { + << + % Example 1 + \new RhythmicStaff { + \set stemLeftBeamCount = #0 + c16[] + r8. + } + % Example 2 + \new RhythmicStaff { + r8. + \set stemRightBeamCount = #0 + 16[] + } + % Example 3 + \new RhythmicStaff { + 16 16 + \set stemRightBeamCount = #2 + 16 r r + \set stemLeftBeamCount = #2 + 16 16 16 + } + % Example 4 + \new RhythmicStaff { + 16 16 + \set stemRightBeamCount = #2 + 16 r16 + 16[] + r16 + \set stemLeftBeamCount = #2 + 16 16 + } + >> +} diff --git a/Documentation/snippets/new/incipit.ly b/Documentation/snippets/new/incipit.ly index 09f50ff56e..3b85ef170c 100644 --- a/Documentation/snippets/new/incipit.ly +++ b/Documentation/snippets/new/incipit.ly @@ -13,10 +13,7 @@ incipit = #(define-music-function (parser location incipit-music) (ly:music?) #{ \once \override Staff.InstrumentName.self-alignment-X = #RIGHT - \once \override Staff.InstrumentName.self-alignment-Y = #UP - \once \override Staff.InstrumentName.Y-offset = - #(lambda (grob) - (+ 4 (system-start-text::calc-y-offset grob))) + \once \override Staff.InstrumentName.self-alignment-Y = ##f \once \override Staff.InstrumentName.padding = #0.3 \once \override Staff.InstrumentName.stencil = #(lambda (grob) @@ -27,7 +24,6 @@ incipit = { { \context MensuralStaff \with { instrumentName = #instrument-name - \override VerticalAxisGroup.Y-extent = #'(-4 . 4) } $incipit-music } \layout { $(ly:grob-layout grob) diff --git a/Documentation/snippets/new/modifying-tuplet-bracket-length.ly b/Documentation/snippets/new/modifying-tuplet-bracket-length.ly new file mode 100644 index 0000000000..6ee36e8201 --- /dev/null +++ b/Documentation/snippets/new/modifying-tuplet-bracket-length.ly @@ -0,0 +1,33 @@ +\version "2.19.0" + +\header { + lsrtags = "really-simple, rhythms" + + texidoc = " +Tuplet brackets can be made to run to prefatory matter or the next +note. Default tuplet brackets end at the right edge of the final note +of the tuplet; full-length tuplet brackets extend farther to the right, +either to cover all the non-rhythmic notation up to the following note, +or to cover only the whitespace before the next item of notation, be +that a clef, time signature, key signature, or another note. The +example shows how to switch tuplets to full length mode and how to +modify what material they cover. + +" + doctitle = "Modifying tuplet bracket length" +} + +\new RhythmicStaff { + % Set tuplets to be extendable... + \set tupletFullLength = ##t + % ...to cover all items up to the next note + \set tupletFullLengthNote = ##t + \time 2/4 + \tuplet 3/2 { c4 4 4 } + % ...or to cover just whitespace + \set tupletFullLengthNote = ##f + \time 4/4 + \tuplet 5/4 { 4 1 } + \time 3/4 + 2. +} diff --git a/Documentation/snippets/new/staff-headword.ly b/Documentation/snippets/new/staff-headword.ly index 67bc0f6286..a23b5cb063 100644 --- a/Documentation/snippets/new/staff-headword.ly +++ b/Documentation/snippets/new/staff-headword.ly @@ -35,22 +35,13 @@ trompette = \relative do'' { do8-. r8 sib4-> | } -tambourin = \relative do' { +tambourin = \drummode { \time 2/4 - r8 do16 do do8 do | - r8 do16 do do8 do | - r8 do r do | - r8 do16 do do8 do | - r8 do r do | -} - -tambourinMidi = \drummode { - \time 2/4 - r8 tamb16 tamb tamb8 tamb | - r8 tamb16 tamb tamb8 tamb | - r8 tamb r tamb | - r8 tamb16 tamb tamb8 tamb | - r8 tamb r tamb | + r8 tamb16 16 8 8 | + r8 16 16 8 8 | + r8 8 r8 8 | + r8 16 16 8 8 | + r8 8 r8 8 | } upper = \relative do' { @@ -102,7 +93,7 @@ lower = \relative do { \trompette } \context DrumStaff = "tambourin" { - \tambourinMidi + \tambourin } \context Staff = "piano" << \upper @@ -113,4 +104,3 @@ lower = \relative do { \tempo 4 = 72 } } - diff --git a/Documentation/snippets/score-for-diatonic-accordion.ly b/Documentation/snippets/score-for-diatonic-accordion.ly index eebc8de67a..46883755e6 100644 --- a/Documentation/snippets/score-for-diatonic-accordion.ly +++ b/Documentation/snippets/score-for-diatonic-accordion.ly @@ -4,7 +4,7 @@ % and then run scripts/auxiliar/makelsr.py % % This file is in the public domain. -%% Note: this file works from version 2.17.20 +%% Note: this file works from version 2.17.30 \version "2.17.30" \header { diff --git a/Documentation/snippets/staff-headword.ly b/Documentation/snippets/staff-headword.ly index 6e81017f84..952b5d833f 100644 --- a/Documentation/snippets/staff-headword.ly +++ b/Documentation/snippets/staff-headword.ly @@ -43,22 +43,13 @@ trompette = \relative do'' { do8-. r8 sib4-> | } -tambourin = \relative do' { +tambourin = \drummode { \time 2/4 - r8 do16 do do8 do | - r8 do16 do do8 do | - r8 do r do | - r8 do16 do do8 do | - r8 do r do | -} - -tambourinMidi = \drummode { - \time 2/4 - r8 tamb16 tamb tamb8 tamb | - r8 tamb16 tamb tamb8 tamb | - r8 tamb r tamb | - r8 tamb16 tamb tamb8 tamb | - r8 tamb r tamb | + r8 tamb16 16 8 8 | + r8 16 16 8 8 | + r8 8 r8 8 | + r8 16 16 8 8 | + r8 8 r8 8 | } upper = \relative do' { @@ -110,7 +101,7 @@ lower = \relative do { \trompette } \context DrumStaff = "tambourin" { - \tambourinMidi + \tambourin } \context Staff = "piano" << \upper diff --git a/Documentation/snippets/unfretted-headword.ly b/Documentation/snippets/unfretted-headword.ly index 8beaa131c5..6cc02b677d 100644 --- a/Documentation/snippets/unfretted-headword.ly +++ b/Documentation/snippets/unfretted-headword.ly @@ -4,7 +4,7 @@ % and then run scripts/auxiliar/makelsr.py % % This file is in the public domain. -%% Note: this file works from version 2.17.24 +%% Note: this file works from version 2.17.30 \version "2.17.30" \header { diff --git a/Documentation/usage/running.itely b/Documentation/usage/running.itely index 9e736bda01..7e7692c86d 100644 --- a/Documentation/usage/running.itely +++ b/Documentation/usage/running.itely @@ -664,6 +664,17 @@ point exceptions. @tab Don't use directories from input files while constructing output file names. +@item @code{strokeadjust} +@tab @code{#f} +@tab Force PostScript stroke adjustment. This option is mostly +relevant when @code{PDF} is generated from PostScript output +(stroke adjustment is usually enabled automatically for +low-resolution bitmap devices). Without this option, +@code{PDF}@tie{}previewers tend to produce widely inconsistent +stem widths at resolutions typical for screen display. The option +does not noticeably affect print quality and causes large file +size increases in @code{PDF} files. + @item @code{svg-woff} @tab @code{#f} @tab Use woff font files in SVG backend. diff --git a/Documentation/usage/updating.itely b/Documentation/usage/updating.itely index 06a960ac8a..ad92a834e3 100644 --- a/Documentation/usage/updating.itely +++ b/Documentation/usage/updating.itely @@ -151,8 +151,11 @@ The following options can be given: @item -d, --diff-version-update increase the @code{\version} string only if the file has actually been changed. In that case, the version header will correspond to -the version after the last actual change. Without that option, -the version will reflect the last @emph{attempted} conversion. +the version after the last actual change. An unstable version +number will be rounded up to the next stable version number unless +that would exceed the target version number. Without this option, +the version will instead reflect the last @emph{attempted} +conversion. @item -e, --edit Apply the conversions direct to the input file, modifying it diff --git a/Documentation/web/news-front.itexi b/Documentation/web/news-front.itexi index 8d45279fb8..7246a04928 100644 --- a/Documentation/web/news-front.itexi +++ b/Documentation/web/news-front.itexi @@ -9,131 +9,36 @@ @c used for news about the upcoming release; see CG 10.2 @newsItem -@subsubheading LilyPond 2.17.95 released! @emph{November 3, 2013} +@subsubheading LilyPond 2.17.96 released! @emph{November 24, 2013} -We are excited to announce the release of LilyPond@tie{}2.17.95 as -beta release for the upcoming stable release@tie{}2.18. The -developers are still busy finding solutions for some last-minute -problems, but the release is supposed to be feature-complete, the +We are excited to announce the release of LilyPond@tie{}2.17.96 as +a further beta release for the upcoming stable release@tie{}2.18. The +developers believe the release to be feature-complete, the documentation to be accurate, and no important issues to be overlooked. For upgrading the syntax of your input files to the -latest version, see @rprogram{Updating files with convert-ly}. +latest version, see @uref{http://www.lilypond.org/doc/v2.17/Documentation/usage/updating-files-with-convert_002dly, Updating files with convert-ly}. Please test this release and report back any problems, see -@rweb{Bug reports}. +@uref{http://www.lilypond.org/website/bug-reports.html, Bug reports}. @newsEnd -@newsItem -@subsubheading LilyPond blog. @emph{June 2, 2013} - -Janek Warchoł has created a LilyPond blog. You can find it at -@uref{http://lilypondblog.org/, lilypondblog.org}! - -@newsEnd - -@newsItem -@subsubheading LilyPond 2.16.2 released! @emph{January 4, 2013} - -We are happy to announce the release of LilyPond 2.16.2. This release is mainly -to correct a problem with lilypond-book running on Windows. We recommend that -only people requiring this functionality upgrade to this version. - -@newsEnd @newsItem -@subsubheading The LilyPond Report #28. @emph{November 12, 2012} - -The @uref{http://news.lilynet.net/?The-LilyPond-Report-28, October -issue of the @emph{LilyPond Report}} focuses on the -@uref{http://news.lilynet.net/?LilyPond-meeting-in-Waltrop, -meeting of LilyPond developers and users} in Waltrop, Germany last -August. Of course, there are also some musings on LilyPond -triggered by the release of 2.16.0 and 2.17.0 occuring from that -venue. +@subsubheading LilyPond 2.17.29 released! @emph{October 20, 2013} -There are also two monthly financial reports from David Kastrup -whose work on LilyPond is -@uref{http://news.lilynet.net/?The-LilyPond-Report-24#an_urgent_request_for_funding, -solely paid for} by financial contributions from other developer -and users (thank you!), and a report about experiences from -@uref{http://scorio.com, a web-based music typesetting service} -using LilyPond internally. +We are happy to announce the release of LilyPond 2.17.29. This +release contains the usual number of bugfixes and 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.16 version. -Come @uref{http://news.lilynet.net/?The-LilyPond-Report-28, read -LilyPond Report 28} now; comments and contributions are warmly -encouraged! @newsEnd -@newsItem -@subsubheading LilyPond 2.16.1 released! @emph{November 9, 2012} - -We are happy to announce the release of LilyPond 2.16.1. This has a number of -updates to the previous stable version, and should cause no problems. We -recommend that everybody upgrade to this version. -@newsEnd @newsItem -@subsubheading Lilypond 2.16.0 released! @emph{August 24, 2012} - -We are proud to announce the release of GNU LilyPond 2.16.1. -LilyPond is a music engraving program, devoted to producing the -highest-quality sheet music possible. It brings the aesthetics of -traditionally engraved music to computer printouts. - -Many improvements have been made in the past year since the previous -main stable version. A few major improvements are: - -@itemize -@item -Support for kievan square notation -@item -User and programming interfaces have greatly improved -@item -Music functions have become quite more versatile -@end itemize - -A full list of new features is given in: - -@example -@uref{http://lilypond.org/doc/v2.16/Documentation/changes/index.html} -@end example - -Happy music typesetting! LilyPond 2.16 was brought to you by... - -Main development team: - -Bertrand Bordage, Trevor Daniels, Colin Hall, Phil Holmes, Ian Hulin, -Reinhold Kainhofer, David Kastrup, Jonathan Kulp, Werner Lemberg, -John Mandereau, Patrick McCarty, Joe Neeman, Han-Wen Nienhuys, -Jan Nieuwenhuizen, Graham Percival, Mark Polesky, Neil Puttock, -Mike Solomon, Carl Sorensen, Francisco Vila, Valentin Villenave, -Jan Warchoł - -Programming contributors: - -Aleksandr Andreev, Sven Axelsson, Peter Chubb, Karin Hoethker, -Marc Hohl, David Nalesnik, Justin Ohmie, Benkő Pál, Julien Rioux, Patrick Schmidt, -Adam Spiers, Heikki Taurainen, Piers Titus van der Torren, -Jan-Peter Voigt, Janek Warchol - -Documentation contributors: - -James Lowe, Pavel Roskin, Alberto Simoes, Stefan Weil - -Bug squad: - -Colin Campbell, Eluze, Phil Holmes, Marek Klein, Ralph Palmer, -James Lowe - -Support: - -Colin Campbell, Christian Hitz, Phil Holmes - -Translation contributors: +@subsubheading LilyPond blog. @emph{June 2, 2013} -Jean-Charles Malahieude, Till Paala, Yoshiki Sawada +Janek Warchoł has created a LilyPond blog. You can find it at +@uref{http://lilypondblog.org/, lilypondblog.org}! @newsEnd - - - diff --git a/Documentation/web/news.itexi b/Documentation/web/news.itexi index 9a548e02d5..f7770300eb 100644 --- a/Documentation/web/news.itexi +++ b/Documentation/web/news.itexi @@ -26,6 +26,21 @@ NOTE: * don't duplicate entries from news-front.itexi @end ignore +@newsItem +@subsubheading LilyPond 2.17.95 released! @emph{November 3, 2013} + +We are excited to announce the release of LilyPond@tie{}2.17.95 as +beta release for the upcoming stable release@tie{}2.18. The +developers are still busy finding solutions for some last-minute +problems, but the release is supposed to be feature-complete, the +documentation to be accurate, and no important issues to be +overlooked. For upgrading the syntax of your input files to the +latest version, see @rprogram{Updating files with convert-ly}. +Please test this release and report back any problems, see +@rweb{Bug reports}. + +@newsEnd + @newsItem @subsubheading LilyPond 2.17.29 released! @emph{October 20, 2013} @@ -250,6 +265,15 @@ a stable version of Lilypond, we recommend using the 2.16 version. @newsEnd +@newsItem +@subsubheading LilyPond 2.16.2 released! @emph{January 4, 2013} + +We are happy to announce the release of LilyPond 2.16.2. This release is mainly +to correct a problem with lilypond-book running on Windows. We recommend that +only people requiring this functionality upgrade to this version. + +@newsEnd + @newsItem @subsubheading LilyPond 2.17.9 released! @emph{December 15, 2012} @@ -283,6 +307,33 @@ a stable version of Lilypond, we recommend using the 2.16 version. @newsEnd +@ignore +As of 2013-12-06 all links to LilyPond Report are broken. +@end ignore + +@newsItem +@subsubheading The LilyPond Report #28. @emph{November 12, 2012} + +The @uref{http://news.lilynet.net/?The-LilyPond-Report-28, October +issue of the @emph{LilyPond Report}} focuses on the +@uref{http://news.lilynet.net/?LilyPond-meeting-in-Waltrop, +meeting of LilyPond developers and users} in Waltrop, Germany last +August. Of course, there are also some musings on LilyPond +triggered by the release of 2.16.0 and 2.17.0 occuring from that +venue. + +There are also two monthly financial reports from David Kastrup +whose work on LilyPond is +@uref{http://news.lilynet.net/?The-LilyPond-Report-24#an_urgent_request_for_funding, +solely paid for} by financial contributions from other developer +and users (thank you!), and a report about experiences from +@uref{http://scorio.com, a web-based music typesetting service} +using LilyPond internally. + +Come @uref{http://news.lilynet.net/?The-LilyPond-Report-28, read +LilyPond Report 28} now; comments and contributions are warmly +encouraged! +@newsEnd @newsItem @subsubheading LilyPond 2.16.1 released! @emph{November 9, 2012} diff --git a/VERSION b/VERSION index e2867ac71c..98fe5b66bb 100644 --- a/VERSION +++ b/VERSION @@ -1,7 +1,7 @@ PACKAGE_NAME=LilyPond MAJOR_VERSION=2 -MINOR_VERSION=17 -PATCH_LEVEL=96 +MINOR_VERSION=19 +PATCH_LEVEL=0 MY_PATCH_LEVEL= VERSION_STABLE=2.16.2 -VERSION_DEVEL=2.17.95 +VERSION_DEVEL=2.17.96 diff --git a/flower/include/std-vector.hh b/flower/include/std-vector.hh index e7f29a8fcb..8275b92930 100644 --- a/flower/include/std-vector.hh +++ b/flower/include/std-vector.hh @@ -30,6 +30,7 @@ #endif #endif +#include "config.hh" /* needed at least for HAVE_STL_DATA_METHOD */ #include /* find, reverse, sort */ #include /* unary_function */ #include diff --git a/flower/string-convert.cc b/flower/string-convert.cc index eebcd92708..745a98ecea 100644 --- a/flower/string-convert.cc +++ b/flower/string-convert.cc @@ -37,8 +37,8 @@ string String_convert::bin2hex (Byte bin_char) { string str; - str += to_string ((char) nibble2hex_byte ((Byte) (bin_char >> 4))); - str += to_string ((char) nibble2hex_byte (bin_char++)); + str += ::to_string ((char) nibble2hex_byte ((Byte) (bin_char >> 4))); + str += ::to_string ((char) nibble2hex_byte (bin_char++)); return str; } @@ -49,8 +49,8 @@ String_convert::bin2hex (const string &bin_string) Byte const *byte = (Byte const *)bin_string.data (); for (ssize i = 0; i < bin_string.length (); i++) { - str += to_string ((char)nibble2hex_byte ((Byte) (*byte >> 4))); - str += to_string ((char)nibble2hex_byte (*byte++)); + str += ::to_string ((char)nibble2hex_byte ((Byte) (*byte >> 4))); + str += ::to_string ((char)nibble2hex_byte (*byte++)); } return str; } @@ -127,7 +127,7 @@ String_convert::hex2bin (string hex_string, string &bin_string_r) int low_i = hex2nibble (*byte++); if (high_i < 0 || low_i < 0) return 1; // invalid char - bin_string_r += to_string ((char) (high_i << 4 | low_i), 1); + bin_string_r += ::to_string ((char) (high_i << 4 | low_i), 1); i += 2; } return 0; @@ -165,10 +165,10 @@ String_convert::int2dec (int i, size_t length_i, char ch) fill_char = '0'; // ugh - string dec_string = to_string (i); + string dec_string = ::to_string (i); // ugh - return to_string (fill_char, ssize_t (length_i - dec_string.length ())) + dec_string; + return ::to_string (fill_char, ssize_t (length_i - dec_string.length ())) + dec_string; } // stupido. Should use int_string () @@ -182,14 +182,14 @@ String_convert::unsigned2hex (unsigned u, size_t length, char fill_char) #if 1 // both go... while (u) { - str = to_string ((char) ((u % 16)["0123456789abcdef"])) + str; + str = ::to_string ((char) ((u % 16)["0123456789abcdef"])) + str; u /= 16; } #else str += int_string (u, "%x"); // hmm. %lx vs. %x -> portability? #endif - str = to_string (fill_char, ssize_t (length - str.length ())) + str; + str = ::to_string (fill_char, ssize_t (length - str.length ())) + str; while ((str.length () > length) && (str[ 0 ] == 'f')) str = str.substr (2); @@ -299,7 +299,7 @@ String_convert::pointer_string (void const *l) string String_convert::precision_string (double x, int n) { - string format = "%." + to_string (max (0, n - 1)) + "e"; + string format = "%." + ::to_string (max (0, n - 1)) + "e"; string str = double_string (abs (x), format.c_str ()); int exp = dec2int (str.substr (str.length () - 3)); @@ -316,9 +316,9 @@ String_convert::precision_string (double x, int n) str = str.substr (0, 1) + str.substr (2); ssize dot = 1 + exp; if (dot <= 0) - str = "0." + to_string ('0', -dot) + str; + str = "0." + ::to_string ('0', -dot) + str; else if (dot >= str.length ()) - str += to_string ('0', dot - str.length ()); + str += ::to_string ('0', dot - str.length ()); else if ((dot > 0) && (dot < str.length ())) str = str.substr (0, dot) + "." + str.substr (dot); else diff --git a/input/regression/auto-beam-exceptions.ly b/input/regression/auto-beam-exceptions.ly index 676bb3aafb..b7d553b123 100644 --- a/input/regression/auto-beam-exceptions.ly +++ b/input/regression/auto-beam-exceptions.ly @@ -1,4 +1,4 @@ -\version "2.16.0" +\version "2.19.0" \header { @@ -11,40 +11,20 @@ \relative c' { \time 2/4 - \set Score.beamExceptions = #'( - ( end . - ( - ( (1 . 32) . (4 4 4 4) ) - ) - ) - ) + \set Score.beamExceptions = + \beamExceptions \repeat unfold 4 { 32[ 32 32 32] } \repeat unfold 16 c32 \time 3/4 - \set Score.beamExceptions = #'( - ( end . - ( - ( (1 . 32) . (4 4 4 4 4 4) ) - ) - ) - ) + \set Score.beamExceptions = + \beamExceptions \repeat unfold 6 { 32[ 32 32 32] } \repeat unfold 24 c32 c8 c32 c32 c32 c32 c16 c16 c32 c32 c32 c32 c16 c32 c32 c32 c32 c32 c32 \time 4/4 - \set Score.beamExceptions = #'( - ( end . - ( - ( (1 . 32) . (4 4 4 4 4 4 4 4) ) - ) - ) - ) + \set Score.beamExceptions = + \beamExceptions \repeat unfold 8 { 32[ 32 32 32] } \repeat unfold 32 c32 \time 6/8 - \set Score.beamExceptions = #'( - ( end . - ( - ( (1 . 32) . (4 4 4 4 4 4) ) - ) - ) - ) + \set Score.beamExceptions = + \beamExceptions \repeat unfold 6 { 32[ 32 32 32] } \repeat unfold 24 c32 } diff --git a/input/regression/chord-dots.ly b/input/regression/chord-dots.ly new file mode 100644 index 0000000000..957788d4bc --- /dev/null +++ b/input/regression/chord-dots.ly @@ -0,0 +1,17 @@ +\version "2.17.16" + +\header { + texidoc = +"The column of dots on a chord is limited to the height +of the chord plus @code{chord-dots-limit} staff-positions." +} + +\layout{ ragged-right = ##t } + +\new Staff \transpose c c' { + \override Staff.DotColumn.chord-dots-limit = #1 + << + { 4. r8 4. r8 } \\ + { f4.. r16 4.. r16} + >> +} diff --git a/input/regression/completion-heads-factor.ly b/input/regression/completion-heads-factor.ly index 79510e1484..cc29f58d4e 100644 --- a/input/regression/completion-heads-factor.ly +++ b/input/regression/completion-heads-factor.ly @@ -1,12 +1,12 @@ -\version "2.16.0" +\version "2.19.0" \header{ texidoc=" If the @code{Note_heads_engraver} is replaced by the @code{Completion_heads_engraver}, -notes with a duration factor still keep their requested appearance. - -" +long notes, longer than @code{measureLength}, are split into un-scaled notes, +even if the original note used a scale-factor. +@code{completionFactor} controls this behavior." } \layout { ragged-right= ##t } @@ -20,5 +20,11 @@ notes with a duration factor still keep their requested appearance. c\breve | c1*2 | c2*4 | - c8*20 + c8*20 r2 \break + \tuplet 3/2 { d1 d d } + % \breve*2/3 is longer than a measure, but we want a tuplet, not repeats. + \set completionFactor = ##f + \tuplet 3/2 { e\breve e e } + \set completionFactor = #2/3 + \tuplet 3/2 { e\breve e e } } diff --git a/input/regression/completion-rest.ly b/input/regression/completion-rest.ly index e39e17aff8..365b7372e2 100644 --- a/input/regression/completion-rest.ly +++ b/input/regression/completion-rest.ly @@ -1,12 +1,12 @@ -\version "2.16.0" +\version "2.19.0" \header{ texidoc=" If the @code{Rest_engraver} is replaced by the @code{Completion_rest_engraver}, -rests with a duration factor still keep their requested appearance. - -" +long rests, longer than @code{measureLength}, are split into +un-scaled rests, even if the original duration used a scale-factor. +@code{completionFactor} controls this behavior." } \layout { ragged-right= ##t } @@ -20,5 +20,9 @@ rests with a duration factor still keep their requested appearance. r\breve | r1*2 | r2*4 | - r8*20 + r8*20 r2 \break + \bar "||" \time 2/4 + r\breve.*2/3 + \set completionFactor = #1/2 + r\breve.*2/3^"explicity request r1*1/2 rests" } diff --git a/input/regression/display-lily-tests.ly b/input/regression/display-lily-tests.ly index a4abc604d1..10dccdded2 100644 --- a/input/regression/display-lily-tests.ly +++ b/input/regression/display-lily-tests.ly @@ -183,6 +183,9 @@ stderr of this run." \test ##[ \tuplet 3/2 { c4 d e \tuplet 5/2 { f4 e d2 d4 } c4 } #] \test ##[ \tuplet 3/2 2 { c4 d e \tuplet 5/2 2 { f4 e d2 d4 } c4 } #] +%% pure rhythm +\test ##[ { 4 4 8 \tuplet 3/2 { 8[ 16] } 16 } #] + %% \relative and \tranpose \test #"NOT A BUG" ##[ \relative c' { c b } #] % RelativeOctaveMusic \test #"NOT A BUG" ##[ \transpose c d { c d } #] % TransposedMusic diff --git a/input/regression/les-nereides.ly b/input/regression/les-nereides.ly index c87772419d..61b79eccd4 100644 --- a/input/regression/les-nereides.ly +++ b/input/regression/les-nereides.ly @@ -1,4 +1,4 @@ -\version "2.17.10" +\version "2.19.0" \header { composer = "ARTHUR GRAY" @@ -233,8 +233,9 @@ middleDynamics = { theScore = \score{ \context PianoStaff << \new Staff = "treble" << - \set beamExceptions = #'((end . (((1 . 8) . (2 2 2 2)) - ((1 . 32) . (4 4 4 4 4 4 4 4))))) + \set beamExceptions = + \beamExceptions { 8[ 8] 8[ 8] 8[ 8] 8[ 8] | + \repeat unfold 8 { 32[ 32 32 32] } } \treble \trebleTwo >> diff --git a/input/regression/make-relative-copies.ly b/input/regression/make-relative-copies.ly new file mode 100644 index 0000000000..93c9fe9c8e --- /dev/null +++ b/input/regression/make-relative-copies.ly @@ -0,0 +1,29 @@ +\header { + texidoc = "@code{make-relative} has to copy its argument expressions +in case the generated music expression is getting copied and modified. + +The code here defines a @code{\\reltranspose} function working inside +of @code{\\relative} and uses it. Both staves should appear +identical." +} + +\layout { + ragged-right = ##t +} + +reltranspose = +#(define-music-function (parser location from to music) + (ly:pitch? ly:pitch? ly:music?) + (make-relative (music) music + #{ \transpose #from #to $music #})) + +mus = +\reltranspose c g { + \partial 4. c8 e g | + c2 r8 c, e g c1 | \bar "|." +} + +<< + \new Staff \relative \mus + \new Staff \relative \mus +>> diff --git a/input/regression/make-relative-music.ly b/input/regression/make-relative-music.ly new file mode 100644 index 0000000000..58266b2b35 --- /dev/null +++ b/input/regression/make-relative-music.ly @@ -0,0 +1,32 @@ +\version "2.19.0" + +\header { + texidoc = "@code{make-relative} can make relativization on music +function calls behave as one would expect from looking at the +function's arguments rather than at the actually resulting +expressions. This regtest defines an example function +@code{\\withOctave} which works equally well inside and outside of +@code{\\relative}." +} + +withOctave = +#(define-music-function (parser location music) + (ly:music?) + (make-relative + (music) music + #{ \context Bottom << $music \transpose c c' $music >> #})) + +mus = { + \partial 4. c'8 e g | + c2 e,4 g | + c,8 c' b a | + 1 | \bar "|." +} + +<< + \relative \new Staff { <>^"original" \mus } + \relative \new Staff { <>^\markup \typewriter "\\relative \\withOctave" + \withOctave \mus } + \new Staff { <>^\markup \typewriter "\\withOctave \\relative" + \withOctave \relative \mus } +>> diff --git a/input/regression/make-relative.ly b/input/regression/make-relative.ly index 706bdb9adc..04bbed3900 100644 --- a/input/regression/make-relative.ly +++ b/input/regression/make-relative.ly @@ -1,4 +1,4 @@ -\version "2.17.11" +\version "2.19.0" \header { texidoc = "@code{make-relative} is a Scheme utility macro mainly @@ -16,7 +16,7 @@ The fragment should appear identical in both cases." ph = #(define-music-function (parser location p1 p2 p3 p4 p5) (ly:pitch? ly:pitch? ly:pitch? ly:pitch? ly:pitch?) - (make-relative (p1 p2 p3 p4 p5) p1 + (make-relative (p1 p2 p3 p4 p5) (make-event-chord (list p1 p2 p3 p4 p5)) #{ \repeat unfold 2 { $p1 2 } | \repeat unfold 2 { r16 $p2 8. ~ $p2 4 } | diff --git a/input/regression/midi-grace-after-rest.ly b/input/regression/midi-grace-after-rest.ly new file mode 100644 index 0000000000..8a99cddcfc --- /dev/null +++ b/input/regression/midi-grace-after-rest.ly @@ -0,0 +1,14 @@ +\header { + texidoc = "Grace notes shorten previous notes only if they'd overlap +them. The A should be a full quarter note, but the C should be shortened +to 1/4 - 9/40 * 1/8 = 71/320 (rounded down to 340/384 in MIDI)." +} +\version "2.18.0" +\score { + \relative c' { + a4 r + \grace b8 c8... r64 + \grace d8 e4 + } + \midi { } +} diff --git a/input/regression/optional-args.ly b/input/regression/optional-args.ly index 83ebf7886a..c92c6a143b 100644 --- a/input/regression/optional-args.ly +++ b/input/regression/optional-args.ly @@ -1,4 +1,4 @@ -\version "2.17.15" +\version "2.19.0" \header{ texidoc= "Test optional music function arguments. @@ -10,23 +10,18 @@ the rest is skipped." \layout { ragged-right = ##t } -% Get following pitch into Scheme -pitch = #(define-scheme-function (parser location p) (ly:pitch?) p) -% The same with a duration -dur = #(define-scheme-function (parser location p) (ly:duration?) p) - % Just like \relative, but defaulting to f as reference, making the % first note of the music the same as if written as absolute pitch ablative = #(define-music-function (parser location ref music) - ((ly:pitch? #{ \pitch f #}) ly:music?) + ((ly:pitch? #{ f #}) ly:music?) #{ \relative $ref $music #}) % Let's take a duration and four pitches, defaulting to 2 c' d' e' zap = #(define-music-function (parser location dur a b c d) - ((ly:duration? #{ \dur 2 #}) (ly:pitch? #{ \pitch c' #}) - (ly:pitch? #{ \pitch d' #}) (ly:pitch? #{ \pitch e' #}) + ((ly:duration? #{ 2 #}) (ly:pitch? #{ c' #}) + (ly:pitch? #{ d' #}) (ly:pitch? #{ e' #}) ly:music?) #{ $a $dur $b $c ^\markup{!} $d #}) \new Voice { \relative c' e' \relative c' { e' } \ablative c' e' \ablative { e' } diff --git a/input/regression/rhythmic-sequence.ly b/input/regression/rhythmic-sequence.ly new file mode 100644 index 0000000000..df647ce7d1 --- /dev/null +++ b/input/regression/rhythmic-sequence.ly @@ -0,0 +1,11 @@ +\version "2.19.0" + +\header { + texidoc = "Durations without pitches are placed into note events +without pitch information. Those are directly useful in +@code{RhythmicStaff}." +} + +\layout { ragged-right = ##t } + +\new RhythmicStaff { 4 4. r | 4 \tuplet 3/2 { 2 4 } 4 } diff --git a/input/regression/score-lines.ly b/input/regression/score-lines.ly new file mode 100644 index 0000000000..edb300fff7 --- /dev/null +++ b/input/regression/score-lines.ly @@ -0,0 +1,40 @@ +\version "2.19.0" + +\header { + texidoc = "The @code{\\score-lines} markup returns individual score +lines as stencils rather than a single stencil. Calling a function +like @code{\\rotate} on @code{\\score-lines} rotates the lines +individually, as contrasted with rotating an entire @code{\\score} +markup." +} + +\markup \fill-line { + \null + \column \rotate #-15 { + \score-lines + { + \new Staff \with { instrumentName = \markup \typewriter + "\\score-lines" } + \repeat unfold 16 c'4 + \layout { + short-indent = 0 + indent = 0 + line-width = 4\cm + } + } + } + \column \rotate #-15 { + \score + { + \new Staff \with { instrumentName = \markup \typewriter + "\\score" } + \repeat unfold 16 c'4 + \layout { + short-indent = 0 + indent = 0 + line-width = 4\cm + } + } + } + \null +} diff --git a/input/regression/tablature-slurs-with-beams.ly b/input/regression/tablature-slurs-with-beams.ly index 1425ed6807..69d68c0fa9 100644 --- a/input/regression/tablature-slurs-with-beams.ly +++ b/input/regression/tablature-slurs-with-beams.ly @@ -1,4 +1,4 @@ -\version "2.17.20" +\version "2.19.0" \header { @@ -10,7 +10,8 @@ either automatic or manual beaming. guitarSolo = { \time 3/4 - \set Timing.beamExceptions = #'((end . (((1 . 8) . (4 2))))) + \set Timing.beamExceptions = + \beamExceptions { 8[ 8 8 8] 8[ 8] } << {bes'2( aes'8-. r)} \\ {r8 cis(-\tag #'beam [ b f'-\tag #'beam ]) -. r} diff --git a/lily/accidental.cc b/lily/accidental.cc index ce05dfff72..3d2906ee85 100644 --- a/lily/accidental.cc +++ b/lily/accidental.cc @@ -163,15 +163,17 @@ Accidental_interface::get_stencil (Grob *me) SCM alist = me->get_property ("glyph-name-alist"); SCM alt = me->get_property ("alteration"); SCM glyph_name = ly_assoc_get (alt, alist, SCM_BOOL_F); + Stencil mol; if (!scm_is_string (glyph_name)) { me->warning (_f ("Could not find glyph-name for alteration %s", ly_scm_write_string (alt).c_str ())); - return SCM_EOL; + mol = fm->find_by_name ("noteheads.s1cross"); } + else + mol = fm->find_by_name (ly_scm2string (glyph_name)); - Stencil mol (fm->find_by_name (ly_scm2string (glyph_name))); if (to_boolean (me->get_property ("restore-first"))) { /* diff --git a/lily/align-interface.cc b/lily/align-interface.cc index 8a2a8d9b81..266016d573 100644 --- a/lily/align-interface.cc +++ b/lily/align-interface.cc @@ -61,85 +61,73 @@ Align_interface::align_to_ideal_distances (SCM smob) return SCM_BOOL_T; } -/* for each grob, find its upper and lower skylines. If the grob has - an empty extent, delete it from the list instead. If the extent is - non-empty but there is no skyline available (or pure is true), just +/* Return upper and lower skylines for VerticalAxisGroup g. If the extent + is non-empty but there is no skyline available (or pure is true), just create a flat skyline from the bounding box */ // TODO(jneem): the pure and non-pure parts seem to share very little // code. Split them into 2 functions, perhaps? -static void -get_skylines (Grob *me, - vector *const elements, +static Skyline_pair +get_skylines (Grob *g, Axis a, - bool pure, int start, int end, - vector *const ret) + Grob *other_common, + bool pure, int start, int end) { - Grob *other_common = common_refpoint_of_array (*elements, me, other_axis (a)); + Skyline_pair skylines; - for (vsize i = elements->size (); i--;) + if (!pure) { - Grob *g = (*elements)[i]; - Skyline_pair skylines; - - if (!pure) - { - Skyline_pair *skys = Skyline_pair::unsmob (g->get_property (a == Y_AXIS - ? "vertical-skylines" - : "horizontal-skylines")); - if (skys) - skylines = *skys; - - /* This skyline was calculated relative to the grob g. In order to compare it to - skylines belonging to other grobs, we need to shift it so that it is relative - to the common reference. */ - Real offset = g->relative_coordinate (other_common, other_axis (a)); - skylines.shift (offset); - } - else + Skyline_pair *skys = Skyline_pair::unsmob (g->get_property (a == Y_AXIS + ? "vertical-skylines" + : "horizontal-skylines")); + if (skys) + skylines = *skys; + + /* This skyline was calculated relative to the grob g. In order to compare it to + skylines belonging to other grobs, we need to shift it so that it is relative + to the common reference. */ + Real offset = g->relative_coordinate (other_common, other_axis (a)); + skylines.shift (offset); + } + else if (Hara_kiri_group_spanner::request_suicide (g, start, end)) + return skylines; + else + { + assert (a == Y_AXIS); + Interval extent = g->pure_height (g, start, end); + + // This is a hack to get better accuracy on the pure-height of VerticalAlignment. + // It's quite common for a treble clef to be the highest element of one system + // and for a low note (or lyrics) to be the lowest note on another. The two will + // never collide, but the pure-height stuff only works with bounding boxes, so it + // doesn't know that. The result is a significant over-estimation of the pure-height, + // especially on systems with many staves. To correct for this, we build a skyline + // in two parts: the part we did above contains most of the grobs (note-heads, etc.) + // while the bit we're about to do only contains the breakable grobs at the beginning + // of the system. This way, the tall treble clefs are only compared with the treble + // clefs of the other staff and they will be ignored if the staff above is, for example, + // lyrics. + if (Axis_group_interface::has_interface (g)) { - assert (a == Y_AXIS); - Interval extent = g->pure_height (g, start, end); - - // This is a hack to get better accuracy on the pure-height of VerticalAlignment. - // It's quite common for a treble clef to be the highest element of one system - // and for a low note (or lyrics) to be the lowest note on another. The two will - // never collide, but the pure-height stuff only works with bounding boxes, so it - // doesn't know that. The result is a significant over-estimation of the pure-height, - // especially on systems with many staves. To correct for this, we build a skyline - // in two parts: the part we did above contains most of the grobs (note-heads, etc.) - // while the bit we're about to do only contains the breakable grobs at the beginning - // of the system. This way, the tall treble clefs are only compared with the treble - // clefs of the other staff and they will be ignored if the staff above is, for example, - // lyrics. - if (Axis_group_interface::has_interface (g) - && !Hara_kiri_group_spanner::request_suicide (g, start, end)) - { - extent = Axis_group_interface::rest_of_line_pure_height (g, start, end); - Interval begin_of_line_extent = Axis_group_interface::begin_of_line_pure_height (g, start); - if (!begin_of_line_extent.is_empty ()) - { - Box b; - b[a] = begin_of_line_extent; - b[other_axis (a)] = Interval (-infinity_f, -1); - skylines.insert (b, other_axis (a)); - } - } - - if (!extent.is_empty ()) + extent = Axis_group_interface::rest_of_line_pure_height (g, start, end); + Interval begin_of_line_extent = Axis_group_interface::begin_of_line_pure_height (g, start); + if (!begin_of_line_extent.is_empty ()) { Box b; - b[a] = extent; - b[other_axis (a)] = Interval (0, infinity_f); + b[a] = begin_of_line_extent; + b[other_axis (a)] = Interval (-infinity_f, -1); skylines.insert (b, other_axis (a)); } } - if (skylines.is_empty ()) - elements->erase (elements->begin () + i); - else - ret->push_back (skylines); + if (!extent.is_empty ()) + { + Box b; + b[a] = extent; + b[other_axis (a)] = Interval (0, infinity_f); + skylines.insert (b, other_axis (a)); + } } - reverse (*ret); + return skylines; } vector @@ -177,7 +165,7 @@ Align_interface::get_minimum_translations_without_min_dist (Grob *me, // else centered dynamics will break when there is a fixed alignment). vector Align_interface::internal_get_minimum_translations (Grob *me, - vector const &all_grobs, + vector const &elems, Axis a, bool include_fixed_spacing, bool pure, int start, int end) @@ -204,15 +192,14 @@ Align_interface::internal_get_minimum_translations (Grob *me, Direction stacking_dir = robust_scm2dir (me->get_property ("stacking-dir"), DOWN); - vector elems (all_grobs); // writable copy - vector skylines; - get_skylines (me, &elems, a, pure, start, end, &skylines); + Grob *other_common = common_refpoint_of_array (elems, me, other_axis (a)); Real where = 0; Real default_padding = robust_scm2double (me->get_property ("padding"), 0.0); vector translates; Skyline down_skyline (stacking_dir); + Grob *last_nonempty_element = 0; Real last_spaceable_element_pos = 0; Grob *last_spaceable_element = 0; Skyline last_spaceable_skyline (stacking_dir); @@ -222,14 +209,26 @@ Align_interface::internal_get_minimum_translations (Grob *me, Real dy = 0; Real padding = default_padding; - if (j == 0) - dy = skylines[j][-stacking_dir].max_height () + padding; + Skyline_pair skyline = get_skylines (elems[j], a, other_common, pure, start, end); + + if (skyline.is_empty ()) + { + translates.push_back (where); + continue; + } + + if (!last_nonempty_element) + { + dy = skyline[-stacking_dir].max_height () + padding; + for (vsize k = j; k-- > 0;) + translates[k] = stacking_dir * dy; + } else { - SCM spec = Page_layout_problem::get_spacing_spec (elems[j - 1], elems[j], pure, start, end); + SCM spec = Page_layout_problem::get_spacing_spec (last_nonempty_element, elems[j], pure, start, end); Page_layout_problem::read_spacing_spec (spec, &padding, ly_symbol2scm ("padding")); - dy = down_skyline.distance (skylines[j][-stacking_dir]) + padding; + dy = down_skyline.distance (skyline[-stacking_dir]) + padding; Real spec_distance = 0; if (Page_layout_problem::read_spacing_spec (spec, &spec_distance, ly_symbol2scm ("minimum-distance"))) @@ -249,7 +248,7 @@ Align_interface::internal_get_minimum_translations (Grob *me, Page_layout_problem::read_spacing_spec (spec, &spaceable_padding, ly_symbol2scm ("padding")); - dy = max (dy, (last_spaceable_skyline.distance (skylines[j][-stacking_dir]) + dy = max (dy, (last_spaceable_skyline.distance (skyline[-stacking_dir]) + stacking_dir * (last_spaceable_element_pos - where) + spaceable_padding)); Real spaceable_min_distance = 0; @@ -263,12 +262,9 @@ Align_interface::internal_get_minimum_translations (Grob *me, } } - if (isinf (dy)) /* if the skyline is empty, maybe max_height is infinity_f */ - dy = 0.0; - dy = max (0.0, dy); down_skyline.raise (-stacking_dir * dy); - down_skyline.merge (skylines[j][stacking_dir]); + down_skyline.merge (skyline[stacking_dir]); where += stacking_dir * dy; translates.push_back (where); @@ -279,32 +275,18 @@ Align_interface::internal_get_minimum_translations (Grob *me, last_spaceable_element_pos = where; last_spaceable_skyline = down_skyline; } - } - - // So far, we've computed the translates for all the non-empty elements. - // Here, we set the translates for the empty elements: an empty element - // gets the same translation as the last non-empty element before it. - vector all_translates; - if (!translates.empty ()) - { - Real w = translates[0]; - for (vsize i = 0, j = 0; j < all_grobs.size (); j++) - { - if (i < elems.size () && all_grobs[j] == elems[i]) - w = translates[i++]; - all_translates.push_back (w); - } + last_nonempty_element = elems[j]; } if (pure) { SCM mta = me->get_property ("minimum-translations-alist"); mta = scm_cons (scm_cons (scm_cons (scm_from_int (start), scm_from_int (end)), - ly_floatvector2scm (all_translates)), + ly_floatvector2scm (translates)), mta); me->set_property ("minimum-translations-alist", mta); } - return all_translates; + return translates; } void diff --git a/lily/arpeggio.cc b/lily/arpeggio.cc index 018d9cd22d..4de173da06 100644 --- a/lily/arpeggio.cc +++ b/lily/arpeggio.cc @@ -163,7 +163,7 @@ Arpeggio::print (SCM smob) if (dir) { Font_metric *fm = Font_interface::get_default_font (me); - arrow = fm->find_by_name ("scripts.arpeggio.arrow." + to_string (dir)); + arrow = fm->find_by_name ("scripts.arpeggio.arrow." + ::to_string (dir)); heads[dir] -= dir * arrow.extent (Y_AXIS).length (); } diff --git a/lily/audio-item.cc b/lily/audio-item.cc index a41357b28f..7934c34c4a 100644 --- a/lily/audio-item.cc +++ b/lily/audio-item.cc @@ -44,11 +44,13 @@ Audio_item::Audio_item () { } -Audio_note::Audio_note (Pitch p, Moment m, bool tie_event, Pitch transposing) +Audio_note::Audio_note (Pitch p, Moment m, bool tie_event, Pitch transposing, + int velocity) : pitch_ (p), length_mom_ (m), transposing_ (transposing), dynamic_ (0), + extra_velocity_ (velocity), tied_ (0), tie_event_ (tie_event) { diff --git a/lily/completion-note-heads-engraver.cc b/lily/completion-note-heads-engraver.cc index 52a7d6c0bd..bddca70abb 100644 --- a/lily/completion-note-heads-engraver.cc +++ b/lily/completion-note-heads-engraver.cc @@ -188,25 +188,24 @@ Completion_heads_engraver::process_music () note that note_dur may be strictly less than left_to_do_ (say, if left_to_do_ == 5/8) */ - if (factor_.denominator () == 1 && factor_ > Rational (1, 1)) - note_dur = Duration (left_to_do_, false); - else - note_dur = Duration (left_to_do_ / factor_, false).compressed (factor_); + note_dur = Duration (left_to_do_ / factor_, false).compressed (factor_); } else { orig = unsmob_duration (note_events_[0]->get_property ("duration")); note_dur = *orig; - factor_ = note_dur.factor (); + SCM factor = get_property ("completionFactor"); + if (ly_is_procedure (factor)) + factor = scm_call_2 (factor, + context ()->self_scm (), + note_dur.smobbed_copy ()); + factor_ = robust_scm2rational (factor, note_dur.factor ()); left_to_do_ = orig->get_length (); } Moment nb = next_moment (note_dur.get_length ()); if (nb.main_part_ && nb < note_dur.get_length ()) { - if (factor_.denominator () == 1 && factor_.numerator () > 1) - note_dur = Duration (nb.main_part_, false); - else - note_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_); + note_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_); } do_nothing_until_ = now.main_part_ + note_dur.get_length (); @@ -314,6 +313,7 @@ ADD_TRANSLATOR (Completion_heads_engraver, "TieColumn ", /* read */ + "completionFactor " "completionUnit " "measureLength " "measurePosition " diff --git a/lily/completion-rest-engraver.cc b/lily/completion-rest-engraver.cc index 61255226ea..aeb6673f37 100644 --- a/lily/completion-rest-engraver.cc +++ b/lily/completion-rest-engraver.cc @@ -184,25 +184,24 @@ Completion_rest_engraver::process_music () note that rest_dur may be strictly less than left_to_do_ (say, if left_to_do_ == 5/8) */ - if (factor_.denominator () == 1 && factor_ > Rational (1, 1)) - rest_dur = Duration (left_to_do_, false); - else - rest_dur = Duration (left_to_do_ / factor_, false).compressed (factor_); + rest_dur = Duration (left_to_do_ / factor_, false).compressed (factor_); } else { orig = unsmob_duration (rest_events_[0]->get_property ("duration")); rest_dur = *orig; - factor_ = rest_dur.factor (); + SCM factor = get_property ("completionFactor"); + if (ly_is_procedure (factor)) + factor = scm_call_2 (factor, + context ()->self_scm (), + rest_dur.smobbed_copy ()); + factor_ = robust_scm2rational (factor, rest_dur.factor()); left_to_do_ = orig->get_length (); } Moment nb = next_moment (rest_dur.get_length ()); if (nb.main_part_ && nb < rest_dur.get_length ()) { - if (factor_.denominator () == 1 && factor_.numerator () > 1) - rest_dur = Duration (nb.main_part_, false); - else - rest_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_); + rest_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_); } do_nothing_until_ = now.main_part_ + rest_dur.get_length (); @@ -268,6 +267,7 @@ ADD_TRANSLATOR (Completion_rest_engraver, "Rest ", /* read */ + "completionFactor " "completionUnit " "middleCPosition " "measurePosition " diff --git a/lily/dot-column.cc b/lily/dot-column.cc index 6cba432639..9b4a3831b0 100644 --- a/lily/dot-column.cc +++ b/lily/dot-column.cc @@ -59,7 +59,7 @@ Dot_column::calc_positioning_done (SCM smob) vector dots = extract_grob_array (me, "dots"); - vector main_heads; + vector parent_stems; Real ss = 0; Grob *commonx = me; @@ -73,7 +73,7 @@ Dot_column::calc_positioning_done (SCM smob) commonx = stem->common_refpoint (commonx, X_AXIS); if (Stem::first_head (stem) == n) - main_heads.push_back (n); + parent_stems.push_back (stem); } } @@ -83,8 +83,8 @@ Dot_column::calc_positioning_done (SCM smob) extract_grob_set (me, "side-support-elements", support); Interval base_x; - for (vsize i = 0; i < main_heads.size (); i++) - base_x.unite (main_heads[i]->extent (commonx, X_AXIS)); + for (vsize i = 0; i < parent_stems.size (); i++) + base_x.unite (Stem::first_head (parent_stems[i])->extent (commonx, X_AXIS)); for (vsize i = 0; i < support.size (); i++) { @@ -152,6 +152,36 @@ Dot_column::calc_positioning_done (SCM smob) we instead must use their pure Y positions. */ vector_sort (dots, pure_position_less); + + SCM chord_dots_limit = me->get_property ("chord-dots-limit"); + if (scm_is_number (chord_dots_limit)) + { + // Sort dots by stem, then check for dots above the limit for each stem + vector > dots_each_stem (parent_stems.size ()); + for (vsize i = 0; i < dots.size (); i++) + if (Grob *stem = unsmob_grob (dots[i]->get_parent (Y_AXIS) + -> get_object ("stem"))) + for (vsize j = 0; j < parent_stems.size (); j++) + if (stem == parent_stems[j]) + { + dots_each_stem[j].push_back (dots[i]); + break; + } + for (vsize j = 0; j < parent_stems.size (); j++) + { + Interval chord = Stem::head_positions (parent_stems[j]); + int total_room = ((int) chord.length () + 2 + + scm_to_int (chord_dots_limit)) / 2; + int total_dots = dots_each_stem[j].size (); + // remove excessive dots from the ends of the stem + for (int first_dot = 0; total_dots > total_room; total_dots--) + if (0 == (total_dots - total_room) % 2) + dots_each_stem[j][first_dot++]->suicide (); + else + dots_each_stem[j][first_dot + total_dots - 1]->suicide (); + } + } + for (vsize i = dots.size (); i--;) { if (!dots[i]->is_live ()) @@ -236,6 +266,7 @@ ADD_INTERFACE (Dot_column, " dots so they do not clash with staff lines.", /* properties */ + "chord-dots-limit " "dots " "positioning-done " "direction " diff --git a/lily/drum-note-performer.cc b/lily/drum-note-performer.cc index 94c2d55ea3..09ab3f7cf4 100644 --- a/lily/drum-note-performer.cc +++ b/lily/drum-note-performer.cc @@ -62,9 +62,9 @@ Drum_note_performer::process_music () { SCM articulations = n->get_property ("articulations"); Stream_event *tie_event = 0; - for (SCM s = articulations; - !tie_event && scm_is_pair (s); - s = scm_cdr (s)) + Moment len = get_event_length (n, now_mom ()); + int velocity = 0; + for (SCM s = articulations; scm_is_pair (s); s = scm_cdr (s)) { Stream_event *ev = unsmob_stream_event (scm_car (s)); if (!ev) @@ -72,12 +72,16 @@ Drum_note_performer::process_music () if (ev->in_event_class ("tie-event")) tie_event = ev; + SCM f = ev->get_property ("midi-length"); + if (ly_is_procedure (f)) + len = robust_scm2moment (scm_call_2 (f, len.smobbed_copy (), + context ()->self_scm ()), + len); + velocity += robust_scm2int (ev->get_property ("midi-extra-velocity"), 0); } - Moment len = get_event_length (n, now_mom ()); - Audio_note *p = new Audio_note (*pit, len, - tie_event, Pitch (0, 0, 0)); + tie_event, Pitch (0, 0, 0), velocity); Audio_element_info info (p, n); announce_element (info); } diff --git a/lily/flag.cc b/lily/flag.cc index 31ddf349c9..f4fcce8e0e 100644 --- a/lily/flag.cc +++ b/lily/flag.cc @@ -105,7 +105,7 @@ Flag::glyph_name (SCM smob) char dir = (d == UP) ? 'u' : 'd'; string font_char = flag_style - + to_string (dir) + staffline_offs + to_string (log); + + ::to_string (dir) + staffline_offs + ::to_string (log); return ly_string2scm ("flags." + font_char); } @@ -143,11 +143,11 @@ Flag::print (SCM smob) string stroke_style = ly_scm2string (stroke_style_scm); if (!stroke_style.empty ()) { - string font_char = flag_style + to_string (dir) + stroke_style; + string font_char = flag_style + ::to_string (dir) + stroke_style; Stencil stroke = fm->find_by_name ("flags." + font_char); if (stroke.is_empty ()) { - font_char = to_string (dir) + stroke_style; + font_char = ::to_string (dir) + stroke_style; stroke = fm->find_by_name ("flags." + font_char); } if (stroke.is_empty ()) diff --git a/lily/freetype-error.cc b/lily/freetype-error.cc index 00e5cae351..88af76c1ae 100644 --- a/lily/freetype-error.cc +++ b/lily/freetype-error.cc @@ -31,7 +31,7 @@ const struct Freetype_error_message const char *err_msg; } ft_errors[] = -#include +#include FT_ERRORS_H ; diff --git a/lily/freetype.cc b/lily/freetype.cc index d7d4843ce8..55a3fb3780 100644 --- a/lily/freetype.cc +++ b/lily/freetype.cc @@ -20,8 +20,8 @@ #include "freetype.hh" #include "warn.hh" -#include -#include +#include FT_OUTLINE_H +#include FT_BBOX_H FT_Library freetype2_library; diff --git a/lily/hairpin.cc b/lily/hairpin.cc index 40e165dd6d..1d9007441b 100644 --- a/lily/hairpin.cc +++ b/lily/hairpin.cc @@ -236,7 +236,8 @@ Hairpin::print (SCM smob) } else { - if (Note_column::has_interface (b) + if (d == RIGHT // end at the left edge of a rest + && Note_column::has_interface (b) && Note_column::has_rests (b)) x_points[d] = e[-d]; else diff --git a/lily/include/audio-item.hh b/lily/include/audio-item.hh index 43ed2e05a9..9ded5301a1 100644 --- a/lily/include/audio-item.hh +++ b/lily/include/audio-item.hh @@ -82,7 +82,7 @@ public: class Audio_note : public Audio_item { public: - Audio_note (Pitch p, Moment m, bool tie_event, Pitch transposition); + Audio_note (Pitch p, Moment m, bool tie_event, Pitch transposition, int velocity); // with tieWaitForNote, there might be a skip between the tied notes! void tie_to (Audio_note *, Moment skip = 0); @@ -93,6 +93,7 @@ public: Moment length_mom_; Pitch transposing_; Audio_dynamic *dynamic_; + int extra_velocity_; Audio_note *tied_; bool tie_event_; diff --git a/lily/input.cc b/lily/input.cc index a091ef9855..2b29c828ba 100644 --- a/lily/input.cc +++ b/lily/input.cc @@ -142,7 +142,7 @@ string Input::line_number_string () const { if (source_file_) - return to_string (source_file_->get_line (start_)); + return ::to_string (source_file_->get_line (start_)); return "?"; } diff --git a/lily/lexer.ll b/lily/lexer.ll index 285de24267..71473faa30 100644 --- a/lily/lexer.ll +++ b/lily/lexer.ll @@ -673,6 +673,10 @@ BOM_UTF8 \357\273\277 yylval = SCM_UNSPECIFIED; return SCORE; } + \\score-lines { + yylval = SCM_UNSPECIFIED; + return SCORELINES; + } \\\" { start_command_quote (); } @@ -954,7 +958,7 @@ Lily_lexer::scan_escaped_word (const string &str) SCM sid = lookup_identifier (str); if (Music *m = unsmob_music (sid)) { - m->set_spot (override_input (last_input_)); + m->set_spot (override_input (here_input ())); } if (sid != SCM_UNDEFINED) @@ -974,7 +978,7 @@ Lily_lexer::scan_shorthand (const string &str) SCM sid = lookup_identifier (str); if (Music *m = unsmob_music (sid)) { - m->set_spot (override_input (last_input_)); + m->set_spot (override_input (here_input ())); } if (sid != SCM_UNDEFINED) @@ -1140,7 +1144,7 @@ Lily_lexer::eval_scm (SCM readerdata, char extra_token) if (Music *m = unsmob_music (v)) { if (!unsmob_input (m->get_property ("origin"))) - m->set_spot (override_input (last_input_)); + m->set_spot (override_input (here_input ())); } int token; @@ -1163,7 +1167,7 @@ Lily_lexer::eval_scm (SCM readerdata, char extra_token) if (Music *m = unsmob_music (sval)) { if (!unsmob_input (m->get_property ("origin"))) - m->set_spot (override_input (last_input_)); + m->set_spot (override_input (here_input ())); } return sval; diff --git a/lily/mensural-ligature.cc b/lily/mensural-ligature.cc index 3bffcb841c..4695eef986 100644 --- a/lily/mensural-ligature.cc +++ b/lily/mensural-ligature.cc @@ -168,7 +168,7 @@ internal_brew_primitive (Grob *me) duration_log--; case MLP_BREVIS: duration_log--; - suffix = to_string (duration_log) + color + suffix = ::to_string (duration_log) + color + (duration_log < -1 ? "lig" : "") + "mensural"; index = prefix + "s"; out = fm->find_by_name (index + "r" + suffix); diff --git a/lily/midi-item.cc b/lily/midi-item.cc index 54d00ff683..f98e3d05e1 100644 --- a/lily/midi-item.cc +++ b/lily/midi-item.cc @@ -193,8 +193,10 @@ Midi_time_signature::to_string () const Midi_note::Midi_note (Audio_note *a) : Midi_channel_item (a), audio_ (a), - dynamic_byte_ (a->dynamic_ && a->dynamic_->volume_ >= 0 - ? Byte (a->dynamic_->volume_ * 0x7f) : Byte (0x5a)) + dynamic_byte_ (min (max (Byte ((a->dynamic_ && a->dynamic_->volume_ >= 0 + ? a->dynamic_->volume_ * 0x7f : 0x5a) + + a->extra_velocity_), + Byte (0)), Byte (0x7f))) { } diff --git a/lily/midi-walker.cc b/lily/midi-walker.cc index b97630b0d1..0ae5265bd3 100644 --- a/lily/midi-walker.cc +++ b/lily/midi-walker.cc @@ -58,7 +58,9 @@ Midi_walker::Midi_walker (Audio_staff *audio_staff, Midi_track *track) index_ = 0; items_ = audio_staff->audio_items_; vector_sort (items_, audio_item_less); - last_tick_ = 0; + //Pieces that begin with grace notes start at negative times. This + //is OK - MIDI output doesn't use absolute ticks, only differences. + last_tick_ = items_.empty () ? 0 : items_[0]->audio_column_->ticks (); percussion_ = audio_staff->percussion_; merge_unisons_ = audio_staff->merge_unisons_; } diff --git a/lily/music.cc b/lily/music.cc index eea6a9ca81..629986d346 100644 --- a/lily/music.cc +++ b/lily/music.cc @@ -211,20 +211,6 @@ transpose_mutable (SCM alist, Pitch delta) if (Pitch *p = unsmob_pitch (val)) { Pitch transposed = p->transposed (delta); - if (transposed.get_alteration ().abs () > Rational (1, 1)) - { - string delta_str; - if (delta.get_alteration ().abs () > Rational (1, 1)) - delta_str = (delta.normalized ().to_string () - + " " + _ ("(normalized pitch)")); - else - delta_str = delta.to_string (); - - warning (_f ("Transposing %s by %s makes alteration larger than double", - p->to_string (), - delta_str)); - transposed = transposed.normalized (); - } if (prop == ly_symbol2scm ("tonic")) transposed = Pitch (-1, transposed.get_notename (), diff --git a/lily/note-head.cc b/lily/note-head.cc index 4bf8168eb1..5d8352e72d 100644 --- a/lily/note-head.cc +++ b/lily/note-head.cc @@ -38,7 +38,7 @@ internal_print (Grob *me, string *font_char) { string style = robust_symbol2string (me->get_property ("style"), "default"); - string suffix = to_string (min (robust_scm2int (me->get_property ("duration-log"), 2), 2)); + string suffix = ::to_string (min (robust_scm2int (me->get_property ("duration-log"), 2), 2)); if (style != "default") suffix = robust_scm2string (me->get_property ("glyph-name"), ""); diff --git a/lily/note-performer.cc b/lily/note-performer.cc index ddf9fe3921..81f35d70ac 100644 --- a/lily/note-performer.cc +++ b/lily/note-performer.cc @@ -36,6 +36,7 @@ protected: void process_music (); DECLARE_TRANSLATOR_LISTENER (note); + DECLARE_TRANSLATOR_LISTENER (breathing); private: vector note_evs_; vector notes_; @@ -65,9 +66,9 @@ Note_performer::process_music () { SCM articulations = n->get_property ("articulations"); Stream_event *tie_event = 0; - for (SCM s = articulations; - !tie_event && scm_is_pair (s); - s = scm_cdr (s)) + Moment len = get_event_length (n, now_mom ()); + int velocity = 0; + for (SCM s = articulations; scm_is_pair (s); s = scm_cdr (s)) { Stream_event *ev = unsmob_stream_event (scm_car (s)); if (!ev) @@ -75,19 +76,23 @@ Note_performer::process_music () if (ev->in_event_class ("tie-event")) tie_event = ev; + SCM f = ev->get_property ("midi-length"); + if (ly_is_procedure (f)) + len = robust_scm2moment (scm_call_2 (f, len.smobbed_copy (), + context ()->self_scm ()), + len); + velocity += robust_scm2int (ev->get_property ("midi-extra-velocity"), 0); } - Moment len = get_event_length (n, now_mom ()); - Audio_note *p = new Audio_note (*pitp, len, - tie_event, transposing); + tie_event, transposing, velocity); Audio_element_info info (p, n); announce_element (info); notes_.push_back (p); /* - Shorten previous note. If it was part of a tie, shorten - the first note in the tie. + Grace notes shorten the previous non-grace note. If it was + part of a tie, shorten the first note in the tie. */ if (now_mom ().grace_part_) { @@ -96,7 +101,11 @@ Note_performer::process_music () for (vsize i = 0; i < last_notes_.size (); i++) { Audio_note *tie_head = last_notes_[i]->tie_head (); - tie_head->length_mom_ += Moment (0, now_mom ().grace_part_); + Moment start = tie_head->audio_column_->when (); + //Shorten the note if it would overlap. It might + //not if there's a rest in between. + if (start + tie_head->length_mom_ > now_mom ()) + tie_head->length_mom_ = now_mom () - start; } } } @@ -124,6 +133,26 @@ Note_performer::listen_note (Stream_event *ev) note_evs_.push_back (ev); } +IMPLEMENT_TRANSLATOR_LISTENER (Note_performer, breathing) +void +Note_performer::listen_breathing (Stream_event *ev) +{ + //Shorten previous note if needed + SCM f = ev->get_property ("midi-length"); + if (ly_is_procedure (f)) + for (vsize i = 0; i < last_notes_.size (); i++) + { + Audio_note *tie_head = last_notes_[i]->tie_head (); + //Give midi-length the available time since the note started, + //including rests. It returns how much is left for the note. + Moment available = now_mom () - tie_head->audio_column_->when (); + Moment len = robust_scm2moment (scm_call_2 (f, available.smobbed_copy (), + context ()->self_scm ()), available); + if (len < tie_head->length_mom_) + tie_head->length_mom_ = len; + } +} + ADD_TRANSLATOR (Note_performer, /* doc */ "", diff --git a/lily/open-type-font.cc b/lily/open-type-font.cc index df6a744d0e..837a1f2300 100644 --- a/lily/open-type-font.cc +++ b/lily/open-type-font.cc @@ -23,7 +23,7 @@ using namespace std; -#include +#include FT_TRUETYPE_TABLES_H #include "dimensions.hh" #include "freetype.hh" diff --git a/lily/optimal-page-breaking.cc b/lily/optimal-page-breaking.cc index 3bddcad4ba..3ff29d01bd 100644 --- a/lily/optimal-page-breaking.cc +++ b/lily/optimal-page-breaking.cc @@ -75,7 +75,9 @@ Optimal_page_breaking::solve () if (page_count > 1 && best.systems_per_page_[page_count - 2] > 1) min_sys_count -= best.systems_per_page_[page_count - 2]; - min_sys_count = max (min_sys_count, (vsize)1); + if (min_sys_count > ideal_sys_count // subtraction wrapped around + || min_sys_count <= 0) + min_sys_count = 1; } } else diff --git a/lily/page-breaking.cc b/lily/page-breaking.cc index 9a6f8f40f2..7220857d91 100644 --- a/lily/page-breaking.cc +++ b/lily/page-breaking.cc @@ -195,7 +195,6 @@ compress_lines (const vector &orig) else { ret.push_back (orig[i]); - ret.back ().force_ = 0; } } return ret; @@ -632,7 +631,11 @@ Page_breaking::make_pages (vector lines_per_page, SCM systems) else config = layout.solution (rag); - last_page_force = layout.force (); + if ((ragged () && layout.force () < 0.0) + || isinf (layout.force ())) + warning (_f ("page %d has been compressed", page_num)); + else + last_page_force = layout.force (); systems_configs_fncounts = scm_cons (scm_cons (lines, config), systems_configs_fncounts); footnote_count += fn_lines; @@ -1169,9 +1172,8 @@ Page_breaking::min_page_count (vsize configuration, vsize first_page_num) cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[page_starter]); cur_page_height -= min_whitespace_at_bottom_of_page (cached_line_details_.back ()); - Real cur_height = cur_rod_height + ((ragged_last () || ragged ()) ? cur_spring_height : 0); if (!too_few_lines (line_count - cached_line_details_.back ().compressed_nontitle_lines_count_) - && cur_height > cur_page_height + && cur_rod_height > cur_page_height /* don't increase the page count if the last page had only one system */ && cur_rod_height > cached_line_details_.back ().full_height ()) ret++; @@ -1437,7 +1439,9 @@ Page_breaking::finalize_spacing_result (vsize configuration, Page_spacing_result line_penalty += uncompressed_line_details_[i].break_penalty_; } - for (vsize i = 0; i < res.force_.size (); i++) + for (vsize i = ragged () ? res.force_.size () - 1 : 0; + i < res.force_.size () - ragged_last (); + i++) { Real f = res.force_[i]; @@ -1545,9 +1549,11 @@ Page_breaking::space_systems_on_2_pages (vsize configuration, vsize first_page_n page1_penalty[i] = line_count_penalty (page1_line_count); page1_status[i] = line_count_status (page1_line_count); - if (ragged2) + if (ragged1) page2_force[page2_force.size () - 1 - i] = (page2.force_ < 0 && i + 1 < page1_force.size ()) ? infinity_f : 0; + else if (ragged2 && page2.force_ > 0) + page2_force[page2_force.size () - 1 - i] = 0.0; else page2_force[page2_force.size () - 1 - i] = page2.force_; page2_penalty[page2_penalty.size () - 1 - i] = line_count_penalty (page2_line_count); diff --git a/lily/page-layout-problem.cc b/lily/page-layout-problem.cc index 5885a66135..8b0be3a5f7 100644 --- a/lily/page-layout-problem.cc +++ b/lily/page-layout-problem.cc @@ -728,12 +728,12 @@ Page_layout_problem::solve_rod_spring_problem (bool ragged, Real fixed_force) Real overflow = spacer.configuration_length (spacer.force ()) - page_height_; if (ragged && overflow < 1e-6) - warning (_ ("cannot fit music on page: ragged-spacing was requested, but page was compressed")); + warning (_ ("ragged-bottom was specified, but page must be compressed")); else { - warning (_f ("cannot fit music on page: overflow is %f", + warning (_f ("compressing over-full page by %.1f staff-spaces", overflow)); - warning (_ ("compressing music to fit")); + force_ = -infinity_f; vsize space_count = solution_.size (); Real spacing_increment = overflow / (space_count - 2); for (vsize i = 2; i < space_count; i++) diff --git a/lily/page-spacing.cc b/lily/page-spacing.cc index a705827d22..a2915febb2 100644 --- a/lily/page-spacing.cc +++ b/lily/page-spacing.cc @@ -329,7 +329,7 @@ Page_spacer::calc_subproblem (vsize page, vsize line) space.prepend_system (lines_[page_start]); bool overfull = (space.rod_height_ > paper_height - || (ragged + || (ragged_ && (space.rod_height_ + space.spring_len_ > paper_height))); // This 'if' statement is a little hard to parse. It won't consider this configuration // if it is overfull unless the current configuration is the first one with this start diff --git a/lily/page-turn-page-breaking.cc b/lily/page-turn-page-breaking.cc index 2055214c82..047ba6a82f 100644 --- a/lily/page-turn-page-breaking.cc +++ b/lily/page-turn-page-breaking.cc @@ -232,7 +232,7 @@ Page_turn_page_breaking::solve () for (vsize i = 0; i < last_break_position (); i++) { calc_subproblem (i); - progress_indication (string ("[") + to_string (i + 1) + "]"); + progress_indication (string ("[") + ::to_string (i + 1) + "]"); } progress_indication ("\n"); diff --git a/lily/pango-font.cc b/lily/pango-font.cc index ee986fc94d..b148a5bc08 100644 --- a/lily/pango-font.cc +++ b/lily/pango-font.cc @@ -22,7 +22,7 @@ #define PANGO_ENABLE_BACKEND #include -#include +#include FT_XFREE86_H #include #include diff --git a/lily/paper-column-engraver.cc b/lily/paper-column-engraver.cc index cdbb2e8b00..cb39f58d1e 100644 --- a/lily/paper-column-engraver.cc +++ b/lily/paper-column-engraver.cc @@ -50,7 +50,7 @@ void Paper_column_engraver::finalize () { if (! (breaks_ % 8)) - progress_indication ("[" + to_string (breaks_) + "]"); + progress_indication ("[" + ::to_string (breaks_) + "]"); if (!made_columns_) { @@ -269,7 +269,7 @@ Paper_column_engraver::stop_translation_timestep () breaks_++; if (! (breaks_ % 8)) - progress_indication ("[" + to_string (breaks_) + "]"); + progress_indication ("[" + ::to_string (breaks_) + "]"); } context ()->get_score_context ()->unset_property (ly_symbol2scm ("forbidBreak")); diff --git a/lily/paper-column.cc b/lily/paper-column.cc index d586058fa0..4379ce1a1d 100644 --- a/lily/paper-column.cc +++ b/lily/paper-column.cc @@ -237,7 +237,7 @@ Paper_column::print (SCM p) { Paper_column *me = dynamic_cast (unsmob_grob (p)); - string r = to_string (Paper_column::get_rank (me)); + string r = ::to_string (Paper_column::get_rank (me)); Moment *mom = unsmob_moment (me->get_property ("when")); string when = mom ? mom->to_string () : "?/?"; diff --git a/lily/parser.yy b/lily/parser.yy index ab09f537b2..79a4b1114f 100644 --- a/lily/parser.yy +++ b/lily/parser.yy @@ -269,6 +269,7 @@ int yylex (YYSTYPE *s, YYLTYPE *loc, Lily_parser *parser); %token REST "\\rest" %token REVERT "\\revert" %token SCORE "\\score" +%token SCORELINES "\\score-lines" %token SEQUENTIAL "\\sequential" %token SET "\\set" %token SIMULTANEOUS "\\simultaneous" @@ -332,6 +333,7 @@ If we give names, Bison complains. %token CONTEXT_MOD_IDENTIFIER %token DRUM_PITCH %token PITCH_IDENTIFIER +%token PITCH_ARG %token DURATION_IDENTIFIER %token EVENT_IDENTIFIER %token EVENT_FUNCTION @@ -473,6 +475,7 @@ embedded_scm_bare_arg: { $$ = parser->lexer_->eval_scm_token ($1); } + | FRACTION | full_markup_list | context_modification | score_block @@ -511,6 +514,18 @@ scm_function_call: } ; +embedded_lilypond_number: + '-' embedded_lilypond_number + { + $$ = scm_difference ($2, SCM_UNDEFINED); + } + | bare_number_common + | UNSIGNED NUMBER_IDENTIFIER + { + $$ = scm_product ($1, $2); + } + ; + embedded_lilypond: /* empty */ { @@ -520,7 +535,31 @@ embedded_lilypond: // contains no source location. $$ = MAKE_SYNTAX ("void-music", @$); } - | identifier_init + | identifier_init_nonumber + | embedded_lilypond_number + | post_event post_events + { + $$ = scm_reverse_x ($2, SCM_EOL); + if (Music *m = unsmob_music ($1)) + { + if (m->is_mus_type ("post-event-wrapper")) + $$ = scm_append + (scm_list_2 (m->get_property ("elements"), + $$)); + else + $$ = scm_cons ($1, $$); + } + if (scm_is_pair ($$) + && scm_is_null (scm_cdr ($$))) + $$ = scm_car ($$); + else + { + Music * m = MY_MAKE_MUSIC ("PostEvents", @$); + m->set_property ("elements", $$); + $$ = m->unprotect (); + } + } + | multiplied_duration | music_embedded music_embedded music_list { $3 = scm_reverse_x ($3, SCM_EOL); if (unsmob_music ($2)) @@ -577,12 +616,8 @@ assignment: identifier_init: - score_block - | book_block - | bookpart_block - | output_def - | context_def_spec_block - | music_assign + identifier_init_nonumber + | number_expression | post_event_nofinger post_events { $$ = scm_reverse_x ($2, SCM_EOL); @@ -605,7 +640,15 @@ identifier_init: $$ = m->unprotect (); } } - | number_expression + ; + +identifier_init_nonumber: + score_block + | book_block + | bookpart_block + | output_def + | context_def_spec_block + | music_assign | FRACTION | string | embedded_scm @@ -1040,6 +1083,18 @@ music_embedded: { $$ = $3; } + | multiplied_duration post_events + { + Music *n = MY_MAKE_MUSIC ("NoteEvent", @$); + + parser->default_duration_ = *unsmob_duration ($1); + n->set_property ("duration", $1); + + if (scm_is_pair ($2)) + n->set_property ("articulations", + scm_reverse_x ($2, SCM_EOL)); + $$ = n->unprotect (); + } ; music_embedded_backup: @@ -1281,11 +1336,7 @@ grouped_music_list: */ function_arglist_nonbackup_common: - EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup FRACTION - { - $$ = check_scheme_arg (parser, @4, $4, $3, $2); - } - | EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup post_event_nofinger + EXPECT_OPTIONAL EXPECT_SCM function_arglist_nonbackup post_event_nofinger { $$ = check_scheme_arg (parser, @4, $4, $3, $2); } @@ -1490,13 +1541,14 @@ function_arglist_nonbackup_reparse: ; +// function_arglist_backup can't occur at the end of an argument +// list. It needs to be careful about avoiding lookahead only until +// it has made a decision whether or not to accept the parsed entity. +// At that point of time, music requiring lookahead to parse becomes +// fine. function_arglist_backup: - function_arglist_backup_common - | function_arglist_common - ; - -function_arglist_backup_common: - EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup embedded_scm_arg_closed + function_arglist_common + | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup embedded_scm_arg_closed { if (scm_is_true (scm_call_1 ($2, $4))) { @@ -1589,16 +1641,6 @@ function_arglist_backup_common: MYBACKUP (NUMBER_IDENTIFIER, $4, @4); } } - | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup FRACTION - { - if (scm_is_true (scm_call_1 ($2, $4))) - { - $$ = scm_cons ($4, $3); - } else { - $$ = scm_cons (loc_on_music (@3, $1), $3); - MYBACKUP (FRACTION, $4, @4); - } - } | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup '-' UNSIGNED { SCM n = scm_difference ($5, SCM_UNDEFINED); @@ -1642,9 +1684,15 @@ function_arglist_backup_common: } | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup PITCH_IDENTIFIER { - if (scm_is_true (scm_call_1 ($2, $4))) + SCM m = make_music_from_simple (parser, @4, $4); + if (unsmob_music (m) && scm_is_true (scm_call_1 ($2, m))) { - $$ = scm_cons ($4, $3); + MYREPARSE (@4, $2, PITCH_IDENTIFIER, $4); + $$ = $3; + } else if (scm_is_true (scm_call_1 ($2, $4))) + { + MYREPARSE (@4, $2, PITCH_ARG, $4); + $$ = $3; } else { $$ = scm_cons (loc_on_music (@3, $1), $3); MYBACKUP (PITCH_IDENTIFIER, $4, @4); @@ -1652,10 +1700,15 @@ function_arglist_backup_common: } | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup NOTENAME_PITCH { - if (scm_is_true (scm_call_1 ($2, $4))) + SCM m = make_music_from_simple (parser, @4, $4); + if (unsmob_music (m) && scm_is_true (scm_call_1 ($2, m))) { MYREPARSE (@4, $2, NOTENAME_PITCH, $4); $$ = $3; + } else if (scm_is_true (scm_call_1 ($2, $4))) + { + MYREPARSE (@4, $2, PITCH_ARG, $4); + $$ = $3; } else { $$ = scm_cons (loc_on_music (@3, $1), $3); MYBACKUP (NOTENAME_PITCH, $4, @4); @@ -1663,10 +1716,15 @@ function_arglist_backup_common: } | EXPECT_OPTIONAL EXPECT_SCM function_arglist_backup TONICNAME_PITCH { - if (scm_is_true (scm_call_1 ($2, $4))) + SCM m = make_music_from_simple (parser, @4, $4); + if (unsmob_music (m) && scm_is_true (scm_call_1 ($2, m))) { MYREPARSE (@4, $2, TONICNAME_PITCH, $4); $$ = $3; + } else if (scm_is_true (scm_call_1 ($2, $4))) + { + MYREPARSE (@4, $2, PITCH_ARG, $4); + $$ = $3; } else { $$ = scm_cons (loc_on_music (@3, $1), $3); MYBACKUP (TONICNAME_PITCH, $4, @4); @@ -1723,6 +1781,11 @@ function_arglist_backup_common: (parser, @3, $3), $1, $2); } + | function_arglist_backup REPARSE pitch_arg + { + $$ = check_scheme_arg (parser, @3, + $3, $1, $2); + } | function_arglist_backup REPARSE bare_number_common { $$ = check_scheme_arg (parser, @3, @@ -1774,11 +1837,6 @@ function_arglist_common: $$ = check_scheme_arg (parser, @3, $3, $2, $1); } - | EXPECT_SCM function_arglist_optional FRACTION - { - $$ = check_scheme_arg (parser, @3, - $3, $2, $1); - } | EXPECT_SCM function_arglist_optional post_event_nofinger { $$ = check_scheme_arg (parser, @3, @@ -1942,11 +2000,6 @@ function_arglist_closed_common: $$ = check_scheme_arg (parser, @3, $3, $2, $1); } - | EXPECT_SCM function_arglist_optional FRACTION - { - $$ = check_scheme_arg (parser, @3, - $3, $2, $1); - } | function_arglist_common_reparse REPARSE SCM_ARG { $$ = check_scheme_arg (parser, @3, @@ -2155,8 +2208,8 @@ re_rhythmed_music: ; context_change: - CHANGE STRING '=' STRING { - $$ = MAKE_SYNTAX ("context-change", @$, scm_string_to_symbol ($2), $4); + CHANGE symbol '=' simple_string { + $$ = MAKE_SYNTAX ("context-change", @$, $2, $4); } ; @@ -2476,7 +2529,6 @@ scalar: { $$ = scm_difference ($2, SCM_UNDEFINED); } - | FRACTION | STRING | full_markup ; @@ -2497,13 +2549,19 @@ event_chord: } } %prec ':' | simple_chord_elements post_events { - SCM elts = ly_append2 ($1, scm_reverse_x ($2, SCM_EOL)); - - Input i; - /* why is this giving wrong start location? -ns - * i = @$; */ - i.set_location (@1, @2); - $$ = MAKE_SYNTAX ("event-chord", i, elts); + if (scm_is_pair ($2)) { + if (unsmob_pitch ($1)) + $1 = make_chord_elements (@1, + $1, + parser->default_duration_.smobbed_copy (), + SCM_EOL); + + SCM elts = ly_append2 ($1, scm_reverse_x ($2, SCM_EOL)); + + $$ = MAKE_SYNTAX ("event-chord", @1, elts); + } else if (!unsmob_pitch ($1)) + $$ = MAKE_SYNTAX ("event-chord", @1, $1); + // A mere pitch drops through. } %prec ':' | CHORD_REPETITION optional_notemode_duration post_events { Input i; @@ -2756,11 +2814,18 @@ direction_reqd_event: } | script_abbreviation { SCM s = parser->lexer_->lookup_identifier ("dash" + ly_scm2string ($1)); - Music *a = MY_MAKE_MUSIC ("ArticulationEvent", @$); - if (scm_is_string (s)) + if (scm_is_string (s)) { + Music *a = MY_MAKE_MUSIC ("ArticulationEvent", @$); a->set_property ("articulation-type", s); - else parser->parser_error (@1, _ ("expecting string as script definition")); - $$ = a->unprotect (); + $$ = a->unprotect (); + } else if (ly_prob_type_p (s, ly_symbol2scm ("ArticulationEvent"))) { + $$ = s; + if (Music *original = unsmob_music (s)) { + Music *a = original->clone (); + a->set_spot (parser->lexer_->override_input (@$)); + $$ = a->unprotect (); + } + } else parser->parser_error (@1, _ ("expecting string or ArticulationEvent as script definition")); } ; @@ -2824,7 +2889,25 @@ steno_tonic_pitch: pitch: steno_pitch - | PITCH_IDENTIFIER + | PITCH_IDENTIFIER quotes { + if (!scm_is_eq (SCM_INUM0, $2)) + { + Pitch p = *unsmob_pitch ($1); + p = p.transposed (Pitch (scm_to_int ($2),0,0)); + $$ = p.smobbed_copy (); + } + } + ; + +pitch_arg: + PITCH_ARG quotes { + if (!scm_is_eq (SCM_INUM0, $2)) + { + Pitch p = *unsmob_pitch ($1); + p = p.transposed (Pitch (scm_to_int ($2),0,0)); + $$ = p.smobbed_copy (); + } + } ; gen_text_def: @@ -3136,6 +3219,7 @@ simple_element: } ; +// Can return a single pitch rather than a list. simple_chord_elements: new_chord { if (!parser->lexer_->is_chord_state ()) @@ -3174,9 +3258,13 @@ lyric_element_music: } %prec ':' ; +// Can return a single pitch rather than a list. new_chord: - steno_tonic_pitch optional_notemode_duration { - $$ = make_chord_elements (@$, $1, $2, SCM_EOL); + steno_tonic_pitch maybe_notemode_duration { + if (SCM_UNBNDP ($2)) + $$ = $1; + else + $$ = make_chord_elements (@$, $1, $2, SCM_EOL); } | steno_tonic_pitch optional_notemode_duration chord_separator chord_items { SCM its = scm_reverse_x ($4, SCM_EOL); @@ -3240,10 +3328,10 @@ step_number: ; tempo_range: - UNSIGNED { + unsigned_number { $$ = $1; - } - | UNSIGNED '-' UNSIGNED { + } %prec ':' + | unsigned_number '-' unsigned_number { $$ = scm_cons ($1, $3); } ; @@ -3312,6 +3400,23 @@ bare_number_closed: unsigned_number: UNSIGNED | NUMBER_IDENTIFIER + { + if (!scm_is_integer ($1) + || scm_is_true (scm_negative_p ($1))) + { + parser->parser_error (@1, _("not an unsigned integer")); + $$ = SCM_INUM0; + } + } + | embedded_scm + { + if (!scm_is_integer ($1) + || scm_is_true (scm_negative_p ($1))) + { + parser->parser_error (@1, _("not an unsigned integer")); + $$ = SCM_INUM0; + } + } ; exclamations: @@ -3355,7 +3460,7 @@ full_markup: ; markup_top: - simple_markup_list { + markup_list { $$ = scm_list_2 (ly_lily_module_constant ("line-markup"), $1); } | markup_head_1_list simple_markup @@ -3383,7 +3488,7 @@ markup_scm: ; -simple_markup_list: +markup_list: markup_composed_list { $$ = $1; } @@ -3401,22 +3506,11 @@ markup_uncomposed_list: { $$ = $2; } - ; - -markup_list: - simple_markup_list - | markup_score - { - $$ = scm_list_1 (scm_list_2 (ly_lily_module_constant ("score-lines-markup-list"), $1)); - } - ; - -markup_score: - SCORE { + | SCORELINES { SCM nn = parser->lexer_->lookup_identifier ("pitchnames"); parser->lexer_->push_note_state (nn); } '{' score_body '}' { - $$ = $4; + $$ = scm_list_1 (scm_list_2 (ly_lily_module_constant ("score-lines-markup-list"), $4)); parser->lexer_->pop_state (); } ; @@ -3439,7 +3533,7 @@ markup_braced_list_body: | markup_braced_list_body markup { $$ = scm_cons ($2, $1); } - | markup_braced_list_body simple_markup_list { + | markup_braced_list_body markup_list { $$ = scm_reverse_x ($2, $1); } ; @@ -3488,6 +3582,13 @@ simple_markup: STRING { $$ = make_simple_markup ($1); } + | SCORE { + SCM nn = parser->lexer_->lookup_identifier ("pitchnames"); + parser->lexer_->push_note_state (nn); + } '{' score_body '}' { + $$ = scm_list_2 (ly_lily_module_constant ("score-markup"), $4); + parser->lexer_->pop_state (); + } | MARKUP_FUNCTION markup_command_basic_arguments { $$ = scm_cons ($1, scm_reverse_x ($2, SCM_EOL)); } @@ -3495,10 +3596,6 @@ simple_markup: { $$ = $2; } - | markup_score - { - $$ = scm_list_2 (ly_lily_module_constant ("score-markup"), $1); - } ; markup: @@ -3736,9 +3833,12 @@ make_music_from_simple (Lily_parser *parser, Input loc, SCM simple) parser->default_duration_.smobbed_copy ()); } else if (parser->lexer_->is_chord_state ()) { if (unsmob_pitch (simple)) - return make_chord_elements (loc, simple, - parser->default_duration_.smobbed_copy (), - SCM_EOL); + return MAKE_SYNTAX + ("event-chord", + loc, + make_chord_elements (loc, simple, + parser->default_duration_.smobbed_copy (), + SCM_EOL)); } return simple; } diff --git a/lily/partial-iterator.cc b/lily/partial-iterator.cc index 7c3b3e965b..681479a69e 100644 --- a/lily/partial-iterator.cc +++ b/lily/partial-iterator.cc @@ -38,14 +38,34 @@ Partial_iterator::process (Moment m) if (Duration * dur = unsmob_duration (get_music ()->get_property ("duration"))) { - Context *ctx = get_outlet (); - Moment now = ctx->now_mom (); - if (now.main_part_ > Rational (0)) - get_music ()->origin ()-> - warning (_ ("trying to use \\partial after the start of a piece")); - Moment length = Moment (dur->get_length ()); - now = Moment (0, now.grace_part_); - ctx->set_property ("measurePosition", (now - length).smobbed_copy ()); + // Partial_iterator is an iterator rather than an engraver, so + // the active context it is getting called in does not depend on + // which context definition the engraver might be defined. + // + // Using where_defined to find the context where measurePosition + // should be overwritten does not actually work since the + // Timing_translator does not set measurePosition when + // initializing. + + Context *timing = unsmob_context (scm_call_2 (ly_lily_module_constant ("ly:context-find"), + get_outlet ()->self_scm (), + ly_symbol2scm ("Timing"))); + + if (!timing) + programming_error ("missing Timing in \\partial"); + else + { + Moment mp = robust_scm2moment (timing->get_property ("measurePosition"), + Rational (0)); + + if (mp.main_part_ > Rational (0)) + mp.main_part_ = measure_length (timing); + else + mp.main_part_ = 0; + + Moment length = Moment (dur->get_length ()); + timing->set_property ("measurePosition", (mp - length).smobbed_copy ()); + } } else programming_error ("invalid duration in \\partial"); diff --git a/lily/performance.cc b/lily/performance.cc index 4e19544d41..dfd23a871a 100644 --- a/lily/performance.cc +++ b/lily/performance.cc @@ -56,7 +56,7 @@ Performance::output (Midi_stream &midi_stream) const for (vsize i = 0; i < audio_staffs_.size (); i++) { Audio_staff *s = audio_staffs_[i]; - debug_output ("[" + to_string (i), true); + debug_output ("[" + ::to_string (i), true); s->output (midi_stream, i, ports_); debug_output ("]", false); } diff --git a/lily/rest.cc b/lily/rest.cc index c4c5de1e73..3a448546b0 100644 --- a/lily/rest.cc +++ b/lily/rest.cc @@ -217,7 +217,7 @@ Rest::glyph_name (Grob *me, int durlog, const string &style, bool try_ledgers, actual_style = ""; } - return ("rests." + to_string (durlog) + (is_ledgered ? "o" : "") + return ("rests." + ::to_string (durlog) + (is_ledgered ? "o" : "") + actual_style); } diff --git a/lily/script-column.cc b/lily/script-column.cc index 0a014a3800..8c963929bf 100644 --- a/lily/script-column.cc +++ b/lily/script-column.cc @@ -152,11 +152,12 @@ Script_column::order_grobs (vector grobs) { SCM last_outside_staff = last->get_property ("outside-staff-priority"); /* - if outside_staff_priority is missing for previous grob, just - use it as a support for the current grob + if outside_staff_priority is missing for previous grob, + use all the scripts so far as support for the current grob */ if (!scm_is_number (last_outside_staff)) - Side_position_interface::add_support (g, last); + for (SCM t = ss; !scm_is_eq (t, s); t = scm_cdr (t)) + Side_position_interface::add_support (g, unsmob_grob (scm_car (t))); /* if outside_staff_priority is missing or is equal to original outside_staff_priority of previous grob, set new diff --git a/lily/simultaneous-music-iterator.cc b/lily/simultaneous-music-iterator.cc index 3b891e8e79..3e0ad4fae7 100644 --- a/lily/simultaneous-music-iterator.cc +++ b/lily/simultaneous-music-iterator.cc @@ -63,7 +63,7 @@ Simultaneous_music_iterator::construct_children () SCM name = ly_symbol2scm (get_outlet ()->context_name ().c_str ()); Context *c = (j && create_separate_contexts_) - ? get_outlet ()->find_create_context (name, to_string (j), SCM_EOL) + ? get_outlet ()->find_create_context (name, ::to_string (j), SCM_EOL) : get_outlet (); if (!c) diff --git a/lily/source-file.cc b/lily/source-file.cc index 26426ae8af..788c78a69e 100644 --- a/lily/source-file.cc +++ b/lily/source-file.cc @@ -181,8 +181,8 @@ Source_file::file_line_column_string (char const *context_str0) const int l, ch, col, offset; get_counts (context_str0, &l, &ch, &col, &offset); - return name_string () + ":" + to_string (l) - + ":" + to_string (col + 1); + return name_string () + ":" + ::to_string (l) + + ":" + ::to_string (col + 1); } } @@ -196,8 +196,8 @@ Source_file::quote_input (char const *pos_str0) const get_counts (pos_str0, &l, &ch, &col, &offset); string line = line_string (pos_str0); string context = line.substr (0, offset) - + to_string ('\n') - + to_string (' ', col) + + ::to_string ('\n') + + ::to_string (' ', col) + line.substr (offset, line.length () - offset); return context; } diff --git a/lily/system-start-delimiter.cc b/lily/system-start-delimiter.cc index d4b523c06c..a45b7dd13a 100644 --- a/lily/system-start-delimiter.cc +++ b/lily/system-start-delimiter.cc @@ -169,7 +169,7 @@ System_start_delimiter::staff_brace (Grob *me, Real y) } while (hi - lo > 1); - Stencil stil (fm->find_by_name ("brace" + to_string (lo))); + Stencil stil (fm->find_by_name ("brace" + ::to_string (lo))); stil.translate_axis (-b[X_AXIS].length () / 2, X_AXIS); stil.translate_axis (-0.2, X_AXIS); diff --git a/lily/system.cc b/lily/system.cc index 1ec46fbaf6..ad4d0bab77 100644 --- a/lily/system.cc +++ b/lily/system.cc @@ -223,7 +223,7 @@ System::get_paper_systems () scm_vector_set_x (lines, scm_from_int (i), system->get_paper_system ()); - debug_output (to_string (i) + "]", false); + debug_output (::to_string (i) + "]", false); } return lines; } diff --git a/lily/time-signature.cc b/lily/time-signature.cc index f00c2563f6..89f20278bf 100644 --- a/lily/time-signature.cc +++ b/lily/time-signature.cc @@ -67,7 +67,7 @@ Time_signature::special_time_signature (Grob *me, SCM scm_style, int n, int d) return numbered_time_signature (me, n, d); if ((style == "default") || (style == "")) - style = to_string ("C"); + style = ::to_string ("C"); if (style == "C") { @@ -77,7 +77,7 @@ Time_signature::special_time_signature (Grob *me, SCM scm_style, int n, int d) return numbered_time_signature (me, n, d); } - string char_name = style + to_string (n) + to_string (d); + string char_name = style + ::to_string (n) + ::to_string (d); me->set_property ("font-encoding", ly_symbol2scm ("fetaMusic")); Stencil out = Font_interface::get_default_font (me) ->find_by_name ("timesig." + char_name); @@ -100,9 +100,9 @@ Time_signature::numbered_time_signature (Grob *me, int num, int den) chain); SCM sn = Text_interface::interpret_markup (me->layout ()->self_scm (), chain, - ly_string2scm (to_string (num))); + ly_string2scm (::to_string (num))); SCM sd = Text_interface::interpret_markup (me->layout ()->self_scm (), chain, - ly_string2scm (to_string (den))); + ly_string2scm (::to_string (den))); Stencil n = *unsmob_stencil (sn); Stencil d = *unsmob_stencil (sd); diff --git a/lily/ttf.cc b/lily/ttf.cc index eaeb67adfb..6d7f97bf37 100644 --- a/lily/ttf.cc +++ b/lily/ttf.cc @@ -20,7 +20,7 @@ #include #include "freetype.hh" -#include +#include FT_TRUETYPE_TABLES_H #include "international.hh" #include "memory-stream.hh" diff --git a/lily/volta-repeat-iterator.cc b/lily/volta-repeat-iterator.cc index 2e386e6fd1..e9b858de39 100644 --- a/lily/volta-repeat-iterator.cc +++ b/lily/volta-repeat-iterator.cc @@ -33,17 +33,27 @@ protected: virtual void next_element (bool); virtual void construct_children (); virtual void process (Moment); + virtual void derived_mark () const; bool first_time_; int alt_count_; int rep_count_; int done_count_; + SCM alt_restores_; }; Volta_repeat_iterator::Volta_repeat_iterator () { done_count_ = alt_count_ = rep_count_ = 0; first_time_ = true; + alt_restores_ = SCM_EOL; +} + +void +Volta_repeat_iterator::derived_mark () const +{ + scm_gc_mark (alt_restores_); + Sequential_iterator::derived_mark (); } SCM @@ -94,17 +104,46 @@ Volta_repeat_iterator::next_element (bool side_effect) { if (alt_count_) { - string repstr = to_string (rep_count_ - alt_count_ + done_count_) + "."; - if (done_count_ > 1) + string repstr = ::to_string (rep_count_ - alt_count_ + done_count_) + "."; + if (done_count_ <= 1) { + alt_restores_ = SCM_EOL; + if (to_boolean (get_outlet ()->get_property ("timing"))) + { + for (SCM lst = get_outlet ()->get_property ("alternativeRestores"); + scm_is_pair (lst); + lst = scm_cdr (lst)) + { + SCM res = SCM_EOL; + Context *t = get_outlet ()->where_defined (scm_car (lst), + &res); + if (t) + { + alt_restores_ = scm_cons + (scm_list_3 (t->self_scm (), scm_car (lst), res), + alt_restores_); + } + } + } + } + else + { + add_repeat_command (scm_list_n (ly_symbol2scm ("volta"), SCM_BOOL_F, SCM_UNDEFINED)); if (done_count_ - 1 < alt_count_) add_repeat_command (ly_symbol2scm ("end-repeat")); + + if (to_boolean (get_outlet ()->get_property ("timing"))) + { + for (SCM p = alt_restores_; scm_is_pair (p); p = scm_cdr (p)) + scm_apply_0 (ly_lily_module_constant ("ly:context-set-property!"), + scm_car (p)); + } } if (done_count_ == 1 && alt_count_ < rep_count_) - repstr = "1.--" + to_string (rep_count_ - alt_count_ + done_count_) + "."; + repstr = "1.--" + ::to_string (rep_count_ - alt_count_ + done_count_) + "."; if (done_count_ <= alt_count_) add_repeat_command (scm_list_n (ly_symbol2scm ("volta"), diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly index 9c8547dd7d..dfaa47e12f 100644 --- a/ly/engraver-init.ly +++ b/ly/engraver-init.ly @@ -169,7 +169,6 @@ contained staves are not connected vertically." \name RhythmicStaff \alias "Staff" - \override BarLine.bar-extent = #'(-2 . 2) \override VoltaBracket.staff-padding = #3 \override StaffSymbol.line-count = #1 @@ -609,6 +608,7 @@ automatically when an output definition (a @code{\\score} or doubleRepeatType = #":..:" startRepeatType = #".|:" endRepeatType = #":|." + alternativeRestores = #'(measurePosition measureLength) barNumberVisibility = #first-bar-number-invisible-and-no-parenthesized-bar-numbers barNumberFormatter = #robust-bar-number-function clefTranspositionFormatter = #clef-transposition-markup @@ -634,6 +634,8 @@ automatically when an output definition (a @code{\\score} or autoBeaming = ##t autoBeamCheck = #default-auto-beam-check + completionFactor = #unity-if-multimeasure + scriptDefinitions = #default-script-alist pedalSustainStrings = #'("Ped." "*Ped." "*") diff --git a/ly/music-functions-init.ly b/ly/music-functions-init.ly index bf738074cd..83c2535af5 100644 --- a/ly/music-functions-init.ly +++ b/ly/music-functions-init.ly @@ -221,6 +221,14 @@ barNumberCheck = "Barcheck failed got ~a expect ~a" cbn n)))))) +beamExceptions = +#(define-scheme-function (parser location music) (ly:music?) + (_i "Extract a value suitable for setting +@code{Timing.beamExceptions} from the given pattern with explicit +beams in @var{music}. A bar check @code{|} has to be used between +bars of patterns in order to reset the timing.") + (extract-beam-exceptions music)) + bendAfter = #(define-event-function (parser location delta) (real?) (_i "Create a fall or doit of pitch interval @var{delta}.") @@ -245,7 +253,15 @@ bookOutputSuffix = breathe = #(define-music-function (parser location) () (_i "Insert a breath mark.") - (make-music 'BreathingEvent)) + (make-music 'BreathingEvent + 'midi-length + (lambda (len context) + ;;Shorten by half, or by up to a second, but always by a power of 2 + (let* ((desired (min (ly:moment-main (seconds->moment 1 context)) + (* (ly:moment-main len) 1/2))) + (scale (inexact->exact (ceiling (/ (log desired) (log 1/2))))) + (breath (ly:make-moment (expt 1/2 scale)))) + (ly:moment-sub len breath))))) clef = #(define-music-function (parser location type) (string?) diff --git a/ly/performer-init.ly b/ly/performer-init.ly index 0a1ac2d374..1a383607f1 100644 --- a/ly/performer-init.ly +++ b/ly/performer-init.ly @@ -26,6 +26,7 @@ \name Staff \accepts Voice \accepts CueVoice + \accepts NullVoice \defaultchild Voice \consists "Staff_performer" @@ -181,6 +182,20 @@ \name "Devnull" } +\context { + \type "Performer_Group" + \name NullVoice + \alias Staff + \alias Voice + %% needed for melismata + %% TODO: at least the tie performer likely does not work without the + %% Note_performer, but I don't know how to shut note output off in + %% MIDI. + \consists "Tie_performer" + \consists "Beam_performer" + \consists "Slur_performer" +} + \context { \Staff \name TabStaff diff --git a/ly/script-init.ly b/ly/script-init.ly index 0cb37947e7..3b3e39ed31 100644 --- a/ly/script-init.ly +++ b/ly/script-init.ly @@ -2,18 +2,10 @@ \version "2.17.25" -% code char abbreviations -dashHat = "marcato" -dashPlus = "stopped" -dashDash = "tenuto" -dashBang = "staccatissimo" -dashLarger = "accent" -dashDot = "staccato" -dashUnderscore = "portato" - harmonic = #(make-music 'HarmonicEvent) -accent = #(make-articulation "accent") +accent = #(make-articulation "accent" + 'midi-extra-velocity 20) coda = #(make-articulation "coda") downbow = #(make-articulation "downbow") downmordent = #(make-articulation "downmordent") @@ -26,10 +18,15 @@ lheel = #(make-articulation "lheel") lineprall = #(make-articulation "lineprall") longfermata = #(make-articulation "longfermata") ltoe = #(make-articulation "ltoe") -marcato = #(make-articulation "marcato") +marcato = #(make-articulation "marcato" + 'midi-extra-velocity 40) mordent = #(make-articulation "mordent") open = #(make-articulation "open") -portato = #(make-articulation "portato") + +portato = #(make-articulation "portato" + 'midi-length + (lambda (len context) + (ly:moment-mul len (ly:make-moment 3/4)))) prall = #(make-articulation "prall") pralldown = #(make-articulation "pralldown") prallmordent = #(make-articulation "prallmordent") @@ -42,8 +39,17 @@ segno = #(make-articulation "segno") shortfermata = #(make-articulation "shortfermata") signumcongruentiae = #(make-articulation "signumcongruentiae") snappizzicato = #(make-articulation "snappizzicato") -staccatissimo = #(make-articulation "staccatissimo") -staccato = #(make-articulation "staccato") +staccatissimo = #(make-articulation "staccatissimo" + 'midi-length + (lambda (len context) + (seconds->moment 1/8 context)) + 'midi-extra-velocity 6) +staccato = #(make-articulation "staccato" + 'midi-length + (lambda (len context) + (moment-min (ly:moment-mul len (ly:make-moment 1/2)) + (seconds->moment 1/2 context))) + 'midi-extra-velocity 4) stopped = #(make-articulation "stopped") tenuto = #(make-articulation "tenuto") thumb = \finger \markup \scale #(cons (magstep 5) (magstep 5)) @@ -55,3 +61,12 @@ upmordent = #(make-articulation "upmordent") upprall = #(make-articulation "upprall") varcoda = #(make-articulation "varcoda") verylongfermata = #(make-articulation "verylongfermata") + +% code char abbreviations +dashHat = \marcato +dashPlus = \stopped +dashDash = \tenuto +dashBang = \staccatissimo +dashLarger = \accent +dashDot = \staccato +dashUnderscore = \portato diff --git a/ps/music-drawing-routines.ps b/ps/music-drawing-routines.ps index 3e62f0366e..03df7c03cb 100644 --- a/ps/music-drawing-routines.ps +++ b/ps/music-drawing-routines.ps @@ -1,4 +1,4 @@ -%!PS-Adobe-1.0: music-drawing-routines.ps +%!PS-Adobe-2.0 % % Functions for direct and embedded PostScript @@ -63,12 +63,7 @@ bind def 0 setgray 0 setlinecap % Prepare graphics state 1 setlinewidth 0 setlinejoin 10 setmiterlimit [ ] 0 setdash newpath - /languagelevel where % If level not equal to 1 then - {pop languagelevel % set strokeadjust and - 1 ne % overprint to their defaults. - {false setstrokeadjust false setoverprint - } if - } if + false setoverprint } bind def /EndEPSF { %def @@ -77,11 +72,18 @@ bind def b4_Inc_state restore } bind def -/stroke_and_fill { +/stroke_and_fill? { + { gsave - stroke + false setstrokeadjust + stroke grestore fill + } + { + stroke + } + ifelse } bind def /vector_add { % x1 y1 x2 y2 vector_add x1+x2 y1+y2 @@ -95,30 +97,104 @@ bind def /draw_round_box % width height x y blot { - dup - 0.0 gt { - setlinewidth % w h x y - rmoveto % w h - 2 copy 0 ne exch 0 ne and + 0 max setlinewidth + matrix currentmatrix 5 1 roll + currentpoint translate newpath translate + 2 copy 0 min exch 0 min exch translate + abs exch abs exch + currentlinewidth 0 eq + { % straight corners + 2 copy 2 mul gt + { % horizontal + 0 1 index 2 div moveto + setlinewidth + 0 rlineto + 0 setlinecap + stroke + } + { + 2 copy exch 2 mul gt + { % vertical + 1 index 2 div 0 moveto + exch setlinewidth + 0 exch rlineto + 0 setlinecap + stroke + } + { + 0 0 4 2 roll rectfill + } + ifelse + } + ifelse + } + { % rounded corners + 2 copy 0 eq exch 0 eq or + { % line shape + 0 0 moveto + rlineto + 1 setlinecap + stroke + 0 setlinecap + } + { % full shape + currentstrokeadjust { + currentlinewidth 2 div + 0 0 2 index 180 270 arc + 2 index 0 2 index 270 360 arc + 3 copy 0 90 arc + 0 2 index 3 -1 roll 90 180 arc + closepath + 2 copy 2 mul gt + { % horizontal + 2 copy add currentlinewidth add 10 add % large enough + 0 1 index neg moveto + 2 index 1 index neg lineto + 2 index 1 index lineto + 0 exch lineto closepath + gsave clip newpath + 0 1 index 2 div moveto + currentlinewidth add setlinewidth + 0 rlineto + 2 setlinecap + stroke + grestore + } { - 0 setlinecap - 1 setlinejoin - currentpoint % w h x1 y1 - 4 2 roll % x1 y1 w h - 4 copy - rectfill - rectstroke - } { - 1 setlinecap - rlineto stroke - } ifelse - } { - pop % w h x y - rmoveto % w h - currentpoint % w h x1 y1 - 4 2 roll % x1 y1 w h - rectfill - } ifelse + 2 copy exch 2 mul gt + { % vertical + 2 copy add currentlinewidth add 10 add % large enough + dup neg 0 moveto + dup 0 lineto + dup 2 index lineto + neg 1 index lineto closepath + gsave clip newpath + 1 index 2 div 0 moveto + exch currentlinewidth add setlinewidth + 0 exch rlineto + 2 setlinecap + stroke + grestore + } + { + pop pop + fill + } + ifelse + } + ifelse + newpath + } + { + 1 setlinejoin + 0 0 4 2 roll 4 copy rectstroke rectfill + } + ifelse + } + ifelse + } + ifelse + setmatrix } bind def /draw_polygon % fill? x(n) y(n) x(n-1) y(n-1) ... x(0) y(0) n blot @@ -136,11 +212,7 @@ bind def rmoveto % x(0) y(0) { polygon_x polygon_y vector_add lineto } repeat % n times closepath - { %fill? - stroke_and_fill - }{ - stroke - } ifelse + stroke_and_fill? } bind def /draw_circle % filled? radius thickness draw_circle @@ -150,9 +222,7 @@ bind def 3 2 roll % f? x0 y0 r dup 0 rmoveto 0 360 arc closepath - { stroke_and_fill } - { stroke } - ifelse + stroke_and_fill? } bind def /draw_ellipse % filled? x-radius y-radius thickness draw_ellipse @@ -164,9 +234,7 @@ bind def 1 0 rmoveto 1 0 360 arc closepath savematrix setmatrix - { stroke_and_fill} - { stroke } - ifelse + stroke_and_fill? } bind def /draw_partial_ellipse % filled connect x-radius y-radius startangle endangle thickness draw_partial_ellipse @@ -205,7 +273,7 @@ bind def connect { startangle cos startangle sin moveto endangle cos endangle sin lineto } if - savematrix setmatrix filled { stroke_and_fill } { stroke } ifelse + savematrix setmatrix filled stroke_and_fill? grestore } bind def @@ -213,7 +281,6 @@ bind def { setlinewidth % dx dy x1 y1 1 setlinecap - 1 setlinejoin rmoveto % dx dy rlineto stroke @@ -222,7 +289,6 @@ bind def /draw_dashed_line % dx dy thickness dashpattern offset draw_dashed_line { 1 setlinecap - 1 setlinejoin setdash % dx dy thickness setlinewidth %dx dy rlineto diff --git a/python/convertrules.py b/python/convertrules.py index e2eb3baa4a..8c472a63e0 100644 --- a/python/convertrules.py +++ b/python/convertrules.py @@ -3683,6 +3683,17 @@ def conv(str): str = re.sub ("New_dynamic_engraver", "Dynamic_engraver", str) return str +@rule ((2, 19, 0), r'''(make-relative (a b) b ...) -> make-relative (a b) #{ a b #}...''') +def conv (str): + str = re.sub (r"(\(make-relative\s+\(\s*(([A-Za-z][-_A-Za-z0-9]*)" + + r"(?:\s+[A-Za-z][-_A-Za-z0-9]*)*)\s*\)\s*)\3(?=\s)", + r"\1(make-event-chord (list \2))", str) + str = re.sub (r"(\(make-relative\s+\(\s*([A-Za-z][-_A-Za-z0-9]*" + + r"(?:\s+([A-Za-z][-_A-Za-z0-9]*))+)\s*\)\s*)\3(?=\s)", + r"\1(make-sequential-music (list \2))", str) + return str + + # Guidelines to write rules (please keep this at the end of this file) # # - keep at most one rule per version; if several conversions should be done, diff --git a/scm/auto-beam.scm b/scm/auto-beam.scm index 14e0209675..b863e5c5a7 100644 --- a/scm/auto-beam.scm +++ b/scm/auto-beam.scm @@ -118,3 +118,52 @@ (if (null? exception-grouping) (beat-end? pos beat-endings) ;; no exception, so check beat ending (member pos exception-moments))))))) ;; check exception rule + +(define-public (extract-beam-exceptions music) + "Creates a value useful for setting @code{beamExceptions} from @var{music}." + (define (car> a b) (> (car a) (car b))) + (define (beatify lst) + ;; takes a collection of end points, sorts them, and returns the + ;; non-zero differences as beaming pattern + (let ((s (sort lst <))) + (remove zero? + (map - s (cons 0 s))))) + ;; TODO: let this do something useful with simultaneous music. + (let loop + ((lst (extract-typed-music (unfold-repeats-fully (event-chord-reduce music)) + '(rhythmic-event bar-check))) + (pos 0) (res '())) + (cond ((null? lst) + (list + (cons 'end + (map + (lambda (l) + (cons (cons (numerator (car l)) (denominator (car l))) + (beatify (cdr l)))) + (sort res car>))))) + ((music-is-of-type? (car lst) 'bar-check) + (loop (cdr lst) 0 res)) + ;; Have rhythmic event. + ((any + (lambda (art) + (and (music-is-of-type? art 'beam-event) + (= (ly:music-property art 'span-direction START) STOP))) + (ly:music-property (car lst) 'articulations)) + (let* ((dur (ly:music-property (car lst) 'duration)) + (len (if (ly:duration? dur) (duration-length dur) 0)) + (pos (+ pos len)) + (ass (assoc len res))) + (cond ((or (zero? len) (not (integer? (/ pos len)))) + (ly:warning (car lst) (_ "Beam end fits no pattern")) + (loop (cdr lst) pos res)) + (ass + (set-cdr! ass (cons (/ pos len) (cdr ass))) + (loop (cdr lst) pos res)) + (else + (loop (cdr lst) pos (cons (list len (/ pos len)) res)))))) + (else + (let* ((dur (ly:music-property (car lst) 'duration)) + (len (if (ly:duration? dur) (duration-length dur) 0))) + (loop (cdr lst) + (+ pos len) + res)))))) diff --git a/scm/bar-line.scm b/scm/bar-line.scm index 03c6f80815..302936e49c 100644 --- a/scm/bar-line.scm +++ b/scm/bar-line.scm @@ -910,50 +910,51 @@ of the volta brackets relative to the bar lines." line-thickness 1/2)) (bar-array (ly:grob-object grob 'bars)) - (bar-array-length (ly:grob-array-length bar-array)) ;; the bar-array starts with the uppermost bar line grob that is ;; covered by the left edge of the volta bracket; more (span) ;; bar line grobs from other staves may follow - (left-bar-line (if (> bar-array-length 0) - (ly:grob-array-ref bar-array 0) - '())) + (left-bar-line (and (ly:grob-array? bar-array) + (positive? (ly:grob-array-length bar-array)) + (ly:grob-array-ref bar-array 0))) ;; we need the vertical-axis-group-index of the left-bar-line ;; to find the corresponding right-bar-line - (vag-index (if (null? left-bar-line) - -1 - (ly:grob-get-vertical-axis-group-index left-bar-line))) + (vag-index (and left-bar-line + (ly:grob-get-vertical-axis-group-index left-bar-line))) ;; the bar line corresponding to the right edge of the volta bracket ;; is the last entry with the same vag-index, so we transform the array to a list, - ;; reverse it and search for suitable entries: - (filtered-grobs (filter (lambda (e) - (eq? (ly:grob-get-vertical-axis-group-index e) - vag-index)) - (reverse (ly:grob-array->list bar-array)))) - ;; we need the first one (if any) - (right-bar-line (if (pair? filtered-grobs) - (car filtered-grobs) - '())) + ;; reverse it and search for the first suitable entry from + ;; the back + (right-bar-line (and left-bar-line + (find (lambda (e) + (eqv? (ly:grob-get-vertical-axis-group-index e) + vag-index)) + (reverse (ly:grob-array->list bar-array))))) ;; the left-bar-line may be a #', ;; so we add "" as a fallback return value - (left-bar-glyph-name (if (null? left-bar-line) - (string annotation-char) - (ly:grob-property left-bar-line 'glyph-name ""))) - (right-bar-glyph-name (if (null? right-bar-line) - (string annotation-char) - (ly:grob-property right-bar-line 'glyph-name ""))) - (left-bar-broken (or (null? left-bar-line) - (not (zero? (ly:item-break-dir left-bar-line))))) - (right-bar-broken (or (null? right-bar-line) - (not (zero? (ly:item-break-dir right-bar-line))))) + (left-bar-glyph-name (if left-bar-line + (ly:grob-property left-bar-line 'glyph-name "") + (string annotation-char))) + (right-bar-glyph-name (if right-bar-line + (ly:grob-property right-bar-line 'glyph-name "") + (string annotation-char))) + ;; This is the original logic. It flags left-bar-broken if + ;; there is no left-bar-line. That seems strange. + (left-bar-broken (not (and left-bar-line + (zero? (ly:item-break-dir left-bar-line))))) + (right-bar-broken (not (and right-bar-line + (zero? (ly:item-break-dir + right-bar-line))))) + ;; Revert to current grob for getting layout info if no + ;; left-bar-line available (left-span-stencil-extent (ly:stencil-extent (span-bar::compound-bar-line - left-bar-line + (or left-bar-line grob) left-bar-glyph-name dummy-extent) X)) (right-span-stencil-extent (ly:stencil-extent (span-bar::compound-bar-line - right-bar-line + (or right-bar-line grob) right-bar-glyph-name dummy-extent) X)) @@ -968,7 +969,7 @@ of the volta brackets relative to the bar lines." (- (max 0 (interval-end left-span-stencil-extent)) (max 0 (interval-end (ly:stencil-extent (bar-line::compound-bar-line - left-bar-line + (or left-bar-line grob) left-bar-glyph-name dummy-extent) X))) diff --git a/scm/c++.scm b/scm/c++.scm index a131e7f342..ec54ed28c9 100644 --- a/scm/c++.scm +++ b/scm/c++.scm @@ -33,6 +33,11 @@ (and (pair? x) (index? (car x)) (index? (cdr x)))) +(define-public (rational-or-procedure? x) + (or + (and (rational? x) (exact? x)) + (procedure? x))) + (define-public (number-or-grob? x) (or (ly:grob? x) (number? x))) diff --git a/scm/define-context-properties.scm b/scm/define-context-properties.scm index 20d77ea72f..69262b061d 100644 --- a/scm/define-context-properties.scm +++ b/scm/define-context-properties.scm @@ -60,6 +60,9 @@ vertical alignment.") numbers. Can be @code{numbers} for going back to the same number or @code{numbers-with-letters} for going back to the same number with letter suffixes. No setting will not go back in measure-number time.") + (alternativeRestores ,symbol-list? "Timing variables that are +restored to their value at the end of the first alternative in +subsequent alternatives.") (associatedVoice ,string? "Name of the @code{Voice} that has the melody for this @code{Lyrics} line.") (autoAccidentals ,list? "List of different ways to typeset an @@ -215,6 +218,17 @@ and @samp{bracketed}.") symbol go, measured in half staff spaces from the center of the staff.") (completionBusy ,boolean? "Whether a completion-note head is playing.") + (completionFactor ,rational-or-procedure? +"When @code{Completion_heads_engraver} and +@code{Completion_rest_engraver} need to split a note or rest with a +scaled duration, such as @code{c2*3}, this specifies the scale factor +to use for the newly-split notes and rests created by the engraver. + +If @code{#f}, the completion engraver uses the scale-factor of +each duration being split. + +If set to a callback procedure, that procedure is called with the +context of the completion engraver, and the duration to be split.") (completionUnit ,ly:moment? "Sub-bar unit of completion.") (connectArpeggios ,boolean? "If set, connect arpeggios across piano staff.") @@ -444,12 +458,12 @@ associated with the current context. Ranges from@tie{}@w{-1} to@tie{}1, where the values@tie{}@w{-1} (@code{#LEFT}),@tie{}0 (@code{#CENTER}) and@tie{}1 (@code{#RIGHT}) correspond to hard left, center, and hard right, respectively.") - (midiReverbLevel ,number? "Reverb effect level for the MIDI channel -associated with the current context. Ranges from 0 to@tie{}1 -(0=off,@tie{}1=full effect).") - (midiChorusLevel ,number? "Chorus effect level for the MIDI channel -associated with the current context. Ranges from 0 to@tie{}1 -(0=off,@tie{}1=full effect).") + (midiReverbLevel ,number? "Reverb effect level for the MIDI +channel associated with the current context. Ranges from 0 +to@tie{}1 (0=off,@tie{}1=full effect).") + (midiChorusLevel ,number? "Chorus effect level for the MIDI +channel associated with the current context. Ranges from 0 +to@tie{}1 (0=off,@tie{}1=full effect).") (minimumFret ,number? "The tablature auto string-selecting mechanism selects the highest string with a fret at least @code{minimumFret}.") diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index a5b0895c9b..cfa2cfb4c1 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -170,6 +170,9 @@ when a spanner is broken at a line break.") ;;; ;;; c ;;; + (chord-dots-limit ,integer? "Limits the column of dots +on each chord to the height of the chord plus +@code{chord-dots-limit} staff-positions.") (circled-tip ,boolean? "Put a circle at start/@/end of hairpins (al/@/del niente).") (clip-edges ,boolean? "Allow outward pointing beamlets at the @@ -1015,7 +1018,8 @@ texts.") ;;; ;;; x ;;; - (X-extent ,number-pair? "Hard coded extent in X@tie{}direction.") + (X-extent ,number-pair? "Extent (size) in the X@tie{}direction, +measured in staff-space units, relative to object's reference point.") (X-offset ,number? "The horizontal amount that this object is moved relative to its X-parent.") (X-positions ,number-pair? "Pair of X staff coordinates of a spanner @@ -1026,7 +1030,8 @@ in the form @code{(@var{left} . @var{right})}, where both @var{left} and ;;; ;;; y ;;; - (Y-extent ,number-pair? "Hard coded extent in Y@tie{}direction.") + (Y-extent ,number-pair? "Extent (size) in the Y@tie{}direction, +measured in staff-space units, relative to object's reference point.") (Y-offset ,number? "The vertical amount that this object is moved relative to its Y-parent.") diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index a4e0d52a76..aede5e7fde 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -727,6 +727,7 @@ (DotColumn . ( (axes . (,X)) + (chord-dots-limit . 3) (direction . ,RIGHT) (positioning-done . ,ly:dot-column::calc-positioning-done) (X-extent . ,ly:axis-group-interface::width) @@ -1898,6 +1899,7 @@ (cross-staff . ,ly:script-interface::calc-cross-staff) (direction . ,ly:script-interface::calc-direction) (font-encoding . fetaMusic) + (horizon-padding . 0.1) ; to avoid interleaving with accidentals (positioning-done . ,ly:script-interface::calc-positioning-done) (side-axis . ,Y) @@ -2501,13 +2503,14 @@ (axes . (,X)) (direction . ,RIGHT) (font-size . -4) + ;; minimum shift to the right, in case the parent note has no stem + (minimum-space . 2.5) + (horizon-padding . 0.1) ; to avoid interleaving with augmentation dots (padding . 0.3) (side-axis . ,X) (stencil . ,parenthesize-elements) (stencils . ,parentheses-item::calc-parenthesis-stencils) - ;; offset a bit to the right, further if needed to clear the main note - (X-offset . ,(lambda (grob) - (ly:side-position-interface::x-aligned-side grob 2.5))) + (X-offset . ,ly:side-position-interface::x-aligned-side) (Y-extent . ,grob::always-Y-extent-from-stencil) (meta . ((class . Item) (interfaces . (axis-group-interface diff --git a/scm/define-markup-commands.scm b/scm/define-markup-commands.scm index 9e5528f5bb..fe1cff509a 100644 --- a/scm/define-markup-commands.scm +++ b/scm/define-markup-commands.scm @@ -1014,13 +1014,9 @@ samplePath = (define-markup-list-command (score-lines layout props score) (ly:score?) - " -This is the same as the @code{\\score} markup but delivers its -systems as a list of lines. This is not usually called directly by -the user. Instead, it is called when the parser encounters -@code{\\score} in a context where only markup lists are allowed. When -used as the argument of a toplevel @code{\\markuplist}, the result can -be split across pages." + "This is the same as the @code{\\score} markup but delivers its +systems as a list of lines. Its @var{score} argument is entered in +braces like it would be for @code{\\score}." (let ((output (ly:score-embedded-format score layout))) (if (ly:music-output? output) @@ -3974,7 +3970,7 @@ Set @var{arg} in superscript with a normal font size. @end lilypond" (ly:stencil-translate-axis (interpret-markup layout props arg) - (* 0.5 baseline-skip) Y)) + (* 0.33 baseline-skip) Y)) (define-markup-command (super layout props arg) (markup?) @@ -4001,7 +3997,7 @@ Set @var{arg} in superscript. layout (cons `((font-size . ,(- font-size 3))) props) arg) - (* 0.5 baseline-skip) + (* 0.33 baseline-skip) Y)) (define-markup-command (translate layout props offset arg) @@ -4049,7 +4045,7 @@ Set @var{arg} in subscript. layout (cons `((font-size . ,(- font-size 3))) props) arg) - (* -0.5 baseline-skip) + (* -0.25 baseline-skip) Y)) (define-markup-command (normal-size-sub layout props arg) @@ -4071,7 +4067,7 @@ Set @var{arg} in subscript with a normal font size. @end lilypond" (ly:stencil-translate-axis (interpret-markup layout props arg) - (* -0.5 baseline-skip) + (* -0.25 baseline-skip) Y)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/scm/define-music-display-methods.scm b/scm/define-music-display-methods.scm index fd759d52d1..32a747aba8 100644 --- a/scm/define-music-display-methods.scm +++ b/scm/define-music-display-methods.scm @@ -526,8 +526,17 @@ Otherwise, return #f." (map-in-order (lambda (event) (music->lily-string event parser)) (ly:music-property note 'articulations)))) - (else ;; unknown? - ""))) + (else + ;; pure duration + ;; FIXME: { c4 c4 4 4 } must not be output as { c4 c 4 4 } + ;; quite tricky to do. Do it when outputting sequences? + (format #f "~a~{~a~}" + (duration->lily-string (ly:music-property note 'duration) + #:force-duration #t + #:remember #t) + (map-in-order (lambda (event) + (music->lily-string event parser)) + (ly:music-property note 'articulations)))))) (define-display-method ClusterNoteEvent (note parser) (simple-note->lily-string note parser)) diff --git a/scm/define-music-properties.scm b/scm/define-music-properties.scm index 5c9c12538e..4469f88ff0 100644 --- a/scm/define-music-properties.scm +++ b/scm/define-music-properties.scm @@ -119,6 +119,12 @@ This property can only be defined as initializer in whether to allow, forbid or force a line break.") (metronome-count ,number-or-pair? "How many beats in a minute?") + (midi-extra-velocity ,integer? "How much louder or softer should +this note be in MIDI output? The default is 0.") + (midi-length ,procedure? "Function to determine how long to play +a note in MIDI. It should take a moment (the written length of the +note) and a context, and return a moment (the length to play the +note).") (moment ,ly:moment? "The moment at which an event happens.") (music-cause ,ly:music? "The music object that is the cause of an event.") diff --git a/scm/framework-ps.scm b/scm/framework-ps.scm index d92affb11c..bb7dc55504 100644 --- a/scm/framework-ps.scm +++ b/scm/framework-ps.scm @@ -84,7 +84,9 @@ "/output-scale " (number->string (ly:output-def-lookup layout 'output-scale)) " def\n" (output-entry "page-height" 'paper-height) - (output-entry "page-width" 'paper-width))) + (output-entry "page-width" 'paper-width) + (if (ly:get-option 'strokeadjust) "true setstrokeadjust\n" "") + )) (define (dump-page outputter page page-number page-count landscape?) (ly:outputter-dump-string @@ -97,7 +99,6 @@ "") "%%EndPageSetup\n" "\n" - "true setstrokeadjust\n" "gsave 0 paper-height translate set-ps-scale-to-lily-scale\n")) (ly:outputter-dump-stencil outputter page) (ly:outputter-dump-string outputter "stroke grestore\nshowpage\n")) diff --git a/scm/lily-library.scm b/scm/lily-library.scm index 43b05e57c2..570c740775 100644 --- a/scm/lily-library.scm +++ b/scm/lily-library.scm @@ -80,6 +80,11 @@ (cons (ly:moment-main-numerator moment) (ly:moment-main-denominator moment))) +(define-public (seconds->moment s context) + "Return a moment equivalent to s seconds at the current tempo." + (ly:moment-mul (ly:context-property context 'tempoWholesPerMinute) + (ly:make-moment (/ s 60)))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; durations @@ -116,6 +121,16 @@ non-visual scale factor 1." duration (base note length and dot count), as a number of whole notes." (duration-length (duration-visual dur))) +(define-public (unity-if-multimeasure context dur) + "Given a context and a duration, return @code{1} if the duration is +longer than the @code{measureLength} in that context, and @code{#f} otherwise. +This supports historic use of @code{Completion_heads_engraver} to split +@code{c1*3} into three whole notes." + (if (ly:momentmake-music arg)) location)) (define-ly-syntax-simple (void-music) diff --git a/scm/music-functions.scm b/scm/music-functions.scm index 383b7f3f6d..9bf47d408e 100644 --- a/scm/music-functions.scm +++ b/scm/music-functions.scm @@ -20,6 +20,7 @@ (use-modules (scm safe-utility-defs)) (use-modules (ice-9 optargs)) +(use-modules (srfi srfi-11)) ;;; ly:music-property with setter ;;; (ly:music-property my-music 'elements) @@ -382,6 +383,28 @@ beats to be distinguished." (unfold-repeats e))) music)) +(define-public (unfold-repeats-fully music) + "Unfolds repeats and expands the resulting @code{unfolded-repeated-music}." + (map-some-music + (lambda (m) + (and (music-is-of-type? m 'unfolded-repeated-music) + (make-sequential-music + (ly:music-deep-copy + (let loop ((n (ly:music-property m 'repeat-count)) + (alts (ly:music-property m 'elements)) + (body (ly:music-property m 'element))) + (cond ((<= n 0) '()) + ((null? alts) + (cons body (loop (1- n) alts body))) + (else + (cons* body (car alts) + (loop (1- n) + (if (pair? (cdr alts)) + (cdr alts) + alts) + body))))))))) + (unfold-repeats music))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; property setting music objs. @@ -614,9 +637,10 @@ in @var{grob}." (make-music 'PropertyUnset 'symbol sym)) -(define-safe-public (make-articulation name) - (make-music 'ArticulationEvent - 'articulation-type name)) +(define-safe-public (make-articulation name . properties) + (apply make-music 'ArticulationEvent + 'articulation-type name + properties)) (define-public (make-lyric-event string duration) (make-music 'LyricEvent @@ -728,7 +752,8 @@ duration is replaced with the specified @var{duration}." (set! (ly:music-property repeat-chord 'articulations) (append! (set-origin! (ly:music-deep-copy arts)) - (ly:music-property repeat-chord 'articulations)))))) + (ly:music-property repeat-chord 'articulations))))) + repeat-chord) (define-public (expand-repeat-chords! event-types music) @@ -747,8 +772,7 @@ respective predecessor chord." last-chord)) (last-chord (set! (ly:music-property music 'duration) '()) - (copy-repeat-chord last-chord music chord-repeat event-types) - music) + (copy-repeat-chord last-chord music chord-repeat event-types)) (else (ly:music-warning music (_ "Bad chord repetition")) #f))) @@ -757,6 +781,73 @@ respective predecessor chord." (ly:music-property music 'elements))))) music) +;;; This does _not_ copy any articulations. Rationale: one main +;;; incentive for pitch-repeating durations is after ties, such that +;;; 4~2~8. can stand in for a 15/16 note in \partial 4 position. In +;;; this use case, any repeated articulations will be a nuisance. +;;; +;;; String assignments in TabStaff might seem like a worthwhile +;;; exception, but they would be better tackled by the respective +;;; engravers themselves (see issue 3662). +;;; +;;; Repeating chords as well seems problematic for things like +;;; \score { +;;; << +;;; \new Staff { c4 c c } +;;; \new RhythmicStaff { 4 4 4 4 } +;;; >> +;;; } +;;; +;;; However, because of MIDI it is not advisable to use RhythmicStaff +;;; without any initial pitch/drum-type. For music functions taking +;;; pure rhythms as an argument, the running of expand-repeat-notes! +;;; at scorification time is irrelevant: at that point of time, the +;;; music function has already run. + +(define-public (expand-repeat-notes! music) + "Walks through @var{music} and gives pitchless notes (not having a +pitch in code{pitch} or a drum type in @code{drum-type}) the pitch(es) +from the predecessor note/chord if available." + (let ((last-pitch #f)) + (map-some-music + (lambda (m) + (define (set-and-ret last) + (set! last-pitch last) + m) + (cond + ((music-is-of-type? m 'event-chord) + (set-and-ret m)) + ((music-is-of-type? m 'note-event) + (cond + ((or (ly:music-property m 'pitch #f) + (ly:music-property m 'drum-type #f)) + => set-and-ret) + ;; ok, naked rhythm. Go through the various cases of + ;; last-pitch + ;; nothing available: just keep as-is + ((not last-pitch) m) + ((ly:pitch? last-pitch) + (set! (ly:music-property m 'pitch) last-pitch) + m) + ((symbol? last-pitch) + (set! (ly:music-property m 'drum-type) last-pitch) + m) + ;; Ok, this is the big bad one: the reference is a chord. + ;; For now, we use the repeat chord logic. That's not + ;; really efficient as cleaning out all articulations is + ;; quite simpler than what copy-repeat-chord does. + (else + (copy-repeat-chord last-pitch + (make-music 'EventChord + 'elements + (ly:music-property m 'articulations) + 'origin + (ly:music-property m 'origin)) + (ly:music-property m 'duration) + '(rhythmic-event))))) + (else #f))) + music))) + ;;; splitting chords into voices. (define (voicify-list lst number) "Make a list of Musics. @@ -1261,6 +1352,7 @@ then revert skipTypesetting." (cons 'rhythmic-event (ly:parser-lookup parser '$chord-repeat-events)) music)) + (lambda (music parser) (expand-repeat-notes! music)) (lambda (music parser) (voicify-music music)) (lambda (x parser) (music-map music-check-error x)) (lambda (x parser) (music-map precompute-music-length x)) @@ -1879,38 +1971,111 @@ yourself." (map (lambda (x) (ly:music-property x 'pitch)) (event-chord-notes event-chord))) -(defmacro-public make-relative (pitches last-pitch music) - "The list of pitch-carrying variables in @var{pitches} is used as a -sequence for creating relativable music from @var{music}. -The variables in @var{pitches} are, when considered inside of -@code{\\relative}, all considered to be specifications to the preceding -variable. The first variable is relative to the preceding musical -context, and @var{last-pitch} specifies the pitch passed as relative -base onto the following musical context." +(define-public (event-chord-reduce music) + "Reduces event chords in @var{music} to their first note event, +retaining only the chord articulations. Returns the modified music." + (map-some-music + (lambda (m) + (and (music-is-of-type? m 'event-chord) + (let*-values (((notes arts) (partition + (lambda (mus) + (music-is-of-type? mus 'rhythmic-event)) + (ly:music-property m 'elements))) + ((dur) (ly:music-property m 'duration)) + ((full-arts) (append arts + (ly:music-property m 'articulations))) + ((first-note) (and (pair? notes) (car notes)))) + (cond (first-note + (set! (ly:music-property first-note 'articulations) + full-arts) + first-note) + ((ly:duration? dur) + ;; A repeat chord. Produce an unpitched note. + (make-music 'NoteEvent + 'duration dur + 'articulations full-arts)) + (else + (ly:music-error m (_ "Missing duration")) + (make-music 'NoteEvent + 'duration (ly:make-duration 2 0 0) + 'articulations full-arts)))))) + music)) + + +(defmacro-public make-relative (variables reference music) + "The list of pitch or music variables in @var{variables} is used as +a sequence for creating relativable music from @var{music}. + +When the constructed music is used outside of @code{\\relative}, it +just reflects plugging in the @var{variables} into @var{music}. + +The action inside of @code{\\relative}, however, is determined by +first relativizing the surrogate @var{reference} with the variables +plugged in and then using the variables relativized as a side effect +of relativizing @var{reference} for evaluating @var{music}. + +Since pitches don't have the object identity required for tracing the +effect of the reference call, they are replaced @emph{only} for the +purpose of evaluating @var{reference} with simple pitched note events. + +The surrogate @var{reference} expression has to be written with that +in mind. In addition, it must @emph{not} contain @emph{copies} of +music that is supposed to be relativized but rather the +@emph{originals}. This @emph{includes} the pitch expressions. As a +rule, inside of @code{#@{@dots{}#@}} variables must @emph{only} be +introduced using @code{#}, never via the copying construct @code{$}. +The reference expression will usually just be a sequential or chord +expression naming all variables in sequence, implying that following +music will be relativized according to the resulting pitch of the last +or first variable, respectively. + +Since the usual purpose is to create more complex music from general +arguments and since music expression parts must not occur more than +once, one @emph{does} generally need to use copying operators in the +@emph{replacement} expression @var{music} when using an argument more +than once there. Using an argument more than once in @var{reference}, +in contrast, does not make sense. + +There is another fine point to mind: @var{music} must @emph{only} +contain freshly constructed elements or copied constructs. This will +be the case anyway for regular LilyPond code inside of +@code{#@{@dots{}#@}}, but any other elements (apart from the +@var{variables} themselves which are already copied) must be created +or copied as well. + +The reason is that it is usually permitted to change music in-place as +long as one does a @var{ly:music-deep-copy} on it, and such a copy of +the whole resulting expression will @emph{not} be able to copy +variables/values inside of closures where the information for +relativization is being stored. +" ;; pitch and music generator might be stored instead in music ;; properties, and it might make sense to create a music type of its ;; own for this kind of construct rather than using ;; RelativeOctaveMusic - (define ((make-relative::to-relative-callback pitches p->m p->p) music pitch) - (let* ((chord (make-event-chord - (map - (lambda (p) - (make-music 'NoteEvent - 'pitch p)) - pitches))) - (pitchout (begin - (ly:make-music-relative! chord pitch) - (event-chord-pitches chord)))) - (set! (ly:music-property music 'element) - (apply p->m pitchout)) - (apply p->p pitchout))) + (define ((make-relative::to-relative-callback variables music-call ref-call) + music pitch) + (let* ((ref-vars (map (lambda (v) + (if (ly:pitch? v) + (make-music 'NoteEvent 'pitch v) + (ly:music-deep-copy v))) + variables)) + (after-pitch (ly:make-music-relative! (apply ref-call ref-vars) pitch)) + (actual-vars (map (lambda (v r) + (if (ly:pitch? v) + (ly:music-property r 'pitch) + r)) + variables ref-vars)) + (rel-music (apply music-call actual-vars))) + (set! (ly:music-property music 'element) rel-music) + after-pitch)) `(make-music 'RelativeOctaveMusic 'to-relative-callback (,make-relative::to-relative-callback - (list ,@pitches) - (lambda ,pitches ,music) - (lambda ,pitches ,last-pitch)) + (list ,@variables) + (lambda ,variables ,music) + (lambda ,variables ,reference)) 'element ,music)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/scripts/build/gen-emmentaler-scripts.py b/scripts/build/gen-emmentaler-scripts.py index dafb50c0ef..e7cbbf00fc 100644 --- a/scripts/build/gen-emmentaler-scripts.py +++ b/scripts/build/gen-emmentaler-scripts.py @@ -85,8 +85,11 @@ Generate("%(filename)s-%(design_size)d.woff"); open (path, 'w').write (script) subfonts = ['feta%(design_size)d', - 'parmesan%(design_size)d', - 'feta-alphabet%(design_size)d'] + 'feta-noteheads%(design_size)d', + 'feta-flags%(design_size)d', + 'parmesan%(design_size)d', + 'parmesan-noteheads%(design_size)d', + 'feta-alphabet%(design_size)d'] ns = [] for s in subfonts: diff --git a/scripts/convert-ly.py b/scripts/convert-ly.py index 641d763713..ede9d4a98b 100644 --- a/scripts/convert-ly.py +++ b/scripts/convert-ly.py @@ -292,17 +292,18 @@ def do_one_file (infile_name): # Note that last_change can be set even if the result is # the same if two conversion rules cancelled out if result == input: - # check the y in x.y.z (minor version number) - previous_stable = (last[0], 2*(last[1]/2), 0) - if ((last[0:2] != from_version[0:2]) and - (previous_stable > from_version)): - # previous stable version - last = previous_stable - else: - # make no (actual) change to the version number - last = from_version + # make no (actual) change to the version number + last = from_version else: last = last_change + # If the last update was to an unstable version + # number, and the final update target is no longer in + # the same unstable series, we update to the stable + # series following the unstable version. + if last[1]%2: # unstable + next_stable = (last[0], last[1]+1, 0) + if next_stable <= to_version: + last = next_stable newversion = r'\version "%s"' % tup_to_str (last) if lilypond_version_re.search (result):