Reply 20 of 25, by hakonrk
- Rank
- Newbie
That's what I'm told.
That's what I'm told.
For completeness, the thread is at
http://news.gmane.org/group/gmane.linux.alsa. … t=/force_load=t
In case anyone is wondering, I've just started working on the bandwidth throttling fix. As for the temporary fix of enlarging the buffers, I should probably mention that this value is actually a module parameter for seq_midi, so if you haven't linked ALSA into the kernel (as I have), you don't need to alter the source and recompile to set the output buffer to 128 KiB.
Here's a fix that works for me with ALSA's default output buffer size. I had to go all the way down to 2 kB/s before I stopped seeing dropped sysex events. Unfortunately, the maximum rate depends on the game, so I don't think this would prevent buffer overflow in the general case. Data transfers to the MIDI port aren't handled by a DMA controller, so the transfer rate might be affected by the system load, not to mention by the hardware itself.
Personally, I'm going back to just increasing the output buffer size. Unless the ALSA people do something with their sequencer interface, I don't know of anything that will guarantee perfect sysex delivery in all situations. If they refuse to change the behavior of the event delivery, perhaps they'll agree to implement a function that returns the available space in the output buffer.
This is also a known problem in Windows, affecting people with real MT-32 or another device connected to MPU-401 (those using other midi interfaces, like software GM or MT-32 emulator aren't affected). I guess windows has bigger buffer so it's harder to get overflow. Known workaround is to set low CPU cycles during sysex output.
I had a though about throttling mechanism and as well looked for a function to poll midi buffer status, but couldn't find that neither in win32 nor in alsa 🙁 .
One possible place to have bandwidth throttling is in MPU-401 emulation which reports status bits on port 331 indicating if it's busy sending data and tells a game/program to wait before sending a byte. So it could be cleared after a fraction of time, though checking time isn't cheap to call in something so frequent as reading of the status bit.
Putting it in sysex transfer is a much lighter approach as it's not active during data playback and sysex can be a long byte sequence. Polling of free space in buffer would IMO be the best solution (if API were available).
Btw. I didn't understand, why does maximum rate depend on the game?
The biggest difference is between games such as Monkey Island 2 and a typical Sierra game. Sierra tends to send a huge chunk of data on startup, while Monkey Island 2 has a few sysex messages here and there, mixed into the music.
Apart from this obvious difference (which I'm sure isn't what you were asking about), I've also seen that some Sierra games overflow the buffer more easily than others, even though both games pushed way more data than than the size of the buffer. I haven't done much testing, so I don't know why one game would require a lower transfer rate, but it might depend on the types of messages sent - perhaps some sysex commands take longer to process than others. It doesn't matter for the kernel driver, since it's continually polling the MPU-401 before pushing more data, but a user space program can't do that without a way to poll the output buffer.
One thing's for sure: It's not a good idea to set a fixed transfer rate. If we're going to use this "solution", it should be configurable in the config file, so that it can be adapted to every situation. Just add another value in the [midi] section. Unfortunately, this isn't very user friendly. :( In Linux, it would surely be better to just tell users to add
options snd-seq-midi output_buffer_size=131072
in /etc/modprobe.conf than to pick a transfer rate that may or may not work for them. Setting the value too low isn't good either: games that upload lots of sysex data on initialization take a long time to start, while games such as Monkey Island 2 get audible interruptions in the sound, which is unacceptable.