I achieved a working solution after I found out about lambda*.
I would like to improve on this, but at least I achieved the expected
result.
The example:
\version "2.19.52"
%Useful definitions
#(define characters.thinSpace (ly:wide-char->utf-8 #x2009))
#(define characters.longDash (ly:wide-char->utf-8 #x2013))
#(define characters.curvyEqual "≈")
%Properties of the customMark
#(define customMark.parenthesized #t)
#(define customMark.tempoEqText "= ca.")
#(define customMark.separator (string-append characters.thinSpace
characters.longDash characters.thinSpace))
#(define (ly:duration-or-false? obj)
(if (or (ly:duration? obj) (and (boolean? obj) (not obj)))
#t
#f))
#(define (number-or-false? obj)
(if (or (number? obj) (and (boolean? obj) (not obj)))
#t
#f))
createCustomMark =
#(define-music-function
(text dur val1 val2)
(markup? ly:duration-or-false? number-or-false? (number-or-false? #f))
#{
\mark \markup { \line { \upright { \fontsize #-2 {
\larger { \bold { #text } }
#(if (or dur val1 val2)
#{
\markup \concat { %\markup needed to avoid "unknown escaped
string: `\concat'"
#(if customMark.parenthesized "(")
#(if dur
#{
\markup \fontsize #-3 { \general-align #Y #DOWN {
\note #(ly:duration->string dur) #1 } }
#}
"") %needed to avoid "not a markup" error when dur is
#f
" "
#customMark.tempoEqText
#characters.thinSpace
#(if val1
(number->string val1)
"") %needed to avoid "not a markup" error when val1 is
#f
#(if val2
(string-append customMark.separator (number->string
val2))
"") %needed to avoid "not a markup" error when val2 is
#f
#(if customMark.parenthesized ")")
}
#}
"") %needed to avoid "not a markup" error when tempo is #f
} } } }
#})
customMark =
#(lambda* (text #:optional (dur #f) (val1 #f) (val2 #f))
(createCustomMark text dur val1 val2))
allegro = #(customMark "Allegro." #{ 4 #} 120 125)
ceder = #(customMark "ceder...")
metromark = #(customMark "" #{ 4 #} 120)
\relative c' {
\allegro c4 d e \ceder f \metromark
}
2016-12-16 13:44 GMT-03:00 Stefano Troncaro <[email protected]>:
> I made some progress, although I'm sure there better and more elegant
> solution.
>
> Example:
>
> \version "2.19.52"
>
> %Useful definitions
> #(define characters.thinSpace (ly:wide-char->utf-8 #x2009))
> #(define characters.longDash (ly:wide-char->utf-8 #x2013))
> #(define characters.curvyEqual "≈")
>
> %Properties of the customMark
> #(define customMark.parenthesized #t)
> #(define customMark.tempoEqText "= ca.")
> #(define customMark.separator (string-append characters.thinSpace
> characters.longDash characters.thinSpace))
>
> #(define (ly:duration-or-false? obj)
> (if (or (ly:duration? obj) (and (boolean? obj) (not obj)))
> #t
> #f))
>
> #(define (number-or-false? obj)
> (if (or (number? obj) (and (boolean? obj) (not obj)))
> #t
> #f))
>
>
> customMark =
> #(define-music-function
> (text tempo dur val1 val2)
> (markup? boolean? ly:duration-or-false? number-or-false?
> number-or-false?)
> #{
> \mark \markup { \line { \upright { \fontsize #-2 {
> \larger { \bold { #text } }
> #(if tempo
> #{
> \markup \concat { %\markup needed to avoid "unknown escaped
> string: `\concat'"
> #(if customMark.parenthesized "(")
> #(if dur
> #{
> \markup \fontsize #-3 { \general-align #Y #DOWN {
> \note #(ly:duration->string dur) #1 } }
> #}
> "") %needed to avoid "not a markup" error when dur is
> #f
> " "
> #customMark.tempoEqText
> #characters.thinSpace
> #(if val1
> (number->string val1)
> "") %needed to avoid "not a markup" error when val1
> is #f
> #(if val2
> (string-append customMark.separator (number->string
> val2))
> "") %needed to avoid "not a markup" error when val2
> is #f
> #(if customMark.parenthesized ")")
> }
> #}
> "") %needed to avoid "not a markup" error when tempo is #f
> } } } }
> #})
>
>
> allegro = \customMark "Allegro." ##t 4 120 125
> ceder = \customMark "ceder..." ##f ##f ##f ##f
> metromark = \customMark "" ##t 4 120 ##f
>
>
> \relative c' {
> \allegro c4 d e \ceder f \metromark
> }
>
> Now, I can't figure out how to achieve that the last 4 parameters of the
> function default to ##f, to avoid errors if I don't pass them.
>
> Again, thanks in advance!
> Stéfano
>
> 2016-12-16 4:17 GMT-03:00 Stefano Troncaro <[email protected]>:
>
>> Hello everyone,
>>
>> I finally decided to start using Scheme functions. For learning purposes,
>> I'm trying to write a function that will imitate the output from this
>> snippet from the repository <http://lsr.di.unimi.it/LSR/Snippet?id=1008>.
>>
>> I achieved the look of the output but I can't seem to figure out how to
>> make a function that accepts different types of parameters. Example:
>>
>> \version "2.19.52"
>>
>> %Properties of the customMark
>> #(define characters.thinSpace (ly:wide-char->utf-8 #x2009))
>> #(define customMark.parenthesized #t)
>> #(define customMark.tempoEqText "= ca.")
>>
>> textandnotemark =
>> #(define-music-function
>> (text dur val)
>> (markup? ly:duration? number?)
>> #{
>> \mark \markup { \line { \upright { \fontsize #-2 {
>> \larger { \bold { #text } }
>> \concat {
>> #(if customMark.parenthesized "(")
>> \fontsize #-3 { \general-align #Y #DOWN { \note
>> #(ly:duration->string dur) #1 } }
>> " "
>> #customMark.tempoEqText
>> #characters.thinSpace
>> #(number->string val)
>> #(if customMark.parenthesized ")")
>> }
>> } } } }
>> #})
>>
>> allegro = \textandnotemark "Allegro." 4 120
>> %ceder = \textandnotemark "ceder..."
>> metromark = \textandnotemark "" 4 120
>>
>> \relative c' {
>> \allegro c4 d e f \metromark
>> }
>>
>> The line that is commented near the end of the example represents the
>> behavior that I'd like to achieve, that is, the case where there is only
>> text. I thought it would be easy to do it by setting defaults, leaving the
>> duration and value parameters blank, and managing the special case, but I
>> can't figure out how to make it work.
>>
>> Thanks in advance for your time!
>> Stéfano.
>>
>
>
_______________________________________________
lilypond-user mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/lilypond-user