k-l-lambda's picture
added node-addon-lilypond
f65fe85
;;;; This file is part of LilyPond, the GNU music typesetter.
;;;;
;;;; Copyright (C) 1998--2020 Han-Wen Nienhuys <[email protected]>
;;;; Jan Nieuwenhuizen <[email protected]>
;;;; Neil Puttock <[email protected]>
;;;; Carl Sorensen <[email protected]>
;;;;
;;;; LilyPond is free software: you can redistribute it and/or modify
;;;; it under the terms of the GNU General Public License as published by
;;;; the Free Software Foundation, either version 3 of the License, or
;;;; (at your option) any later version.
;;;;
;;;; LilyPond is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
;; TODO: should link back into user manual.
(define (mm-rest-child-list music)
"Generate events for multimeasure rests,
to be used by the sequential-iterator"
(ly:set-origin! (list (make-music 'BarCheck)
(make-music 'MultiMeasureRestEvent
(ly:music-deep-copy music))
(make-music 'BarCheck))
music))
(define (make-unfolded-set music)
(let ((n (ly:music-property music 'repeat-count))
(alts (ly:music-property music 'elements))
(body (ly:music-property music 'element)))
(cond ((<= n 0) '())
((null? alts) (make-list n body))
(else
(concatenate
(zip (make-list n body)
(append! (make-list (max 0 (- n (length alts)))
(car alts))
alts)))))))
(define (make-volta-set music)
(let* ((alts (ly:music-property music 'elements))
(lalts (length alts))
(times (ly:music-property music 'repeat-count)))
(map (lambda (x y)
(make-music
'SequentialMusic
'elements
;; set properties for proper bar numbering
(append
(list (make-music 'AlternativeEvent
'alternative-dir (if (= y 0)
-1
0)
'alternative-increment
(if (= 0 y)
(1+ (- times
lalts))
1)))
(list x)
(if (= y (1- lalts))
(list (make-music 'AlternativeEvent
'alternative-dir 1
'alternative-increment 0))
'()))))
alts
(iota lalts))))
(define (make-ottava-set music)
"Set context properties for an ottava bracket."
(let ((octavation (ly:music-property music 'ottava-number)))
(list (context-spec-music
(make-apply-context
(lambda (context)
(let* ((offset (* -7 octavation))
(markups (ly:context-property context 'ottavationMarkups))
(ottavation-markup (assoc-get octavation markups)))
(set! (ly:context-property context 'middleCOffset) offset)
(set! (ly:context-property context 'ottavation) ottavation-markup)
(if (and (not (zero? octavation))
(not (markup? ottavation-markup)))
(ly:warning "Could not find ottavation markup for ~a octaves up." octavation))
(ly:set-middle-C! context))))
'Staff))))
(define (make-time-signature-set music)
"Set context properties for a time signature."
(let* ((num (ly:music-property music 'numerator))
(den (ly:music-property music 'denominator))
(structure (ly:music-property music 'beat-structure))
(fraction (cons num den)))
(list (context-spec-music
(make-apply-context
(lambda (context)
(let* ((time-signature-settings
(ly:context-property context 'timeSignatureSettings))
(my-base-length
(base-length fraction time-signature-settings))
(my-beat-structure
(if (null? structure)
(beat-structure my-base-length
fraction
time-signature-settings)
structure))
(beaming-exception
(beam-exceptions fraction time-signature-settings))
(new-measure-length (ly:make-moment num den)))
(ly:context-set-property!
context 'timeSignatureFraction fraction)
(ly:context-set-property!
context 'baseMoment (ly:make-moment my-base-length))
(ly:context-set-property!
context 'beatStructure my-beat-structure)
(ly:context-set-property!
context 'beamExceptions beaming-exception)
(ly:context-set-property!
context 'measureLength new-measure-length))))
'Timing)
;; (make-music 'TimeSignatureEvent music) would always
;; create a Bottom context. So instead, we just send the
;; event to whatever context may be currently active. If
;; that is not contained within an existing context with
;; TimeSignatureEngraver at the time \time is iterated, it
;; will drop through the floor which mostly means that
;; point&click and tweaks are not available for any time
;; signatures engraved due to the Timing property changes
;; but without a \time of its own. This is more a
;; "notification" rather than an "event" (which is always
;; sent to Bottom) but we don't currently have iterators for
;; that.
(descend-to-context
(make-apply-context
(lambda (context)
(ly:broadcast (ly:context-event-source context)
(ly:make-stream-event
(ly:make-event-class 'time-signature-event)
(ly:music-mutable-properties music)))))
'Score))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Some MIDI callbacks -- is this a good place for them?
(define-public (breathe::midi-length len context)
;;Shorten by half, or by up to a second, but always by a power of 2
(let* ((desired (min (ly:moment-main (seconds->moment 1 context))
(* (ly:moment-main len) 1/2)))
(scale (inexact->exact (ceiling (/ (log desired) (log 1/2)))))
(breath (ly:make-moment (expt 1/2 scale))))
(ly:moment-sub (ly:make-moment (ly:moment-main len)) breath)))