I hope this message lands in the right 2018 thread. I find an ossia function very worth the work! I tried several things yesterday but none of them really worked. I amended a few details to Urs/David's code (a couple of \with attributes) but there are still some minor issues (other than this big 13 years old bug https://gitlab.com/lilypond/lilypond/-/issues/127). When I look at the code (see below) I would expect this to happen: \ossia {%ossiamusic} {%music}. What happens is the opposite. This is trivial, since the only thing you have to tell the user is that the normal music goes before the ossia music, but it makes me wonder why anyways... Other minor issues are that the ossia music doesn't inherit the clef from the normal music, and that placing all this inside a \relative is not reliable (the first note of whichever of both components might be in an unexpected octave). Does Urs, who started working on this, or David (or anyone :-)) have any idea on how to solve these minor issues? Here the amended code with an example that demonstrate them: #(define-music-function (music ossia-music) (ly:music? ly:music?) (let ((name "initialized")) #{ \applyContext #(lambda (context) (set! name (ly:context-id (ly:context-find context 'Staff))) ) << \new Staff \with { #(ly:make-context-mod `((apply ,(lambda (c) (set! (ly:context-property c 'alignAboveContext) name) )))) \remove "Time_signature_engraver" \magnifyStaff #2/3 \hide Clef firstClef = ##f } { #ossia-music } #music >> % Create \new Staff with ossia-music #})) \new Staff = "viola" \relative { \clef alto c'4 d e g \ossia {c^"c'?" b c d } { e^"Treble clef? I'm not a violin!" d f e } c b c2 } ![]() Cheers, Martín. -- |
On 2020-09-27 3:23 am, Martín Rincón Botero wrote:
> I hope this message lands in the right 2018 thread. I find an ossia > function very worth the work! I tried several things yesterday but > none of them really worked. I amended a few details to Urs/David's > code (a couple of \with attributes) but there are still some minor > issues (other than this big 13 years old bug > https://gitlab.com/lilypond/lilypond/-/issues/127). > > When I look at the code (see below) I would expect this to happen: > \ossia {%ossiamusic} {%music}. What happens is the opposite. This is > trivial, since the only thing you have to tell the user is that the > normal music goes before the ossia music, but it makes me wonder why > anyways... Other minor issues are that the ossia music doesn't inherit > the clef from the normal music, and that placing all this inside a > \relative is not reliable (the first note of whichever of both > components might be in an unexpected octave). Does Urs, who started > working on this, or David (or anyone :-)) have any idea on how to > solve these minor issues? Here the amended code with an example that > demonstrate them: > > [ . . . ] relating to this thread, so I very well might be missing important details. I can see no reason why the order of arguments could not be swapped so that the ossia-music comes first. This is very useful as it clarifies why \relative works the way it does. The ossia-music expression gets processed before the remaining music. The first "c" in the remaining music follows the final "e" in the ossia-music, not the "g" is the preceding music. Regarding clefs, I have a patched version of \ossia that attempts to match the current clef settings by mimicking how \clef works: %%%% \version "2.20.0" \layout { \context { \Staff \name OssiaStaff \alias Staff \remove "Time_signature_engraver" \magnifyStaff #2/3 \hide Clef firstClef = ##f } \inherit-acceptability OssiaStaff Staff } ossia = #(define-music-function (ossia-music music) (ly:music? ly:music?) (let ((staff-name #f) (clef-props '(clefGlyph middleCClefPosition clefPosition clefTransposition clefTranspositionStyle))) (define (initialize context) (set! staff-name (ly:context-id (ly:context-find context 'Staff))) (set! clef-props (map (lambda (prop) (cons prop (ly:context-property context prop))) clef-props))) (define (update context) (ly:context-set-property! context 'alignAboveContext staff-name) (for-each (lambda (prop) (ly:context-set-property! context (car prop) (cdr prop))) clef-props) (ly:set-middle-C! context)) #{ \applyContext #initialize << \new OssiaStaff \with #(ly:make-context-mod `((apply ,update))) { #ossia-music } #music >> #})) \new Staff = "viola" \relative { \clef alto c'4 d e g \ossia { e^"Treble clef? No, it's alto now." d f e } { c^"c'? Yes, because \\relative says so." b c d } c b c2 } %%%% Note that I went ahead and defined an OssiaStaff context so that properties relating to it are not buried within the \ossia function. Also a little refactoring should make the function's logic a little easier to follow. -- Aaron Hill |
Dear Aaron, this is, as usual, excellent. Thank you very much! I was reading Elaine Gould's book regarding ossias and two things would improve this snippet: Naming the ossia staff "ossia" (adding instrumentName = "ossia" to \context { \Staff ...} doesn't work) and joining both systems with dashed bar lines except for the first barline of the system (putting \new StaffGroup \with { \override SpanBar.glyph-name = #"!" \remove System_start_delimiter_engraver
} before << \new OssiaStaff... >> doesn't work either). What am I missing? Best regards, Martín. Am So., 27. Sept. 2020 um 13:26 Uhr schrieb Aaron Hill <[hidden email]>: On 2020-09-27 3:23 am, Martín Rincón Botero wrote: -- |
Sorry, I wasn't paying attention. shortInstrumentName = "ossia" clearly works (instrumentName should work as well!). Am So., 27. Sept. 2020 um 16:46 Uhr schrieb Martín Rincón Botero <[hidden email]>:
-- |
I wasn't paying enough attention either for the dashed bar lines connecting both staves. If this could be made to work into the function itself would be great, but I suppose it's quite difficult if not impossible since Lilypond has to be aware of the Staffgroup first, before even engraving the ossia measure, right? \version "2.20.0" \layout { \context { \Staff \name OssiaStaff \alias Staff \remove "Time_signature_engraver" \magnifyStaff #2/3 \hide Clef firstClef = ##f instrumentName = "ossia" shortInstrumentName = "ossia" } \inherit-acceptability OssiaStaff Staff } ossia = #(define-music-function (ossia-music music) (ly:music? ly:music?) (let ((staff-name #f) (clef-props '(clefGlyph middleCClefPosition clefPosition clefTransposition clefTranspositionStyle))) (define (initialize context) (set! staff-name (ly:context-id (ly:context-find context 'Staff))) (set! clef-props (map (lambda (prop) (cons prop (ly:context-property context prop))) clef-props))) (define (update context) (ly:context-set-property! context 'alignAboveContext staff-name) (for-each (lambda (prop) (ly:context-set-property! context (car prop) (cdr prop))) clef-props) (ly:set-middle-C! context)) #{ \applyContext #initialize << \new OssiaStaff \with #(ly:make-context-mod `((apply ,update))) { #ossia-music } #music >> #})) << \new Staff = "violin" \relative { c'4 d e g f d e g f d e g \time 3/4 c b c \time 4/4 c b c2 } \new StaffGroup \with { \override SystemStartBracket.stencil = ##f \override SpanBar.glyph-name = #"!" } << \new Staff = "viola" \relative { \clef alto c'4 d e g f d e g f d e g \time 3/4 \ossia { e^"Treble clef? No, it's alto now." d f } { c^"c'? Yes, because \\relative says so." b c } \time 4/4 c b c2 } >> >> ![]() Cheers, Martín. Am So., 27. Sept. 2020 um 16:50 Uhr schrieb Martín Rincón Botero <[hidden email]>:
-- |
I said
Thinking twice, I guess the user should have the freedom to make an ossia that's not connected to the main staff. My problem has been solved then! :-) What does Urs think of this? Am So., 27. Sept. 2020 um 17:02 Uhr schrieb Martín Rincón Botero <[hidden email]>:
-- |
In reply to this post by Aaron Hill
On Sun 27 Sep 2020 at 04:25:21 (-0700), Aaron Hill wrote:
> On 2020-09-27 3:23 am, Martín Rincón Botero wrote: > > When I look at the code (see below) I would expect this to happen: > > \ossia {%ossiamusic} {%music}. What happens is the opposite. This is > > trivial, since the only thing you have to tell the user is that the > > normal music goes before the ossia music, but it makes me wonder why > > […] Other minor issues are […] that placing all this inside a > > \relative is not reliable (the first note of whichever of both > > components might be in an unexpected octave). Does Urs, who started > > working on this, or David (or anyone :-)) have any idea on how to > > solve these minor issues? Here the amended code with an example that > > demonstrate them: > I can see no reason why the order of arguments could not be swapped so > that the ossia-music comes first. This is very useful as it clarifies > why \relative works the way it does. The ossia-music expression gets > processed before the remaining music. The first "c" in the remaining > music follows the final "e" in the ossia-music, not the "g" is the > preceding music. I'm not sure that it does produce clarity (as opposed to merely explaining the unreliability in perception). Would it not be clearer to put the ossia music inside a \relative{}, so that the main sequence of pitches carries through undisturbed, and the ossia has its correct octave specified within itself, locally. I always think it rather risky to put structure inside \relative{}, rather than putting the \relative{}s inside the structure. In the attached, I have omitted any clefs so that notes can be read more simply, and chosen the notes so that the octavation of each segment is more obvious. Cheers, David. |
On 2020-09-27 7:35 pm, David Wright wrote:
> I'm not sure that it does produce clarity (as opposed to merely > explaining the unreliability in perception). Would it not be > clearer to put the ossia music inside a \relative{}, so that > the main sequence of pitches carries through undisturbed, and > the ossia has its correct octave specified within itself, locally. > > I always think it rather risky to put structure inside \relative{}, > rather than putting the \relative{}s inside the structure. \relative is nothing more than a tool for a job. Providing one understands how it works and can manage the sequencing of notes, it is not wrong nor unreliable to use at a top-level. If it were either, then LilyPond should not accept such usage. The original \ossia function flips the arguments so the ordering of notes behind the scenes as \relative sees them no longer matches the natural progression within the input file. As such, argument order matters to accommodate folks who choose to use \relative at the higher level and maintain consistency with the existing precedent that parallel sections of music are processed in the order they occur within the source: %%%% \relative { 1st 2nd << { 3rd 4th } \\ { 5th 6th } >> 7th 8th } %%%% With the original \ossia function, one must follow this sequencing: %%%% \relative { 1st 2nd \ossia { 5th(!) 6th } { 3rd(!) 4th } 7th(!) 8th } %%%% That is three times the natural ordering is disturbed, so fixing the argument order definitely adds clarity. Mind you, a user is always free to use \relative in a more localized scope: %%%% { \relative { 1st 2nd } \ossia \relative { 1st 2nd } \relative { 1st 2nd } \relative { 1st 2nd } } %%%% But surely the music argument *nearest* the \ossia command should be the notes in the ossia itself, regardless of ones preference on using \relative. The alternative seems madness: %%%% { music preceding \ossia { careful, these are not the notes for the ossia } { here, written *below* those notes in the source, are the notes that will appear *above* them. } music following } %%%% -- Aaron Hill |
Thank you David for this example. I agree with Aaron that ossia notes should be first when the ossia measure goes above the music. That way you have a similar "feeling" of the \relative effect as when using << { %abovemusic} \\ {%belowmusic} >>. However, I went ahead, and, for the sake of completeness, split Aaron's code into two functions, namely \ossiaAbove and \ossiaBelow, because both options should be available (writing f. ex. ossia measures for the left hand of the piano is usually done below the staff). The below ossia poses the question "should notes be written first or after?". By analogy to the << {} \\ {} >> construction, I think they should be written after, since they're some sort of "below" or "second" voice. In that case, as David suggests, an independent \relative block should always be used: \version "2.20.0" \layout { \context { \Staff \name OssiaStaff \alias Staff \remove "Time_signature_engraver" \magnifyStaff #2/3 %\hide Clef %firstClef = ##f instrumentName = "ossia" shortInstrumentName = "ossia" } \inherit-acceptability OssiaStaff Staff } ossiaAbove = #(define-music-function (ossia-music music) (ly:music? ly:music?) (let ((staff-name #f) (clef-props '(clefGlyph middleCClefPosition clefPosition clefTransposition clefTranspositionStyle))) (define (initialize context) (set! staff-name (ly:context-id (ly:context-find context 'Staff))) (set! clef-props (map (lambda (prop) (cons prop (ly:context-property context prop))) clef-props))) (define (update context) (ly:context-set-property! context 'alignAboveContext staff-name) (for-each (lambda (prop) (ly:context-set-property! context (car prop) (cdr prop))) clef-props) (ly:set-middle-C! context)) #{ \applyContext #initialize << \new OssiaStaff \with #(ly:make-context-mod `((apply ,update))) { #ossia-music } #music >> #})) ossiaBelow = #(define-music-function (ossia-music music) (ly:music? ly:music?) (let ((staff-name #f) (clef-props '(clefGlyph middleCClefPosition clefPosition clefTransposition clefTranspositionStyle))) (define (initialize context) (set! staff-name (ly:context-id (ly:context-find context 'Staff))) (set! clef-props (map (lambda (prop) (cons prop (ly:context-property context prop))) clef-props))) (define (update context) (ly:context-set-property! context 'alignBelowContext staff-name) (for-each (lambda (prop) (ly:context-set-property! context (car prop) (cdr prop))) clef-props) (ly:set-middle-C! context)) #{ \applyContext #initialize << \new OssiaStaff \with #(ly:make-context-mod `((apply ,update))) { #music } #ossia-music >> #})) << \new StaffGroup \with { \override SystemStartBracket.stencil = ##f \override SpanBar.glyph-name = #"!" } << \new Staff = "violin" \relative { c'4 d e g f d e g f d e g \time 3/4 c b c \time 4/4 \ossiaAbove {c b c2 } {e4 f g2} } >> \new StaffGroup \with { \override SystemStartBracket.stencil = ##f \override SpanBar.glyph-name = #"!" } << \new Staff = "viola" \relative { \clef alto c'4 d e g f d e g f d e g \time 3/4 \ossiaBelow { e d f } \relative { c' b c } \time 4/4 c b c2 } >> >> ![]() I'd love to see these functions together with the new OssiaStaff context incorporated into Lilypond by default. Doing so wouldn't only provide a syntax for ossias and a useful new context but would also bring the necessary attention that the respective part in the manual is currently in need of. Best regards, Martín. Am Mo., 28. Sept. 2020 um 08:33 Uhr schrieb Aaron Hill <[hidden email]>: On 2020-09-27 7:35 pm, David Wright wrote: -- |
In reply to this post by Aaron Hill
On Sun 27 Sep 2020 at 23:32:08 (-0700), Aaron Hill wrote:
> On 2020-09-27 7:35 pm, David Wright wrote: > > I'm not sure that it does produce clarity (as opposed to merely > > explaining the unreliability in perception). Would it not be > > clearer to put the ossia music inside a \relative{}, so that > > the main sequence of pitches carries through undisturbed, and > > the ossia has its correct octave specified within itself, locally. > > > > I always think it rather risky to put structure inside \relative{}, > > rather than putting the \relative{}s inside the structure. > > \relative is nothing more than a tool for a job. Providing one > understands how it works and can manage the sequencing of notes, it is > not wrong nor unreliable to use at a top-level. If it were either, > then LilyPond should not accept such usage. I did not say it's wrong, but risky. Nor that it's unreliable (AFAICT it's deterministic): I quoted the observation of the OP, "placing all this inside a \relative is not reliable", which is their perception. That wasn't my point, which was that placing structure within \relative{} sequences increases the burden of remembering which structures can affect \relative's idea of note order, and hence octavation. Add enough structure and the benefit of \relative could be outweighed. Examples on this list abound, the most common (IMHO) being provoked by tags. My understanding (which could be flawed) is that some people here recommend never using \relative on this account. But my example was designed to ameliorate the problem, just by enclosing the ossia phrase in its own \relative{}. > The original \ossia function flips the arguments so the ordering of > notes behind the scenes as \relative sees them no longer matches the > natural progression within the input file. As such, argument order > matters to accommodate folks who choose to use \relative at the higher > level and maintain consistency with the existing precedent that > parallel sections of music are processed in the order they occur > within the source: […] > But surely the music argument *nearest* the \ossia command should be > the notes in the ossia itself, regardless of ones preference on using > \relative. The alternative seems madness: Yes, I'd agree that locality is of overriding importance for the arguments in the call, and also that the function should respect the note ordering so that \relative works in the expected manner. (The implementation of that would be "way above my pay-grade".) Actually, my post didn't express any opinion about ordering, and the example was based on the Botero one merely because it was easier to eliminate consideration of clefs too. The recommendation demonstrated in the example was only to add a \relative to the ossia phrase, and a further benefit can be illustrated by the attached, which shows how relatively (!) easy it is to add or remove any number of ossias if you use this construction. Removing one is just a matter of commenting out its line (only one line when used with your sensible ordering of arguments), and adding one only requires the extra burden of putting { } round the main sequence of notes covering the same time interval. The octavation of the original remains undisturbed. Of course, I would agree that: \ossia \relative { f''^"ossia" c g d } { a^"main" f d b } looks much more tidy and hence understandable than: \ossia { a^"main" f d b } \relative { f''^"ossia" c g d } Even if, as suggested later in the thread, you have ossia-above and ossia-below, I don't think that should affect this ordering. Any analogy with the << { } \\ { } >> construction is probably unwise, as that's something which appears not always to be understood anyway. Cheers, David. |
On a second thought, I agree. Ordering of arguments in this function seems to be of utmost importance, not only because of the \relative construction, but also because the function needs to appear first no matter what (I can't for example use {#music } \ossiaBelow {#ossia-music}). So it makes more sense to attach the notes that the function appears to contain on its side and not afterwards. For the sake of "discoverability" here the code again with #ossia-music back to where it belongs: \version "2.20.0" \layout { \context { \Staff \name OssiaStaff \alias Staff \remove "Time_signature_engraver" \magnifyStaff #2/3 %\hide Clef %firstClef = ##f instrumentName = "ossia" shortInstrumentName = "ossia" } \inherit-acceptability OssiaStaff Staff } ossiaAbove = #(define-music-function (ossia-music music) (ly:music? ly:music?) (let ((staff-name #f) (clef-props '(clefGlyph middleCClefPosition clefPosition clefTransposition clefTranspositionStyle))) (define (initialize context) (set! staff-name (ly:context-id (ly:context-find context 'Staff))) (set! clef-props (map (lambda (prop) (cons prop (ly:context-property context prop))) clef-props))) (define (update context) (ly:context-set-property! context 'alignAboveContext staff-name) (for-each (lambda (prop) (ly:context-set-property! context (car prop) (cdr prop))) clef-props) (ly:set-middle-C! context)) #{ \applyContext #initialize << \new OssiaStaff \with #(ly:make-context-mod `((apply ,update))) { #ossia-music } #music >> #})) ossiaBelow = #(define-music-function (ossia-music music) (ly:music? ly:music?) (let ((staff-name #f) (clef-props '(clefGlyph middleCClefPosition clefPosition clefTransposition clefTranspositionStyle))) (define (initialize context) (set! staff-name (ly:context-id (ly:context-find context 'Staff))) (set! clef-props (map (lambda (prop) (cons prop (ly:context-property context prop))) clef-props))) (define (update context) (ly:context-set-property! context 'alignBelowContext staff-name) (for-each (lambda (prop) (ly:context-set-property! context (car prop) (cdr prop))) clef-props) (ly:set-middle-C! context)) #{ \applyContext #initialize << \new OssiaStaff \with #(ly:make-context-mod `((apply ,update))) { #ossia-music } #music >> #})) << \new StaffGroup \with { \override SystemStartBracket.stencil = ##f \override SpanBar.glyph-name = #"!" } << \new Staff = "violin" \relative { c'4 d e g f d e g f d e g \time 3/4 c b c \time 4/4 \ossiaAbove {c b c2 } {e4 f g2} } >> \new StaffGroup \with { \override SystemStartBracket.stencil = ##f \override SpanBar.glyph-name = #"!" } << \new Staff = "viola" \relative { \clef alto c'4 d e g f d e g f d e g \time 3/4 \ossiaBelow { e d f } { c b c } \time 4/4 c b c2 } >> >> By the way, the thread I was hoping to be replying to with my first message was this one http://lilypond.1069038.n5.nabble.com/Align-above-quot-current-quot-staff-td214624.html. Cheers, Martín. Am Mo., 28. Sept. 2020 um 17:51 Uhr schrieb David Wright <[hidden email]>: On Sun 27 Sep 2020 at 23:32:08 (-0700), Aaron Hill wrote: -- |
Free forum by Nabble | Edit this page |