Re: Scheme performers/translators

2021-09-30 Thread David Kastrup
Han-Wen Nienhuys  writes:

> On Thu, Sep 30, 2021 at 12:24 AM David Kastrup  wrote:
>>
>> Well, this is not as much supporting the MIDI layer as it is
>> employing the translator level for messing with music during
>> iteration.  It's sort of annoying that it doesn't work by default.
>
> It doesn't work by default because we never bothered to invest time in
> improving it.

You are changing the topic.  It's sort of annoying that employing the
translator level for messing with music during iteration doesn't work by
default since all that is required for that is not deleting the already
instantiated translator from the respective lists.

> It's not obvious to me that a principled approach to MIDI rendering
> would use a broadcast/acknowledge type architecture like the
> typography part does.

Not relevant at all to this patch.

-- 
David Kastrup



Re: Scheme performers/translators

2021-09-30 Thread Han-Wen Nienhuys
On Thu, Sep 30, 2021 at 12:24 AM David Kastrup  wrote:
>
> Aaron Hill  writes:
>
> > On 2021-09-29 12:39 pm, David Kastrup wrote:
> >> The question is whether we should do something like this as default,
> >> possibly conditioned on whether any acknowledgers are present?  Because
> >> even if we cannot react to Midi data structures (since they are not
> >> Scheme-accessible for now), sometimes a translator may be enough to do
> >> the trick.
> >
> > You say "for now" above, so is allowing Scheme to interact directly
> > with the MIDI stream something that is planned?
>
> I have no idea what you call "planned".  It is a deficiency that one
> cannot use LilyPond in anything but a hardwired manner for creating
> Midi.  That does not mean that I know this to be in anybody's personal
> work queue.  At the current point of time, the Midi data structures are
> not even in the Scheme memory management.  I think most of them just
> stick around without ever getting deleted.

Audio elements get deleted in Performance::~Performance, and I'd be
surprised if the MIDI stuff gets leaked. MIDI didn't show up the
memory leak hunt Jonas and I did about 9 months ago. File a bug if you
can repro a leak?

> > Between what you have just shown and the work that already occurs in
> > articulate.ly, it seems a lot of practical manipulation is possible
> > without going down to the MIDI layer.  So, your little patch to enable
> > wider use of Scheme translators seems quite useful.  At the very
> > least, the more folks build on this and start playing around with the
> > music, the more we would understand what a potential full Scheme
> > performer support would entail.
>
> Well, this is not as much supporting the MIDI layer as it is employing
> the translator level for messing with music during iteration.  It's sort
> of annoying that it doesn't work by default.

It doesn't work by default because we never bothered to invest time in
improving it. It's not obvious to me that a principled approach to
MIDI rendering would use a broadcast/acknowledge type architecture
like the typography part does.

-- 
Han-Wen Nienhuys - hanw...@gmail.com - http://www.xs4all.nl/~hanwen



Re: Scheme performers/translators

2021-09-29 Thread David Kastrup
Aaron Hill  writes:

> On 2021-09-29 12:39 pm, David Kastrup wrote:
>> The question is whether we should do something like this as default,
>> possibly conditioned on whether any acknowledgers are present?  Because
>> even if we cannot react to Midi data structures (since they are not
>> Scheme-accessible for now), sometimes a translator may be enough to do
>> the trick.
>
> You say "for now" above, so is allowing Scheme to interact directly
> with the MIDI stream something that is planned?

I have no idea what you call "planned".  It is a deficiency that one
cannot use LilyPond in anything but a hardwired manner for creating
Midi.  That does not mean that I know this to be in anybody's personal
work queue.  At the current point of time, the Midi data structures are
not even in the Scheme memory management.  I think most of them just
stick around without ever getting deleted.

> Between what you have just shown and the work that already occurs in
> articulate.ly, it seems a lot of practical manipulation is possible
> without going down to the MIDI layer.  So, your little patch to enable
> wider use of Scheme translators seems quite useful.  At the very
> least, the more folks build on this and start playing around with the
> music, the more we would understand what a potential full Scheme
> performer support would entail.

Well, this is not as much supporting the MIDI layer as it is employing
the translator level for messing with music during iteration.  It's sort
of annoying that it doesn't work by default.

-- 
David Kastrup



Re: Scheme performers/translators

2021-09-29 Thread Aaron Hill

On 2021-09-29 12:39 pm, David Kastrup wrote:

The question is whether we should do something like this as default,
possibly conditioned on whether any acknowledgers are present?  Because
even if we cannot react to Midi data structures (since they are not
Scheme-accessible for now), sometimes a translator may be enough to do
the trick.


You say "for now" above, so is allowing Scheme to interact directly with 
the MIDI stream something that is planned?  Between what you have just 
shown and the work that already occurs in articulate.ly, it seems a lot 
of practical manipulation is possible without going down to the MIDI 
layer.  So, your little patch to enable wider use of Scheme translators 
seems quite useful.  At the very least, the more folks build on this and 
start playing around with the music, the more we would understand what a 
potential full Scheme performer support would entail.



-- Aaron Hill



Re: Scheme performers/translators

2021-09-29 Thread David Kastrup
David Kastrup  writes:

> So I tried the following
>
> Stress_performer =
> #(define-scheme-function (strong weak) (index? index?)
>(lambda (ctx)
>  (define fired #f)
>  (define (emit weight)
>(ly:broadcast (ly:event-source ctx)
>(ly:make-stream-event
> (ly:make-event-class 'articulation-event)
> `((articulation-type . "accent")
>   (midi-extra-velocity . ,weight)
>  (make-engraver
>   ((stop-translation-timestep c) (set! fired #f))
>; TODO: don't go against syncopation: if there has been an
>; explicit accent less than a beat ago, don't do anything
>   (listeners ((note-event performer event)
> (if (not fired)
> (let ((mp (ly:context-property ctx 'measurePosition))
>   (tf (ly:context-property ctx 'timeSignatureFraction 
> '(4 . 4)))
>   (bmm (ly:context-property ctx 'baseMoment))
>   (bm (if (ly:moment? bmm)
>   (ly:moment-main bmm)
>   (/ (cdr tf
>   (bs (ly:context-property ctx 'beatStructure)))
>   (set! fired #t)
>   (and (zero? (ly:moment-grace mp))
>(zero? (ly:moment-main (ly:moment-mod mp bm)))
>(let loop ((mp (ly:moment-main mp)) (bs bs) (w 
> strong))
>  (cond ((zero? mp) (emit w))
>((positive? mp)
> (if (pair? bs)
> (loop (- mp (* bm (car bs))) (cdr bs) 
> weak)
> (loop (- mp bm) bs weak)
>
>
> and it did nothing when used via
>
> \midi { \context { \DrumVoice \consists \Stress_performer 20 10 } }
>
> when the intent was that there should be additional midi velocity on the
> start of the bar and then on each beat.  Now the code, not having run,
> may very well be defective still.  But the point is that it doesn't even
> get called because a Scheme_engraver is an engraver and engravers are
> not getting called in \midi.
>
> This actually does nothing that couldn't be done in general by any
> translator: it doesn't even require to specifically be an engraver or
> performer.
>
> I am somewhat loth to just copy scheme-engraver.{cc,hh} to
> scheme-performer.{cc,hh}, throw out everything Engraver-specific
> (basically acknowledgers and possibly the associated processing phases)
> and get something pretty much the same for now.
>
> Does anybody have a better proposal?

Ok, I now fixed the performer for basic use:

Stress_performer =
#(define-scheme-function (strong weak) (index? index?)
   (lambda (ctx)
 (define fired #f)
 (define (emit weight)
   (ly:broadcast (ly:context-event-source ctx)
 (ly:make-stream-event
  (ly:make-event-class 'articulation-event)
  `((articulation-type . "accent")
(midi-extra-velocity . ,weight)
 (make-engraver
  ((stop-translation-timestep c) (set! fired #f))
   ; TODO: don't go against syncopation: if there has been an
   ; explicit accent less than a beat ago, don't do anything
  (listeners ((note-event performer event)
  (if (not fired)
  (let* ((mp (ly:context-property ctx 'measurePosition))
 (mpm (ly:moment-main mp))
 (tf (ly:context-property ctx 
'timeSignatureFraction '(4 . 4)))
 (bmm (ly:context-property ctx 'baseMoment))
 (bm (if (ly:moment? bmm)
 (ly:moment-main bmm)
 (/ (cdr tf
 (bs (ly:context-property ctx 'beatStructure)))
(set! fired #t)
(and (zero? (ly:moment-grace mp))
 (integer? (/ mpm bm))
 (let loop ((mp mpm) (bs bs) (w strong))
   (cond ((zero? mp) (emit w))
 ((positive? mp)
  (if (pair? bs)
  (loop (- mp (* bm (car bs))) (cdr bs) 
weak)
  (loop (- mp bm) bs weak)

And it works as

  \midi {
\context { \DrumVoice
   \consists \Stress_performer 20 10
 }
  }

as long as I apply the following simplistic patch:

diff --git a/lily/translator-group.cc b/lily/translator-group.cc
index 07ba2f0395..4447747b73 100644
--- a/lily/translator-group.cc
+++ b/lily/translator-group.cc
@@ -156,7 +156,9 @@ Translator_group::create_child_translator (SCM sev)
   if (dynamic_cast (g))

Scheme performers/translators

2021-09-29 Thread David Kastrup


So I tried the following

Stress_performer =
#(define-scheme-function (strong weak) (index? index?)
   (lambda (ctx)
 (define fired #f)
 (define (emit weight)
   (ly:broadcast (ly:event-source ctx)
 (ly:make-stream-event
  (ly:make-event-class 'articulation-event)
  `((articulation-type . "accent")
(midi-extra-velocity . ,weight)
 (make-engraver
  ((stop-translation-timestep c) (set! fired #f))
   ; TODO: don't go against syncopation: if there has been an
   ; explicit accent less than a beat ago, don't do anything
  (listeners ((note-event performer event)
  (if (not fired)
  (let ((mp (ly:context-property ctx 'measurePosition))
(tf (ly:context-property ctx 'timeSignatureFraction 
'(4 . 4)))
(bmm (ly:context-property ctx 'baseMoment))
(bm (if (ly:moment? bmm)
(ly:moment-main bmm)
(/ (cdr tf
(bs (ly:context-property ctx 'beatStructure)))
(set! fired #t)
(and (zero? (ly:moment-grace mp))
 (zero? (ly:moment-main (ly:moment-mod mp bm)))
 (let loop ((mp (ly:moment-main mp)) (bs bs) (w 
strong))
   (cond ((zero? mp) (emit w))
 ((positive? mp)
  (if (pair? bs)
  (loop (- mp (* bm (car bs))) (cdr bs) 
weak)
  (loop (- mp bm) bs weak)


and it did nothing when used via

\midi { \context { \DrumVoice \consists \Stress_performer 20 10 } }

when the intent was that there should be additional midi velocity on the
start of the bar and then on each beat.  Now the code, not having run,
may very well be defective still.  But the point is that it doesn't even
get called because a Scheme_engraver is an engraver and engravers are
not getting called in \midi.

This actually does nothing that couldn't be done in general by any
translator: it doesn't even require to specifically be an engraver or
performer.

I am somewhat loth to just copy scheme-engraver.{cc,hh} to
scheme-performer.{cc,hh}, throw out everything Engraver-specific
(basically acknowledgers and possibly the associated processing phases)
and get something pretty much the same for now.

Does anybody have a better proposal?

-- 
David Kastrup