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?
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.
Danke, das klappt. Für meine Zwecke ist das vollkommen ausreichend!
Jetzt muss ich dich nochmals belästigen. Geht das für die Tonart auch? Ich kann nicht enträtseln, wie das gehen kann.
\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.
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.
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