lilypond-user
[Top][All Lists]
Advanced

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

Re: LilyPond to Scheme to Lilypond and variadic function


From: Aaron Hill
Subject: Re: LilyPond to Scheme to Lilypond and variadic function
Date: Thu, 26 Nov 2020 21:43:23 -0800
User-agent: Roundcube Webmail/1.4.9

(Adding mailing list for visibility...)

On 2020-11-26 5:27 pm, Daniel Tomas wrote:
We are trying to pass from LilyPond code a list of smaller lists, which
contains musical data to a function func1 which will also use many LilyPond code and send musical elements also to another function func2 which also will return musical data. I hope this sentence make more clear what i mean. Until now i only receive information about Scheme, but i think there are 2
things to keep in mind :
a) How to call it from LilyPond code ?

While this is not the entire solution, it is important to know that you can use sequential music within simultaneous music to get lists of lists of music. Here's an example focusing just on pitches:

%%%%
\version "2.20.0"

#(define (simultaneous-music? arg)
  (and (ly:music? arg) (music-is-of-type? arg 'simultaneous-music)))

music-to-lists-of-pitches =
#(define-void-function
  (lists-of-pitches)
  (simultaneous-music?)
  (set! lists-of-pitches
   (map music-pitches
    (extract-typed-music lists-of-pitches 'sequential-music)))
  (format #t "~{\n pitches: ~{~s~^ ~}~}" lists-of-pitches))

\music-to-lists-of-pitches
  << { d ees fis } \relative { g, g, a' a' } \fixed c' { b r c' } >>
%%%%
====
Parsing...
 pitches: #<Pitch d > #<Pitch ees > #<Pitch fis >
 pitches: #<Pitch g, > #<Pitch g,, > #<Pitch a, > #<Pitch a >
 pitches: #<Pitch b' > #<Pitch c'' >
Success: compilation successfully completed
====

What is nice here is that you can take advantage of commands like \relative and \fixed.


b) I suppose we need to use *define-music-function *because we need to
write more musical sentences and LilyPond need to have information about
musical sheets contexts in order to process returned music.
define-music-function
contains 2 more variables, and i think there will need that.

Yes, define-music-function would be appropriate if it is your intention to return music from the procedure to be used within the wider context. But you can technically use any regular procedure to return musical information:

%%%%
\version "2.20.0"

#(define (foo a b c)
  (make-music 'NoteEvent
   'pitch (ly:make-pitch a b)
   'duration (ly:make-duration c)))

#(define (baz a b) (ly:make-duration a b))

{ a'2 #(foo 0 6 2) g'4 | a'2 b' $(baz 2 1) g'8 }
%%%%


I already have some clues about this points : If we send a list in form of Scheme, LilyPond will not confuse with posterior elements. Now, i am not
very clear about how to write it from LilyPond, like that : ?
#(func1 (ls1 ls2 ls3 ... lsn))
?
But each ls(i) contains also musical information like 'd4'. How to write
them from within Scheme, like this : ?
#(func1 ( (#{ d4 #}  3 4) (#{ e4 #} 2 3 ...)))
?
I only guess i write it wrong, but you have some clues about how to write
it ?

You would need to use the list procedure to create a list in such syntax, or you could use quoting/quasi-quoting:

%%%%
\version "2.20.0"

#(define (print-pitches lists-of-pitches)
  (format #t "~{\n pitches: ~{~s~^ ~}~}" lists-of-pitches))

#(print-pitches
  (list (list #{ d #} #{ ees #} #{ fis #})
        (list #{ g, #} #{ a' #})))
#(print-pitches
  `((,#{ d #} ,#{ ees #} ,#{ fis #})
    (,#{ g, #} ,#{ a' #})))
%%%%
====
Parsing...
 pitches: #<Pitch d > #<Pitch ees > #<Pitch fis >
 pitches: #<Pitch g, > #<Pitch a' >
 pitches: #<Pitch d > #<Pitch ees > #<Pitch fis >
 pitches: #<Pitch g, > #<Pitch a' >
Success: compilation successfully completed
====

But this option is less ideal as the #{ #} syntax would quickly become cumbersome.

The challenge is being able to use LilyPond music syntax and mixing in arbitrary data. Here is potentially one way to do that:

%%%%
\version "2.20.0"

#(define (define-music-descriptions new-descriptions)
  ;; Logic borrowed from define-music-types.scm
  (set! new-descriptions
   (map
    (lambda (x)
     (set-object-property! (car x)
      'music-description (cdr (assq 'description (cdr x))))
     (let ((lst (cdr x)))
      (set! lst (assoc-set! lst 'name (car x)))
      (set! lst (assq-remove! lst 'description))
      (hashq-set! music-name-to-property-table (car x) lst)
      (cons (car x) lst)))
    new-descriptions))
  (set! music-descriptions
    (sort (append music-descriptions new-descriptions) alist<?)))

#(define-event-class 'data-event 'StreamEvent)
#(define-music-descriptions
  '((DataEvent
     . ((description . "Container for arbitrary data.")
        (types . (data-event))))))

data =
#(define-music-function (value) (scheme?)
  (make-music 'DataEvent 'value value))

foo =
#(define-void-function
  (music)
  (ly:music?)
  (format #t "~{\n ~a~}"
   (map
    (lambda (m)
     (cond ((music-is-of-type? m 'data-event)
            (format #f "[data] value=~s"
             (ly:music-property m 'value)))
           ((music-is-of-type? m 'note-event)
           (format #f "[note] pitch=~s, duration=~s"
             (ly:music-property m 'pitch)
             (ly:music-property m 'duration)))))
    (extract-typed-music music '(data-event note-event)))))

\foo \fixed c' { b4 \data 3 g \data foo a2 }
%%%%
====
Parsing...
 [note] pitch=#<Pitch b' >, duration=#<Duration 4 >
 [data] value=3
 [note] pitch=#<Pitch g' >, duration=#<Duration 4 >
 [data] value="foo"
 [note] pitch=#<Pitch a' >, duration=#<Duration 2 >
Success: compilation successfully completed
====


-- Aaron Hill



reply via email to

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