Deutschsprachiges LilyPond Forum

Allgemeine Fragen und Probleme => Fragen und Probleme aller Art => Thema gestartet von: ingmar am Dienstag, 21. April 2026, 14:01

Titel: Ambitus feststellen? [gelöst]
Beitrag von: ingmar am Dienstag, 21. April 2026, 14:01
Wir hatten hier ja schon eine Diskussion zum Thema "Wie kriege ich den Ambitus in die 2. Zeile? (https://lilypondforum.de/index.php/topic,1591.0.html)" (dazu weiterführend, hier aber nicht relevant, siehe noch "Ambitus 2. Zeile: Lösung funktioniert nicht mit 2.25.x (https://lilypondforum.de/index.php/topic,1596.0.html)")

Da mir die Frage nach höchstem und tiefsten Ton immer wieder mal begegnet, möchte ich das Thema doch nochmal aufgreifen. Allerdings geht es mir hier gar nicht um die Darstellung eines Tonumfangs, sondern nur um eine Funktion, der eine Voice oder ein Staff übergeben wird und die den höchsten (und mit Minimaländerung den tiefsten) vorkommenden Ton zurückgibt.

Also sowas wie:
myVoice = \relativ {
  c'4 d e f g2 g
a4 a a a g1
a4 a a a g1
f4 f f f e2 e
d4 d d d c1
}
hi = \highest \myVoice
lo = \lowest \myVoice

%hi = { c' }
%lo = { a' }
   
\score { <<
   \new Staff = "Umfang" <<
      \new Voice = "Melodie" { << \hi \lo >> }
   >>
>> }

Was mir halt fehlt, sind die beiden Funktionen \highest und \lowest. In Harms sehr umfangreichem Code (siehe oben verlinkten Thread) finde ich mich leider trotz heftigen Bemühens nicht zurecht; man muss sich ja eigentlich nur den Startton merken und dann bei jedem weiteren Ton mit diesem neuen Ton überschreiben oder eben nicht, und am Schluss den letzten Stand zurückgeben.

Also brauchen wir
   (lambda (p1 p2)
           (ly:pitch<? p2 p1))

... aber für das Drumherum
bin ich offenbar zu dumm ...

Sicher kann mir jemand von Euch auf die Sprünge helfen..? : - )

Herzlichen Dank!
--ingmar

Titel: Antw:Ambitus feststellen?
Beitrag von: Manuela am Dienstag, 21. April 2026, 17:33
Meinst sowas wie diese Funktion?

\version "2.25.80"

musicextrema =
#(define-music-function (mus)(ly:music?)
   (let*
    (
      (alle-pitches
       (let loop ((mus mus) (pitches '()))
         (let ((p  (ly:music-property mus 'pitch)))
           (if (ly:pitch? p)
               (cons p pitches)
               (let ((elt (ly:music-property mus 'element)))
                 (fold loop
                       (if (ly:music? elt)
                           (loop elt pitches)
                           pitches)
                       (ly:music-property mus 'elements)))))))
      (alle-sortiert (sort alle-pitches ly:pitch<?))
      (tief (car alle-sortiert))
      (hoch (car (reverse alle-sortiert)))
      )
    ;     (display tief )(display hoch)
    ;     (write-me "alle pitches----> " (list? alle-pitches))
    (make-music
     'SequentialMusic
     'elements
     (list
      (make-music
       'NoteEvent
       'duration
       (ly:make-duration 2)
       'pitch
       tief)
      (make-music
       'NoteEvent
       'pitch
       hoch
       'duration
       (ly:make-duration 2))))
    ))

mymus = \relative { c' c c, c,, }
{ \clef bass \musicextrema \mymus }

Mit wenig Aufwand kannst du aus diesem Code die gewünschten Funktionen basteln.
Titel: re: Ambitus feststellen?
Beitrag von: ingmar am Samstag, 25. April 2026, 19:54
ZitatMit wenig Aufwand kannst du aus diesem Code die gewünschten Funktionen basteln.

Das war schon mehr, als ich gehofft hatte. Der Code funktioniert einwandfrei. – Danke, Manuela! : - )

Nur, was du an der Stelle
      (let ((elt (ly:music-property mus 'element)))
         (fold loop ...

..genau machst, ist mir nicht klar.

Gruß, : - )
--ingmar
Titel: Antw:Ambitus feststellen?
Beitrag von: Manuela am Sonntag, 26. April 2026, 07:18
Zitat von: ingmar am Samstag, 25. April 2026, 19:54Nur, was du an der Stelle
      (let ((elt (ly:music-property mus 'element)))
         (fold loop ...

..genau machst, ist mir nicht klar.

Mir auch nicht, der Code ist natürlich von Harm. So wie ich das verstehe, arbeitet sich das Programm durch alle Musikelemente durch, aber Scheme ist für mich sehr schwer zu durchschauen.
Titel: Antw:Ambitus feststellen?
Beitrag von: harm6 am Sonntag, 26. April 2026, 16:33
Zitatder Code ist natürlich von Harm.
Hm, da erinnere ich mich nicht dran. Hast du einen link?

Gruß,
  Harm
Titel: Antw:Ambitus feststellen?
Beitrag von: Manuela am Sonntag, 26. April 2026, 20:58
Zitat von: harm6 am Sonntag, 26. April 2026, 16:33
Zitatder Code ist natürlich von Harm.
Hm, da erinnere ich mich nicht dran. Hast du einen link?

Gruß,
  Harm

Hast recht, anscheinend habe ich  einen vorhandenen Code umgeschrieben, hier der Link Niedrigste/höchste Note aus Musik herausfiltern (https://lilypondforum.de/index.php/topic,1407.msg6934.html). Bin ich doch schlauer als ich dachte?  ;)
Titel: re: Ambitus feststellen?
Beitrag von: ingmar am Freitag, 1. Mai 2026, 12:21
Zitat von: Manuela am Sonntag, 26. April 2026, 20:58Bin ich doch schlauer als ich dachte?  ;)

Ja – bist du!

Ahem. – Nun aber noch ein Frage! Es ist für mich kein großes Problem, den Code so zu ändern, dass wahlweise nur der höchste oder nur der tiefste Ton herauskommt.*) Auch nicht, die Dauer auf ganze Noten zu ändern. Wenn ich nun allerdings höchsten und tiefsten Ton einzeln feststelle und versuche, sie mittels { <\tiefster-ton \hoechster-ton >1 } untereinander anzuordnen, krieg ich einen Fehler – vielleicht, weil ihnen in deinem Code ja bereits Dauern zugewiesen worden waren.

Das als Hintergrund – Nun frage ich mich, wie ich diese eckigen Klammern < > schon oben im Code um die Liste packe, damit das gleich als Zweiklang herauskommt. Sicher hat jemand eine zündende Idee? : - )

Danke, Gruß,
--ingmar


*) (meine Lösung ist allerdings nicht schön, weil ich der Einfachheit halber auch einen einzelnen Ton als 'Sequential-Music in einer Liste ausgebe...)
Titel: Antw:Ambitus feststellen?
Beitrag von: Manuela am Sonntag, 3. Mai 2026, 06:58
Ich habe dieses kleine Programm gefunden, das aus einer Liste Akkorde macht. Momentan habe ich keine Zeit, vielleicht kannst du was damit anfangen
#(define (pitches->chord plist)
   (make-music
    'EventChord 'elements
    (if (list? plist)
        (map (lambda (p)
               (make-music
                'NoteEvent 'duration (ly:make-duration 0)
                'pitch p))
             plist)
        (make-music
         'NoteEvent 'duration (ly:make-duration 0)
         'pitch plist)
        )))

Update: Es ging anhand des Beispiels gar nicht so schwer, einen Akkord aus den Noten zu machen. Ich habe das Programm so erweitert, dass man die Notendauer des Akkords als Parameter eingeben kann.

\version "2.26.0"

myambitus =
#(define-music-function (mus dur)(ly:music? integer?)
   (let*
    (
      (alle-pitches
       (let loop ((mus mus) (pitches '()))
         (let ((p  (ly:music-property mus 'pitch)))
           (if (ly:pitch? p)
               (cons p pitches)
               (let ((elt (ly:music-property mus 'element)))
                 (fold loop
                       (if (ly:music? elt)
                           (loop elt pitches)
                           pitches)
                       (ly:music-property mus 'elements)))))))
      (alle-sortiert (sort alle-pitches ly:pitch<?))
      (tief (car alle-sortiert))
      (hoch (car (reverse alle-sortiert)))
      )
    ;     (display tief )(display hoch)
    ;     (write-me "alle pitches----> " (list? alle-pitches))
    (make-music
     'EventChord 'elements
     (list
      (make-music
       'NoteEvent
       'duration
       (ly:make-duration dur)
       'pitch
       tief)
      (make-music
       'NoteEvent
       'pitch
       hoch
       'duration
       (ly:make-duration dur))))
    ))

mymus = \relative { c' c f,, }
{ \clef bass \myambitus \mymus #3 }

Und hier noch eine Variante, wo man eine Lilypond-Notendauer als Parameter eingibt (und nicht einen Zahlenwert)

\version "2.26.0"

myambitus =
#(define-music-function (mus dur)(ly:music? ly:duration?)
   (let*
    (
      (alle-pitches
       (let loop ((mus mus) (pitches '()))
         (let ((p  (ly:music-property mus 'pitch)))
           (if (ly:pitch? p)
               (cons p pitches)
               (let ((elt (ly:music-property mus 'element)))
                 (fold loop
                       (if (ly:music? elt)
                           (loop elt pitches)
                           pitches)
                       (ly:music-property mus 'elements)))))))
      (alle-sortiert (sort alle-pitches ly:pitch<?))
      (tief (car alle-sortiert))
      (hoch (car (reverse alle-sortiert)))
      )
    ;     (display tief )(display hoch)
    ;     (write-me "alle pitches----> " (list? alle-pitches))
    (make-music
     'EventChord 'elements
     (list
      (make-music
       'NoteEvent
       'duration
       dur
       'pitch
       tief)
      (make-music
       'NoteEvent
       'pitch
       hoch
       'duration
       dur)))
    ))

mymus = \relative { c' c f,, }
{ \clef bass \myambitus \mymus #(ly:make-duration 0) }
{ \clef bass \myambitus \transpose c e \mymus 2. }
Titel: re: Ambitus feststellen? [gelöst]
Beitrag von: ingmar am Sonntag, 3. Mai 2026, 12:11
Ah, so geht das! : - )

Statt 'SequentialMusic nehmen wir 'EventChord. Ich hatte die ganze Doku nach "SequentialMusic" durchsucht, in der Hoffnung, dort irgendeinen Hinweis zu finden, aber Pustekuchen..

Danke für deine Hilfe, Manuela. – Ich werde jetzt wohl klarkommen.

Gruß,
--ingmar
Titel: Antw:Ambitus feststellen?
Beitrag von: harm6 am Sonntag, 3. Mai 2026, 12:25
Hallo zusammen,

ich habe mir mal ein paar Gedanken gemacht. Nicht verstanden habe ich allerdings warum der übliche Ambitus nicht hinreichend ist.
Seis drum...
Gesucht habe ich eine Möglichkeit beim Aufruf der Funktion mit LilyPond Syntax das Ergebnis als Akkord, sequentielle bzw simultane Musik darzustellen. Sowie eine simple Methode nur den höchsten oder tiefsten Ton darzustellen.

Hier das Ergebnis:
\version "2.26.0"

#(define (make-note-event pitch duration)
  "Takes PITCH and DURATION and returns a NoteEvent."
  (make-music
   'NoteEvent
   'duration duration
   'pitch pitch))
 
#(define (bottom-top-notes music duration)
  "Takes MUSIC and returns lowest and highest note each with duration DURATION
as a plain list."
  (let* ((all-pitches (music-pitches music))
         (sorted-pitches (sort all-pitches ly:pitch<?)))
    (map
      (lambda (pitch) (make-note-event pitch duration))
      (list (car sorted-pitches) (last sorted-pitches)))))

extrema =
#(define-music-function (proc m music duration)
  ((procedure? identity) ly:music? ly:music? ly:duration?)
"Takes MUSIC and returns sequential music, simultaneous music or an event-chord
with duration DURATION, relying on the type M provides.
The optional PROC, supposed to be @code{first} or @code{last}, may be used to
get the bottom or top note only."
  (ly:music-set-property! m 'elements
    (ensure-list (proc (bottom-top-notes music duration))))
  m)
   
%%%%%%%%%%%%
%% EXAMPLES
%%%%%%%%%%%%

testMus = \relative { d' e fis g a b cis }
 
{ \extrema {} \testMus 4 }
%% Below, preceed with \new Staff to avoid implicit creation of two staves
{ \extrema <<>> \testMus 4 }
{ \extrema <> \testMus 4 }

%% Get only bottom or top note
{ \extrema #first {} \testMus 4 }
{ \extrema #last {} \testMus 4 }

Manuelas 'alle-pitches' ist im wesentlichen dasselbe wie das builtin 'music-pitches'. Lediglich ein reverse! in 'music-pitches' ist in unserem Fall überflüssig. Ich halte diesen hier unnötigen Schritt aber nicht für performance-kritisch.
'bottom-top-notes' gibt nur eine Liste von Noten zurück keine fertige Musik. Das hat den Vorteil, dass die Musikfunktion 'extrema', je nach Eingabe ({} oder <<>> oder <>) entscheidet was tatsächlich erscheint.
Ein optionales Argument dient der Möglichkeit nur den höchsten oder tiefsten Ton darzustellen.

HTH,
  Harm
Titel: Antw:Ambitus feststellen? [gelöst]
Beitrag von: Manuela am Sonntag, 3. Mai 2026, 12:55
Danke, Harm.

Unsereins ist schon froh, wenn er es überhaupt hinkriegt, auch wenn es umständlicher ist als nötig.  ;)
Titel: re: Ambitus feststellen?
Beitrag von: ingmar am Sonntag, 3. Mai 2026, 13:34
Zitat von: harm6 am Sonntag,  3. Mai 2026, 12:25Nicht verstanden habe ich allerdings warum der übliche Ambitus nicht hinreichend ist.

Weil er Analyse und Darstellung des Ergebnisses nicht trennt. (Ich hatte dazu hier (https://lilypondforum.de/index.php/topic,1591.msg7676.html#msg7676) schon was geschrieben..)

Ich schreibe sehr viel Noten, und manchmal taucht tatsächlich die Frage nach Tonumfängen der Einzelstimmen auf. Aber meine Frage lautet dann selten: "Welchen Tonumfang hat die vierte Stimme in diesem Stück?" Sie lautet häufiger: "Was sind die Tonumfänge der vierten Stimmen aller Einzelsätze in diesem File?" (und in Zukunft vielleicht auch mal "... in diesem Ordner?"). Dazu muss ich dann die Ergebnisse der Einzelanalysen jeder Stimme nicht in diese hineinschreiben, sondern sie irgendwie sammeln und gesondert auflisten.

Danke fürs Interesse!
--ingmar
Titel: re: Ambitus feststellen? [gelöst]
Beitrag von: ingmar am Dienstag, 5. Mai 2026, 20:19
Hab mir inzwischen deine elegante Lösung angeschaut, harm – auch dafür vielen Dank!

Da ich noch mit einer veralterten LilyPond-Version arbeite, die ensure-list noch nicht kennt, werde ich temporär erstmal noch mit Manuelas Ansatz weiterarbeiten, der ja auch funktioniert; das werde ich dann aber später nachziehen.

Nochmal euch beiden herzlichen Dank für Eure Zeit! – Gruß, --ingmar

Titel: Antw:Ambitus feststellen? [gelöst]
Beitrag von: harm6 am Dienstag, 5. Mai 2026, 21:46
Ich würde die Definition einfach dazu packen:
#(define-public (ensure-list item-or-list-of-items)
  "Ensure the argument is a list. If it is not put it in one."
  (if (list? item-or-list-of-items)
      item-or-list-of-items
      (list item-or-list-of-items)))

Gruß,
  Harm
Titel: Antw:Ambitus feststellen? [gelöst]
Beitrag von: harm6 am Dienstag, 5. Mai 2026, 21:49
Zitat von: Manuela am Sonntag,  3. Mai 2026, 12:55Unsereins ist schon froh, wenn er es überhaupt hinkriegt, auch wenn es umständlicher ist als nötig.  ;)

Hallo Manuela,

stell dein Licht nicht unter den Scheffel!
Dein Code hat gemacht was er sollte und das Problem ebenfalls gelöst.

Gruß,
  Harm
Titel: Antw:Ambitus feststellen? [gelöst]
Beitrag von: harm6 am Dienstag, 5. Mai 2026, 21:55
Zitat von: ingmar am Sonntag,  3. Mai 2026, 13:34
Zitat von: harm6 am Sonntag,  3. Mai 2026, 12:25Nicht verstanden habe ich allerdings warum der übliche Ambitus nicht hinreichend ist.

Weil er Analyse und Darstellung des Ergebnisses nicht trennt. (Ich hatte dazu hier (https://lilypondforum.de/index.php/topic,1591.msg7676.html#msg7676) schon was geschrieben..)

Ich schreibe sehr viel Noten, und manchmal taucht tatsächlich die Frage nach Tonumfängen der Einzelstimmen auf. Aber meine Frage lautet dann selten: "Welchen Tonumfang hat die vierte Stimme in diesem Stück?" Sie lautet häufiger: "Was sind die Tonumfänge der vierten Stimmen aller Einzelsätze in diesem File?" (und in Zukunft vielleicht auch mal "... in diesem Ordner?"). Dazu muss ich dann die Ergebnisse der Einzelanalysen jeder Stimme nicht in diese hineinschreiben, sondern sie irgendwie sammeln und gesondert auflisten.

Danke fürs Interesse!
--ingmar


Ich hatte deinen verlinkten post früher schon gelesen, aber nicht recht verstanden. Ich hoffe das jetzt erreicht zu haben.

Mir will scheinen, das du eigentlich gar nichts gegen den Ambitus hast, so wie er momentan implementiert ist. Aber du wünschst dir eine ähnlich gelagerte Funktionalität mit anderem/breiteren Anwendungsmöglichkeiten.

Wenn wir das weiter diskutieren wollen sollten wir aber einen neuen thread aufmachen...

Gruß,
  Harm