[alsa-devel] Help with midi player application
I am hoping someone has a bit of patience to help. I apologize in advance if this is not appropriate use of this mailing list.
I am trying to incorporate ALSA's sequencer within an application I am writing to play MIDI pieces, and provide controls (start at measure, tempo changes, etc), while output is sent to a piano player system with midi i/o (specifically it's a Pianodisc system). The result (if it ever works) will be open source.
The good news is I can get it to work. The bad news is I am having some kind of timing or buffering issue, and am at a bit of a loss where to look.
I am convinced the problem is in my code, or environment, as I can get pmidi (1.7.1) to work (including build it from source, so same compile environment).
The actual application is in a QT5.8 application, so it is conceivable that some aspect of QT's environment is at issue. I have embedded the calls to the ALSA sequencer inside of a separate QThread so as to isolate it from QT's event loop. Since the code fails only in context, it is not practical to post the whole code. And yes I'm sure it is related to my code, I get that, am hoping for some trouble shooting ideas, or pointers to tools.
The symptoms are on a fast, long piece play hangs for a long period of time (many seconds). I put into the loop queries as to queue info/state/etc, and what I see is the queue tick advancing correctly during this pause, but the events in the queue are steady at about 80%full and not emptying. I have set this up to run through qmidinet which outputs each notes as ALSA hands it off, and that pauses also (qmidinet is not the cause; writing direct to the midi port also pauses).
My hope with this email is to get some suggestions how to find out what is happening when it pauses inappropriately. "It" here is whatever processes are draining the queue; the thread making the snd_seq calls continues to run, I can query the queue and see its status, etc.
I have tried this with no self-written buffer management, just letting ALSA pause the thread; I also have it running managing the queue myself looking for it getting near full and waiting until it gets more empty (staying above the "room" size). Neither work, both do approximately the same, though trying to manage the buffer seems to work better and gives me event-count visibility in the queue.
Allocating a much larger queue buffer (snd_seq_set_client_pool_output) delays the pause significantly but does not solve the problem. The queue is not full (but also is not empty) when the pauses occur. My initial thoughts were the tick in the events was incorrect and so waiting, but that is not the case as best I can tell (also, that would not cause a larger buffer to pause less often). Something is stopping the queue from processing outbound for longish periods.
Essentially what I do is:
snd_seq_open to get the handle send_seq_alloc_queue snd_seq_client and snd_seq_create_simple_port to get the client port snd_seq_connect_to to connect snd_seq_set_queue_tempo (initially with default snd_deq_start_queue snd_seq_drain_output (until ret = 0)
Then I loop through all the midi events. Each event has:
snd_seq_ev_schedule_tick called with parameter 2 = 1 for relative ticks. snd_seq_event_output snd_seq_drain_output (until ret = 0) (every 10 events) check queue events and if getting full pause for 10ms
I have tried it with and without the drain after each send, neither one works, with the drain seems to work a bit better (and with the drain I can call the queue status and get more info).
The environment is a HyperV x64 Ubuntu 16.04.01 install with QT5.8 built from source, and ALSA from the distro version (not built from source). The same thing occurs on a Raspberry Pi 3B (which is my eventual target) running Ubuntu 16.04 Mate.
Both environments will run pmidi with the same song correctly. Yes, I know it's my code, not an ALSA bug.
What I'm hoping is some suggestion as to how to get more visibility as to what is happening when it pauses. Some kind of trace or debug mode, hopefully without trying to build and manually instrument ALSA.
Conversely.... maybe I am using ALSA inappropriate to send just to the sequencer and on to a midi device? I just wanted its scheduler to deal with timing, there is no near term plan to use a synthesizer or other connection instead.
Any suggestions or insights appreciated. I started with too little hair, and fear even more has been pulled out now.
Linwood Ferguson
amidi@LEFerguson.com wrote:
The symptoms are on a fast, long piece play hangs for a long period of time (many seconds). I put into the loop queries as to queue info/ state/etc, and what I see is the queue tick advancing correctly during this pause, but the events in the queue are steady at about 80%full and not emptying.
This sounds as if the events have the wrong time stamp.
snd_seq_ev_schedule_tick called with parameter 2 = 1 for relative ticks.
Why relative? (I'm not aware of anybody ever using this flags; it's possible that there is some bug ...)
Regards, Clemens
I took the technique from what pmidi did, which seemed like the most on-topic example. It also seemed a bit easier to change tempo.
I agree it sounds like they are wrong, except (a) I do not think they actually are (debug output as I queued them) and (b) when I increase the output size of the queue, the pauses happen at different times, even though the enqueued data is otherwise identical.
But that said I don't think it is hard to do the running calculations and change it, if you think there's merit?
Related question: Is there any way to query the queue for what is in it? Not just how many? See if somehow they ticks in the queue indeed are later than the current queue tick?
Linwood
PS. Thanks for the quick reply!
-----Original Message----- From: Clemens Ladisch [mailto:clemens@ladisch.de] Sent: Friday, February 17, 2017 9:19 AM To: amidi@LEFerguson.com; alsa-devel@alsa-project.org Subject: Re: [alsa-devel] Help with midi player application
amidi@LEFerguson.com wrote:
The symptoms are on a fast, long piece play hangs for a long period of time (many seconds). I put into the loop queries as to queue info/ state/etc, and what I see is the queue tick advancing correctly during this pause, but the events in the queue are steady at about 80%full and not emptying.
This sounds as if the events have the wrong time stamp.
snd_seq_ev_schedule_tick called with parameter 2 = 1 for relative ticks.
Why relative? (I'm not aware of anybody ever using this flags; it's possible that there is some bug ...)
Regards, Clemens
amidi@LEFerguson.com wrote:
I took the technique from what pmidi did
AFAICS pmidi uses absolute timestamps.
But that said I don't think it is hard to do the running calculations and change it, if you think there's merit?
There appears to be a problem with timestamps. I don't know where (I haven't seen your calculations). You have mentioned only snd_seq_ev_schedule_tick(), so that is the only one I can suggest to change.
Is there any way to query the queue for what is in it?
No.
Regards, Clemens
amidi@LEFerguson.com wrote:
I took the technique from what pmidi did
AFAICS pmidi uses absolute timestamps.
Hmmm.... Starting to doubt my memory now... I see it does use a 0 in that parameter. Not sure where I got using relative. Let me go back and review. Maybe I am scheduling the math incorrectly.
Thank you for emphasizing that. I could have sworn I copied it from pmidi, but I must have changed at some point for some reason. Need to rethink it.
More to follow...
Linwood
Bingo. It was entirely that. I tracked back through the changes and let's just say it got tangled up in some confusion I had earlier about how I was going to start a song in the middle. The documentation is correct; at the time I conflated the "realtime" and "absolute" aspects. I changed this, and never revisited the relative time flag..
I quite literally just changed it to absolute instead of relative and it started working. Obviously it was rescheduling the longer pieces based on an advancing clock. Short pieces were dumped into the queue all essentially at tick 0. With each "inhale" the next inhale was further delayed. Makes sense now.
Just need to clean up all the debugging and extra drains and such I put in. :(
Thank you very much.
Linwood
amidi@LEFerguson.com wrote:
I took the technique from what pmidi did
AFAICS pmidi uses absolute timestamps.
Hmmm.... Starting to doubt my memory now... I see it does use a 0 in that parameter. Not sure where I got using relative. Let me go back and review. Maybe I am scheduling the math incorrectly.
Thank you for emphasizing that. I could have sworn I copied it from pmidi, but I must have changed at some point for some reason. Need to rethink it.
More to follow...
Linwood
_______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
participants (2)
-
amidi@LEFerguson.com
-
Clemens Ladisch