Auto-panner

2014-01-27 Thread Vaughan McAlley
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

2014-01-27 Thread Jan-Peter Voigt
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

2014-01-27 Thread David Kastrup
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

2014-01-27 Thread Jan-Peter Voigt
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

2014-01-27 Thread David Kastrup
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

2014-01-27 Thread Jan-Peter Voigt
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

2014-01-27 Thread David Kastrup
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

2014-01-27 Thread Jan-Peter Voigt
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

2014-01-27 Thread Vaughan McAlley
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