Re: custom replace/map of one set of pitches to another
Lukas-Fabian Moser writes: > Hi Valentin, > > Am 01.09.23 um 00:41 schrieb Valentin Petzel: >> I don’t think this is a particularly good idea. Lilypond conceptually first >> creates data for the sementic meaning of the music (or the actual content) >> and >> have engravers turn this into graphical content. >> >> Mapping pitches to other pitches is not a layout option, but a musical >> transformation and should thus be done on the music level, not the layout >> level. Using an engraver will mean it is hard to combine this with other >> musical transformations, and it will also cause order issues as soon as you >> have an engraver that depends on the pitch property. > > I agree about the possible problems, and to be honest, I wasn't aware > that a music function solution like yours can deal with \transpose and > \relative gracefully (since the assignment of actual pitches is > complete when the music function is applied on the outside). Iff the music function is applied on the outside. -- David Kastrup
Re: custom replace/map of one set of pitches to another
Hi Valentin, Am 01.09.23 um 00:41 schrieb Valentin Petzel: I don’t think this is a particularly good idea. Lilypond conceptually first creates data for the sementic meaning of the music (or the actual content) and have engravers turn this into graphical content. Mapping pitches to other pitches is not a layout option, but a musical transformation and should thus be done on the music level, not the layout level. Using an engraver will mean it is hard to combine this with other musical transformations, and it will also cause order issues as soon as you have an engraver that depends on the pitch property. I agree about the possible problems, and to be honest, I wasn't aware that a music function solution like yours can deal with \transpose and \relative gracefully (since the assignment of actual pitches is complete when the music function is applied on the outside). What I don't necessarily agree with is the philosophical notion of engravers being tied to the layout level (which is admittedly suggested by their name): As long as I work with listeners (as opposed to acknowledgers), I see no problem in using them for "semantic" transformations that need the music sorted by timestep (which nevertheless is not the case in the current situation). Lukas
Re: custom replace/map of one set of pitches to another
Thank you Valentin for this solution and the following explanation why it is likely safer. All responses have been much appreciated. Best, Michael Sep 1, 2023, 00:15 by valen...@petzel.at: > Hi Michael, > > some time ago I created a function for exactly that for a stackexchange > question: > https://music.stackexchange.com/questions/127175/lilypond-transpose-a-sequence-to-modes-with-different-intervallic-structure > > Essentially it introduces a function to map one scale to another, and it does > so by basepitch to retain alteration. One could easily adapt this function to > match by base pitch and alteration: > > transposePitchClasses = > #(define-music-function (scaleA scaleB music) (ly:music? ly:music? ly:music?) > (let* ((scaleA (ly:music-property scaleA 'elements)) > (scaleB (ly:music-property scaleB 'elements)) > (scaleA (map (lambda (x) (ly:music-property x 'pitch)) scaleA)) > (scaleB (map (lambda (x) (ly:music-property x 'pitch)) scaleB)) > (classesA (map (lambda (p) (cons (ly:pitch-notename p) (ly:pitch- > alteration p))) scaleA))) > (map-some-music > (lambda (m) > (let ((p (ly:music-property m 'pitch))) > (if (not (null? p)) > (let* ((nn (ly:pitch-notename p)) > (oct (ly:pitch-octave p)) > (alt (ly:pitch-alteration p)) > (pos (list-index (lambda (x) (and (= (car x) nn) (= (cdr x) > alt))) classesA))) > (if pos > (let* ((p2 (list-ref scaleA pos)) > (oct2 (ly:pitch-octave p2)) > (p3 (list-ref scaleB pos)) > (new-pitch (ly:pitch-transpose p3 (ly:make-pitch (- > oct oct2) 0 > (ly:music-set-property! m 'pitch new-pitch))) > m) > #f))) > music) > music)) > > \transposePitchClasses {d fih g aih} {dih f gis a} > { c' cis' d' dis' f' fih' fis' g' a' aih' } > > Am Donnerstag, 31. August 2023, 12:53:26 CEST schrieb Michael Winter via > LilyPond user discussion: > >> I would like to do something (hopefully simple), which is basically a custom >> find and replace for a set of notes in an entire score. >> >> For example {c cis d dis fih g aih} -> {c cis dih dis f gis a} >> >> So basically on arbitrary list of pitches / scale to another. >> >> Is this possible without writing a custom function. If not, any hints on how >> to tackle the problem would be much appreciated. Thanks in advance. >> >> -Michael >>
Re: custom replace/map of one set of pitches to another
Hello Lukas, I don’t think this is a particularly good idea. Lilypond conceptually first creates data for the sementic meaning of the music (or the actual content) and have engravers turn this into graphical content. Mapping pitches to other pitches is not a layout option, but a musical transformation and should thus be done on the music level, not the layout level. Using an engraver will mean it is hard to combine this with other musical transformations, and it will also cause order issues as soon as you have an engraver that depends on the pitch property. Cheers, Valentin Am Donnerstag, 31. August 2023, 14:35:45 CEST schrieb Lukas-Fabian Moser: > Hi Michael, > > over time, I found that doing something like this in an engraver (as > opposed to a music function) is actually much easier and conceptually > clear, in spite of the seeming difficulty of the engraver syntax. The > advantage of using an engraver being that you see the "actual" pitches > and don't have to fight with problems of \relative, \transpose and so on. > > \version "2.24.0" > > pitch-replace-dictionary = > #(list >(cons #{ c #} #{ cis #}) >(cons #{ d #} #{ des #}) >) > > #(define (pitch-class= p q) > (and > (= (ly:pitch-notename p) (ly:pitch-notename q)) > (= (ly:pitch-alteration p) (ly:pitch-alteration q > > Pitch_replace_engraver = > #(lambda (context) > (make-engraver > (listeners > ((note-event engraver event) >(let* > ((pitch (ly:event-property event 'pitch)) > (rule (assoc pitch pitch-replace-dictionary pitch-class=))) > > (if rule > (ly:event-set-property! > event 'pitch > (ly:make-pitch (ly:pitch-octave pitch) > (ly:pitch-notename (cdr rule)) > (ly:pitch-alteration (cdr rule)) > > \layout { >\context { > \Score > \consists #Pitch_replace_engraver >} > } > > \relative { >c'4 d e c8 8 >\transpose f c \relative { > f'4 g a >} > } > > This engraver can also be added to just a single score (\layout inside > \score {}) or even a single Staff or Voice. At the moment, the > replacement dictionary is global, but this could be changed if needed. > > At the moment the mechanism I chose is too crude to do replacements that > involve changing the pitch-octave (eg from c to b,). Do you need this? > > Lukas > > Am 31.08.23 um 12:53 schrieb Michael Winter via LilyPond user discussion: > > I would like to do something (hopefully simple), which is basically a > > custom find and replace for a set of notes in an entire score. > > > > For example {c cis d dis fih g aih} -> {c cis dih dis f gis a} > > > > So basically on arbitrary list of pitches / scale to another. > > > > Is this possible without writing a custom function. If not, any hints > > on how to tackle the problem would be much appreciated. Thanks in advance. > > > > -Michael signature.asc Description: This is a digitally signed message part.
Re: custom replace/map of one set of pitches to another
Hi Michael, some time ago I created a function for exactly that for a stackexchange question: https://music.stackexchange.com/questions/127175/lilypond-transpose-a-sequence-to-modes-with-different-intervallic-structure Essentially it introduces a function to map one scale to another, and it does so by basepitch to retain alteration. One could easily adapt this function to match by base pitch and alteration: transposePitchClasses = #(define-music-function (scaleA scaleB music) (ly:music? ly:music? ly:music?) (let* ((scaleA (ly:music-property scaleA 'elements)) (scaleB (ly:music-property scaleB 'elements)) (scaleA (map (lambda (x) (ly:music-property x 'pitch)) scaleA)) (scaleB (map (lambda (x) (ly:music-property x 'pitch)) scaleB)) (classesA (map (lambda (p) (cons (ly:pitch-notename p) (ly:pitch- alteration p))) scaleA))) (map-some-music (lambda (m) (let ((p (ly:music-property m 'pitch))) (if (not (null? p)) (let* ((nn (ly:pitch-notename p)) (oct (ly:pitch-octave p)) (alt (ly:pitch-alteration p)) (pos (list-index (lambda (x) (and (= (car x) nn) (= (cdr x) alt))) classesA))) (if pos (let* ((p2 (list-ref scaleA pos)) (oct2 (ly:pitch-octave p2)) (p3 (list-ref scaleB pos)) (new-pitch (ly:pitch-transpose p3 (ly:make-pitch (- oct oct2) 0 (ly:music-set-property! m 'pitch new-pitch))) m) #f))) music) music)) \transposePitchClasses {d fih g aih} {dih f gis a} { c' cis' d' dis' f' fih' fis' g' a' aih' } Am Donnerstag, 31. August 2023, 12:53:26 CEST schrieb Michael Winter via LilyPond user discussion: > I would like to do something (hopefully simple), which is basically a custom > find and replace for a set of notes in an entire score. > > For example {c cis d dis fih g aih} -> {c cis dih dis f gis a} > > So basically on arbitrary list of pitches / scale to another. > > Is this possible without writing a custom function. If not, any hints on how > to tackle the problem would be much appreciated. Thanks in advance. > > -Michael signature.asc Description: This is a digitally signed message part.
Re: custom replace/map of one set of pitches to another
That is very helpful. Thank you. I will ping again if I have any further questions. Aug 31, 2023, 14:35 by l...@gmx.de: > Hi Michael, > > over time, I found that doing something like this in an engraver (as opposed > to a music function) is actually much easier and conceptually clear, in spite > of the seeming difficulty of the engraver syntax. The advantage of using an > engraver being that you see the "actual" pitches and don't have to fight with > problems of \relative, \transpose and so on. > > \version "2.24.0" > > pitch-replace-dictionary = > #(list > (cons #{ c #} #{ cis #}) > (cons #{ d #} #{ des #}) > ) > > #(define (pitch-class= p q) > (and > (= (ly:pitch-notename p) (ly:pitch-notename q)) > (= (ly:pitch-alteration p) (ly:pitch-alteration q > > Pitch_replace_engraver = > #(lambda (context) > (make-engraver > (listeners > ((note-event engraver event) > (let* > ((pitch (ly:event-property event 'pitch)) > (rule (assoc pitch pitch-replace-dictionary pitch-class=))) > > (if rule > (ly:event-set-property! > event 'pitch > (ly:make-pitch (ly:pitch-octave pitch) > (ly:pitch-notename (cdr rule)) > (ly:pitch-alteration (cdr rule)) > > \layout { > \context { > \Score > \consists #Pitch_replace_engraver > } > } > > \relative { > c'4 d e c8 8 > \transpose f c \relative { > f'4 g a > } > } > > This engraver can also be added to just a single score (\layout inside \score > {}) or even a single Staff or Voice. At the moment, the replacement > dictionary is global, but this could be changed if needed. > > At the moment the mechanism I chose is too crude to do replacements that > involve changing the pitch-octave (eg from c to b,). Do you need this? > > Lukas > > Am 31.08.23 um 12:53 schrieb Michael Winter via LilyPond user discussion: > >> I would like to do something (hopefully simple), which is basically a custom >> find and replace for a set of notes in an entire score. >> >> For example {c cis d dis fih g aih} -> {c cis dih dis f gis a} >> >> So basically on arbitrary list of pitches / scale to another. >> >> Is this possible without writing a custom function. If not, any hints on how >> to tackle the problem would be much appreciated. Thanks in advance. >> >> -Michael >>
Re: custom replace/map of one set of pitches to another
Hi Michael, over time, I found that doing something like this in an engraver (as opposed to a music function) is actually much easier and conceptually clear, in spite of the seeming difficulty of the engraver syntax. The advantage of using an engraver being that you see the "actual" pitches and don't have to fight with problems of \relative, \transpose and so on. \version "2.24.0" pitch-replace-dictionary = #(list (cons #{ c #} #{ cis #}) (cons #{ d #} #{ des #}) ) #(define (pitch-class= p q) (and (= (ly:pitch-notename p) (ly:pitch-notename q)) (= (ly:pitch-alteration p) (ly:pitch-alteration q Pitch_replace_engraver = #(lambda (context) (make-engraver (listeners ((note-event engraver event) (let* ((pitch (ly:event-property event 'pitch)) (rule (assoc pitch pitch-replace-dictionary pitch-class=))) (if rule (ly:event-set-property! event 'pitch (ly:make-pitch (ly:pitch-octave pitch) (ly:pitch-notename (cdr rule)) (ly:pitch-alteration (cdr rule)) \layout { \context { \Score \consists #Pitch_replace_engraver } } \relative { c'4 d e c8 8 \transpose f c \relative { f'4 g a } } This engraver can also be added to just a single score (\layout inside \score {}) or even a single Staff or Voice. At the moment, the replacement dictionary is global, but this could be changed if needed. At the moment the mechanism I chose is too crude to do replacements that involve changing the pitch-octave (eg from c to b,). Do you need this? Lukas Am 31.08.23 um 12:53 schrieb Michael Winter via LilyPond user discussion: I would like to do something (hopefully simple), which is basically a custom find and replace for a set of notes in an entire score. For example {c cis d dis fih g aih} -> {c cis dih dis f gis a} So basically on arbitrary list of pitches / scale to another. Is this possible without writing a custom function. If not, any hints on how to tackle the problem would be much appreciated. Thanks in advance. -Michael
Re: custom replace/map of one set of pitches to another
I am now realizing that it would be useful to have this both at the level of the entire score and individually for each part. Aug 31, 2023, 12:53 by mwin...@unboundedpress.org: > I would like to do something (hopefully simple), which is basically a custom > find and replace for a set of notes in an entire score. > > For example {c cis d dis fih g aih} -> {c cis dih dis f gis a} > > So basically on arbitrary list of pitches / scale to another. > > Is this possible without writing a custom function. If not, any hints on how > to tackle the problem would be much appreciated. Thanks in advance. > > -Michael >
custom replace/map of one set of pitches to another
I would like to do something (hopefully simple), which is basically a custom find and replace for a set of notes in an entire score. For example {c cis d dis fih g aih} -> {c cis dih dis f gis a} So basically on arbitrary list of pitches / scale to another. Is this possible without writing a custom function. If not, any hints on how to tackle the problem would be much appreciated. Thanks in advance. -Michael