Hi Jean, Thank you so much for that clear and thorough explanation. I was so caught up in my functional transformations, that I didn't even stop to think if mutation could be at play. I sprinkled a handful of deep-copies over my functions and voila!
- and thanks again! I really appreciate you taking the time to help me understand and explain these details. Best regards, Morten On Thu, Feb 22, 2024 at 11:38 PM Jean Abou Samra <j...@abou-samra.fr> wrote: > Hi Morten, > > Le jeudi 22 février 2024 à 23:00 +0100, Morten Lemvigh a écrit : > > \version "2.24.1" > > > > double = > > #(define-music-function (music)(ly:music?) > > (let ((notes (ly:music-property music 'elements))) > > (make-music 'SequentialMusic > > 'elements > > (list > > (make-music 'SequentialMusic > > 'elements notes) > > (make-music 'SequentialMusic > > 'elements notes))))) > > > > \relative c' { > > \double {e4 e} > > } > > > Several things are wrong here. > > First, although you are unwrapping `music`, you are not copying the > individual > elements of `notes`. They end up duplicated in the output. This should > never > happen, because music objects are mutable. \relative is in fact a good > example > of this, but perhaps a simpler one is \scaleDurations: try > > \scaleDurations 1/2 \double { e'1 1 } > > and you will see that the whole notes are scaled by 1/4 instead of 1/2. > The reason > is that calling [note1] and [note2] the two note objects, you end up with > > [note1] [note2] [note1] [note2] > > and when \scaleDurations goes through the music and scales it, since > [note1] > and [note2] both appear twice, they get scaled twice. > > That's the reason you should always copy music with ly:music-deep-copy > or an equivalent if you need it to appear in several places. > > In your example > > \relative c' { > \double {e4 e} > } > > what happens is the following: \relative changes the first e4 into an > absolute > e'4, to match the octave of c' . Then the second e is changed to e'4 as > well, > to have the same octave as the first. Then the third e is processed, but > it's > actually the same object as the first e4, which was mutated into e'4, so > this > tells \relative to go an octave higher, and that e'4 is mutated a second > time > into an e''4. And finally, the fourth e is processed, it's the same as the > second > e which was turned into e', which goes an octave up, so it becomes e'''. > And that's why the end result is e''4 e''' e''4 e'''. > > So this is already a better version: > > double = > #(define-music-function (music)(ly:music?) > (make-music 'SequentialMusic > 'elements (list (ly:music-deep-copy music) > (ly:music-deep-copy music)))) > > or more simply put: > > double = > #(define-music-function (music)(ly:music?) > #{ $music $music #}) > > but in fact this is still not correct because \relative is a somewhat > special beast. The problem is that > > \relative c' { > \double {e'4 e} > } > > now unfolds to > > \relative c' { > { e'4 e e'4 e } > } > > where the third e'4 goes an octave up compared to the second, but you > don't want that, you want it to be the same as the first e'4. For that > case, there is a special macro called make-relative. It's used like this: > > \version "2.24.1" > > double = > #(define-music-function (music) (ly:music?) > (make-relative (music) music > #{ $music $music #})) > > > Best, > Jean > >