overriding voiceOne to add properties to that specific voice context

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

overriding voiceOne to add properties to that specific voice context

Maurits Lamers-2
Hi,

As part of my attempt at having Lilypond generate music braille (which is slowly succeeding), I am currently working to have a bit more control over voices and the way these can be ordered in music braille.
Lilypond uses \voiceX and \oneVoice to add semantic meaning for voices. These commands however only translate in offsets on the engraver as far as I can see, but not to anything simple that I could retrieve as part of the voice context properties. It would be very useful to have this information somehow.

I am receiving the note events through listeners on the voice context, and have access to the voice context itself through (ly:translator-context engraver).
Is there a way that I can override / replace the default \voiceX and \oneVoice commands with versions that both do their default task as well as set a voice context property which would allow me to read the voice number back later as part of the specific voice context properties?

I have been trying a few things with (context-spec-music) but as I don't really understand what it returns (or does) exactly, it is a bit hard to know what to do exactly.

Thanks in advance!

Maurits
Reply | Threaded
Open this post in threaded view
|

Re: overriding voiceOne to add properties to that specific voice context

Lukas-Fabian Moser
Hi Maurits,

> I am receiving the note events through listeners on the voice context, and have access to the voice context itself through (ly:translator-context engraver).
> Is there a way that I can override / replace the default \voiceX and \oneVoice commands with versions that both do their default task as well as set a voice context property which would allow me to read the voice number back later as part of the specific voice context properties?
>
> I have been trying a few things with (context-spec-music) but as I don't really understand what it returns (or does) exactly, it is a bit hard to know what to do exactly.

I don't have much experience with custom engravers, but I think one can
define a new context property and upgrade the \voiceX / \oneVoice
commands to also set this context property:

\version "2.21.0"

% tool for defining new context properties
% (from https://www.mail-archive.com/lilypond-user@.../msg133263.html)

#(define (define-translator-property symbol type? description)
   (if (not (and (symbol? symbol)
                 (procedure? type?)
                 (string? description)))
       (ly:error "error in call of define-translator-property"))
   (if (not (equal? (object-property symbol 'translation-doc) #f))
       (ly:error (_ "symbol ~S redefined") symbol))

   (set-object-property! symbol 'translation-type? type?)
   (set-object-property! symbol 'translation-doc description)
   symbol)

% define a new context property "structuralVoice"
#(for-each
   (lambda (x)
     (apply define-translator-property x))
     `((structuralVoice
        ,integer?
        "The current voice is a first/second/... voice (1,2,3,4) or
single voice (empty list)")))

setStructuralVoice =
#(define-scheme-function (num) (integer?)
    (make-apply-context
      (lambda (context)
      (let ((fontSize (ly:context-property context 'fontSize)))
        (ly:context-set-property! context 'structuralVoice (if (> num 0)
num '()))))))

oneVoice = { \setStructuralVoice 0 \oneVoice }
voiceOne = { \setStructuralVoice 1 \voiceOne }
voiceTwo = { \setStructuralVoice 2 \voiceTwo }
voiceThree = { \setStructuralVoice 3 \voiceThree }
voiceFour = { \setStructuralVoice 4 \voiceFour }

displayCurrentStructuralVoice = \applyContext
#(lambda (context)
    (pretty-print
     (ly:context-property context 'structuralVoice)))

\relative {
   \displayCurrentStructuralVoice % not yet defined
   a'4
   \voiceTwo e f
   \displayCurrentStructuralVoice
   \voiceOne e' f
   \displayCurrentStructuralVoice
   \oneVoice e d c b a g f
   \displayCurrentStructuralVoice
}

Note that this does not work yet with voice distinctions created using
the \\ shorthand.

Best
Lukas


Reply | Threaded
Open this post in threaded view
|

Re: overriding voiceOne to add properties to that specific voice context

Lukas-Fabian Moser

> I don't have much experience with custom engravers, but I think one
> can define a new context property and upgrade the \voiceX / \oneVoice
> commands to also set this context property:

... I'm sorry, there's a superfluous (let ((fontSize .... ))) in my
code, a relic from a snippet by Harm that I started from. Please
simplify to:

\version "2.21.0"

% tool for defining new context properties
% (from https://www.mail-archive.com/lilypond-user@.../msg133263.html)

#(define (define-translator-property symbol type? description)
    (if (not (and (symbol? symbol)
                  (procedure? type?)
                  (string? description)))
        (ly:error "error in call of define-translator-property"))
    (if (not (equal? (object-property symbol 'translation-doc) #f))
        (ly:error (_ "symbol ~S redefined") symbol))

    (set-object-property! symbol 'translation-type? type?)
    (set-object-property! symbol 'translation-doc description)
    symbol)

% define a new context property "structuralVoice"
#(for-each
   (lambda (x)
     (apply define-translator-property x))
   `((structuralVoice
      ,integer?
      "The current voice is a first/second/... voice (1,2,3,4) or single
voice (empty list)")))

setStructuralVoice =
#(define-scheme-function (num) (integer?)
    (make-apply-context
     (lambda (context)
       (ly:context-set-property! context 'structuralVoice (if (> num 0)
num '())))))

oneVoice = { \setStructuralVoice 0 \oneVoice }
voiceOne = { \setStructuralVoice 1 \voiceOne }
voiceTwo = { \setStructuralVoice 2 \voiceTwo }
voiceThree = { \setStructuralVoice 3 \voiceThree }
voiceFour = { \setStructuralVoice 4 \voiceFour }

displayCurrentStructuralVoice = \applyContext
#(lambda (context)
    (pretty-print
     (ly:context-property context 'structuralVoice)))

\relative {
   \displayCurrentStructuralVoice % not yet defined
   a'4
   \voiceTwo e f
   \displayCurrentStructuralVoice % should be 2
   \voiceOne e' f
   \displayCurrentStructuralVoice % should be 1
   \oneVoice e d c b a g f
   \displayCurrentStructuralVoice
}



Reply | Threaded
Open this post in threaded view
|

Re: overriding voiceOne to add properties to that specific voice context

Maurits Lamers-2
Hi,

Great! This is the perfect solution. I had to adjust the (define-scheme-function) call a bit to run also under 2.18:

setStructuralVoice = #(define-scheme-function (parser location num) (integer?)
  (make-apply-context
    (lambda (context)
        (ly:context-set-property! context 'structuralVoice (if (> num 0) num '())))))

It might need even more tweaks to run under 2.14 which is my target. I know it is a very old version, but there is a large body of Lilypond code my work depends on and that is lilypond 2.14. I am afraid that it would distract the current effort and cost too much time at the moment to convert that body of work to a more recent version of lilypond.

So, it will probably end up like this, as I am unsure whether lilypond v20 can deal with v18 type calls to define-scheme-function.

setStructuralVoice = #(case (second (ly:version))
  ( (18)
      (define-scheme-function (parser location num) (integer?)
         (make-apply-context
           (lambda (context)
             (ly:context-set-property! context 'structuralVoice (if (> num 0) num '())))))
  )
  ( (20)
       (define-scheme-function (num) (integer?)
          (make-apply-context
             (lambda (context)
                (ly:context-set-property! context 'structuralVoice (if (> num 0) num '())))))
   ))

Thanks a lot!

cheers

Maurits

> Op 20 aug. 2020, om 02:00 heeft Lukas-Fabian Moser <[hidden email]> het volgende geschreven:
>
>
>> I don't have much experience with custom engravers, but I think one can define a new context property and upgrade the \voiceX / \oneVoice commands to also set this context property:
>
> ... I'm sorry, there's a superfluous (let ((fontSize .... ))) in my code, a relic from a snippet by Harm that I started from. Please simplify to:
>
> \version "2.21.0"
>
> % tool for defining new context properties
> % (from https://www.mail-archive.com/lilypond-user@.../msg133263.html)
>
> #(define (define-translator-property symbol type? description)
>    (if (not (and (symbol? symbol)
>                  (procedure? type?)
>                  (string? description)))
>        (ly:error "error in call of define-translator-property"))
>    (if (not (equal? (object-property symbol 'translation-doc) #f))
>        (ly:error (_ "symbol ~S redefined") symbol))
>
>    (set-object-property! symbol 'translation-type? type?)
>    (set-object-property! symbol 'translation-doc description)
>    symbol)
>
> % define a new context property "structuralVoice"
> #(for-each
>   (lambda (x)
>     (apply define-translator-property x))
>   `((structuralVoice
>      ,integer?
>      "The current voice is a first/second/... voice (1,2,3,4) or single voice (empty list)")))
>
> setStructuralVoice =
> #(define-scheme-function (num) (integer?)
>    (make-apply-context
>     (lambda (context)
>       (ly:context-set-property! context 'structuralVoice (if (> num 0) num '())))))
>
> oneVoice = { \setStructuralVoice 0 \oneVoice }
> voiceOne = { \setStructuralVoice 1 \voiceOne }
> voiceTwo = { \setStructuralVoice 2 \voiceTwo }
> voiceThree = { \setStructuralVoice 3 \voiceThree }
> voiceFour = { \setStructuralVoice 4 \voiceFour }
>
> displayCurrentStructuralVoice = \applyContext
> #(lambda (context)
>    (pretty-print
>     (ly:context-property context 'structuralVoice)))
>
> \relative {
>   \displayCurrentStructuralVoice % not yet defined
>   a'4
>   \voiceTwo e f
>   \displayCurrentStructuralVoice % should be 2
>   \voiceOne e' f
>   \displayCurrentStructuralVoice % should be 1
>   \oneVoice e d c b a g f
>   \displayCurrentStructuralVoice
> }
>
>


Reply | Threaded
Open this post in threaded view
|

Re: overriding voiceOne to add properties to that specific voice context

David Kastrup
Maurits Lamers <[hidden email]> writes:

> Hi,
>
> Great! This is the perfect solution. I had to adjust the (define-scheme-function) call a bit to run also under 2.18:
>
> setStructuralVoice = #(define-scheme-function (parser location num) (integer?)
>   (make-apply-context
>     (lambda (context)
> (ly:context-set-property! context 'structuralVoice (if (> num 0) num '())))))
>
> It might need even more tweaks to run under 2.14 which is my target. I
> know it is a very old version, but there is a large body of Lilypond
> code my work depends on and that is lilypond 2.14. I am afraid that it
> would distract the current effort and cost too much time at the moment
> to convert that body of work to a more recent version of lilypond.

Have you even tried running convert-ly on it?

--
David Kastrup

Reply | Threaded
Open this post in threaded view
|

Re: overriding voiceOne to add properties to that specific voice context

Lukas-Fabian Moser
In reply to this post by Maurits Lamers-2
Hi Maurits,

Am 20.08.20 um 11:10 schrieb Maurits Lamers:

> Hi,
>
> Great! This is the perfect solution. I had to adjust the (define-scheme-function) call a bit to run also under 2.18:
>
> setStructuralVoice = #(define-scheme-function (parser location num) (integer?)
>    (make-apply-context
>      (lambda (context)
> (ly:context-set-property! context 'structuralVoice (if (> num 0) num '())))))
>
> It might need even more tweaks to run under 2.14 which is my target. I know it is a very old version, but there is a large body of Lilypond code my work depends on and that is lilypond 2.14. I am afraid that it would distract the current effort and cost too much time at the moment to convert that body of work to a more recent version of lilypond.
>
> So, it will probably end up like this, as I am unsure whether lilypond v20 can deal with v18 type calls to define-scheme-function.

[...]

No need for that: When David K. got rid of the need to write out
parser/location in every function definition five years ago, he also
added a mechanism that detects and supports old-style usage (starting
with "parser"). So your above definition works just fine in 2.20/2.21.

Nevertheless, I'd urge you to try and make sure that everything you
develop will work with current LilyPond versions. Not only in order to
lower the barrier for developers to help you (or others to make use of
your additions), but also because LilyPond simply has evolved a great
deal in the in the nine (!!) years since 2.14.2 was released, and is now
at the same time much more feature-rich _and_ easier to use.

Lukas


Reply | Threaded
Open this post in threaded view
|

Re: overriding voiceOne to add properties to that specific voice context

David Kastrup
Lukas-Fabian Moser <[hidden email]> writes:

> Hi Maurits,
>
> Am 20.08.20 um 11:10 schrieb Maurits Lamers:
>> Hi,
>>
>> Great! This is the perfect solution. I had to adjust the (define-scheme-function) call a bit to run also under 2.18:
>>
>> setStructuralVoice = #(define-scheme-function (parser location num) (integer?)
>>    (make-apply-context
>>      (lambda (context)
>> (ly:context-set-property! context 'structuralVoice (if (> num 0) num '())))))
>>
>> It might need even more tweaks to run under 2.14 which is my target. I know it is a very old version, but there is a large body of Lilypond code my work depends on and that is lilypond 2.14. I am afraid that it would distract the current effort and cost too much time at the moment to convert that body of work to a more recent version of lilypond.
>>
>> So, it will probably end up like this, as I am unsure whether lilypond v20 can deal with v18 type calls to define-scheme-function.
>
> [...]
>
> No need for that: When David K. got rid of the need to write out
> parser/location in every function definition five years ago, he also
> added a mechanism that detects and supports old-style usage (starting
> with "parser"). So your above definition works just fine in 2.20/2.21.
>
> Nevertheless, I'd urge you to try and make sure that everything you
> develop will work with current LilyPond versions. Not only in order to
> lower the barrier for developers to help you (or others to make use of
> your additions), but also because LilyPond simply has evolved a great
> deal in the in the nine (!!) years since 2.14.2 was released, and is
> now at the same time much more feature-rich _and_ easier to use.

Well, that's not much of a motivation to upgrade existing documents
(unless you want to add to them).  But the typesetting has become quite
a bit better, too.

--
David Kastrup

Reply | Threaded
Open this post in threaded view
|

Re: overriding voiceOne to add properties to that specific voice context

Lukas-Fabian Moser
Hi,

>> Nevertheless, I'd urge you to try and make sure that everything you
>> develop will work with current LilyPond versions. Not only in order to
>> lower the barrier for developers to help you (or others to make use of
>> your additions), but also because LilyPond simply has evolved a great
>> deal in the in the nine (!!) years since 2.14.2 was released, and is
>> now at the same time much more feature-rich _and_ easier to use.
> Well, that's not much of a motivation to upgrade existing documents
> (unless you want to add to them).  But the typesetting has become quite
> a bit better, too.

My understanding was that the issue was not the upgrading of existing
documents, but of the codebase used in a newly-developed framework (for
Braille support/export). But of course it's also very true that, if I
have to go back to an archaic version of LilyPond in order to use a
specific framework, I lose not only features and ease-of-use, but also
pay the price of an inferior typesetting quality.

Maurits, I think the situation seems to be perfectly suited to a
collaborative approach using a git tree, where one person can work on
extending a framework, and the other could work in a separate branch on
making the codebase usable with recent versions of LilyPond. The latter
might be a task that I could try my hands on.

Lukas


Reply | Threaded
Open this post in threaded view
|

Re: overriding voiceOne to add properties to that specific voice context

Maurits Lamers-2
Hi all,

@David: No, I haven't attempted to run convert-ly and I am very hesitant to do so because I have no clue exactly where to start. That is because it is a songbook with over 1000 songs, with choir arrangments and organ parts for each of those songs, with many complex includes and external music definitions. Wilfried Berendsen should be very familiar with it, as IIRC he supervised its creation. He might know a way of upgrading it to a more recent Lilypond version.

Also, the songbook is so 2.14 specific that I also cannot compile it using 2.18. So, my assumption is that trying to run convert-ly on this system will have a huge chance of breaking things. As it is the main source for my testing material at the moment, i rather not break it as I am dependent on it to work.

To complicate matters I was only granted access to this songbook with the limitation (at the moment of me writing this) that we cannot use it for any other purpose than to create the music braille system. So @Lukas, I need to talk with the other people of the project whether we can do this, and such an attempt would have to be on a private git tree somewhere, because of those limitations.

I would definitely love to bring the entire system to the most recent version of Lilypond, or at least 2.18.2 (which is the version installed by default under Ubuntu 18.04LTS and all derivatives), but at the moment I think it could cause problems that would stand in the way of the main objective, which is a working music braille output for Lilypond.

cheers

Maurits


> Op 20 aug. 2020, om 15:42 heeft Lukas-Fabian Moser <[hidden email]> het volgende geschreven:
>
> Hi,
>
>>> Nevertheless, I'd urge you to try and make sure that everything you
>>> develop will work with current LilyPond versions. Not only in order to
>>> lower the barrier for developers to help you (or others to make use of
>>> your additions), but also because LilyPond simply has evolved a great
>>> deal in the in the nine (!!) years since 2.14.2 was released, and is
>>> now at the same time much more feature-rich _and_ easier to use.
>> Well, that's not much of a motivation to upgrade existing documents
>> (unless you want to add to them).  But the typesetting has become quite
>> a bit better, too.
>
> My understanding was that the issue was not the upgrading of existing documents, but of the codebase used in a newly-developed framework (for Braille support/export). But of course it's also very true that, if I have to go back to an archaic version of LilyPond in order to use a specific framework, I lose not only features and ease-of-use, but also pay the price of an inferior typesetting quality.
>
> Maurits, I think the situation seems to be perfectly suited to a collaborative approach using a git tree, where one person can work on extending a framework, and the other could work in a separate branch on making the codebase usable with recent versions of LilyPond. The latter might be a task that I could try my hands on.
>
> Lukas
>


Reply | Threaded
Open this post in threaded view
|

Re: overriding voiceOne to add properties to that specific voice context

David Kastrup
Maurits Lamers <[hidden email]> writes:

> Hi all,
>
> @David: No, I haven't attempted to run convert-ly and I am very
> hesitant to do so because I have no clue exactly where to start. That
> is because it is a songbook with over 1000 songs, with choir
> arrangments and organ parts for each of those songs, with many complex
> includes and external music definitions. Wilfried Berendsen should be
> very familiar with it, as IIRC he supervised its creation. He might
> know a way of upgrading it to a more recent Lilypond version.
>
> Also, the songbook is so 2.14 specific that I also cannot compile it
> using 2.18. So, my assumption is that trying to run convert-ly on this
> system will have a huge chance of breaking things. As it is the main
> source for my testing material at the moment, i rather not break it as
> I am dependent on it to work.

Computers have this wonderful facility called a "copy".

> I would definitely love to bring the entire system to the most recent
> version of Lilypond, or at least 2.18.2 (which is the version
> installed by default under Ubuntu 18.04LTS and all derivatives), but
> at the moment I think it could cause problems that would stand in the
> way of the main objective, which is a working music braille output for
> Lilypond.

You mean, a "working" music Braille output for an ancient historical
version of LilyPond that does not compile on current systems, likely
runs limited to 32bit, has much worse programming features and has no
useful online support by current users and programmers because everyone
has moved on.

To get anywhere useful except for a single-shot project, you'll not get
around upgrading, and upgrading may make getting anywhere useful easier.

Just saying.

--
David Kastrup

Reply | Threaded
Open this post in threaded view
|

Re: overriding voiceOne to add properties to that specific voice context

Maurits Lamers-2
Hey,
>
> Computers have this wonderful facility called a "copy".
I know, and also version systems like git :)

>
>> I would definitely love to bring the entire system to the most recent
>> version of Lilypond, or at least 2.18.2 (which is the version
>> installed by default under Ubuntu 18.04LTS and all derivatives), but
>> at the moment I think it could cause problems that would stand in the
>> way of the main objective, which is a working music braille output for
>> Lilypond.
>
> You mean, a "working" music Braille output for an ancient historical
> version of LilyPond that does not compile on current systems, likely
> runs limited to 32bit, has much worse programming features and has no
> useful online support by current users and programmers because everyone
> has moved on.
>
> To get anywhere useful except for a single-shot project, you'll not get
> around upgrading, and upgrading may make getting anywhere useful easier.
>
> Just saying.

I appreciate your concern, but I think you might have misunderstood me a bit.
I do most of my work in 2.18 at the moment, and I try to provide workarounds for 2.14 where necessary.
The only areas where I have been needing adjustments for 2.14 have been the way listeners are added to contexts.
These adjustments also still work in 2.18 and as a result, the braille system works fine in 2.18.2. I haven't tested it yet on 2.20.

As my work is mostly done in Scheme, I am having more issues due to the rather old version of Guile that Lilypond runs on than limitations by Lilypond itself.
Lilypond 2.14.1 was released in on the 11th of July 2011, but if I am not mistaken even the most recent Lilypond uses a version of guile that was released on the 5th of July 2009 (1.8.7).
Don't get me wrong: that is what happens when things work fine, and upgrading is costly. I am fine with that and will try to work around whatever issues I encounter.

cheers

Maurits