Re: A challenging music transformation...

2021-08-26 Thread lilypond
Hello Gordon,

I’ve created a function for replacing arbitrary chords with other chords. Note 
that this requires the use of absolute notation, because to support relative 
notation I’d need to implement my own parser just to know what octave the 
notes are in.

Cheers,
Valentin\version "2.22"

% returns a string representation of a pitch
#(define (pitch->str p)
   (string-append "Po"
  (number->string (ly:pitch-octave p))
  "n"
  (number->string (ly:pitch-notename p

% returns a symbol representation of a list of pitches
#(define (signature pitches)
   (let
((sp (sort pitches ly:pitchsymbol (apply string-append (map pitch->str sp)

% takes a alist that maps symbol representations of chords to a list of pitches and some music
% and replaces all occurences of chords with the key pitches in the alist with chords with the
% pitches associated with that key
replaceChords =
#(define-music-function (replacements mus) (list? ly:music?)
   ; get a list of all notes in music
   (define (extract-notes music)
 (let
  ((name (ly:music-property music 'name))
   (elt (ly:music-property music 'element))
   (elts (ly:music-property music 'elements)))
  (if (eq? name 'NoteEvent)
  (let
   ((nelt (if (null? elt) elt (extract-notes elt)))
(nelts (apply append (map extract-notes elts
   (cons music (append nelt nelts)))
  (let
   ((nelt (if (null? elt) elt (extract-notes elt)))
(nelts (apply append (map extract-notes elts
   (append nelt nelts)
   ; get the duration of a chord from one of the notes in the chord
   (define (extract-duration notes)
 (if (null? notes) 0
 (ly:music-property (first notes) 'duration)))
   ; get pitch from a note
   (define (extract-one-pitch note)
 (ly:music-property note 'pitch))
   ; get list of pitches from a list of notes
   (define (extract-pitch notes)
 (map extract-one-pitch notes))
   ; check if argument is a note
   (define (is-note? music)
 (eq? (ly:music-property music 'name) 'NoteEvent))
   ; check if argument is not a note
   (define (is-not-note? music)
 (not (is-note? music)))
   ; remove all notes from 'elements
   (define (remove-notes music)
 (let
  ((elt (ly:music-property music 'element))
   (elts (ly:music-property music 'elements)))
  (if (not (null? elt))
  (if (is-note? elt)
  (ly:music-set-property! music 'element '())
  (remove-notes elt)))
  (ly:music-set-property! music 'elements
  (filter is-not-note? elts))
  (map remove-notes (ly:music-property music 'elements
   ; add specified notes to 'elements
   (define (add-notes music pitches dur)
 (define (add-note p)
   (if (not (null? p))
   (begin
(ly:music-set-property! music 'elements
(cons
 (make-music
   'NoteEvent
   'pitch
   (car p)
   'duration
   (ly:make-duration 2))
 (ly:music-property music 'elements)))
(add-note (cdr p)
 (add-note pitches))
   ; parse music tree
   (define (walk-music-tree music)
 (let
  ((name (ly:music-property music 'name))
   (elt (ly:music-property music 'element))
   (elts (ly:music-property music 'elements)))
  ; is music a chord?
  (if (eq? name 'EventChord)
  (let*
   ((note-raw (extract-notes music))
(duration (extract-duration note-raw))
(notes (sort (extract-pitch note-raw) ly:pitchpitches mus)
   (define (extract-notes music)
 (let
  ((name (ly:music-property music 'name))
   (elt (ly:music-property music 'element))
   (elts (ly:music-property music 'elements)))
  (if (eq? name 'NoteEvent)
  (let
   ((nelt (if (null? elt) elt (extract-notes elt)))
(nelts (apply append (map extract-notes elts
   (cons music (append nelt nelts)))
  (let
   ((nelt (if (null? elt) elt (extract-notes elt)))
(nelts (apply append (map extract-notes elts
   (append nelt nelts)
   (define (extract-one-pitch note)
 (ly:music-property note 'pitch))
   (define (extract-pitch notes)
 (map extract-one-pitch notes))
   ; is music a chord?
   (let
((note-raw (extract-notes mus)))
(sort (extract-pitch note-raw) ly:pitchpitches mus)))

% takes music of the form { a1 a2 b1 b2 ... } and returns a replacement alist
% for replacing a1 with a2, b1 with b2, ...
replistfrommusic=#(define-scheme-function (mus) (ly:music?)
   (define (walk-elts elts)
(if (or (null? elts) (null? (cdr elts)))
'()
(cons (cons (sigchord 

Re: A challenging music transformation...

2021-08-25 Thread David Kastrup
Gordon Bower  writes:

> Your problem is simpler in one essential way: you are neither adding nor
> subtracting any notes, just repitching existing notes. I feel fairly
> confident I could solve yours -- use map-some-music to find every
> NoteEvent, and for each one, read the old pitch, look up the corresponding
> new pitch, and write the new pitch.
>
> The writers of \addNote and \pitchChange found ways to deal with having the
> replacement have more notes than the original did. "Convert a note into a
> chord with all the same slurs, dots, etc etc hanging off it" still eludes
> me. It seems that articulations get stored in two different places
> according to whether they apply to a note or to a chord.

LilyPond will typeset articulations placed into the 'articulations
property of an EventChord even though that is not the "correct" way to
write them.  That makes it somewhat easier to arrive at working
transformations.

-- 
David Kastrup



Re: A challenging music transformation...

2021-08-25 Thread Gordon Bower
Your problem is simpler in one essential way: you are neither adding nor
subtracting any notes, just repitching existing notes. I feel fairly
confident I could solve yours -- use map-some-music to find every
NoteEvent, and for each one, read the old pitch, look up the corresponding
new pitch, and write the new pitch.

The writers of \addNote and \pitchChange found ways to deal with having the
replacement have more notes than the original did. "Convert a note into a
chord with all the same slurs, dots, etc etc hanging off it" still eludes
me. It seems that articulations get stored in two different places
according to whether they apply to a note or to a chord.

GRB

On Wed, Aug 25, 2021 at 5:37 PM Craig Comstock 
wrote:

> Maybe check this thread out. It mostly worked for me but I think your
> problem if solved will help me even more!
>
> https://mail.gnu.org/archive/html/lilypond-user/2021-08/msg00018.html
>
>
>


Re: A challenging music transformation...

2021-08-25 Thread Craig Comstock
Maybe check this thread out. It mostly worked for me but I think your problem 
if solved will help me even more!

https://mail.gnu.org/archive/html/lilypond-user/2021-08/msg00018.html

Sent from my iPhone

> On Aug 25, 2021, at 5:47 PM, David Kastrup  wrote:
> 
> Gordon Bower  writes:
> 
>> In a nutshell, I would like to write a function that would let me replace a
>> given note or chord with a different chord -- I might have a table of what
>> gets replaced with what -- but leave all the articulations the same.
>> 
>> Am I missing something obvious?
>> 
>> The \addNote snippet does something similar - except that there isn't a
>> convenient way to delete the original note after the replacements are added.
>> 
>> The \changePitch snippet also does something similar. (But I am envision a
>> chord-by-chord replacement of a whole line.)
>> 
>> My own efforts at trying to make sense of how music-map or map-some-music
>> work have *cough* not been going well. Would be nice not to completely
>> reinvent a wheel here.
>> 
>> If I do have to write it myself: I think I could figure out how to extract
>> a list of pitches in all the NoteEvents in a chord, and push new NoteEvents
>> to the chord - but I don't have much grasp as to how I replace a single
>> note by a chord.
>> 
>> (Why would I want to do this? I am trying to write a function that turns
>> the written notes of the accordion's left hand into the sounding notes.
>> Written notes between c, and b, get turned into parallel octaves depending
>> which reed banks are sounding; written notes between d and c' get turned
>> into 3- 6- or 9-note chords, depending which reed banks are sounding.)
> 
> It's probably not going to help a whole lot, cough cough.  But here is
> the code I used to illustrate the 168 different bass registrations of
> my accordion in a reasonably compact arrangement.  Of course you'll
> likely need to outcomment the image inclusion.
> 
> 
> \version "2.19.22" \paper { ragged-last = ##f } #(define (number-or-pitch? a) 
> (or (integer? a) (ly:pitch? a))) bass-staff = "lo" bass-clef = "bass" 
> bass-desc = \markuplist { } bari-low-desc = \markuplist { (stem down, solid 
> heads) } bv-one = { \voiceOne \harmonicsOn } bv-two = { \voiceTwo 
> \harmonicsOn } tv-one = { \voiceOne \harmonicsOn } tv-two = \voiceTwo sv-one 
> = { \voiceOne \harmonicsOn } sv-two = \voiceTwo %%{ bass-staff = "hi" 
> bass-clef = "treble" bass-desc = \markuplist { (stem down, diamond heads) } 
> bari-low-desc = \markuplist { (stem up, solid heads) } bv-one = { \voiceFour 
> \harmonicsOn } bv-two = { \voiceTwo \harmonicsOn } tv-one = { \voiceOne 
> \harmonicsOn } tv-two = \voiceThree sv-one = { \voiceOne \harmonicsOn } 
> sv-two = \voiceTwo %} #(define stats (make-hash-table 20)) #(define 
> (add-to-stats pitch chordname count) (let ((p (hashv-create-handle! stats 
> count '())) (num (modulo (ly:pitch-semitones (ly:pitch-diff pitch #{ a #})) 
> 12))) (set-cdr! p (cons (cons num chordname) (cdr p) #(define 
> (stats-list) (define (sort-pairs lst) (map cdr (sort-list lst car<))) (map 
> (lambda (e) #{ \markuplist \override-lines #'(word-space . 1) \wordwrap-lines 
> #(cons (format #f "~d reeds:" (car e)) (fold-right (lambda (next lst) (cons 
> (string-append next (if (null? lst) "." ",")) lst)) '() (sort-pairs (reverse 
> (cdr e) #}) (sort-list (hash-table->alist stats) car<))) chordmap = 
> #(define-music-function (start width music) (number-or-pitch? index? 
> ly:music?) (if (ly:pitch? start) (set! start (ly:pitch-semitones start))) 
> (map-some-music (lambda (m) (and (music-is-of-type? m 'event-chord) (begin 
> (set! (ly:music-property m 'elements) (append-map (lambda (x) (let ((p 
> (ly:music-property x 'pitch))) (if (ly:pitch? p) (let loop ((n (ly:make-pitch 
> (- (ly:pitch-octave p) (floor (/ (- (ly:pitch-semitones p) start) 12))) 
> (ly:pitch-notename p) (ly:pitch-alteration p))) (l '())) (if (< 
> (ly:pitch-semitones n) (+ start width)) (loop (ly:pitch-transpose 
> (ly:make-pitch 1 0 0) n) (cons (music-clone x 'pitch n) l)) l)) (list x 
> (ly:music-property m 'elements))) m))) music)) #(define (conflate keys vals) 
> (define (folder k v res) (if (or (null? res) (not (equal? v (cdar res 
> (cons (cons (list k) v) res) (cons (cons (cons k (caar res)) (cdar res)) (cdr 
> res (fold-right folder '() keys vals)) #(define (one-set start count 
> music) (map (lambda (kv) (let ((keys (car kv)) (m (cdr kv))) (cons (if (null? 
> (cdr keys)) (format "~d" (car keys)) (format "~d–~d" (car keys) (last keys))) 
> m))) (conflate (iota count 1) (map (lambda (i) #{ \chordmap #i #12 $music #}) 
> (iota count (ly:pitch-semitones start)) #(define (bass-format-set pitch 
> name) (let ((bass #{ \chordmap e,, 12 < $pitch >4 #}) (accf #{ \chordmap a, 
> 41 < $pitch >4 #}) (accp (one-set #{ a, #} 20 #{ < $pitch >4 #}))) 
> (add-to-stats pitch (string-upcase name) (+ 2 (* 2 (length (ly:music-property 
> accf ' elements) #{ << \context Staff = "hi" << \new Voice 

A challenging music transformation...

2021-08-25 Thread Gordon Bower
In a nutshell, I would like to write a function that would let me replace a
given note or chord with a different chord -- I might have a table of what
gets replaced with what -- but leave all the articulations the same.

Am I missing something obvious?

The \addNote snippet does something similar - except that there isn't a
convenient way to delete the original note after the replacements are added.

The \changePitch snippet also does something similar. (But I am envision a
chord-by-chord replacement of a whole line.)

My own efforts at trying to make sense of how music-map or map-some-music
work have *cough* not been going well. Would be nice not to completely
reinvent a wheel here.

If I do have to write it myself: I think I could figure out how to extract
a list of pitches in all the NoteEvents in a chord, and push new NoteEvents
to the chord - but I don't have much grasp as to how I replace a single
note by a chord.

(Why would I want to do this? I am trying to write a function that turns
the written notes of the accordion's left hand into the sounding notes.
Written notes between c, and b, get turned into parallel octaves depending
which reed banks are sounding; written notes between d and c' get turned
into 3- 6- or 9-note chords, depending which reed banks are sounding.)

GRB