Auto-panner
I was so excited by \set Score.midiPanPosition that I was inspired to write a function in Scheme that spreads the voices evenly from left to right. It can’t look ahead to find the number of voices or staves, that needs to be specified at the start or before a new \score definition: \version 2.18.0 \include autopan.ly \SetTotalAutopanStaves #4 myMusic = \relative c' { \time 4/4 c4 d e f g1 } \score { \new Staff { \autopan \transpose c bes \myMusic } \new Staff { \autopan \transpose c g \myMusic } \new Staff { \autopan \transpose c e \myMusic } \new Staff { \autopan \transpose c c \myMusic } \layout {} \midi {} } %% Because I’m lazy, I’d love to include the \autopan command in \global, but it looks like when \global is evaluated, the function is evaluated and its return value is permanently made part of \global, which means everything is panned to the far left. Is there a way to make the function run every time \global appears? Vaughan autopan.ly Description: Binary data ___ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user
Re: Auto-panner
Hi Vaughan, if global is a music-function calling autopan, it will evaluate it everytime. If global is a variable, its value is set, once it is assigned. So if you have to wrap it in music-function. If you always have a variable global containing all you need, you can wrap that in a function: music = { c'' } global = { \time 4/4 } % another name than global! meta = #(define-music-function (parser location)() #{ \autopan \global #}) \new Staff \meta \music global is only a function, if it is declared one. Otherwise it is just a variable. BTW, nice autopan utility ;) HTH, Jan-Peter Am 27.01.2014 13:54, schrieb Vaughan McAlley: Because I’m lazy, I’d love to include the \autopan command in \global, but it looks like when \global is evaluated, the function is evaluated and its return value is permanently made part of \global, which means everything is panned to the far left. Is there a way to make the function run every time \global appears? ___ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user
Re: Auto-panner
Jan-Peter Voigt jp.vo...@gmx.de writes: Hi Vaughan, if global is a music-function calling autopan, it will evaluate it everytime. If global is a variable, its value is set, once it is assigned. So if you have to wrap it in music-function. If you always have a variable global containing all you need, you can wrap that in a function: I'd recommend putting this into an \applyContext call. That way, you get a call for each use in a different context. -- David Kastrup ___ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user
Re: Auto-panner
Thanks, David. @Vaughan For a short test ... this compiles, but I can't listen to the resulting pan in midi I changed the PropertySet to ApplyContext with a lambda. This should work in variables, as it returns an applyContext expression. As with the previous solution, you have to care about the order autopan is called. It might be a good idea to either use a performer (engraver in midi context) and/or to track context id's, so that each context is counted once. HTH, Jan-Peter On 27.01.2014 15:15, David Kastrup wrote: Jan-Peter Voigt jp.vo...@gmx.de writes: Hi Vaughan, if global is a music-function calling autopan, it will evaluate it everytime. If global is a variable, its value is set, once it is assigned. So if you have to wrap it in music-function. If you always have a variable global containing all you need, you can wrap that in a function: I'd recommend putting this into an \applyContext call. That way, you get a call for each use in a different context. \version 2.18.0 %%% %{ Auto panner Spreads voices evenly from -1 (LEFT) to 1 (RIGHT) Usage: \include autopanner.ly \SetTotalAutopanStaves #2 % or \SetTotalAutopanVoices \score { \new Staff \set Staff.midiInstrument = #violin \autopan { ... music here } \new Staff \set Staff.midiInstrument = #cello \autopan { ... music here } } %} %%% #(define autopan-total-voices 2.0) #(define autopan-current-voice -1.0) #(define autopan-staff-or-voice 'Staff) ResetAutoPanning = #(define-void-function (parser location) () (set! autopan-current-voice -1.0) ) SetTotalAutopanVoices = #(define-void-function (parser location total-voices) (number?) (begin (set! autopan-total-voices total-voices) (set! autopan-current-voice -1.0) (set! autopan-staff-or-voice 'Voice) ) ) SetTotalAutopanStaves = #(define-void-function (parser location total-voices) (number?) (begin (set! autopan-total-voices total-voices) (set! autopan-current-voice -1.0) (set! autopan-staff-or-voice 'Staff) ) ) autopan = #(define-scheme-function (parser location)() (begin (set! autopan-current-voice (+ autopan-current-voice 1.0)) (make-music 'ApplyContext 'procedure (lambda (context) (let ((ctx (ly:context-find context autopan-staff-or-voice))) (if (not (ly:context? ctx)) (set! ctx context)) ;(ly:message context ~A ctx) (ly:context-set-property! ctx 'midiPanPosition (+ -1.0 (* autopan-current-voice (/ 2.0 (- autopan-total-voices 1.0) ) ) ))) )) )) ___ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user
Re: Auto-panner
Jan-Peter Voigt jp.vo...@gmx.de writes: Thanks, David. @Vaughan For a short test ... this compiles, but I can't listen to the resulting pan in midi \version 2.18.0 %%% %{ Auto panner Spreads voices evenly from -1 (LEFT) to 1 (RIGHT) Usage: \include autopanner.ly \SetTotalAutopanStaves #2 % or \SetTotalAutopanVoices [...] #(define autopan-total-voices 2.0) #(define autopan-current-voice -1.0) #(define autopan-staff-or-voice 'Staff) ResetAutoPanning = #(define-void-function (parser location) () (set! autopan-current-voice -1.0) ) SetTotalAutopanVoices = #(define-void-function (parser location total-voices) (number?) (begin (set! autopan-total-voices total-voices) (set! autopan-current-voice -1.0) (set! autopan-staff-or-voice 'Voice) ) ) [...] autopan = #(define-scheme-function (parser location)() Why define-scheme-function when returning music? (begin (set! autopan-current-voice (+ autopan-current-voice 1.0)) (make-music 'ApplyContext 'procedure (lambda (context) (let ((ctx (ly:context-find context autopan-staff-or-voice))) (if (not (ly:context? ctx)) (set! ctx context)) ;(ly:message context ~A ctx) (ly:context-set-property! ctx 'midiPanPosition (+ -1.0 (* autopan-current-voice (/ 2.0 (- autopan-total-voices 1.0) Doesn't work. At the time the function gets called, _all_ instances of the function get to see the same value of autopan-current-voice. If you want to keep tabs on your current voice, you need to use a score-level context property. -- David Kastrup ___ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user
Re: Auto-panner
On 27.01.2014 16:54, David Kastrup wrote: autopan = #(define-scheme-function (parser location)() Why define-scheme-function when returning music? Perhaps this function had another meaning in the first place? I overlooked this, when injecting my ApplyContext lines. (begin (set! autopan-current-voice (+ autopan-current-voice 1.0)) (make-music 'ApplyContext 'procedure (lambda (context) (let ((ctx (ly:context-find context autopan-staff-or-voice))) (if (not (ly:context? ctx)) (set! ctx context)) ;(ly:message context ~A ctx) (ly:context-set-property! ctx 'midiPanPosition (+ -1.0 (* autopan-current-voice (/ 2.0 (- autopan-total-voices 1.0) Doesn't work. At the time the function gets called, _all_ instances of the function get to see the same value of autopan-current-voice. Good point. Now all Voices turned to the right ;) If you want to keep tabs on your current voice, you need to use a score-level context property. What about a closure? %% autopan = #(define-music-function (parser location)() (let ((mypan (+ autopan-current-voice 1.0))) (set! autopan-current-voice mypan) (make-music 'ApplyContext 'procedure (lambda (context) (let ((ctx (ly:context-find context autopan-staff-or-voice))) (if (not (ly:context? ctx)) (set! ctx context)) (ly:message context ~A pan ~A ctx mypan) (ly:context-set-property! ctx 'midiPanPosition (+ -1.0 (* mypan (/ 2.0 (- autopan-total-voices 1.0) ) ) ))) )) )) %% At least now every Staff gets its own midiPanPosition. I like the idea of auto-stereo-spreading midi channels. Now it should also work, if autopan is used inside a global variable. Still, I'd recommend usage of either a global context property or a performer/engraver that keeps track of all contexts using autopan. Perhaps it is possible to count all contexts joining autopan automatically. But thats out of scope for me right now ;) (i might come back later on this topic) Best, Jan-Peter ___ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user
Re: Auto-panner
Jan-Peter Voigt jp.vo...@gmx.de writes: On 27.01.2014 16:54, David Kastrup wrote: autopan = #(define-scheme-function (parser location)() Why define-scheme-function when returning music? Perhaps this function had another meaning in the first place? I overlooked this, when injecting my ApplyContext lines. (begin (set! autopan-current-voice (+ autopan-current-voice 1.0)) (make-music 'ApplyContext 'procedure (lambda (context) (let ((ctx (ly:context-find context autopan-staff-or-voice))) (if (not (ly:context? ctx)) (set! ctx context)) ;(ly:message context ~A ctx) (ly:context-set-property! ctx 'midiPanPosition (+ -1.0 (* autopan-current-voice (/ 2.0 (- autopan-total-voices 1.0) Doesn't work. At the time the function gets called, _all_ instances of the function get to see the same value of autopan-current-voice. Good point. Now all Voices turned to the right ;) If you want to keep tabs on your current voice, you need to use a score-level context property. What about a closure? Won't be able to distinguish being called another time from the same output (\layout, \midi, \musicxml (this one's hypothetical yet), \addQuote...) or the next one. -- David Kastrup ___ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user
Re: Auto-panner
On 27.01.2014 20:51, David Kastrup wrote: What about a closure? Won't be able to distinguish being called another time from the same output (\layout, \midi, \musicxml (this one's hypothetical yet), \addQuote...) or the next one. of course not ... I see Vaughans idea as a first draft ... and now he's able to use it in a global variable. At least the example, he provided, should work this way. But for a more robust implementation, there need to be score-level context-properties - perhaps an engraver. We'll see later ;) Cheers, Jan-Peter ___ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user
Re: Auto-panner
On 28 January 2014 07:07, Jan-Peter Voigt jp.vo...@gmx.de wrote: On 27.01.2014 20:51, David Kastrup wrote: What about a closure? Won't be able to distinguish being called another time from the same output (\layout, \midi, \musicxml (this one's hypothetical yet), \addQuote...) or the next one. of course not ... I see Vaughans idea as a first draft ... and now he's able to use it in a global variable. Thanks Jan-Peter David. Yes, what I submitted above was very much a draft, as I had got as far as I could by myself. I suspected I would learn more than just how to put it in \global, for example: Why define-scheme-function when returning music? Perhaps this function had another meaning in the first place? Yes, that. Plus me being a complete Guile-noob :-) I’m getting a much better idea of how Lilypond code interacts with Scheme now. So even though music is a Scheme value, define-music-function is optimized for returning music and would work better in corner cases? But for a more robust implementation, there need to be score-level context-properties - perhaps an engraver. We'll see later ;) 90% of the music I work with is one staff to a part, eg renaissance choir music or chamber music, so personally I don’t need much robustness. For listening to renaissance music I set all voices to clarinet (artificial, not sampled) with the panning spread. It lets me hear all the parts and identify which part a problem might be in. Thanks again, Vaughan ___ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user