Autor Thema: Verallgemeinerung einer Funktion  (Gelesen 3295 mal)

erich

  • Member
Verallgemeinerung einer Funktion
« am: Samstag, 12. April 2014, 09:52 »
Hallo Lilypondies.

Das Lilypondprogramm
\version "2.18.0"
\language "twintet"

#(define (zerointervall pitch)
    (*(-(+(ly:pitch-steps pitch)(ly:pitch-alteration pitch))(ly:pitch-octave pitch))2)
 )

add =
#(define-music-function (parser location music)
   (ly:music?)
   (let ((result-music (ly:music-deep-copy music)))
     (case (length (ly:music-property result-music 'elements))
         ((1) (let ((pitch (ly:music-property(car(ly:music-property result-music 'elements))'pitch)))
                 (set! (ly:music-property result-music 'elements)
                    (cons (make-music 'FingeringEvent
                                      'direction -1
                                      'digit (zerointervall pitch))
                          (ly:music-property result-music 'elements)))
              )
         )
         ((2) result-music)
         ((3) result-music)
         ((4) result-music)
         (else result-music)
     )
     
     result-music))

\score {
   \new Staff \with {\override StaffSymbol #'line-positions = #'(2 0 -2 -4 -10 )
      \remove "Time_signature_engraver"
      \remove "Bar_number_engraver"
      \remove "Bar_engraver"
      \remove "Clef_engraver"
      staffLineLayoutFunction = #(lambda (p) (- (ly:pitch-steps p) (ly:pitch-octave p)))
   }
   { s2 \add<c'>2 \add<e'>2 \add<gis'>2 \add<c''>2 \add<e''>2 \add<gis''>2}
}

berechnet bei meiner Sprachdefinition \language "twintet" die als Fingerprint angegebenen Intervalle (= Anzahl der Halbtonschritte von c' aus gerechnet) korrekt.


Löscht man die Sprachdefinition, weil man sie nicht zur Verfügung hat, so erhält man falsche Werte, was für meine Fragestellung unerheblich ist.

Nun kommt's: ich möchte nicht vor jede Note \add schreiben müssen, sonder möchte auch \add{<c'>2 <e'> <gis'> <c''> <e''> <gis''>} schreiben können.

Über eine Lösung würde ich mich freuen

Gruß
Erich

p.s. Ich weiß nicht, wie man hier das Bild in den laufenden Text einfügen kann.

harm6

  • Member
Re: Verallgemeinerung einer Funktion
« Antwort #1 am: Samstag, 12. April 2014, 11:59 »
Hallo Erich,

bevor ich mich hier dransetze:
In Deinem Beispiel kommen nur 'EventChords mit einem 'NoteEvent vor. Wie soll sich \add verhalten, wenn der Akkord mehrere Noten beinhaltet?
Dein case hat ja Einträge dafür, die aber im Moment alle result-music ausgeben, dem Minimal-Beispiel geschuldet?

Falls Du daran denkst jeder einzelnen Note einen quasi-Fingersatz mitzugeben, wäre es dann nicht besser diese Zahl in die 'articulations der einzelnen Note und nicht den 'elements einzugliedern?

Gruß,
  Harm

Zitat
p.s. Ich weiß nicht, wie man hier das Bild in den laufenden Text einfügen kann.
Du mußt das Bild irgenwo hochladen und dann den link dahin einfügen



« Letzte Änderung: Samstag, 12. April 2014, 12:02 von harm6 »

harm6

  • Member
Re: Verallgemeinerung einer Funktion
« Antwort #2 am: Samstag, 12. April 2014, 12:17 »
Zitat von: Harm
Falls Du daran denkst jeder einzelnen Note einen quasi-Fingersatz mitzugeben, wäre es dann nicht besser diese Zahl in die 'articulations der einzelnen Note und nicht den 'elements einzugliedern?

Das würde zu folgendem führen:

\version "2.18.0"
%\language "twintet"

#(define (zerointervall pitch)
    (*
       (-
          (+ (ly:pitch-steps pitch)
                   (ly:pitch-alteration pitch))
          (ly:pitch-octave pitch))
       2))

add =
#(define-music-function (parser location music)
   (ly:music?)
   (let ((result-music (ly:music-deep-copy music)))
   
   (music-map
     (lambda (m)
       (if (music-is-of-type? m 'note-event)
           (let ((pitch (ly:music-property m 'pitch)))
             (ly:music-set-property! m 'articulations
                (cons (make-music 'FingeringEvent
                                  'direction -1
                                  'digit (zerointervall pitch))
                      (ly:music-property m 'articulations)))
              m)
         m))
     result-music)))
     

\score {
   \new Staff \with {\override StaffSymbol #'line-positions = #'(2 0 -2 -4 -10 )
      \remove "Time_signature_engraver"
      \remove "Bar_number_engraver"
      \remove "Bar_engraver"
      \remove "Clef_engraver"
      staffLineLayoutFunction = #(lambda (p) (- (ly:pitch-steps p) (ly:pitch-octave p)))
   }
   \add { s2 <c' e' g'>2 <e'>2 <gis'>2 <c''>2 <e''>2 <gis''>2}
}

Gruß,
  Harm

erich

  • Member
Re: Verallgemeinerung einer Funktion
« Antwort #3 am: Samstag, 12. April 2014, 12:59 »
Hallo Harm

Dein case hat ja Einträge dafür, die aber im Moment alle result-music ausgeben, dem Minimal-Beispiel geschuldet?
so ist es; ich wollte das Problem klein halten. Bei den Akkorden will ich die Intervalle, die zwischen den Noten bestehen, ausgeben. Eigentlich soll auch nur der unterste Ton stehen bleiben, aber soweit bin ich noch nicht. Es hat dann Verwandtschaft mit dem Generalbass, nur die Schrift ist viel einfacher und ich kann die Griffe auf dem Klavier ablesen.



Du mußt das Bild irgenwo hochladen und dann den link dahin einfügen
Ich muss mir wohl ansehen, wie der Link lautet, wenn ich das Bild hier im Forum hochgeladen habe; ich hatte einfach den Namen der Datei genommen; aber das war es nicht

Dein Output, den Du erhalten hast, ist schon "richtig"

Ich grüß Dich
Erich
« Letzte Änderung: Samstag, 12. April 2014, 14:50 von erich »

erich

  • Member
Re: Verallgemeinerung einer Funktion
« Antwort #4 am: Samstag, 12. April 2014, 22:30 »
Hallo allen, die dieses lesen.

Inzwischen habe ich im Programm die fehlenden case-Fälle vervollständigt, sodass ich die Ausgabe erhalte,
die ich in meinem letzten Post schon mitgeteilt hatte; nur hatte ich das da noch von Hand gemacht.

\version "2.18.0"
\language "twintet"

#(define (zerointervall pitch)
    (*(-(+(ly:pitch-steps pitch)(ly:pitch-alteration pitch))(ly:pitch-octave pitch))2)
 )

add =
#(define-music-function (parser location music)
   (ly:music?)
   (let ((result-music (ly:music-deep-copy music)))
     (case (length (ly:music-property result-music 'elements))
         ((1) (let ((pitch (ly:music-property(car(ly:music-property result-music 'elements))'pitch)))
                 (set! (ly:music-property result-music 'elements)
                    (cons (make-music 'FingeringEvent
                                      'direction -1
                                      'digit (zerointervall pitch))
                          (ly:music-property result-music 'elements)))
              )
         )
         ((2) (let ((p (ly:music-property(car(ly:music-property result-music 'elements))'pitch))
                    (q (ly:music-property(cadr(ly:music-property result-music 'elements))'pitch))
                    )
                 (set! (ly:music-property result-music 'elements)
                    (cons (make-music 'FingeringEvent
                                      'direction -1
                                      'digit (-(zerointervall q)(zerointervall p)))
                          (ly:music-property result-music 'elements)))
               )
         )
         ((3) (let ((p (ly:music-property(car(ly:music-property result-music 'elements))'pitch))
                    (q (ly:music-property(cadr(ly:music-property result-music 'elements))'pitch))
                    (r (ly:music-property(caddr(ly:music-property result-music 'elements))'pitch))
                    )
                 (set! (ly:music-property result-music 'elements)
                    (cons (make-music 'FingeringEvent
                                      'direction -1
                                      'digit (-(zerointervall r)(zerointervall q))) 
                    (cons (make-music 'FingeringEvent
                                      'direction -1
                                      'digit (-(zerointervall q)(zerointervall p)))
                          (ly:music-property result-music 'elements))))
                    (set! (ly:music-property result-music 'elements)
                           (cddr(reverse (ly:music-property result-music 'elements))))
                 
               )
         )
         ((4) (let ((p (ly:music-property(car(ly:music-property result-music 'elements))'pitch))
                    (q (ly:music-property(cadr(ly:music-property result-music 'elements))'pitch))
                    (r (ly:music-property(caddr(ly:music-property result-music 'elements))'pitch))
                    (s (ly:music-property(cadddr(ly:music-property result-music 'elements))'pitch))
                    )
                 (set! (ly:music-property result-music 'elements)
                    (cons (make-music 'FingeringEvent
                                      'direction -1
                                      'digit (-(zerointervall s)(zerointervall r)))     
                    (cons (make-music 'FingeringEvent
                                      'direction -1
                                      'digit (-(zerointervall r)(zerointervall q))) 
                    (cons (make-music 'FingeringEvent
                                      'direction -1
                                      'digit (-(zerointervall q)(zerointervall p)))
                          (ly:music-property result-music 'elements)))))
                 (set! (ly:music-property result-music 'elements)
                           (cdddr(reverse (ly:music-property result-music 'elements))))
               )
         )
         (else result-music)
     )
     
     result-music))
vorzeichen = \new Voice 
     \set Staff.keySignature = #`((3 . ,FLAT)
                                  (4 . ,FLAT)
                                  (5 . ,FLAT)) 
     
notenDown = {
\add<f'' a'' c'''>4.
\add<e'' g'' c'''>8
\add<d'' g'' b'''>2
\add<c'' f'' a''>
\add<c'' e'' g''>4.
\add<b'' d'' g''>8
\add<a' c'' f''>2
\add<g' c'' e''>
\add<g' b'' d''>4
\add<f' a' c''>
\add<e' g' c''>1
}     

\include "addcDurDown.ly"
\score {
   \new Staff \with {\override StaffSymbol #'line-positions = #'(2 0 -2 -4 -10 )
      \remove "Time_signature_engraver"
      \remove "Bar_number_engraver"
      %\remove "Bar_engraver"
      \remove "Clef_engraver"
      staffLineLayoutFunction = #(lambda (p) (- (ly:pitch-steps p) (ly:pitch-octave p)))
   }
   { #(set-accidental-style 'forget) s1

   \vorzeichen \notenDown
   }
}

Jedoch bleibt noch immer die Frage, wie kann es so programmieren, dass ich nicht

{
\add<f'' a'' c'''>4.
\add<e'' g'' c'''>8
\add<d'' g'' b'''>2
\add<c'' f'' a''>
\add<c'' e'' g''>4.
\add<b'' d'' g''>8
\add<a' c'' f''>2
\add<g' c'' e''>
\add<g' b'' d''>4
\add<f' a' c''>
\add<e' g' c''>1
}     
schreiben muss, sondern das \add herausziehen kann. Natürlich kann man das auch mit einem suchen-ersetzen-Befehl in einem Texteditor erreichen.

Gruß
Erich

harm6

  • Member
Re: Verallgemeinerung einer Funktion
« Antwort #5 am: Samstag, 12. April 2014, 23:35 »
Hallo Erich,

das Bild zeigt die Ausgabe Deines Codes (ohne Twintet natürlich) oben, darunter die Noten die Du eigentlich eingegeben hast (und die ich dann ja auch hören müßte)



Ich kann allerdings keinen Zusammenhang zwischen der klingenden Notation und den Zahlen erkennen.
Solange ich schlichtweg keine Ahnung von der Bedeutung dieser Zahlen habe, fürchte ich Dir nicht mehr helfen zu können.

Gruß,
  Harm

erich

  • Member
Re: Verallgemeinerung einer Funktion
« Antwort #6 am: Sonntag, 13. April 2014, 07:47 »
Hallo Harm,

vielen Dank, dass Du Dir soviel Mühe mit meiner Sache gibst. Das Problem, das ich habe, dürfte man zwar rein formal angehen können, aber ich gebe zu: das kann eine Zumutung sein.

Da ich annehme, dass Du keine Schwierigkeit haben wirst, den Twintet-Sprachcode in der define-note-names.scm einzupflegen, stelle ich ihn hier mal zur Verfügung:

;; Language: Twintet ------------------------------------------;
   
       (twintet . (
                   (b . ,(ly:make-pitch -1 0 FLAT))
                   (h . ,(ly:make-pitch -1 0 FLAT))
                   (ces . ,(ly:make-pitch -1 0 FLAT))
                   (c . ,(ly:make-pitch -1 0 NATURAL))
                   (cis . ,(ly:make-pitch -1 0 SHARP))
                   (des . ,(ly:make-pitch -1 1 FLAT))
                   (d . ,(ly:make-pitch -1 1 NATURAL))
                   (dis . ,(ly:make-pitch -1 1 SHARP))
                   (es . ,(ly:make-pitch -1 2 FLAT))
                   (e . ,(ly:make-pitch -1 2 NATURAL))
                   (eis . ,(ly:make-pitch -1 2 SHARP))
                   (f . ,(ly:make-pitch -1 3 FLAT))
                   (fis . ,(ly:make-pitch -1 3 NATURAL))
                   (ges . ,(ly:make-pitch -1 3 NATURAL))
                   (fus . ,(ly:make-pitch -1 3 SHARP))
                   (g . ,(ly:make-pitch -1 4 FLAT))
                   (gis . ,(ly:make-pitch -1 4 NATURAL))
                   (as . ,(ly:make-pitch -1 4 NATURAL))
                   (gus . ,(ly:make-pitch -1 4 SHARP))
                   (a . ,(ly:make-pitch -1 5 FLAT))
                   (ais . ,(ly:make-pitch -1 5 NATURAL))
                   (bes . ,(ly:make-pitch -1 5 NATURAL))
                   (aus . ,(ly:make-pitch -1 5 SHARP))
                  ))
 

In Twintet werden den Notenlinien und den Zwischenräumen feste Tonhöhen zugeordnet, deshalb haben die Noten auch ohne Schlüssel eine definierte Tonhöhe. Die Aufschlüsselung kannst Du aus der bildlichen Darstellung ersehen; der Schlüssel ist gewissenmaßen nur nachrichtlich, er markiert das C. Die Note H wird als B eingegeben und als Ces dargestellt; deshalb muss die Oktace wie beim C angegeben werden. Das ist der Grund, warum Du so eine kaum erklärbare Darstellung erhälts.
Die Vorzeichen dienen dazu, F, G und A wie traditionell geschrieben erscheinen zu lassen; eigentlich sind es Fises, Gises und Aises; G würde sonst beispielsweise auf der gis-Linie mit einem b davor dargestellt.

Übrigens:#(set-accidental-style 'forget) bewirkt, dass Versetzungszeichen immer nur für die Note gelten, vor der sie stehen.

Gruß und einen schönen Sonntag
Erich



« Letzte Änderung: Sonntag, 13. April 2014, 08:15 von erich »

harm6

  • Member
Re: Verallgemeinerung einer Funktion
« Antwort #7 am: Sonntag, 13. April 2014, 13:59 »
Hallo Erich,

vielen Dank, daß Du den Twintet-Sprachcode zur Verfügung gestellt hast, jetzt bin ich weitergekommen.

Tatsächlich habe ich mir die Freiheit genommen, (fast) alles neu zu kodieren um all die Code-Wiederholungen los zu werden.

Im "BASIC STUFF" habe ich twintet so eingebunden, daß man define-note-names.scm nicht mehr patchen muß, sowie eine procedure aus 2.19,  'event-chord-reduce', eingefügt, die nur die erste geschriebene Note eines Akkords zurückgibt. Dabei habe ich bemerkt, daß 'event-chord-reduce' zwei kleine bugs beinhaltet. Die sind hier aber ohne Bedeutung, denke ich.

Ansonsten habe ich einige Kommentare eingefügt, falls etwas unklar ist, melde Dich.

\version "2.18.0"

%%%%%%%%%%%%%%%%%%%%%%%%%
%% BASIC STUFF
%%%%%%%%%%%%%%%%%%%%%%%%%

%% Making available 'twintet' without need to patch define-note-names.scm
%% Could be included from another file.
twintet-pitch-names =
  #`(
     (b . ,(ly:make-pitch -1 0 FLAT))
     (h . ,(ly:make-pitch -1 0 FLAT))
     (ces . ,(ly:make-pitch -1 0 FLAT))
     (c . ,(ly:make-pitch -1 0 NATURAL))
     (cis . ,(ly:make-pitch -1 0 SHARP))
     (des . ,(ly:make-pitch -1 1 FLAT))
     (d . ,(ly:make-pitch -1 1 NATURAL))
     (dis . ,(ly:make-pitch -1 1 SHARP))
     (es . ,(ly:make-pitch -1 2 FLAT))
     (e . ,(ly:make-pitch -1 2 NATURAL))
     (eis . ,(ly:make-pitch -1 2 SHARP))
     (f . ,(ly:make-pitch -1 3 FLAT))
     (fis . ,(ly:make-pitch -1 3 NATURAL))
     (ges . ,(ly:make-pitch -1 3 NATURAL))
     (fus . ,(ly:make-pitch -1 3 SHARP))
     (g . ,(ly:make-pitch -1 4 FLAT))
     (gis . ,(ly:make-pitch -1 4 NATURAL))
     (as . ,(ly:make-pitch -1 4 NATURAL))
     (gus . ,(ly:make-pitch -1 4 SHARP))
     (a . ,(ly:make-pitch -1 5 FLAT))
     (ais . ,(ly:make-pitch -1 5 NATURAL))
     (bes . ,(ly:make-pitch -1 5 NATURAL))
     (aus . ,(ly:make-pitch -1 5 SHARP))
    )

#(ly:parser-set-note-names parser twintet-pitch-names)

%% 'event-chord-reduce' isn't available in 2.18.0
%% c/p from 2.19.3

#(use-modules (srfi srfi-11))

#(define-public (event-chord-reduce music)
  "Reduces event chords in @var{music} to their first note event,
retaining only the chord articulations.  Returns the modified music."
  (map-some-music
   (lambda (m)
     (and (music-is-of-type? m 'event-chord)
          (let*-values (((notes arts) (partition
                                       (lambda (mus)
                                         (music-is-of-type? mus 'rhythmic-event))
                                       (ly:music-property m 'elements)))
                        ((dur) (ly:music-property m 'duration))
                        ((full-arts) (append arts
                                             (ly:music-property m 'articulations)))
                        ((first-note) (and (pair? notes) (car notes))))
            (cond (first-note
                   (set! (ly:music-property first-note 'articulations)
                         full-arts)
                   first-note)
                  ((ly:duration? dur)
                   ;; A repeat chord. Produce an unpitched note.
                   (make-music 'NoteEvent
                               'duration dur
                               'articulations full-arts))
                  (else
                   (ly:music-error m (_ "Missing duration"))
                   (make-music 'NoteEvent
                               'duration (ly:make-duration 2 0 0)
                               'articulations full-arts))))))
   music))
   
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% THE DEFINITIONS/FUNCTIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#(define (zerointervall pitch)
  (*
     (-
        (+ (ly:pitch-steps pitch)
                 (ly:pitch-alteration pitch))
        (ly:pitch-octave pitch))
     2))

#(define (make-fingering direction digit)
;; returns a FingeringEvent
  (make-music 'FingeringEvent
    'direction direction
    'digit digit))
   
#(define (make-fingering-down digit) (make-fingering -1 digit))

#(define (number-list-diffs number-list)
;; takes a list of numbers and returns a list of diffs of all adjacent elements
  (define (helper l1 l2)
    (if (>= 1 (length l1))
        (reverse l2)
        (helper (cdr l1) (cons (- (cadr l1) (car l1)) l2))))
  (helper number-list '()))

#(define (print-half-steps-as-fingerings m)
;; returns only the first entered note of an EventChord
;; adds the half-note-steps of adjacent notes as fingerings below
;; the order of notes entered in the EventChord matters, changing them will
;; cause a different result
  (if (music-is-of-type? m 'event-chord)
      (let* ((evt-chrd-notes (event-chord-notes m))
             (evt-chrd-pitches (event-chord-pitches m))
             (zerointervall-list
               (map (lambda (p) (zerointervall p)) evt-chrd-pitches))
             (pitch-diffs (number-list-diffs zerointervall-list))
             (fingerings
               (map (lambda (n) (make-fingering-down n)) pitch-diffs))
             (evt-chrd-elts (ly:music-property m 'elements)))
        (ly:music-set-property! m 'elements (append evt-chrd-elts fingerings))
        (event-chord-reduce m))
      m))

adds =
#(define-music-function (parser location music)(ly:music?)
  (music-map
    (lambda (m) (print-half-steps-as-fingerings m))
    music))
   
%%%%%%%%%%%%%
%% TEST
%%%%%%%%%%%%
   
vorzeichen =
  \new Voice 
    \set Staff.keySignature = #`((3 . ,FLAT)
                                 (4 . ,FLAT)
                                 (5 . ,FLAT)) 
                                 
remark =
  \markup
    \override #'(line-width . 30)
    \wordwrap-string
    #"NOTE: different entering order will cause different result:"

noten-down = {
  <f'' a'' c'''>4.
  <e'' g'' c'''>8
  <d'' g'' b'''>2
  <c'' f'' a''>
  <c'' e'' g''>4.
  <b'' d'' g''>8
  <a' c'' f''>2
  <g' c'' e''>
  <g' b'' d''>4
  <f' a' c''>
  %% <>^"whatever" doesn't work with 'event-chord-reduce', bug!
  s1*0^\remark
  <e' g' c''>1
  <e' c'' g'>1
  <c'' e' g'>1


\score {
  \new Staff
    \with {
      \override StaffSymbol #'line-positions = #'(2 0 -2 -4 -10)
      \remove "Time_signature_engraver"
      \remove "Bar_number_engraver"
      %\remove "Bar_engraver"
      \remove "Clef_engraver"
      staffLineLayoutFunction =
        #(lambda (p) (- (ly:pitch-steps p) (ly:pitch-octave p)))
      \accidentalStyle forget
    }
    \adds { s1 \vorzeichen \noten-down }
}

HTH,
  Harm
« Letzte Änderung: Sonntag, 13. April 2014, 14:03 von harm6 »

erich

  • Member
Re: Verallgemeinerung einer Funktion
« Antwort #8 am: Sonntag, 13. April 2014, 15:58 »
Hallo Harm

vielen Dank für die Antwort; gefallen tut mir, die define-note-names.scm nicht mehr verändern zu müssen, das war doch lästig, bei jeder Neuinstallation die Änderungen nachzutragen.

#(ly:parser-set-note-names parser twintet-pitch-names)nach solch einem Mechanismus hatte ich Ausschau gehalten, aber nichts gefunden; ich hatte gemeint, Entsprechendes in einem versteckten Ordner in meiner home-Directory finden zu müssen, wie es in Unix-Systemen üblich ist.

Ich weiß, Du liebst es, alles möglichst weit zu parametrisieren; ich hatte es bei der Langform gelassen, da man dann besser erkennt, wie es entwickelt wurde.

Da ich kein 2.19.xer Lilypond installiert habe, habe ich Deinen Code noch nicht genauer angesehen. Aber eine Frage habe ich schon; klar ist, dass die Reihenfolge der Eingabe der Noten in einem Akkord, die Fingerings  beeinflussen, aber: ist die Vertauschung der Fingerings programmiernotwendig? ich hätte sie gerne in entgegengesetzter Reihenfolge.

Grüß Dich
Erich

harm6

  • Member
Re: Verallgemeinerung einer Funktion
« Antwort #9 am: Sonntag, 13. April 2014, 19:01 »
Zitat
eine Frage habe ich schon; klar ist, dass die Reihenfolge der Eingabe der Noten in einem Akkord, die Fingerings  beeinflussen, aber: ist die Vertauschung der Fingerings programmiernotwendig? ich hätte sie gerne in entgegengesetzter Reihenfolge.
Hm, Dein Original-Code zeigt es so, ich habe es dann genauso nachgebaut.
Ist aber kein Problem es zu ändern (hab noch eine winzige Verbesserung zusätzlich eingefügt):

\version "2.18.0"

%%%%%%%%%%%%%%%%%%%%%%%%%
%% BASIC STUFF
%%%%%%%%%%%%%%%%%%%%%%%%%

%% Making available 'twintet' without need to patch define-note-names.scm
%% Could be included from another file.
twintet-pitch-names =
  #`(
     (b . ,(ly:make-pitch -1 0 FLAT))
     (h . ,(ly:make-pitch -1 0 FLAT))
     (ces . ,(ly:make-pitch -1 0 FLAT))
     (c . ,(ly:make-pitch -1 0 NATURAL))
     (cis . ,(ly:make-pitch -1 0 SHARP))
     (des . ,(ly:make-pitch -1 1 FLAT))
     (d . ,(ly:make-pitch -1 1 NATURAL))
     (dis . ,(ly:make-pitch -1 1 SHARP))
     (es . ,(ly:make-pitch -1 2 FLAT))
     (e . ,(ly:make-pitch -1 2 NATURAL))
     (eis . ,(ly:make-pitch -1 2 SHARP))
     (f . ,(ly:make-pitch -1 3 FLAT))
     (fis . ,(ly:make-pitch -1 3 NATURAL))
     (ges . ,(ly:make-pitch -1 3 NATURAL))
     (fus . ,(ly:make-pitch -1 3 SHARP))
     (g . ,(ly:make-pitch -1 4 FLAT))
     (gis . ,(ly:make-pitch -1 4 NATURAL))
     (as . ,(ly:make-pitch -1 4 NATURAL))
     (gus . ,(ly:make-pitch -1 4 SHARP))
     (a . ,(ly:make-pitch -1 5 FLAT))
     (ais . ,(ly:make-pitch -1 5 NATURAL))
     (bes . ,(ly:make-pitch -1 5 NATURAL))
     (aus . ,(ly:make-pitch -1 5 SHARP))
    )

#(ly:parser-set-note-names parser twintet-pitch-names)

%% 'event-chord-reduce' isn't available in 2.18.0
%% c/p from 2.19.3

#(use-modules (srfi srfi-11))

#(define-public (event-chord-reduce music)
  "Reduces event chords in @var{music} to their first note event,
retaining only the chord articulations.  Returns the modified music."
  (map-some-music
   (lambda (m)
     (and (music-is-of-type? m 'event-chord)
          (let*-values (((notes arts) (partition
                                       (lambda (mus)
                                         (music-is-of-type? mus 'rhythmic-event))
                                       (ly:music-property m 'elements)))
                        ((dur) (ly:music-property m 'duration))
                        ((full-arts) (append arts
                                             (ly:music-property m 'articulations)))
                        ((first-note) (and (pair? notes) (car notes))))
            (cond (first-note
                   (set! (ly:music-property first-note 'articulations)
                         full-arts)
                   first-note)
                  ((ly:duration? dur)
                   ;; A repeat chord. Produce an unpitched note.
                   (make-music 'NoteEvent
                               'duration dur
                               'articulations full-arts))
                  (else
                   (ly:music-error m (_ "Missing duration"))
                   (make-music 'NoteEvent
                               'duration (ly:make-duration 2 0 0)
                               'articulations full-arts))))))
   music))
   
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% THE DEFINITIONS/FUNCTIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#(define (zerointervall pitch)
  (*
     (-
        (+ (ly:pitch-steps pitch)
                 (ly:pitch-alteration pitch))
        (ly:pitch-octave pitch))
     2))

#(define (make-fingering direction digit)
;; returns a FingeringEvent
  (make-music 'FingeringEvent
    'direction direction
    'digit digit))
   
#(define (make-fingering-down digit) (make-fingering -1 digit))

#(define (number-list-diffs number-list)
;; takes a list of numbers and returns a list of diffs of all adjacent elements
  (define (helper l1 l2)
    (if (>= 1 (length l1))
        (reverse l2)
        (helper (cdr l1) (cons (- (cadr l1) (car l1)) l2))))
  (helper number-list '()))

#(define (print-half-steps-as-fingerings m)
;; returns only the first entered note of an EventChord
;; adds the half-note-steps of adjacent notes as fingerings below
;; the order of notes entered in the EventChord matters, changing them will
;; cause a different result
  (if (and (music-is-of-type? m 'event-chord)
           (not (null? (event-chord-notes m))))
      (let* ((evt-chrd-notes (event-chord-notes m))
             (evt-chrd-pitches (event-chord-pitches m))
             (zerointervall-list
               (map (lambda (p) (zerointervall p)) evt-chrd-pitches))
             (pitch-diffs (number-list-diffs zerointervall-list))
             (fingerings
               (reverse (map (lambda (n) (make-fingering-down n)) pitch-diffs)))
             (evt-chrd-elts (ly:music-property m 'elements)))
        (ly:music-set-property! m 'elements (append evt-chrd-elts fingerings))
        (event-chord-reduce m))
      m))

adds =
#(define-music-function (parser location music)(ly:music?)
  (music-map
    (lambda (m) (print-half-steps-as-fingerings m))
    music))
   
%%%%%%%%%%%%%
%% TEST
%%%%%%%%%%%%
   
vorzeichen =
  \new Voice 
    \set Staff.keySignature = #`((3 . ,FLAT)
                                 (4 . ,FLAT)
                                 (5 . ,FLAT)) 
                                 
remark =
  \markup
    \override #'(line-width . 30)
    \wordwrap-string
    #"NOTE: different entering order will cause different result:"

noten-down = {
  <f'' a'' c'''>4.
  <e'' g'' c'''>8
  <d'' g'' b'''>2
  <c'' f'' a''>
  <c'' e'' g''>4.
  <b'' d'' g''>8
  <a' c'' f''>2
  <g' c'' e''>
  <g' b'' d''>4
  <f' a' c''>
  <>^\remark
  <e' g' c''>1
  <e' c'' g'>1
  <c'' e' g'>1


\score {
  \new Staff
    \with {
      \override StaffSymbol #'line-positions = #'(2 0 -2 -4 -10)
      \remove "Time_signature_engraver"
      \remove "Bar_number_engraver"
      %\remove "Bar_engraver"
      \remove "Clef_engraver"
      staffLineLayoutFunction =
        #(lambda (p) (- (ly:pitch-steps p) (ly:pitch-octave p)))
      \accidentalStyle forget
    }
    \adds { s1 \vorzeichen \noten-down }
}

Zitat
Da ich kein 2.19.xer Lilypond installiert habe, habe ich Deinen Code noch nicht genauer angesehen.

Nicht das wir uns falsch verstehen, mein Code ist für 2.18.0 und kompiliert dort einwandfrei (natürlich mag es noch unentdeckte Probleme geben, das wird die weitere Anwendung dann aufzeigen).
Also, kein 2.19 nötig.

Zitat
Ich weiß, Du liebst es, alles möglichst weit zu parametrisieren; ich hatte es bei der Langform gelassen, da man dann besser erkennt, wie es entwickelt wurde.

Nun denn, hier Deine Fassung, die Fingerings habe ich aber nicht umgedreht.
War mir zu viel Arbeit (bei meiner Fassung reichte die Einfügung eines Befehls). :D

\version "2.18.0"

%%%%%%%%%%%%%%%%%%%%%%%%%
%% BASIC STUFF
%%%%%%%%%%%%%%%%%%%%%%%%%

%% Making available 'twintet' without need to patch define-note-names.scm
%% Could be included from another file.
twintet-pitch-names =
  #`(
     (b . ,(ly:make-pitch -1 0 FLAT))
     (h . ,(ly:make-pitch -1 0 FLAT))
     (ces . ,(ly:make-pitch -1 0 FLAT))
     (c . ,(ly:make-pitch -1 0 NATURAL))
     (cis . ,(ly:make-pitch -1 0 SHARP))
     (des . ,(ly:make-pitch -1 1 FLAT))
     (d . ,(ly:make-pitch -1 1 NATURAL))
     (dis . ,(ly:make-pitch -1 1 SHARP))
     (es . ,(ly:make-pitch -1 2 FLAT))
     (e . ,(ly:make-pitch -1 2 NATURAL))
     (eis . ,(ly:make-pitch -1 2 SHARP))
     (f . ,(ly:make-pitch -1 3 FLAT))
     (fis . ,(ly:make-pitch -1 3 NATURAL))
     (ges . ,(ly:make-pitch -1 3 NATURAL))
     (fus . ,(ly:make-pitch -1 3 SHARP))
     (g . ,(ly:make-pitch -1 4 FLAT))
     (gis . ,(ly:make-pitch -1 4 NATURAL))
     (as . ,(ly:make-pitch -1 4 NATURAL))
     (gus . ,(ly:make-pitch -1 4 SHARP))
     (a . ,(ly:make-pitch -1 5 FLAT))
     (ais . ,(ly:make-pitch -1 5 NATURAL))
     (bes . ,(ly:make-pitch -1 5 NATURAL))
     (aus . ,(ly:make-pitch -1 5 SHARP))
    )

#(ly:parser-set-note-names parser twintet-pitch-names)


#(define (zerointervall pitch)
    (*(-(+(ly:pitch-steps pitch)(ly:pitch-alteration pitch))(ly:pitch-octave pitch))2)
 )

add =
#(define-music-function (parser location original-music)
   (ly:music?)
  (let ((result-music (ly:music-deep-copy original-music)))
    (music-map
      (lambda (music)
        (if (music-is-of-type? music 'event-chord)
            (case (length (ly:music-property music 'elements))
                ((1) (let ((pitch (ly:music-property(car(ly:music-property music 'elements))'pitch)))
                        (set! (ly:music-property music 'elements)
                           (cons (make-music 'FingeringEvent
                                             'direction -1
                                             'digit (zerointervall pitch))
                                 (ly:music-property music 'elements)))
                        music
                     )
                )
                ((2) (let ((p (ly:music-property(car(ly:music-property music 'elements))'pitch))
                           (q (ly:music-property(cadr(ly:music-property music 'elements))'pitch))
                           )
                        (set! (ly:music-property music 'elements)
                           (cons (make-music 'FingeringEvent
                                             'direction -1
                                             'digit (-(zerointervall q)(zerointervall p)))
                                 (ly:music-property music 'elements)))
                        music
                      )
                )
                ((3) (let ((p (ly:music-property(car(ly:music-property music 'elements))'pitch))
                           (q (ly:music-property(cadr(ly:music-property music 'elements))'pitch))
                           (r (ly:music-property(caddr(ly:music-property music 'elements))'pitch))
                           )
                        (set! (ly:music-property music 'elements)
                           (cons (make-music 'FingeringEvent
                                             'direction -1
                                             'digit (-(zerointervall r)(zerointervall q))) 
                           (cons (make-music 'FingeringEvent
                                             'direction -1
                                             'digit (-(zerointervall q)(zerointervall p)))
                                 (ly:music-property music 'elements))))
                           (set! (ly:music-property music 'elements)
                                  (cddr(reverse (ly:music-property music 'elements))))
                        music
                      )
                )
                ((4) (let ((p (ly:music-property(car(ly:music-property music 'elements))'pitch))
                           (q (ly:music-property(cadr(ly:music-property music 'elements))'pitch))
                           (r (ly:music-property(caddr(ly:music-property music 'elements))'pitch))
                           (s (ly:music-property(cadddr(ly:music-property music 'elements))'pitch))
                           )
                        (set! (ly:music-property music 'elements)
                           (cons (make-music 'FingeringEvent
                                             'direction -1
                                             'digit (-(zerointervall s)(zerointervall r)))     
                           (cons (make-music 'FingeringEvent
                                             'direction -1
                                             'digit (-(zerointervall r)(zerointervall q))) 
                           (cons (make-music 'FingeringEvent
                                             'direction -1
                                             'digit (-(zerointervall q)(zerointervall p)))
                                 (ly:music-property music 'elements)))))
                        (set! (ly:music-property music 'elements)
                                  (cdddr(reverse (ly:music-property music 'elements))))
                        music
                      )
                )
                (else music)
         )
         music))
      result-music)))
 
vorzeichen = \new Voice 
     \set Staff.keySignature = #`((3 . ,FLAT)
                                  (4 . ,FLAT)
                                  (5 . ,FLAT)) 
     
notenDown =  {
  <f'' a'' c'''>4.
  <e'' g'' c'''>8
  <d'' g'' b'''>2
  <c'' f'' a''>
  <c'' e'' g''>4.
  <b'' d'' g''>8
  <a' c'' f''>2
  <g' c'' e''>
  <g' b'' d''>4
  <f' a' c''>
  <e' g' c''>1
}     


\score {
   \new Staff \with {\override StaffSymbol #'line-positions = #'(2 0 -2 -4 -10 )
      \remove "Time_signature_engraver"
      \remove "Bar_number_engraver"
      %\remove "Bar_engraver"
      \remove "Clef_engraver"
      staffLineLayoutFunction = #(lambda (p) (- (ly:pitch-steps p) (ly:pitch-octave p)))
   }
    \add { #(set-accidental-style 'forget) s1

   \vorzeichen \notenDown
   }
}

Gruß,
  Harm

erich

  • Member
Re: Verallgemeinerung einer Funktion
« Antwort #10 am: Montag, 14. April 2014, 12:20 »
Hallo Harm,

danke, dass Du meine Version so weit wie möglich übernommen hast; so konnte ich das Wesentliche erkennen:

Wenn man die eigentliche Berechnung bei Seite lässt und nur eine identische Funktion behalten will, aber eine benannte Funktion als Argument von music-map verwendem will, dann bleibt folgendes Gerippe übrig:


#(define function
   (lambda(x) x))

add =
#(define-music-function (parser location original-music)
   (ly:music?)
  (let ((result-music (ly:music-deep-copy original-music)))
    (music-map

      function
     
      result-music)))

Ich hatte immer versucht, der Funktion function ein Argument mitzugeben; dann scheint  es aber nicht mehr möglich zu sein,  über dieses Argument einen Wert zurückzugeben.

Gruß
Erich