lilypond-user
[Top][All Lists]
Advanced

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

Re: Harp Pedals?


From: Carl D. Sorensen
Subject: Re: Harp Pedals?
Date: Thu, 14 Aug 2008 10:42:00 -0600



On 8/14/08 8:50 AM, "Valentin Villenave" <address@hidden> wrote:

> 2007/7/8 Dewdman42 <address@hidden>:
>>
>> I can't seem to find anything in the Lilypond manual about creating harp
>> pedal symbols.  I would think this issue has been covered a lot by users of
>> Lilypond.  how do I do it, or something like it:
>>
>> http://www.nabble.com/file/p11492013/ScreenHunter_03%2BJul.%2B08%2B12.40.jpg
>
> Greetings Carl, hi everybody,
>
> I've been trying to implement this harp diagrams feature for a while,
> but my implementation is quite dirty and not fully working. Basically,
> I tried to write a markup command that would take seven arguments, one
> for each pedal. However, for some reason I cannot pass more than three
> arguments to the markup command (see below).

Valentin, you made my day.  To have somebody asking _me_ questions
about LilyPond programming is a first.  I've been the one asking
everybody else questions.  Thanks!

>
> 1 - What I'd really like to achieve is to have one single argument
> containing the whole set of pedals, like you do with your diagrams,
> such as
> \harp #"0;-1;0;1;0;0;1;"
> instead of
> \harp #0 #-1 #0 #1 #0 #0 #1
>
> However, I cannot parse the string to extract the values (I've tried
> to figure it out from your code, but it's way over my skills).

You really don't want to get in the string business for this case.
If you do you'd  have to first split the string (using the Scheme
function string-split) and then convert the resulting codes from
strings to numbers (using the Scheme function string->number).

It's much easier to just pass one argument to the function, a
list of pedal values.

See below, where I've shown what the call would look like.

>
> 2 - The implementation I provide is very dirty, as I said. I don't
> know if it would be best to haave a separate stencil function, and
> inside the function I don't know how I can increment the values for
> the horizontal placement of the boxes in an elegant way.
>
> 3 - Ideally, we should add something like
> (if (> a 0) set! a 1
> (if (< a 0) set! a 1))
> so to allow users to use any values bigger values than 1 or lower than
> -1 without breaking their result.
>

If you really want to do this (why would users want to have values
greater than 1 or less than -1?  I don't know harp music, so I can't say),
then probably the best way to do it is something like

(let ((normalized-pedal-list (map (lambda(x) (if (> x 1) 1
                                                 (if (< x -1) -1 x)))
                                  (user-pedal-list)))

The parentheses don't match in this example on purpose, because it's only
part of your let assignments.

This requires you to use lambda expressions, which are kind of confusing.
I think of lambda expressions as defining a temporary function of the
argument, without giving the function a name. So in this case we define
an unnamed function that will take an argument x and return 1 if x > 1,
-1 if x < -1 and x otherwise.  Then we map that unnamed function to
each element of user-pedal list, and return a list containing the results
of that function being applied to each element of the pedal list.

If you're going to do scheme programming with lilypond, lambda functions
are your friends, even though they can be confusing.

> Can you please have a quick look at the code below, when you have a minute?
>
>
> % I have to define some variables  separately or else
> % compiling fails miserably.
>
> % The following three are already
> % defined using the main function
>
> %#(define d 0)
> %#(define c 0)
> %#(define b 0)
> #(define e 0)
> #(define f 0)
> #(define g 0)
> #(define a 0)
>
> #(define-markup-command (harp layout props d c b) (integer? integer? integer?)
#(define-markup-command (harp layout props pedal-list)
    (list?)

>      ; FIXME the size variable should be defined by a prop. lookup
props lookup is done with chain-assoc-get, which you can see in
scm/fret-diagrams.scm
>
>   (define sz 1.2)
>      ; TODO is it worth adding a thickness variable here
At the time I wrote fret-diagrams, constants like 4, 2, and 0.4
were frowned upon.  So I used variables connected to properties
every time I needed a constant like this, and there was concern about
polluting the property name space, so I created fret-diagram-details.

I'd recommend that for right now you define variables like
(let* ((width 4)
       (height 2)
       (stencil-width (* size width))
       (stencil-height (* size height))
and so forth.

That way, you are declaring (by the variable name) what the constant is
before you use it.  But you're not putting it in the property list
unless you think it's something users may need to vary.  It took me a
while to figure this approach out, so I thought I'd help you out
from the beginning.

Also, LilyPond coding standards call for using full words rather than
abbreviations for variable names.  x, y, a, b and so forth should only
be used as part of a lambda function definition.

I'd try something like
(define (make-pedal-stencil pedal-item pedals-list box-height)
   (let ((my-pedal (list-ref pedals-list pedal-item)
         (half-height (/ box-height 2))
       (make-filled-box-stencil
          (cons (+ (- (* space pedal-item) x) box-width)
                (- (* (+ space box-width) pedal-item) x))
          (cons (+ (- y half-height) my-pedal)
                (+ y half-height my-pedal))))))

Note: I haven't debugged this code!

>
>   (let ((x (* sz 4))
>         (y (* sz 2))
>         (box-width (* sz 0.4))
>         (box-height (* sz 1))
>         (space (* sz 0.5)))

With make-pedal-stencil defined you can now add a new variable to your let
assignment list:

          (pedals-stencil (make-pedal-stencil 1 pedal-list box-height))

And before your code to add stencils you can do a for-each:

      (for-each (lambda (x) (set! pedals-stencil
                              (ly:stencil-add pedals-stencil
                                             (make-pedal-stencil
                                                 x
                                                 pedal-list
                                                 box-height))))
                (iota (1- (length pedal-list)) 2 1))

Which should glue all of your pedal stencils together in one big
stencil pedals-stencil.

To use the iota procedure, you may need to add
(use-modules (srfi srfi-1))
to your file.
>     (ly:stencil-add
>       (ly:make-stencil
>        `(draw-line 0.2 ; horizontal line
>            ,(- 0 x) ,y ,x ,y))
>       (ly:make-stencil
>        `(draw-line 0.2 0 0 0 ,(* y 2))) ; vertical line (shorter)
>
You could then add
        pedals-stencil)

right here and be done with the markup.

>      ;; FIXME: the boxes should be drawn using a separate function
>

>         (cons (- space x) (+ (- space x) box-width))
>         (cons (+ (- y (/ box-height 2)) d) (+ (+ y (/ box-height 2)) d)))
>
>       (make-filled-box-stencil  ;; pedal C
>         (cons (+ (- (* space 2) x) box-width) (- (* (+ space box-width) 2) x))
>         (cons (+ (- y (/ box-height 2)) c) (+ (+ y (/ box-height 2)) c)))
>
>       (make-filled-box-stencil  ;; pedal B
>         (cons (+ (- (* space 3) x) (* box-width 2)) (- (* (+ space
> box-width) 3) x))
>         (cons (+ (- y (/ box-height 2)) b) (+ (+ y (/ box-height 2)) b)))
>
>       (make-filled-box-stencil  ;; pedal E
>         (cons space (+ space box-width))
>         (cons (+ (- y (/ box-height 2)) e) (+ (+ y (/ box-height 2)) e)))
>
>       (make-filled-box-stencil  ;; pedal F
>         (cons (+ (* space 2) box-width) (* (+ space box-width) 2))
>         (cons (+ (- y (/ box-height 2)) f) (+ (+ y (/ box-height 2)) f)))
>
>       (make-filled-box-stencil  ;; pedal G
>         (cons (+ (* space 3) (* box-width 2)) (* (+ space box-width) 3))
>         (cons (+ (- y (/ box-height 2)) g) (+ (+ y (/ box-height 2)) g)))
>
>       (make-filled-box-stencil  ;; pedal A
>         (cons (+ (* space 4) (* box-width 3)) (* (+ space box-width) 4))
>         (cons (+ (- y (/ box-height 2)) a) (+ (+ y (/ box-height 2)) a))))))
>
>
> \new Staff {
> c1-\markup {
>
>  % This function should take 7 arguments, or
>  % the seven pedal indications in one single arg.
>   \harp #1 #-1 #0
Your call would then be
     \harp #'( 1 -1 0 1 0 1 0)

>   }
> }
>

Please note -- I have not debugged (or even tried) any of this code.

There may be syntax errors or missing parentheses.  But it's indicative
of the way I would approach the problem

I think it's good for you to figure out how it works, so I've left the
debugging to you.  If you have more questions, feel free to ask.

Thanks,

Carl





reply via email to

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