Deutschsprachiges LilyPond-Forum

Allgemeine Fragen und Probleme => Fragen und Probleme aller Art => Thema gestartet von: Manuela am Sonntag, 9. April 2023, 08:42

Titel: Einzelne Abschnitte aus Musikausdrücken extrahieren
Beitrag von: Manuela am Sonntag, 9. April 2023, 08:42
Nach wochenlangem Suchen habe ich folgendes im LSR gefunden: Extracting unmodified fragments of a music expression (https://lsr.di.unimi.it/LSR/Item?id=542)

Ein geniales Stück Code, sowas hätte ich nie im Ansatz zusammengebracht.
Leider übernimmt es die Notenschlüssel nicht, wenn man nicht beim ersten Takt beginnt.
\version "2.23.5"

%% http://lsr.di.unimi.it/LSR/Item?id=542

#(use-modules (srfi srfi-39))

#(define *current-moment* (make-parameter (ly:make-moment 0/1 0/1)))

#(define moment-null (ly:make-moment 0/1 0/1))

#(define (music-has-no-length? music)
  "Is music empty of notes, rests or skips?"
  (equal? (ly:music-length music) moment-null))

#(define (simultaneous? music)
  (memq (ly:music-property music 'name)
    (list 'SimultaneousMusic 'EventChord)))

#(define (defined-music? music)
  (not (eq? 'Music (ly:music-property music 'name))))

#(define (chord-event? music)
  (eq? 'EventChord (ly:music-property music 'name)))

#(define (get-duration music)
  (ly:music-property music 'duration))

#(define (moment>=? momentA momentB)
  (not (ly:moment<? momentA momentB)))

#(define (moment-inside? moment from-moment to-moment)
  (and
    (moment>=? moment from-moment)
    (ly:moment<? moment to-moment)))

#(define (whole-music-inside? begin-music end-music left-range right-range)
  (and
    (moment>=? begin-music left-range)
    (moment>=? right-range end-music )
    (not (equal? begin-music right-range))))

#(define (whole-music-outside? begin-music end-music left-range right-range)
  (or
    (moment>=? left-range end-music)
    (moment>=? begin-music right-range)))

#(define (moment->duration moment)
  ;see duration.cc in Lilypond sources (Duration::Duration)
  (let* ((p (ly:moment-main-numerator moment))
         (q (ly:moment-main-denominator moment))
         (k (- (ly:intlog2 q) (ly:intlog2 p)))
         (dots 0))
   ;(ash p k) = p * 2^k
   (if (< (ash p k) q) (set! k (1+ k)))
   (set! p (- (ash p k) q))
   (while (begin (set! p (ash p 1))(>= p q))
    (set! p (- p q))
    (set! dots (1+ dots)))
   (if (> k 6)
    (ly:make-duration 6 0)
    (ly:make-duration k dots))
))

#(define (extract-music music from to)
  "Keeps only music between `from' and `to', `from' and `to' as moment"
  (let ((begin-pos (*current-moment*))
        (end-pos (ly:moment-add
                   (*current-moment*)
                   (ly:music-length music))))
   (cond
    ((whole-music-inside? begin-pos end-pos from to)
      (*current-moment* end-pos)
      music)
    ((whole-music-outside? begin-pos end-pos from to)
      (*current-moment* end-pos)
      (make-music 'Music))
    ; the intervals [begin-pos end-pos] [from to] overlap
    (else
    (cond
    ; inside a chords or for multiRest events
    ((ly:duration? (get-duration music))
      (if (moment-inside? begin-pos from to)
        (set! end-pos to)
        (begin
          (set! begin-pos from)
          (if (not (moment-inside? end-pos from to))(set! end-pos to))))
      (ly:music-set-property! music 'duration
          (moment->duration  (ly:moment-sub end-pos begin-pos)))
      (*current-moment* end-pos)
      music)
    (else     ; for containers of chords
      (let ((elts (ly:music-property music 'elements))
          (elt  (ly:music-property music 'element)))
        (if (ly:music? elt)
        (ly:music-set-property! music 'element (extract-music elt from to)))
        (if (pair? elts)
        (cond
          ((simultaneous? music)    ; simultaneous music OR EventChords
          (ly:music-set-property! music 'elements (filter
            (lambda (evt)
              (or (music-has-no-length? evt) ; i.e for 'VoiceSeparator
                (begin
                  (*current-moment* begin-pos)  ; restore *current-moment*
                  (set! evt (extract-music evt from to))
                  (defined-music? evt)))) ; keeps if not (make-music 'Music)
            elts))
          (*current-moment* end-pos))
         (else              ; sequential music
          (ly:music-set-property! music 'elements (filter
            (lambda (evt)
              (set! evt (extract-music evt from to))
              (defined-music? evt))
            elts)))))
        music)))))))

%%%%%%%%%%%%%%%%%%%%%% the main function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
extractMusic =
#(define-music-function (music from during) (ly:music? ly:music? ly:music?)
  (let* ((from-length (ly:music-length from))
         (during-length (ly:music-length during))
         (to-length (ly:moment-add during-length from-length)))
    (parameterize ((*current-moment* (ly:make-moment 0/1 0/1)))
                  (extract-music music from-length to-length))))
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

mus = \relative { c4 c c c d2 d e1 f8 f f f f f f f }
muso = { \clef treble \transpose c c' \mus }
musu = { \clef bass \mus }

music = \new PianoStaff <<
  \new Staff \new Voice \muso
  \new Staff \new Voice \musu
>>
\extractMusic \music  {} s1*2
\extractMusic \music s1 s1*2

Kann man da etwas dagegen tun? Wenn ja, was?
Titel: Antw:Einzelne Abschnitte aus Musikausdrücken extrahieren
Beitrag von: juergen74 am Dienstag, 18. April 2023, 11:16
Hallo Manuela,

im einfachsten Fall kann man Musik vom Typ "ContextSpeccedMusic" im Moment 0 "behalten"; siehe Ergänzung im Code ab Zeile 76:
\version "2.24.0"

%% http://lsr.di.unimi.it/LSR/Item?id=542

#(use-modules (srfi srfi-39))

#(define *current-moment* (make-parameter (ly:make-moment 0/1 0/1)))

#(define moment-null (ly:make-moment 0/1 0/1))

#(define (music-has-no-length? music)
   "Is music empty of notes, rests or skips?"
   (equal? (ly:music-length music) moment-null))

#(define (simultaneous? music)
   (memq (ly:music-property music 'name)
     (list 'SimultaneousMusic 'EventChord)))

#(define (defined-music? music)
   (not (eq? 'Music (ly:music-property music 'name))))

#(define (chord-event? music)
   (eq? 'EventChord (ly:music-property music 'name)))

#(define (get-duration music)
   (ly:music-property music 'duration))

#(define (moment>=? momentA momentB)
   (not (ly:moment<? momentA momentB)))

#(define (moment-inside? moment from-moment to-moment)
   (and
    (moment>=? moment from-moment)
    (ly:moment<? moment to-moment)))

#(define (whole-music-inside? begin-music end-music left-range right-range)
   (and
    (moment>=? begin-music left-range)
    (moment>=? right-range end-music )
    (not (equal? begin-music right-range))))

#(define (whole-music-outside? begin-music end-music left-range right-range)
   (or
    (moment>=? left-range end-music)
    (moment>=? begin-music right-range)))

#(define (moment->duration moment)
   ;see duration.cc in Lilypond sources (Duration::Duration)
   (let* ((p (ly:moment-main-numerator moment))
          (q (ly:moment-main-denominator moment))
          (k (- (ly:intlog2 q) (ly:intlog2 p)))
          (dots 0))
     ;(ash p k) = p * 2^k
     (if (< (ash p k) q) (set! k (1+ k)))
     (set! p (- (ash p k) q))
     (while (begin (set! p (ash p 1))(>= p q))
       (set! p (- p q))
       (set! dots (1+ dots)))
     (if (> k 6)
         (ly:make-duration 6 0)
         (ly:make-duration k dots))
     ))

#(define (extract-music music from to)
   "Keeps only music between `from' and `to', `from' and `to' as moment"
   (let ((begin-pos (*current-moment*))
         (end-pos (ly:moment-add
                   (*current-moment*)
                   (ly:music-length music))))
     (cond
      ((whole-music-inside? begin-pos end-pos from to)
       (*current-moment* end-pos)
       music)
      ((whole-music-outside? begin-pos end-pos from to)
       (*current-moment* end-pos)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
       ; always add ContextSpeccedMusic at moment 0
       (if (and (equal? begin-pos (ly:make-moment 0/1 0/1))
                (eq?  'ContextSpeccedMusic (ly:music-property music 'name)))
           music
           (make-music 'Music)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

      ; the intervals [begin-pos end-pos] [from to] overlap
      (else
       (cond
        ; inside a chords or for multiRest events
        ((ly:duration? (get-duration music))
         (if (moment-inside? begin-pos from to)
             (set! end-pos to)
             (begin
              (set! begin-pos from)
              (if (not (moment-inside? end-pos from to))(set! end-pos to))))
         (ly:music-set-property! music 'duration
           (moment->duration  (ly:moment-sub end-pos begin-pos)))
         (*current-moment* end-pos)
         music)
        (else     ; for containers of chords
          (let ((elts (ly:music-property music 'elements))
                (elt  (ly:music-property music 'element)))
            (if (ly:music? elt)
                (ly:music-set-property! music 'element (extract-music elt from to)))
            (if (pair? elts)
                (cond
                 ((simultaneous? music)    ; simultaneous music OR EventChords
                   (ly:music-set-property! music 'elements (filter
                                                            (lambda (evt)
                                                              (or (music-has-no-length? evt) ; i.e for 'VoiceSeparator
                                                                  (begin
                                                                   (*current-moment* begin-pos)  ; restore *current-moment*
                                                                   (set! evt (extract-music evt from to))
                                                                   (defined-music? evt)))) ; keeps if not (make-music 'Music)
                                                            elts))
                   (*current-moment* end-pos))
                 (else              ; sequential music
                   (ly:music-set-property! music 'elements (filter
                                                            (lambda (evt)
                                                              (set! evt (extract-music evt from to))
                                                              (defined-music? evt))
                                                            elts)))))
            music)))))))

%%%%%%%%%%%%%%%%%%%%%% the main function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
extractMusic =
#(define-music-function (music from during) (ly:music? ly:music? ly:music?)
   (let* ((from-length (ly:music-length from))
          (during-length (ly:music-length during))
          (to-length (ly:moment-add during-length from-length)))
     (parameterize ((*current-moment* (ly:make-moment 0/1 0/1)))
       (extract-music music from-length to-length))))
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

mus = \relative { c4 c c c d2 d e1 f8 f f f f f f f }
muso = { \clef treble \transpose c c' \mus }
musu = { \clef bass \mus }

music = \new PianoStaff <<
  \new Staff \new Voice \muso
  \new Staff \new Voice \musu
>>
\extractMusic \music  {} s1*2
\extractMusic \music s1 s1*2

Sinnvollerweise sollte man wohl noch untersuchen, was in ContextSpeccedMusic denn genau drin steht.
Und um alle denkbaren Variationen abzufangen (z.B. Änderung des Notenschlüssels mittendrin), müsste der Code unter "(whole-music-outside? begin-pos end-pos from to)" noch deutlich erweitert werden.



Grüße, Jürgen.
Titel: Antw:Einzelne Abschnitte aus Musikausdrücken extrahieren
Beitrag von: Manuela am Donnerstag, 27. April 2023, 14:59
Danke, das klappt. Für meine Zwecke ist das vollkommen ausreichend!
Titel: Antw:Einzelne Abschnitte aus Musikausdrücken extrahieren
Beitrag von: Manuela am Freitag, 28. April 2023, 16:38
Jetzt muss ich dich nochmals belästigen. Geht das für die Tonart auch? Ich kann nicht enträtseln, wie das gehen kann.
Titel: Antw:Einzelne Abschnitte aus Musikausdrücken extrahieren
Beitrag von: juergen74 am Freitag, 28. April 2023, 18:55
\version "2.24.0"

%% http://lsr.di.unimi.it/LSR/Item?id=542

#(use-modules (srfi srfi-39))

#(define *current-moment* (make-parameter (ly:make-moment 0/1 0/1)))

#(define moment-null (ly:make-moment 0/1 0/1))

#(define (music-has-no-length? music)
   "Is music empty of notes, rests or skips?"
   (equal? (ly:music-length music) moment-null))

#(define (simultaneous? music)
   (memq (ly:music-property music 'name)
     (list 'SimultaneousMusic 'EventChord)))

#(define (defined-music? music)
   (not (eq? 'Music (ly:music-property music 'name))))

#(define (chord-event? music)
   (eq? 'EventChord (ly:music-property music 'name)))

#(define (get-duration music)
   (ly:music-property music 'duration))

#(define (moment>=? momentA momentB)
   (not (ly:moment<? momentA momentB)))

#(define (moment-inside? moment from-moment to-moment)
   (and
    (moment>=? moment from-moment)
    (ly:moment<? moment to-moment)))

#(define (whole-music-inside? begin-music end-music left-range right-range)
   (and
    (moment>=? begin-music left-range)
    (moment>=? right-range end-music )
    (not (equal? begin-music right-range))))

#(define (whole-music-outside? begin-music end-music left-range right-range)
   (or
    (moment>=? left-range end-music)
    (moment>=? begin-music right-range)))

#(define (moment->duration moment)
   ;see duration.cc in Lilypond sources (Duration::Duration)
   (let* ((p (ly:moment-main-numerator moment))
          (q (ly:moment-main-denominator moment))
          (k (- (ly:intlog2 q) (ly:intlog2 p)))
          (dots 0))
     ;(ash p k) = p * 2^k
     (if (< (ash p k) q) (set! k (1+ k)))
     (set! p (- (ash p k) q))
     (while (begin (set! p (ash p 1))(>= p q))
       (set! p (- p q))
       (set! dots (1+ dots)))
     (if (> k 6)
         (ly:make-duration 6 0)
         (ly:make-duration k dots))
     ))

#(define (extract-music music from to)
   "Keeps only music between `from' and `to', `from' and `to' as moment"
   (let ((begin-pos (*current-moment*))
         (end-pos (ly:moment-add
                   (*current-moment*)
                   (ly:music-length music))))
     (cond
      ((whole-music-inside? begin-pos end-pos from to)
       (*current-moment* end-pos)
       music)
      ((whole-music-outside? begin-pos end-pos from to)
       (*current-moment* end-pos)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
       ; uncomment for analysis
       ; (ly:message "Music name: ~a" (ly:music-property music 'name))
       ; (display-scheme-music music)
       
       ; always keep ContextSpeccedMusic at moment 0
       (if (and (equal? begin-pos (ly:make-moment 0/1 0/1))
                (eq?  'ContextSpeccedMusic (ly:music-property music 'name)))
           music
           ; always keep KeyChangeEvent at moment 0
           (if (and (equal? begin-pos (ly:make-moment 0/1 0/1))
                    (eq?  'KeyChangeEvent (ly:music-property music 'name)))
               music
               (make-music 'Music))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

      ; the intervals [begin-pos end-pos] [from to] overlap
      (else
       (cond
        ; inside a chords or for multiRest events
        ((ly:duration? (get-duration music))
         (if (moment-inside? begin-pos from to)
             (set! end-pos to)
             (begin
              (set! begin-pos from)
              (if (not (moment-inside? end-pos from to))(set! end-pos to))))
         (ly:music-set-property! music 'duration
           (moment->duration  (ly:moment-sub end-pos begin-pos)))
         (*current-moment* end-pos)
         music)
        (else     ; for containers of chords
          (let ((elts (ly:music-property music 'elements))
                (elt  (ly:music-property music 'element)))
            (if (ly:music? elt)
                (ly:music-set-property! music 'element (extract-music elt from to)))
            (if (pair? elts)
                (cond
                 ((simultaneous? music)    ; simultaneous music OR EventChords
                   (ly:music-set-property! music 'elements (filter
                                                            (lambda (evt)
                                                              (or (music-has-no-length? evt) ; i.e for 'VoiceSeparator
                                                                  (begin
                                                                   (*current-moment* begin-pos)  ; restore *current-moment*
                                                                   (set! evt (extract-music evt from to))
                                                                   (defined-music? evt)))) ; keeps if not (make-music 'Music)
                                                            elts))
                   (*current-moment* end-pos))
                 (else              ; sequential music
                   (ly:music-set-property! music 'elements (filter
                                                            (lambda (evt)
                                                              (set! evt (extract-music evt from to))
                                                              (defined-music? evt))
                                                            elts)))))
            music)))))))

%%%%%%%%%%%%%%%%%%%%%% the main function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
extractMusic =
#(define-music-function (music from during) (ly:music? ly:music? ly:music?)
   (let* ((from-length (ly:music-length from))
          (during-length (ly:music-length during))
          (to-length (ly:moment-add during-length from-length)))
     (parameterize ((*current-moment* (ly:make-moment 0/1 0/1)))
       (extract-music music from-length to-length))))
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

mus = \relative { \key g \major c4 c c c d2 d e1 f8 f f f f f f f }
muso = { \clef treble \transpose c c' \mus }
musu = { \clef bass \mus }

music = \new PianoStaff <<
  \new Staff \new Voice \muso
  \new Staff \new Voice \musu
>>
\extractMusic \music  {} s1*2
\extractMusic \music s1 s1*2

Nochmal hart codiert, nicht schön...

Wie wäre es mit einem (optionalen?) Parameter, mit dem man festlegen kann, welche Music-Expressions immer behalten werden sollen, unabhängig der Parameter "from" und "to"?

Grüße, Jürgen.
Titel: Antw:Einzelne Abschnitte aus Musikausdrücken extrahieren
Beitrag von: juergen74 am Freitag, 28. April 2023, 19:00
Zitat von: Manuela am Freitag, 28. April 2023, 16:38[...] Ich kann nicht enträtseln, wie das gehen kann.

siehe

       ; uncomment for analysis
       ; (ly:message "Music name: ~a" (ly:music-property music 'name))
       ; (display-scheme-music music)

Anders kann ich das auch nicht...  ;)

Grüße, Jürgen.
Titel: Antw:Einzelne Abschnitte aus Musikausdrücken extrahieren
Beitrag von: Manuela am Freitag, 28. April 2023, 21:57
Danke, das klappt wunderbar.

Schön langsam kapiere ich auch das System dahinter.

BTW, optionale Parameter bei scheme-music-function sind nicht möglich AFAIK