[prev in list] [next in list] [prev in thread] [next in thread] 

List:       lilypond-user
Subject:    Re: LilyPond to Scheme to Lilypond and variadic function
From:       Aaron Hill <lilypond () hillvisions ! com>
Date:       2020-11-27 5:43:23
Message-ID: feed33ae1fd25b106fe317b00680fc9e () hillvisions ! com
[Download RAW message or body]

(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

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic