lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Scheme coding] how to turn pitches into music


From: Aaron Hill
Subject: Re: [Scheme coding] how to turn pitches into music
Date: Sat, 25 Jan 2020 08:23:18 -0800
User-agent: Roundcube Webmail/1.3.8

On 2020-01-25 7:48 am, Kieren MacMillan wrote:
Perhaps the simplest option is to avoid ly:music and instead use splicing to let the parser do the heavy lifting:

I assume you mean the "$@", which is the only thing in this code I
don’t understand?

Yes. The list-splicing forms of # and $ are #@ and $@, respectively. In this case, we are using $@ to take the list of bare pitches and have the parser handle them the same as if the user had simply entered them.

Note that I refactored your nested maps into a single one.

Will the performance be improved, or only the compactness of the code?

I have learned to never make assumptions on performance without concrete, profiling data. It is possible that Guile's compiler is smart enough to optimize the nested maps, so performance might not differ. In general, a single map means only one pass through a collection, so cache utilization is often better. But on such small data sets, the benefits are going to be minimal.

Mainly, I wanted to show you a different coding pattern just so you are aware of the options available. Nested maps are useful when you need to manipulate the collection as a whole in-between steps. But if you are only operating on the individual elements, a single map usually makes more sense.

Also: I notice that rests and skips are ignored:

This is intuitive/understandable to me (given the functions we’re
using); and I’m glad they’re just ignored [rather than causing
errors]. But how can I turn every rest or skip into a skip [of
equivalent duration] in the output? My intuition tells me I should use
an if statement… but I’m betting there’s a more automagic way.  =)

music-pitches extracts just the pitch information from the music. That means a lot of what makes up a music expression is lost in the process. For instance, chords will appear as individual pitches. Depending on your needs, this could be acceptable.

However, is it ultimately your intention to transform a music expression by altering the pitches according to some process (like a \modalTranspose)? If so, extracting pitches is probably not the best approach. Instead, you will want to use music-map (or one of its kin) to help you traverse the music expression, so you can then conditionally modify each part as needed.

%%%%
\version "2.19.83"
\language "english"

rowrefs = #'(6 8 7 2 3 12 5 4 11 1 10 9)
test = { ef4. <fs' a'>8 g2 r4 <b d''>8 cs' }

row-staff-notes =
#(define-music-function (mus) (ly:music?)
  #{ $@(map (lambda (pitch)
              (let* ((semitone (ly:pitch-semitones pitch))
                     (index (modulo semitone (length rowrefs))))
                (ly:make-pitch 0 (list-ref rowrefs index) 0)))
            (music-pitches mus)) #})

<<
  { <>8 $@(music-pitches test) }
  { <>8 \row-staff-notes \test }


xform-pitches =
#(define-music-function (music) (ly:music?)
  (music-map
    (lambda (elem)
      (if (memq 'note-event (ly:music-property elem 'types))
        (let* ((pitch (ly:music-property elem 'pitch))
               (semitone (ly:pitch-semitones pitch))
               (index (modulo semitone (length rowrefs))))
          (ly:music-set-property! elem 'pitch
            (ly:make-pitch 0 (list-ref rowrefs index) 0))))
      elem)
    music)
  music)

<<
  { \test }
  { \xform-pitches \test }

%%%%

-- Aaron Hill



reply via email to

[Prev in Thread] Current Thread [Next in Thread]