[alsa-devel] How to send non-SysEx system messages via ALSA?
Hi,
seqmid.h contains function that declare the major event types like snd_seq_ev_set_noteon and snd_seq_ev_set_sysex. However, seq_event.h knows many more types, e.g. SND_SEQ_EVENT_START and SND_SEQ_EVENT_CLOCK/TICK.
Now, consider an app playing a MIDI file or a debug tool that allows to send arbitrary messages. How should such an app send e.g. the 2-byte MTC Quarter Frame sequence via ALSA?
A. Use a 2 byte buffer F1 xx and snd_seq_ev_set_sysex(&event, 2, buf);
B. Use SND_SEQ_EVENT_TICK and figure out some copy&paste code from seqmidi.h, perhaps snd_seq_ev_set_queue_control(ev,SND_SEQ_EVENT_TICK,SND_SEQ_QUEUE_DIRECT,xx) But why does that alter my destination port via snd_seq_ev_set_dest(ev, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_TIMER)?
C. It's SND_SEQ_EVENT_CLOCK actually, TICK being the one byte F8 real-time message?
Background: Wine on Linux needs to generate such messages on behalf of applications and users with real MIDI HW. So far Wine assumes that it can encapsulate all system messages in a SysEx, IOW Wine does A. Is that usage of the set_sysex API correct? More generally, can Wine transparently stuff system messages into a byte buffer and send them off via snd_seq_ev_set_sysex?
Thank you, Jörg Höhle
Joerg-Cyril.Hoehle@t-systems.com wrote:
seqmid.h contains function that declare the major event types like snd_seq_ev_set_noteon and snd_seq_ev_set_sysex. However, seq_event.h knows many more types, e.g. SND_SEQ_EVENT_START and SND_SEQ_EVENT_CLOCK/TICK.
The functions in seqmid.h are just helpers for the most common messages; you can fill the snd_seq_event_t structure manually.
Now, consider an app playing a MIDI file or a debug tool that allows to send arbitrary messages. How should such an app send e.g. the 2-byte MTC Quarter Frame sequence via ALSA? ... B. Use SND_SEQ_EVENT_TICK
This is not a MIDI message. (In fact, this message is not used at all. Er, and don't believe what its comment says.)
snd_seq_ev_set_queue_control(ev,...) But why does that alter my destination port via snd_seq_ev_set_dest(ev, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_TIMER)?
Certain messages are use for sequencer-specific notification and control purposes. Messages that affect (queue) timers are sent to the special system timer client.
C. It's SND_SEQ_EVENT_CLOCK actually,
SND_SEQ_EVENT_CLOCK is MIDI Clock (F8).
MTC Quarter Frame (F1) is SND_SEQ_EVENT_QFRAME.
Background: Wine on Linux needs to generate such messages on behalf of applications and users with real MIDI HW. So far Wine assumes that it can encapsulate all system messages in a SysEx, IOW Wine does A. Is that usage of the set_sysex API correct?
It works, but it's not what this event type was designed for. In any case, all MIDI messages have a corresponding sequencer event type, so you should use that.
You could save much work by using ALSA's built-in MIDI encoder: http://www.alsa-project.org/alsa-doc/alsa-lib/group___m_i_d_i___event.html
Regards, Clemens
On Tue, Mar 5, 2013 at 3:51 AM, Clemens Ladisch clemens@ladisch.de wrote:
Joerg-Cyril.Hoehle@t-systems.com wrote:
B. Use SND_SEQ_EVENT_TICK
This is not a MIDI message. (In fact, this message is not used at all. Er, and don't believe what its comment says.)
I thought SND_SEQ_EVENT_TICK corresponded to a non-standard (formerly standard?) MIDI message:
http://www.blitter.com/~russtopia/MIDI/~jglatt/tech/midispec/tick.htm
Devin Anderson wrote:
On Tue, Mar 5, 2013 at 3:51 AM, Clemens Ladisch clemens@ladisch.de wrote:
Joerg-Cyril.Hoehle@t-systems.com wrote:
B. Use SND_SEQ_EVENT_TICK
This is not a MIDI message. (In fact, this message is not used at all. Er, and don't believe what its comment says.)
I thought SND_SEQ_EVENT_TICK corresponded to a non-standard (formerly standard?) MIDI message:
http://www.blitter.com/~russtopia/MIDI/~jglatt/tech/midispec/tick.htm
SND_SEQ_EVENT_TICK doesn't correspond to anything. It's unused.
And F9 has never been standardized.
Regards, Clemens
On 03/05/2013 02:56 AM, Joerg-Cyril.Hoehle@t-systems.com wrote:
Now, consider an app playing a MIDI file or a debug tool that allows to send arbitrary messages. How should such an app send e.g. the 2-byte MTC Quarter Frame sequence via ALSA?
If you want to send arbitrary MIDI messages, you'll find the rawmidi interface more flexible. The seq interface is very restrictive in this case.
For example, I think you can send arbitrary (even random/invalid) stuff using the CLI `amidi`. It was intended for Sysex dumps, but I think it's more flexable. It uses the rawmidi api.
http://www.alsa-project.org/alsa-doc/alsa-lib/group___raw_midi.html
The down-side of using rawmidi is that you're now on your own for sequencing (timing).
A. Use a 2 byte buffer F1 xx and snd_seq_ev_set_sysex(&event, 2, buf);
Set up a snd_seq_event_t with type SND_SEQ_EVENT_QFRAME and fill out the snd_seq_event_t::control structure with the appropriate data. Your 1-byte payload message should go into the 'value' field... and ignore the 'channel' and 'param' fields.
B. Use SND_SEQ_EVENT_TICK and figure out some copy&paste code from seqmidi.h, perhaps snd_seq_ev_set_queue_control(ev,SND_SEQ_EVENT_TICK,SND_SEQ_QUEUE_DIRECT,xx) But why does that alter my destination port via snd_seq_ev_set_dest(ev, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_TIMER)?
Inspecting the source, it looks like the kernel seq driver drops the non-standard 'Tick' message (0xF9). The only way I know to send it is to use the rawmidi API. [Anybody: please correct me if I'm wrong here.]
Background: Wine on Linux needs to generate such messages on behalf of applications and users with real MIDI HW. So far Wine assumes that it can encapsulate all system messages in a SysEx, IOW Wine does A. Is that usage of the set_sysex API correct? More generally, can Wine transparently stuff system messages into a byte buffer and send them off via snd_seq_ev_set_sysex?
Since Wine is sending/receiving midi data (without timing) that is to be sent/received _immediately_ -- you might find life easier by using the rawmidi api. Using this, it might even be as simple as passing raw data back and forth without having to decode anything yourself.
-gabriel
Gabriel M. Beddingfield wrote:
Since Wine is sending/receiving midi data (without timing) that is to be sent/received _immediately_ -- you might find life easier by using the rawmidi api.
But this would work only with rawmidi devices; hardware synthesizers (OPL3/4/Emu10k1) and any software applications would be excluded (without contortions like snd-virmidi).
Regards, Clemens
On Sat, Mar 9, 2013 at 1:01 PM, Clemens Ladisch clemens@ladisch.de wrote:
Gabriel M. Beddingfield wrote:
Since Wine is sending/receiving midi data (without timing) that is to be sent/received _immediately_ -- you might find life easier by using the rawmidi api.
But this would work only with rawmidi devices; hardware synthesizers (OPL3/4/Emu10k1) and any software applications would be excluded (without contortions like snd-virmidi).
Correct me if I'm wrong, but his options are:
1. Drop support for any non-standard midi byte streams (e.g. "Tick") by using the seq API, or 2. Drop the ability to have a virtual midi device by using the rawmidi API.
The choice is up to him.
<off_topic> Me? I would prefer to have the ability to send raw midi through the seq interface. (Again, let me know if that exists somewhere -- I couldn't find it.) Something like SND_SEQ_EVENT_RAW_MIDI with a length and a short array for data. In most applications that I've worked on, I need to be able to read/write raw midi bytestreams for other parts of the application. I find it annoying that I have to translate them to/from the seq API's 'helper' structs.
...so if someone were to implement such a beast -- would it be welcome? </off_topic>
-gabriel
Gabriel Beddingfield wrote:
Inspecting the source, it looks like the kernel seq driver drops the non-standard 'Tick' message (0xF9). The only way I know to send it is to use the rawmidi API. [Anybody: please correct me if I'm wrong here.] Since Wine is sending/receiving midi data (without timing) that is to be sent/received _immediately_ -- you might find life easier by using the rawmidi api.
Indeed, that sounded like a perfect match.
But this would work only with rawmidi devices; hardware synthesizers (OPL3/4/Emu10k1) and any software applications would be excluded (without contortions like snd-virmidi).
OTOH, that sounds like a killer argument against rawmidi.
Correct me if I'm wrong, but his options are:
- Drop support for any non-standard midi byte streams (e.g. "Tick") by using the seq API, or
- Drop the ability to have a virtual midi device by using the rawmidi API.
The choice is up to him.
Wine's CoreAudio MIDI driver for MacOS already drives two different API, one called CoreMidi and another one for the built-in SW-synth. So WineALSA could do something similar.
However, my current knowledge does not allow me to infer when to open rawmidi and when the seq interface. Likewise, Wine presents all MIDI interfaces as MIDI_PORT to applications and barely knows a difference between things like Timidity / FluidSynth and HW serial ports.
How would I distinguish and decide which API to use?
Heck, I even find it funny that Timidity and FluidSynth declare different capabilities bits.
Presumably most people use MIDI in Wine to allow music from games to play. At least, that's my case, so I toyed with Timidity and FluidSynth.
However, there are some pro Wine users with real MIDI hardware. These guys found bugs in Wine in the past, such as the 2-byte MTC not being generated or getting through, or a KORG editor SW hanging after sending a strange SysEx F0 ... F7 00 00 00 (terminated by three NUL bytes!). That's why I want to handle those cases well too, not just the SW-synth case. Thus I'd like to be able to generate and send correct system messages and do something reasonable with weird data like the above trailing 00 00 00 bytes.
Solved MTC bug in Wine http://bugs.winehq.org/show_bug.cgi?id=26928 Open SysEx+00 00 00 bug in Wine http://bugs.winehq.org/show_bug.cgi?id=33126
Regards, Jörg Höhle
participants (5)
-
Clemens Ladisch
-
Devin Anderson
-
Gabriel Beddingfield
-
Gabriel M. Beddingfield
-
Joerg-Cyril.Hoehle@t-systems.com