All of lore.kernel.org
 help / color / mirror / Atom feed
* sending a sequencer event to a delayed queue
@ 2012-03-10 18:20 Henning Thielemann
  2012-03-10 20:51 ` Clemens Ladisch
  0 siblings, 1 reply; 13+ messages in thread
From: Henning Thielemann @ 2012-03-10 18:20 UTC (permalink / raw)
  To: alsa-devel


Unfortunately the ALSA doc does not say, what happens if I send an event 
to a queue that is not running. I expected that the event is being 
delivered once the queue is started. But it seems that instead the event 
is dropped. What is the reason for that behaviour?

  What I want to do is the following: I have a program that computes a 
sequence of events in real-time. Since computation of an event requires 
varying amount of time, I want to add a latency in order to get a 
correctly timed output. To this end I set up two queues: One queue 
triggers computation of events via Echo messages and the other queue 
delivers the computed events. I want to use the same time stamps for both 
queues and just start the queues with a delay between them.
  Why is it not possible to use one queue and add latency manually to the 
timestamps? Because the user of the program shall be able to halt the 
computation. Thus the computation must be halted first and the delivery of 
events must be halted later. I cannot achieve this with one queue and a 
queue_stop command.
  Now the problem is: When my program starts it computes the first event 
and sends it to the second (delayed) queue. But since this queue is 
started only after a delay, it is not yet running and thus my event is not 
delayed, but lost. :-( How to solve that problem? Is there a proposed way 
to manage latency in ALSA sequencing?


Regards,
Henning

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: sending a sequencer event to a delayed queue
  2012-03-10 18:20 sending a sequencer event to a delayed queue Henning Thielemann
@ 2012-03-10 20:51 ` Clemens Ladisch
  2012-03-11 15:41   ` Henning Thielemann
  0 siblings, 1 reply; 13+ messages in thread
From: Clemens Ladisch @ 2012-03-10 20:51 UTC (permalink / raw)
  To: Henning Thielemann; +Cc: alsa-devel

Henning Thielemann wrote:
> Unfortunately the ALSA doc does not say, what happens if I send an event
> to a queue that is not running.

Exactly the same as with a running queue: the event stays in the client's
output buffer if its scheduled time has not yet been reached.

> I expected that the event is being delivered once the queue is started.
> But it seems that instead the event is dropped.

Perhaps it was delivered too early?


Regards,
Clemens

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: sending a sequencer event to a delayed queue
  2012-03-10 20:51 ` Clemens Ladisch
@ 2012-03-11 15:41   ` Henning Thielemann
  2012-03-11 20:40     ` Clemens Ladisch
  0 siblings, 1 reply; 13+ messages in thread
From: Henning Thielemann @ 2012-03-11 15:41 UTC (permalink / raw)
  To: alsa-devel; +Cc: Clemens Ladisch

[-- Attachment #1: Type: text/plain, Size: 1008 bytes --]

Clemens Ladisch schrieb:
> Henning Thielemann wrote:
>> Unfortunately the ALSA doc does not say, what happens if I send an event
>> to a queue that is not running.
> 
> Exactly the same as with a running queue: the event stays in the client's
> output buffer if its scheduled time has not yet been reached.
> 
>> I expected that the event is being delivered once the queue is started.
>> But it seems that instead the event is dropped.
> 
> Perhaps it was delivered too early?

I have attached a C program that demonstrates the effect: I start the
"player" queue with one second delay and immediately send a message with
a timestamp 0 that is meant to be the local time of the "player" queue.
I expected that this event is delivered when the player queue starts,
that is, one second after program start. But actually it is played
immediately. If I choose a time larger than 0, say 1ns or 1s, then the
event is not delivered at all.

I use output_direct, but the effect is the same if I use output and drain.

[-- Attachment #2: send-note-delayed.c --]
[-- Type: text/x-c++src, Size: 2168 bytes --]

#include <alsa/asoundlib.h>
#include <time.h>

void connect (snd_seq_t *seq, int port, const char* dest_name) {
  snd_seq_addr_t addr;
  snd_seq_parse_address(seq, &addr, dest_name);
  snd_seq_connect_to(seq, port, addr.client, addr.port);
  printf("connect to %s: %d:%d\n", dest_name, addr.client, addr.port);
}

int main () {
  snd_seq_t *seq;
  snd_seq_event_t ev;
  snd_seq_ev_clear(&ev);

  snd_seq_open(&seq, "default", SND_SEQ_OPEN_OUTPUT, 0);
  int port = snd_seq_create_simple_port(seq, "out",
                 SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
                 SND_SEQ_PORT_TYPE_MIDI_GENERIC);

  connect (seq, port, "aseqdump");
  connect (seq, port, "TiMidity");

  int control = snd_seq_alloc_queue(seq);
  int player = snd_seq_alloc_queue(seq);

  /* start controller queue */
  snd_seq_control_queue(seq, control, SND_SEQ_EVENT_START, 0, NULL);
  snd_seq_drain_output(seq);

  /* start player queue after one second using controller queue for timing */
  const int absolute = 0;
  snd_seq_real_time_t rtime;
  rtime.tv_sec = 1;
  rtime.tv_nsec = 0;
  snd_seq_ev_schedule_real(&ev, control, absolute, &rtime);
  snd_seq_control_queue(seq, player, SND_SEQ_EVENT_START, 0, &ev);
  snd_seq_drain_output(seq);

  snd_seq_ev_set_source(&ev, port);
  snd_seq_ev_set_subs(&ev);

  /* send note-on to player queue with local time 0 */
  /* this is played too early,
     if you increase the time, then the note is not played at all. */
  rtime.tv_sec = 0;
  rtime.tv_nsec = 0;
  snd_seq_ev_schedule_real(&ev, player, absolute, &rtime);
  snd_seq_ev_set_noteon(&ev, 0, 60, 64);
  snd_seq_event_output_direct(seq, &ev);

  /* send note-off to player queue with local time 1 */
  /* this event is dropped */
  rtime.tv_sec = 1;
  rtime.tv_nsec = 0;
  snd_seq_ev_schedule_real(&ev, player, absolute, &rtime);
  snd_seq_ev_set_noteoff(&ev, 0, 60, 64);
  snd_seq_event_output_direct(seq, &ev);

  snd_seq_sync_output_queue(seq);

  /* make sure that we do not destroy pending messages */
  sleep(3);

  snd_seq_free_queue(seq, control);
  snd_seq_free_queue(seq, player);
  snd_seq_delete_simple_port(seq, port);
  snd_seq_close(seq);

  return 0;
}

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: sending a sequencer event to a delayed queue
  2012-03-11 15:41   ` Henning Thielemann
@ 2012-03-11 20:40     ` Clemens Ladisch
  2012-03-11 21:08       ` Henning Thielemann
                         ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Clemens Ladisch @ 2012-03-11 20:40 UTC (permalink / raw)
  To: Henning Thielemann; +Cc: alsa-devel

Henning Thielemann wrote:
> Clemens Ladisch schrieb:
>> Henning Thielemann wrote:
>>> Unfortunately the ALSA doc does not say, what happens if I send an event
>>> to a queue that is not running.
>>
>> Exactly the same as with a running queue: the event stays in the client's
>> output buffer if its scheduled time has not yet been reached.
>
> I have attached a C program that demonstrates the effect: I start the
> "player" queue with one second delay and immediately send a message with
> a timestamp 0 that is meant to be the local time of the "player" queue.
> I expected that this event is delivered when the player queue starts,
> that is, one second after program start. But actually it is played
> immediately.

Yes; whether an event is delivered depends only on its scheduled time,
not whether the queue is running.

> If I choose a time larger than 0, say 1ns or 1s, then the
> event is not delivered at all.

Starting a queue also clears it.  (This is done explicitly in the code,
so I guess this is a feature.)


I'd suggest to use one queue for both kinds of events, and to add the
delay to the scheduled time.  To remove certain events, use
snd_seq_remove_events().


Regards,
Clemens

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: sending a sequencer event to a delayed queue
  2012-03-11 20:40     ` Clemens Ladisch
@ 2012-03-11 21:08       ` Henning Thielemann
  2012-03-11 22:14         ` Henning Thielemann
  2012-03-12  8:21         ` Clemens Ladisch
  2012-03-13 22:33       ` Henning Thielemann
  2012-03-14 17:37       ` Henning Thielemann
  2 siblings, 2 replies; 13+ messages in thread
From: Henning Thielemann @ 2012-03-11 21:08 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: alsa-devel


On Sun, 11 Mar 2012, Clemens Ladisch wrote:

> Yes; whether an event is delivered depends only on its scheduled time,
> not whether the queue is running.

That is, if the queue time is zero and the event time is zero, then the 
event is sent, independent of whether the queue is running or not. Right?

This is good to know and good to be documented. Is this documented 
somewhere and if not how could I document it myself? I remember there is 
an ALSA wiki ...


>> If I choose a time larger than 0, say 1ns or 1s, then the
>> event is not delivered at all.
>
> Starting a queue also clears it.  (This is done explicitly in the code,
> so I guess this is a feature.)

Should be certainly documented somehow. So maybe, 'CONTINUE' is the 
solution.

> I'd suggest to use one queue for both kinds of events, and to add the
> delay to the scheduled time.  To remove certain events, use
> snd_seq_remove_events().

I'll think about that.


Since we are at documentation. seq.h states:

#define SND_SEQ_PORT_CAP_SYNC_READ	(1<<2)	/**< allow read subscriptions */
#define SND_SEQ_PORT_CAP_SYNC_WRITE	(1<<3)	/**< allow write subscriptions */

...

#define SND_SEQ_PORT_CAP_SUBS_READ	(1<<5)	/**< allow read subscription */
#define SND_SEQ_PORT_CAP_SUBS_WRITE	(1<<6)	/**< allow write subscription */


So are the comments for SYNC_READ and SYNC_WRITE correct?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: sending a sequencer event to a delayed queue
  2012-03-11 21:08       ` Henning Thielemann
@ 2012-03-11 22:14         ` Henning Thielemann
  2012-03-12  8:21         ` Clemens Ladisch
  1 sibling, 0 replies; 13+ messages in thread
From: Henning Thielemann @ 2012-03-11 22:14 UTC (permalink / raw)
  To: alsa-devel; +Cc: Clemens Ladisch


On Sun, 11 Mar 2012, Henning Thielemann wrote:

> Should be certainly documented somehow. So maybe, 'CONTINUE' is the solution.

Yes, CONTINUE works as I want, great!

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: sending a sequencer event to a delayed queue
  2012-03-11 21:08       ` Henning Thielemann
  2012-03-11 22:14         ` Henning Thielemann
@ 2012-03-12  8:21         ` Clemens Ladisch
  2012-03-14 20:01           ` Henning Thielemann
  1 sibling, 1 reply; 13+ messages in thread
From: Clemens Ladisch @ 2012-03-12  8:21 UTC (permalink / raw)
  To: Henning Thielemann; +Cc: alsa-devel

Henning Thielemann wrote:
> On Sun, 11 Mar 2012, Clemens Ladisch wrote:
>> Yes; whether an event is delivered depends only on its scheduled time,
>> not whether the queue is running.
>
> That is, if the queue time is zero and the event time is zero, then
> the event is sent, independent of whether the queue is running or not.

Yes.

> Since we are at documentation. seq.h states:
>
> #define SND_SEQ_PORT_CAP_SYNC_READ    (1<<2)    /**< allow read subscriptions */
> #define SND_SEQ_PORT_CAP_SYNC_WRITE    (1<<3)    /**< allow write subscriptions */
> ...
> #define SND_SEQ_PORT_CAP_SUBS_READ    (1<<5)    /**< allow read subscription */
> #define SND_SEQ_PORT_CAP_SUBS_WRITE    (1<<6)    /**< allow write subscription */
>
> So are the comments for SYNC_READ and SYNC_WRITE correct?

No, they should say "obsolete; no effect".


Regards,
Clemens

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: sending a sequencer event to a delayed queue
  2012-03-11 20:40     ` Clemens Ladisch
  2012-03-11 21:08       ` Henning Thielemann
@ 2012-03-13 22:33       ` Henning Thielemann
  2012-03-14  8:22         ` Clemens Ladisch
  2012-03-14 17:37       ` Henning Thielemann
  2 siblings, 1 reply; 13+ messages in thread
From: Henning Thielemann @ 2012-03-13 22:33 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: alsa-devel


On Sun, 11 Mar 2012, Clemens Ladisch wrote:

> I'd suggest to use one queue for both kinds of events, and to add the
> delay to the scheduled time.  To remove certain events, use
> snd_seq_remove_events().

In order to understand how snd_seq_remove_events works, I looked into its 
source code ... I wondered why I can set the queue as condition with 
snd_seq_remove_events_set_queue but there is no flag that enables queue 
matching and actually the queue is not checked in remove_match, as far as 
I can see.

I have another question: Is snd_seq_remove_events atomic, that is, if some 
events have the same time stamp, is it guaranteed that they are removed 
all or none at all? Are events still delivered while removing? Or is there 
a possibility to check what I actually removed? I also thought about using 
snd_seq_extract_output, but I am concerned about removing events while 
events are delivered.


Regards,
Henning

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: sending a sequencer event to a delayed queue
  2012-03-13 22:33       ` Henning Thielemann
@ 2012-03-14  8:22         ` Clemens Ladisch
  0 siblings, 0 replies; 13+ messages in thread
From: Clemens Ladisch @ 2012-03-14  8:22 UTC (permalink / raw)
  To: Henning Thielemann; +Cc: alsa-devel

Henning Thielemann wrote:
> In order to understand how snd_seq_remove_events works, I looked into
> its source code ... I wondered why I can set the queue as condition
> with snd_seq_remove_events_set_queue but there is no flag that enables
> queue matching

SND_SEQ_REMOVE_DEST enables queue/client/port matching.

> and actually the queue is not checked in remove_match, as far as I can
> see.

Well, it's checked in the kernel. :)  I guess this is a bug in alsa-lib.

> I have another question: Is snd_seq_remove_events atomic, that is, if
> some events have the same time stamp, is it guaranteed that they are
> removed all or none at all? Are events still delivered while removing?

Queues are locked one at a time; events in the same queue with the same
timestamping mode should be removed atomically.


Regards,
Clemens

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: sending a sequencer event to a delayed queue
  2012-03-11 20:40     ` Clemens Ladisch
  2012-03-11 21:08       ` Henning Thielemann
  2012-03-13 22:33       ` Henning Thielemann
@ 2012-03-14 17:37       ` Henning Thielemann
  2 siblings, 0 replies; 13+ messages in thread
From: Henning Thielemann @ 2012-03-14 17:37 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: alsa-devel


On Sun, 11 Mar 2012, Clemens Ladisch wrote:

> I'd suggest to use one queue for both kinds of events, and to add the
> delay to the scheduled time.  To remove certain events, use
> snd_seq_remove_events().

Hm, I am thinking about how to make use of snd_seq_remove_events in my 
application. It's sad that I cannot find out what events I have actually 
removed. It would be bad if e.g. a NoteOff gets lost and thus a tone is 
played forever. It would be great if I could find out pending events in 
the queue (in the kernel space). Then I could fetch them and re-send them 
immediately, when the user stops my sequencer.
  Unfortunately snd_seq_extract_output only fetches events from the user 
buffer. Is there a snd_seq_extract_output for drained messages?


Regards,
Henning

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: sending a sequencer event to a delayed queue
  2012-03-12  8:21         ` Clemens Ladisch
@ 2012-03-14 20:01           ` Henning Thielemann
  2012-03-14 20:22             ` Henning Thielemann
  0 siblings, 1 reply; 13+ messages in thread
From: Henning Thielemann @ 2012-03-14 20:01 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: alsa-devel


On Mon, 12 Mar 2012, Clemens Ladisch wrote:

> Henning Thielemann wrote:
>> On Sun, 11 Mar 2012, Clemens Ladisch wrote:
>>> Yes; whether an event is delivered depends only on its scheduled time,
>>> not whether the queue is running.
>>
>> That is, if the queue time is zero and the event time is zero, then
>> the event is sent, independent of whether the queue is running or not.
>
> Yes.

Ok, I had an idea of how to solve my problem. I want to halt the queue and 
send all messages immediately that are still in the queue. To this end I 
think I could just increase the queue time.

Thus I did a test whether this will work. I did the following:

output note-on event with timestamp 1s
output note-off event with timestamp 2s
control_queue SND_SEQ_EVENT_SETPOS_TIME 3s
drain

Nothing happens.

I continue the queue after increasing the time:

output note-on event with timestamp 1s
output note-off event with timestamp 2s
control_queue SND_SEQ_EVENT_SETPOS_TIME 3s
control_queue SND_SEQ_EVENT_CONTINUE
drain

Now the note events are scheduled at 1s and 2s as if the SETPOS_TIME 
control was ignored.

Then I continued the queue before increasing the time:

output note-on event with timestamp 1s
output note-off event with timestamp 2s
control_queue SND_SEQ_EVENT_CONTINUE
control_queue SND_SEQ_EVENT_SETPOS_TIME 3s
drain

Now the events arrive instantly. This is the behavior I want to have.

It looks like SETPOS_TIME is ignored if the queue is halted. Is this 
correct?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: sending a sequencer event to a delayed queue
  2012-03-14 20:01           ` Henning Thielemann
@ 2012-03-14 20:22             ` Henning Thielemann
  2012-03-14 21:36               ` Clemens Ladisch
  0 siblings, 1 reply; 13+ messages in thread
From: Henning Thielemann @ 2012-03-14 20:22 UTC (permalink / raw)
  To: alsa-devel; +Cc: Clemens Ladisch


I get interesting result if I print the queue time using
snd_seq_queue_status_get_real_time.


On Wed, 14 Mar 2012, Henning Thielemann wrote:

> Ok, I had an idea of how to solve my problem. I want to halt the queue and 
> send all messages immediately that are still in the queue. To this end I 
> think I could just increase the queue time.
>
> Thus I did a test whether this will work. I did the following:
>
> output note-on event with timestamp 1s
> output note-off event with timestamp 2s
> control_queue SND_SEQ_EVENT_SETPOS_TIME 3s
> drain
>
> Nothing happens.


Queue time is exactly 3s after drain.


> I continue the queue after increasing the time:
>
> output note-on event with timestamp 1s
> output note-off event with timestamp 2s
> control_queue SND_SEQ_EVENT_SETPOS_TIME 3s
> control_queue SND_SEQ_EVENT_CONTINUE
> drain
>
> Now the note events are scheduled at 1s and 2s as if the SETPOS_TIME control 
> was ignored.


Queue time is some microseconds larger than 0.


That is, SETPOS_TIME seems to successfully alter the time, but then 
CONTINUE seems to reset the time. Is this a bug or a feature?

SETPOS_TIME does not emit events that become older than queue time. Is it 
a bug or a feature?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: sending a sequencer event to a delayed queue
  2012-03-14 20:22             ` Henning Thielemann
@ 2012-03-14 21:36               ` Clemens Ladisch
  0 siblings, 0 replies; 13+ messages in thread
From: Clemens Ladisch @ 2012-03-14 21:36 UTC (permalink / raw)
  To: Henning Thielemann; +Cc: alsa-devel

Henning Thielemann wrote:
> On Wed, 14 Mar 2012, Henning Thielemann wrote:
>> output note-on event with timestamp 1s
>> output note-off event with timestamp 2s
>> control_queue SND_SEQ_EVENT_SETPOS_TIME 3s
>> drain
>>
>> Nothing happens.

To get events to be dispatched, you need a timer tick, i.e., you
have to make the timer run again.

>> I continue the queue after increasing the time:
>>
>> output note-on event with timestamp 1s
>> output note-off event with timestamp 2s
>> control_queue SND_SEQ_EVENT_SETPOS_TIME 3s
>> control_queue SND_SEQ_EVENT_CONTINUE
>> drain
>>
>> Now the note events are scheduled at 1s and 2s as if the SETPOS_TIME control was ignored.
>
> Queue time is some microseconds larger than 0.
>
>
> That is, SETPOS_TIME seems to successfully alter the time, but then CONTINUE seems to reset the time. Is this a bug or a feature?

CONTINUE behaves like START if the timer hasn't run yet.


Regards,
Clemens

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2012-03-14 21:37 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-03-10 18:20 sending a sequencer event to a delayed queue Henning Thielemann
2012-03-10 20:51 ` Clemens Ladisch
2012-03-11 15:41   ` Henning Thielemann
2012-03-11 20:40     ` Clemens Ladisch
2012-03-11 21:08       ` Henning Thielemann
2012-03-11 22:14         ` Henning Thielemann
2012-03-12  8:21         ` Clemens Ladisch
2012-03-14 20:01           ` Henning Thielemann
2012-03-14 20:22             ` Henning Thielemann
2012-03-14 21:36               ` Clemens Ladisch
2012-03-13 22:33       ` Henning Thielemann
2012-03-14  8:22         ` Clemens Ladisch
2012-03-14 17:37       ` Henning Thielemann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.