Re: need help building a Scheme function

2024-06-25 Thread Lukas-Fabian Moser

[Sorry! I wrote this two days ago on a train in one of the famous German
cell connection dead zones - and then forgot to actually send it later.]

Hi Kieren,


The last "m" in your innermost (if ...) is unnecessary: As with the difference between "for" and 
"map" in plain Scheme, the return value of the lambda function in for-some-music gets discarded ("for" 
functions are supposed to _do_ something, not _return_ something). So your branch stating "... else return m" can be 
omitted.

Excellent.


Well, modulo David's correction. :-)

It's true that the lambda function in for-some-music isn't supposed to
return the music it has produced. But since its return value determines
(as a boolean) whether to recurse, we should make sure to

- return ##f if our music argument m is not a note-event (but might
contain one)
- return a true value if we don't want to recurse any further. Since
note-events usually don't contain any other music, this might never
actually matter, but it is good to also read your code in the note-event
case and check which value gets returned in which case.

It might be worth noting that an (if condition then-clause) expression
without an else-clause returns and unspecified value if condition is #f.
https://www.gnu.org/software/guile/manual/html_node/Conditionals.html


Next, as you already hinted: If you use the same expression more than once 
(here (ly:music-property m 'pitch)), it is usually reasonably to store it in a 
variable, i.e. use (let ...).

Why wouldn’t I use let* here? I 
readhttps://extending-lilypond.gitlab.io/en/scheme/local-variables.html#let-syntax,
 and unless there’s some big-ticket efficiency problem under the hood, I don’t 
see why anyone would use let instead of let*.

I do not know if there are efficiency differences between let and let*
(but I doubt it). Personally, I use let if I don't need let*, since this
way, when I re-read my code, I immediately know that the let-assignments
do not depend on one another.



we rather want a list of pairs (old-pitch . new-pitch)

That’s the interface I was thinking of.


In order to construct such a list of pairs from two music inputs as above, (map 
...) provides a very elegant way.

In the case of a simple scale,

\adjustPitches scaleIn scaleOut

and then post-processing into lists, etc., makes some sense. But what about 
sending in pairs instead? e.g.

\adjustPitches ((ces c) (c b') (e g))

There would be the question of whether the user wants to process each pair 
consecutively (e.g., all ces become c, then all c [including the old ces] 
become b', etc.)… Maybe both options made available, with either a switch or 
optional parameter(s)?


The problem is that (ces c), or rather (ces . c), is Scheme syntax (and
requires ` and , when ces and c should not be taken as mere symbols),
but we don't have note name input in Scheme. So this would actually be
something like

(list (cons #{ ces #} #{ c #}) (cons #{ c #} #{ b #}))

or

`((,#{ ces #} . ,#{ c #}) (,#{ c #} . ,#{ b #}))

both of which make my brain hurt :-).

A way of inputting the pitches in LilyPond syntax might be much more
convenient. Possibilites that come to mind might be

{ ces c e } { c b' g }

{ ces c c b' e g }

{}

etc., all of which are comparatively easy to implement (the first one
probably being the easiest).

Lukas



Re: need help building a Scheme function

2024-06-23 Thread Kieren MacMillan
Hi Lukas!

Thanks for the patient and helpful tutorial(s).  :)

> The last "m" in your innermost (if ...) is unnecessary: As with the 
> difference between "for" and "map" in plain Scheme, the return value of the 
> lambda function in for-some-music gets discarded ("for" functions are 
> supposed to _do_ something, not _return_ something). So your branch stating 
> "... else return m" can be omitted.

Excellent.

> Next, as you already hinted: If you use the same expression more than once 
> (here (ly:music-property m 'pitch)), it is usually reasonably to store it in 
> a variable, i.e. use (let ...).

Why wouldn’t I use let* here? I read 
https://extending-lilypond.gitlab.io/en/scheme/local-variables.html#let-syntax, 
and unless there’s some big-ticket efficiency problem under the hood, I don’t 
see why anyone would use let instead of let*.

> Also some food for thought, if I may:
> - What if I want to replace each b by the c _above_ it?

Yes, you are thinking what I’m thinking, for the final version.  :)

> we rather want a list of pairs (old-pitch . new-pitch)

That’s the interface I was thinking of.

> In order to construct such a list of pairs from two music inputs as above, 
> (map ...) provides a very elegant way.

In the case of a simple scale,

   \adjustPitches scaleIn scaleOut

and then post-processing into lists, etc., makes some sense. But what about 
sending in pairs instead? e.g.

   \adjustPitches ((ces c) (c b') (e g))

There would be the question of whether the user wants to process each pair 
consecutively (e.g., all ces become c, then all c [including the old ces] 
become b', etc.)… Maybe both options made available, with either a switch or 
optional parameter(s)?

Cheers,
Kieren.
__

My work day may look different than your work day. Please do not feel obligated 
to read or respond to this email outside of your normal working hours.




Re: need help building a Scheme function

2024-06-23 Thread Lukas-Fabian Moser

The last "m" in your innermost (if ...) is unnecessary: As with the
difference between "for" and "map" in plain Scheme, the return value of
the lambda function in for-some-music gets discarded ("for" functions
are supposed to _do_ something, not _return_ something).

No, it doesn't.  It is a boolean that determines whether to recurse (#f)
or not (everything else).


Of course you're right, my bad. To be more precise:

- Plain Scheme (for ...) is indeed not supposed to return something but
rather do something.
- LilyPond's (for-some-music ...) is intended to i) do something, ii)
return a boolean indicating whether the recursion should continue (kind
of "is my work done in this branch of music?").

Of course that's what you explained, I just wanted to point out the
comparison with standard "for".

So @Kieren: In your example you should take care to control the return
value of your lambda (in particular, also in the else-branches of your
if's.)

Lukas


Re: need help building a Scheme function

2024-06-23 Thread Lukas-Fabian Moser

Hi David,


If you don't want to call upon undocumented internals of LilyPond (the
(@@ (lily) ...) bit), you can just use


[with-output-to-string]

Wow, thanks! I hadn't encountered this possibility yet.

Also thanks for pointing out the possibility of in-place modification.

Lukas


Re: need help building a Scheme function

2024-06-23 Thread Lukas-Fabian Moser

Hi Kieren,


for-some-music does not return music.  It works on music in-place.  So
the last thing in your music function must not be for-some-music but
rather the music that you have been working on.

So…

%%%  SNIPPET BEGINS
adjustPitch =
#(define-music-function (pitchIn pitchOut music) (ly:pitch? ly:pitch? ly:music?)
(for-some-music
 (lambda (m)
 (if (music-is-of-type? m 'note-event)
 (if (and (= (ly:pitch-notename (ly:music-property m 'pitch)) 
(ly:pitch-notename pitchIn))
   (= (ly:pitch-alteration (ly:music-property m 
'pitch)) (ly:pitch-alteration pitchIn)))
 (ly:music-set-property! m 'pitch
 (ly:make-pitch
  (ly:pitch-octave (ly:music-property m 
'pitch))
  (ly:pitch-notename pitchOut)
  (ly:pitch-alteration pitchOut)))
 m)
 #f))
 music)
 music)

testmusic = \fixed c' { c4 d es e f g c' es' eis }

{ \testmusic }

{ \adjustPitch ees e \testmusic }
%%%  SNIPPET ENDS

??


The last "m" in your innermost (if ...) is unnecessary: As with the
difference between "for" and "map" in plain Scheme, the return value of
the lambda function in for-some-music gets discarded ("for" functions
are supposed to _do_ something, not _return_ something). So your branch
stating "... else return m" can be omitted.

Next, as you already hinted: If you use the same expression more than
once (here (ly:music-property m 'pitch)), it is usually reasonably to
store it in a variable, i.e. use (let ...).

Also some food for thought, if I may:

- What if I want to replace each b by the c _above_ it?

- I've been thinking about a conventient user interface. If I understand
you correctly, you aim for something like a list of input-pitches and a
list of output-pitches, both preferably given as music, so we can do

\adjustPitch { c d e } { fis e d } \music

meaning: turn c into fis, d into e, and e into d. If I'm right, you'll
probably be able to make good use of (music-pitches ...). Also, for
search-and-replace tasks in Scheme, using an association list (alist) as
a dictionary is often convenient. This would mean we rather want a list
of pairs (old-pitch . new-pitch). In order to construct such a list of
pairs from two music inputs as above, (map ...) provides a very elegant way.

See also:

https://www.gnu.org/software/guile/manual/html_node/Association-Lists.html
https://www.gnu.org/software/guile/manual/html_node/List-Mapping.html

Lukas


Re: need help building a Scheme function

2024-06-22 Thread Kieren MacMillan
Hi David,

> for-some-music does not return music.  It works on music in-place.  So
> the last thing in your music function must not be for-some-music but
> rather the music that you have been working on.

So…

%%%  SNIPPET BEGINS
adjustPitch =
#(define-music-function (pitchIn pitchOut music) (ly:pitch? ly:pitch? ly:music?)
   (for-some-music
(lambda (m)
(if (music-is-of-type? m 'note-event)
(if (and (= (ly:pitch-notename (ly:music-property m 'pitch)) 
(ly:pitch-notename pitchIn))
  (= (ly:pitch-alteration (ly:music-property m 'pitch)) 
(ly:pitch-alteration pitchIn)))
(ly:music-set-property! m 'pitch
(ly:make-pitch
 (ly:pitch-octave (ly:music-property m 
'pitch))
 (ly:pitch-notename pitchOut)
 (ly:pitch-alteration pitchOut)))
m)
#f))
music)
music)

testmusic = \fixed c' { c4 d es e f g c' es' eis }

{ \testmusic }

{ \adjustPitch ees e \testmusic }
%%%  SNIPPET ENDS

??

Thanks,
Kieren.
__

My work day may look different than your work day. Please do not feel obligated 
to read or respond to this email outside of your normal working hours.




Re: need help building a Scheme function

2024-06-22 Thread David Kastrup
Kieren MacMillan  writes:

> I tried a few times, but got errors (about returning
> unspecified). Hints appreciated.

for-some-music does not return music.  It works on music in-place.  So
the last thing in your music function must not be for-some-music but
rather the music that you have been working on.

-- 
David Kastrup



Re: need help building a Scheme function

2024-06-22 Thread Kieren MacMillan
Hi David,

> This will also adjust eis and eses to e.  Note names are numbers and can
> be compared with = .  (make-music 'NoteEvent m) is silly and creates an
> unnecessary copy.  You can just use m instead.

Thanks — current version:

%%%  SNIPPET BEGINS
\version "2.25.11"

adjustPitch =
#(define-music-function (pitchIn pitchOut music) (ly:pitch? ly:pitch? ly:music?)
   (music-map
(lambda (m)
(if (music-is-of-type? m 'note-event)
(if (and (= (ly:pitch-notename (ly:music-property m 'pitch)) 
(ly:pitch-notename pitchIn))
  (= (ly:pitch-alteration (ly:music-property m 'pitch)) 
(ly:pitch-alteration pitchIn)))
(ly:music-set-property! m 'pitch
(ly:make-pitch
 (ly:pitch-octave (ly:music-property m 
'pitch))
 (ly:pitch-notename pitchOut)
 (ly:pitch-alteration pitchOut)))
m)
#f)
m)
music))

testmusic = \fixed c' { c4 d es e f g c' es' eis' }

{ \testmusic }

{ \adjustPitch ees e \testmusic }
%%%  SNIPPET ENDS

Q: Is there a more efficient way to test for note name and alteration 
independent of octave?

> If you do, you don't replace any music, so music-map is unnecessary.
> This can be better done with for-some-music .

I tried a few times, but got errors (about returning unspecified). Hints 
appreciated.

As for next step(s): I’m thinking some let-ing would make sense?

Thanks,
Kieren.
__

My work day may look different than your work day. Please do not feel obligated 
to read or respond to this email outside of your normal working hours.




Re: need help building a Scheme function

2024-06-22 Thread David Kastrup
Kieren MacMillan  writes:

> Hi again,
>
>> There is no necessity to return a new NoteEvent; you can just change
>> pitch on the existing one.
>> 
>> Music functions are allowed to modify their music arguments in place.
>
> This is what I have so far, which appears to do what I want:
>
> %%%  SNIPPET BEGINS
> \version "2.25.11"
>
> adjustPitch = 
> #(define-music-function (pitchIn pitchOut music) (ly:pitch? ly:pitch? 
> ly:music?)
>(music-map
> (lambda (m)
> (if (music-is-of-type? m 'note-event)
> (if (equal? (ly:pitch-notename (ly:music-property m 'pitch)) 
> (ly:pitch-notename pitchIn))
> (ly:music-set-property! m 'pitch (ly:make-pitch 
> (ly:pitch-octave (ly:music-property m 'pitch)) (ly:pitch-notename pitchOut) 
> 0))
> (make-music 'NoteEvent m))
> (ly:message "Not of type"))
> m)
> music))
>
> \adjustPitch ees e \fixed c' { c4 d es f g c' es' }
> %%%  SNIPPET ENDS
>
> Comments before I move to the next step…?

This will also adjust eis and eses to e.  Note names are numbers and can
be compared with = .  (make-music 'NoteEvent m) is silly and creates an
unnecessary copy.  You can just use m instead.

If you do, you don't replace any music, so music-map is unnecessary.
This can be better done with for-some-music .

-- 
David Kastrup



Re: need help building a Scheme function

2024-06-22 Thread Kieren MacMillan
Hi again,

> There is no necessity to return a new NoteEvent; you can just change
> pitch on the existing one.
> 
> Music functions are allowed to modify their music arguments in place.

This is what I have so far, which appears to do what I want:

%%%  SNIPPET BEGINS
\version "2.25.11"

adjustPitch = 
#(define-music-function (pitchIn pitchOut music) (ly:pitch? ly:pitch? ly:music?)
   (music-map
(lambda (m)
(if (music-is-of-type? m 'note-event)
(if (equal? (ly:pitch-notename (ly:music-property m 'pitch)) 
(ly:pitch-notename pitchIn))
(ly:music-set-property! m 'pitch (ly:make-pitch 
(ly:pitch-octave (ly:music-property m 'pitch)) (ly:pitch-notename pitchOut) 0))
(make-music 'NoteEvent m))
(ly:message "Not of type"))
m)
music))

\adjustPitch ees e \fixed c' { c4 d es f g c' es' }
%%%  SNIPPET ENDS

Comments before I move to the next step…?

Thanks,
Kieren.
__

My work day may look different than your work day. Please do not feel obligated 
to read or respond to this email outside of your normal working hours.




Re: need help building a Scheme function

2024-06-21 Thread David Kastrup
Lukas-Fabian Moser  writes:

> Elaborating on David's explanation, it might be instructive to study the
> output of:
>
> \version "2.25.9"
>
> mappingFunction =
> #(define-music-function (music) (ly:music?)
>(music-map
> (lambda (m)
>   (ly:message "Considering music:\n~a\n-\n"
>   ((@@ (lily) music->lily-string) m))
>   m)
> music))
>
> \mappingFunction
> \new PianoStaff
> <<
>   \new Staff \relative { c'4 d e c }
>   \new Staff \relative { c' g c c }
>>>

If you don't want to call upon undocumented internals of LilyPond (the
(@@ (lily) ...) bit), you can just use

\version "2.25.9"

mappingFunction =
#(define-music-function (music) (ly:music?)
   (music-map
(lambda (m)
 (ly:message "Considering music:~a-\n"
  (with-output-to-string (lambda () (displayLilyMusic m
  m)
music))

\mappingFunction
\new PianoStaff
<<
  \new Staff \relative { c'4 d e c }
  \new Staff \relative { c' g c c }
>>


-- 
David Kastrup


Re: need help building a Scheme function

2024-06-21 Thread David Kastrup
Lukas-Fabian Moser  writes:

> But: Whether you use music-map or map-some-music, your helper function
> (your lambda) is expected to return the new music into which the given
> argument m should be transformed. So in any case, your lambda function
> should return music - in the trivial case, it could return m itself
> without change, but in the long run, you want to return a new
> note-event, i.e. (make-music 'NoteEvent ...).
>
> For this, it will come in handy that it's possible to do
>
> (make-music 'NoteEvent m)
>
> i.e. create a new NoteEvent that takes its 'pitch (which you're going to
> overwrite using an additional 'pitch ), 'articulation etc.
> properties from m. (This is explained somewhere in Jean's guide.)

There is no necessity to return a new NoteEvent; you can just change
pitch on the existing one.

Music functions are allowed to modify their music arguments in place.

-- 
David Kastrup



Re: need help building a Scheme function

2024-06-21 Thread Lukas-Fabian Moser

Hi Kieren,

Am 21.06.24 um 20:25 schrieb Kieren MacMillan:

Hi all,

Thank you for the rapid-iteration non-isochronous Scheme class!  :)

Before I do the next step, is this optimal at this point?

%%%  SNIPPET BEGINS
\version "2.25.11"

adjustPitch =
#(define-music-function (pitchIn pitchOut music) (ly:pitch? ly:pitch? ly:music?)
(music-map
 (lambda (m)
 (if (music-is-of-type? m 'note-event)
 (ly:message "Pitch is: ~a" (ly:music-property m 'pitch))
 #f)
 m)
 music))

\adjustPitch es es \fixed c' { c4 d e f g a b c' }
%%%  SNIPPET ENDS


While it's possible to use music-map, I'd still recommend
map-some-music: Instead of considering all the various music objects in
a tree (and then specialising to only considering note events),
map-some-music is tailor-made for applications where we want to reach a
specific type of music objects in our recursion and then, in each case,
declaring the job done, i.e. not recursing any further. (The actual
difference should be very small, since also music-map can't help but
stop recursing at note-events, since these don't contain other music
objects.)

But: Whether you use music-map or map-some-music, your helper function
(your lambda) is expected to return the new music into which the given
argument m should be transformed. So in any case, your lambda function
should return music - in the trivial case, it could return m itself
without change, but in the long run, you want to return a new
note-event, i.e. (make-music 'NoteEvent ...).

For this, it will come in handy that it's possible to do

(make-music 'NoteEvent m)

i.e. create a new NoteEvent that takes its 'pitch (which you're going to
overwrite using an additional 'pitch ), 'articulation etc.
properties from m. (This is explained somewhere in Jean's guide.)

Lukas




Re: need help building a Scheme function

2024-06-21 Thread Kieren MacMillan
Hi Lukas,

> Elaborating on David's explanation, it might be instructive to study the 
> output of:
> [snip]
> In short: music-map really considers every music object in a music tree.

That was instructive — thanks!
Kieren.
__

My work day may look different than your work day. Please do not feel obligated 
to read or respond to this email outside of your normal working hours.




Re: need help building a Scheme function

2024-06-21 Thread Lukas-Fabian Moser

Hi Kieren,


I’m a little confused that the output of

%%%  SNIPPET BEGINS
\version "2.25.11"

adjustPitch =
#(define-music-function (pitchIn pitchOut music) (ly:pitch? ly:pitch? ly:music?)
(music-map
 (lambda (m)
   (ly:message "Pitch is: ~a" (ly:music-property m 'pitch)) m)
 music))

\adjustPitch es es \fixed c' { c4 d e f g a b c' }
%%%  SNIPPET ENDS

is

Pitch is: #
Pitch is: #
Pitch is: #
Pitch is: #
Pitch is: #
Pitch is: #
Pitch is: #
Pitch is: #
Pitch is: ()
Pitch is: ()

What is causing the last two output lines?


Elaborating on David's explanation, it might be instructive to study the
output of:

\version "2.25.9"

mappingFunction =
#(define-music-function (music) (ly:music?)
   (music-map
    (lambda (m)
  (ly:message "Considering music:\n~a\n-\n"
  ((@@ (lily) music->lily-string) m))
  m)
    music))

\mappingFunction
\new PianoStaff
<<
  \new Staff \relative { c'4 d e c }
  \new Staff \relative { c' g c c }
>>

In short: music-map really considers every music object in a music tree.

Lukas


Re: need help building a Scheme function

2024-06-21 Thread Kieren MacMillan
Hi David,

> To say something is "optimal", you have to state your objective.

I guess the immediate objective was to output [in the log] a list of pitches 
given the 'music' input.

> music-map is used for changing music, and you don't appear to do any
> useful changes to the music.  In fact, you replace note events with
> *undefined* which appears comparatively useless.
> 
> So what are you trying to achieve here?

The longer-term objective is to write

  \adjustMusic es e { c d es f g c' es' }

and get

  { c d e f g c' e' }

i.e., turn all E flats [at any octave] into E naturals.

Thanks,
Kieren.
__

My work day may look different than your work day. Please do not feel obligated 
to read or respond to this email outside of your normal working hours.




Re: need help building a Scheme function

2024-06-21 Thread David Kastrup
Kieren MacMillan  writes:

> Hi all,
>
> Thank you for the rapid-iteration non-isochronous Scheme class!  :)
>
> Before I do the next step, is this optimal at this point?
>
> %%%  SNIPPET BEGINS
> \version "2.25.11"
>
> adjustPitch = 
> #(define-music-function (pitchIn pitchOut music) (ly:pitch? ly:pitch? 
> ly:music?)
>(music-map
> (lambda (m)
> (if (music-is-of-type? m 'note-event)
> (ly:message "Pitch is: ~a" (ly:music-property m 'pitch))
> #f)
> m)
> music))
>
> \adjustPitch es es \fixed c' { c4 d e f g a b c' }
> %%%  SNIPPET ENDS

To say something is "optimal", you have to state your objective.
music-map is used for changing music, and you don't appear to do any
useful changes to the music.  In fact, you replace note events with
*undefined* which appears comparatively useless.

So what are you trying to achieve here?

-- 
David Kastrup



Re: need help building a Scheme function

2024-06-21 Thread Kieren MacMillan
Hi all,

Thank you for the rapid-iteration non-isochronous Scheme class!  :)

Before I do the next step, is this optimal at this point?

%%%  SNIPPET BEGINS
\version "2.25.11"

adjustPitch = 
#(define-music-function (pitchIn pitchOut music) (ly:pitch? ly:pitch? ly:music?)
   (music-map
(lambda (m)
(if (music-is-of-type? m 'note-event)
(ly:message "Pitch is: ~a" (ly:music-property m 'pitch))
#f)
m)
music))
   
\adjustPitch es es \fixed c' { c4 d e f g a b c' }
%%%  SNIPPET ENDS

Thanks,
Kieren.
__

My work day may look different than your work day. Please do not feel obligated 
to read or respond to this email outside of your normal working hours.




Re: need help building a Scheme function

2024-06-21 Thread Kieren MacMillan
Hi David,

> If you want to only look at note events, you need to check for them
> yourself.  music-map is not discriminating.

Ah! Lovely Socratic lesson. :)

Thanks,
Kieren.
__

My work day may look different than your work day. Please do not feel obligated 
to read or respond to this email outside of your normal working hours.




Re: need help building a Scheme function

2024-06-21 Thread David Kastrup
Kieren MacMillan  writes:

> Hi again,
>
> I’m a little confused that the output of
>
> %%%  SNIPPET BEGINS
> \version "2.25.11"
>
> adjustPitch = 
> #(define-music-function (pitchIn pitchOut music) (ly:pitch? ly:pitch? 
> ly:music?)
>(music-map
> (lambda (m)
>   (ly:message "Pitch is: ~a" (ly:music-property m 'pitch)) m)
> music))
>
> \adjustPitch es es \fixed c' { c4 d e f g a b c' }
> %%%  SNIPPET ENDS
>
> is
>
> Pitch is: #
> Pitch is: #
> Pitch is: #
> Pitch is: #
> Pitch is: #
> Pitch is: #
> Pitch is: #
> Pitch is: #
> Pitch is: ()
> Pitch is: ()
>
> What is causing the last two output lines?

Well, what do you think should be the pitch of

{ c4 d e f g a b c' }

and of

\fixed c' { c4 d e f g a b c' }

?

If you want to only look at note events, you need to check for them
yourself.  music-map is not discriminating.

-- 
David Kastrup



Re: need help building a Scheme function

2024-06-21 Thread Kieren MacMillan
Hi Timothy,

> Your lambda function for the mapping returns the value of ly:message, which 
> is #. You need to return some music. Changing the lambda 
> function to
> (lambda (m)
>   (ly:message "Pitch is: ~a" (ly:music-property m 'pitch)) m)
> maps the music to itself without any changes.

Oh! I see that now.

Thanks!
Kieren.
__

My work day may look different than your work day. Please do not feel obligated 
to read or respond to this email outside of your normal working hours.




Re: need help building a Scheme function

2024-06-21 Thread Kieren MacMillan
Hi again,

I’m a little confused that the output of

%%%  SNIPPET BEGINS
\version "2.25.11"

adjustPitch = 
#(define-music-function (pitchIn pitchOut music) (ly:pitch? ly:pitch? ly:music?)
   (music-map
(lambda (m)
  (ly:message "Pitch is: ~a" (ly:music-property m 'pitch)) m)
music))

\adjustPitch es es \fixed c' { c4 d e f g a b c' }
%%%  SNIPPET ENDS

is

Pitch is: #
Pitch is: #
Pitch is: #
Pitch is: #
Pitch is: #
Pitch is: #
Pitch is: #
Pitch is: #
Pitch is: ()
Pitch is: ()

What is causing the last two output lines?

Thanks,
Kieren.
__

My work day may look different than your work day. Please do not feel obligated 
to read or respond to this email outside of your normal working hours.




Re: need help building a Scheme function

2024-06-21 Thread Timothy Lanfear

On 21/06/2024 17:36, Kieren MacMillan wrote:

Hi Lukas!

All right… already back for more specific help.

I struggled with map-some-music, and failed. Scanned through Jean’s [amazing] 
“Extending” docs — yes, yes, I need to RTM on that one, page-by-page! — and 
found an example with music-map, so tried that instead. Also failed.

Your lambda function for the mapping returns the value of ly:message, 
which is #. You need to return some music. Changing the 
lambda function to


(lambda (m) (ly:message "Pitch is: ~a" (ly:music-property m 'pitch)) m)

maps the music to itself without any changes.

--
Timothy Lanfear, Bristol, UK.


Re: need help building a Scheme function

2024-06-21 Thread Kieren MacMillan
Hi Lukas!

All right… already back for more specific help.

I struggled with map-some-music, and failed. Scanned through Jean’s [amazing] 
“Extending” docs — yes, yes, I need to RTM on that one, page-by-page! — and 
found an example with music-map, so tried that instead. Also failed.

%%%  SNIPPET BEGINS
\version "2.25.11"

adjustPitch = 
#(define-music-function (pitchIn pitchOut music) (ly:pitch? ly:pitch? ly:music?)
   (music-map
(lambda (m)
  (ly:message "Pitch is: ~a" (ly:music-property m 'pitch)))
music))

melody = {
  c'2 g'2 es'2. d'4 |
  c' es' d' c' |
  b d' g2
}

\adjustPitch es es \fixed c' { c d e f g a b c' }
%%%  SNIPPET ENDS

Helps/Hints appreciated.
Kieren
__

My work day may look different than your work day. Please do not feel obligated 
to read or respond to this email outside of your normal working hours.




Re: need help building a Scheme function

2024-06-21 Thread Kieren MacMillan
Hi L-F!

>> Is map-some-music the correct next move?
> Yes.

Thanks!

> I take it you're only asking for confirmation you're on the right track? :-)

Correct. I’ll try to ask more specific questions when I need more than 
confirmation.

> So I only suggest use the ly:pitch? predicate for pitchIn/pitchOut instead of 
> ly:music?.

Good point. I *think* I eventually want to allow a set (array?) of pitches 
in/out, but for now, I’ll start the input as small as the output.

Thanks!
Kieren.
__

My work day may look different than your work day. Please do not feel obligated 
to read or respond to this email outside of your normal working hours.




Re: need help building a Scheme function

2024-06-21 Thread Lukas-Fabian Moser

Hi Kieren,

Am 21.06.24 um 16:39 schrieb Kieren MacMillan:

%%%  SNIPPET BEGINS
\version "2.25.11"

adjustPitch =
#(define-music-function (pitchIn pitchOut music) (ly:music? ly:music? ly:music?)
(ly:message "Pitch is: ~a" (ly:pitch-notename (ly:music-property pitchIn 
'pitch)))
music)

melody = {
   c'2 g'2 es'2. d'4 |
   c' es' d' c' |
   b d' g2
}

\adjustPitch es es \fixed c' { c d e f g a b c' }
%%%  SNIPPET ENDS

This does exactly what it says on the can. Now I want to “map” the message 
[stand-in] function to the music provided, so it outputs the pitch for each 
note in the 'music' input.

Is map-some-music the correct next move?


Yes. I take it you're only asking for confirmation you're on the right
track? :-)

So I only suggest use the ly:pitch? predicate for pitchIn/pitchOut
instead of ly:music?.

Lukas


need help building a Scheme function

2024-06-21 Thread Kieren MacMillan
Hey list!

Trying to work up to being a bigger and better contributor to The ’Pond. Found 
and copied that “transpose major to minor” scale function in the previous 
thread I contributed to, but (a) don’t really know if it’s the best way to do 
what the OP wanted, (b) thought it might be overkill for what the OP wanted, 
and (c) figured writing another function attacking the same problem with a 
slightly different approach might be a good way to climb the learning curve.

So… I‘m writing a function called \adjustPitch, where

\adjustPitch e es { c d e f g c' e' }

should output

{ c d es f g c' es'  }

Started like this:

%%%  SNIPPET BEGINS
\version "2.25.11"

adjustPitch = 
#(define-music-function (pitchIn pitchOut music) (ly:music? ly:music? ly:music?)
   (ly:message "Pitch is: ~a" (ly:pitch-notename (ly:music-property pitchIn 
'pitch)))
   music)

melody = {
  c'2 g'2 es'2. d'4 |
  c' es' d' c' |
  b d' g2
}

\adjustPitch es es \fixed c' { c d e f g a b c' }  
%%%  SNIPPET ENDS

This does exactly what it says on the can. Now I want to “map” the message 
[stand-in] function to the music provided, so it outputs the pitch for each 
note in the 'music' input.

Is map-some-music the correct next move?

Thanks,
Kieren.
__

My work day may look different than your work day. Please do not feel obligated 
to read or respond to this email outside of your normal working hours.