Snippet: easy-chord-input

Begonnen von juergen74, Mittwoch, 1. März 2023, 18:46

« vorheriges - nächstes »

juergen74

Hallo,

ich spiele Ukulele und nach dem Entschluss, meine Noten nicht mehr nur handschriftlich auf Papier zu bringen, bin ich sehr schnell bei LilyPond gelandet. Was mir allerdings nicht gefällt, ist die Unterscheidung zwischen chordmode und notemode, insbesondere da ich bei meinen Interpretationen häufig zwischen beiden Modi wechsle. Zur vereinfachten Eingabe habe ich deshalb ein Snippet geschrieben, das ich gerne hier teilen möchte. (...nicht zuletzt, weil meine bescheidenen lilypond-scheme Kenntnisse zu einem nicht unerheblichen Teil diesem Forum zu verdanken sind)

Funktion: Die Prozedur mapChords untersucht die in music enthaltenen note-events auf ArticulationEvent und FingeringEvent. Ist ein Event mit dem entsprechenden Parameter in der shortcuts-Tabelle enthalten, wird die Note durch den in der Tabelle eingetragenen Akkord ersetzt. Der boolsche Parameter in der Tabelle legt fest, ob der Akkord transponiert werden soll (sinnvoll bei Einträgen wie \chordmode { c:min }) oder nicht (evtl. sinnvoll bei frei definierten Einträgen wie <a' d' fs' d''>)

\version "2.24.0"
\language "english"

#(define (note-event? m)
   (music-is-of-type? m 'note-event))

#(define (event-chord? m)
   (music-is-of-type? m 'event-chord))

%{----------------------------------------------------------------------------------------
Init hash-table with chord shortcuts
Examples: note g-- (articulation type) tenuto may be transformed to chord g-minor
Chordmode syntax for easy input, chord will be transposed depending on boolean parameter
User defined chords also possible with lilypond syntax: <g' d' fis' d''> %}

#(define init-shortcuts
   ;PROCEDURE DESCRIPTION AS STRING???
   (let((ht (make-hash-table 20)))

     (hash-set! ht (make-music 'ArticulationEvent 'articulation-type 'stopped)
       (cons #{ \chordmode { c } #}  #t))

     (hash-set! ht (make-music 'ArticulationEvent 'articulation-type 'tenuto)
       (cons #{ \chordmode { c:min } #} #t))

     (hash-set! ht (make-music 'ArticulationEvent 'articulation-type 'marcato)
       (cons #{ \chordmode { c:7 } #} #t))

     (hash-set! ht (make-music 'FingeringEvent 'digit 2)
       (cons #{ \chordmode { c:sus2 } #} #t))

     (hash-set! ht (make-music 'FingeringEvent 'digit 4)
       (cons #{ \chordmode { c:sus4 } #} #t))

     (hash-set! ht (make-music 'FingeringEvent 'digit 11)
       (cons #{ <a' d' fs' d''>  #} #f))

     ht))

%-----------------------------------------------------------------------------------------

#(define (note->Chord note chrd transp?)
   "Replace  @var{note} with @var{chord}, optionally transposed."
   (let* ((root (ly:music-property note 'pitch))
          (dur (ly:music-property note 'duration)))

     (if transp? (set! chrd (ly:music-transpose chrd root)))
     (set! note chrd)
     (music-map
      (lambda (m)
        (if (note-event? m)
            (ly:music-set-property! m 'duration dur))
        m)
      note))

   note)

%-----------------------------------------------------------------------------------------

mapChords =
#(define-music-function (music) (ly:music?)
   "Check if any articulation of the note-events in @var{music} is defined in the
    shortcut-hashtable and then replace note-event with defined event-chord.
    !!! Restriction / ToDo: Shortcut should be first articulation !!!
    !!! Articulations before first valid shortcut will be skipped !!!

    !!! ToDo: For sure there is something i did not thought of ;-) "
   (let(
         (sh init-shortcuts))
     (music-map
      (lambda (note)
        (if (note-event? note)
            ;iterate articulations in note-event
            (for-each
             (lambda (art)
               (let*(
                      ;construct key for search in shortcuts
                      (hash-key (cond
                                 ((music-is-of-type? art 'articulation-event)
                                  (make-music 'ArticulationEvent
                                    'articulation-type
                                    (ly:music-property art 'articulation-type)))
                                 ((music-is-of-type? art 'fingering-event)
                                  (make-music 'FingeringEvent 'digit (ly:music-property art 'digit)))
                                 (else
                                  #f)))
                      ;get value from shortcuts if key exists
                      (val (hash-ref sh hash-key #f))
                      ;get chord-pattern if key exists
                      (chrd (if val (ly:music-deep-copy (car val)) #f))
                      ;get transpose-flag if key exists
                      (transp? (if val (cdr val) #f)))

                 ;Chord-pattern valid and note not already changed to chord?
                 (if (and chrd (note-event? note))
                     ;Map chord to note
                     (set! note (note->Chord note chrd transp?))
                     ;Else: Copy articulation
                     ;!!! Restriction: Shortcut should be first articulation !!!
                     ;!!! Articulations before first valid shortcut will be skipped !!!
                     (music-map
                      (lambda (c)
                        (if (event-chord? c)
                            (ly:music-set-property! c 'elements
                              (cons art (ly:music-property c 'elements))))
                        c)
                      note))))
             (ly:music-property note 'articulations)))
        note)
      music)
     music))

%-----------------------------------------------------------------------------------------

\mapChords \relative c'  {
  a'4-- a8. 8 8 b8 c8.
  g4-+  b8. 8 8 8 a8.
  a2--\(  q\) r1 r1
  d,4-11       % user-defined chord
  c-----+-1-2-3-4 % first shortcut: '--' following articulations preserved
  d2-1-3-+-7-8      % first shortcut: '-+' previous articulations omitted
  f-2 g-4
}

Die Tabelle mit den shortcuts kann frei definiert werden. Wer Tenuto und Finger-Nummern benötigt, könnte z.B. nur Finger-Nummern ab 10 oder 100 definieren.

Speziell für die Ukulele kann ich in Kombination mit  "predefined-ukulele-fretboards.ly" und diesem Snippet using-chordmode-in-tabstaff-for-ukulele-shows-the-wrong-fretted-strings jetzt sehr schnell meine Noten eintippen und Staff sowie (korrektes) TabStaff erzeugen.

Fragen, Krititk und Anregungen sind erwünscht. (Ich glaube mit der scheme-Logik habe ich hier und da noch Probleme...)

Grüße, Jürgen.

PS: Wäre es ein Problem (mal davon abgesehen, dass jemand Lexer und Parser umprogrammieren müsste  8) ) folgende Eingaben gleichwertig zu behandeln?
{ \chordmode {a:min f:1.3.5.7} \notemode {A:min F:1.3.5.7} }