[alsa-devel] RawMIDI behaviour with MidiFace 4x4
Kalvas, Taneli
taneli.v.m.kalvas at jyu.fi
Sat Mar 7 18:26:43 CET 2015
Dear All,
I am developing a patch librarian for a synthesizer. Because the communication happens with Midi sysex and timing is not relevant I chose RawMIDI interface and not the alsa sequencer. The problem I have encountered is that writing to the midi port with snd_rawmidi_write() seems to broken. The function accepts any size of data block and claims to have sent everything. In reality only a part of the message is sent. For a large block size I can see the activity light blinking for fraction of a second. This happens both in blocking and non-blocking mode. I would expect the snd_rawmidi_write() to accept only a part of the message.
My hardware is Miditech Midiface 4x4, a USB midi interface:
$ cat /proc/asound/cards
0 [PCH ]: HDA-Intel - HDA Intel PCH
HDA Intel PCH at 0xe0610000 irq 45
1 [MIDI4x4 ]: USB-Audio - MIDI4x4
MIDIPLUS MIDI4x4 at usb-0000:00:14.0-1, full speed
usbid: 1acc:1a0b
My alsa is quite recent (aplay shows version 1.0.27.2), I am running Ubuntu with 3.13.0-39-generic kernel.
I have tested the system by connecting the output port to an input port on the hardware and having another program output the received bytes on stdout. My observations:
- As long as the buffer size is 276 bytes or less it gets sent ok
- Larger buffer sizes cause corruption and roughly 300 bytes of received.
- Alsa reports midi ring buffer size of 4096.
- snd_rawmidi_status_get_xruns() on both ends reports 0 errors.
- If I write N=128 byte blocks and usleep for 352*N after each write, everything works ok.
Is this due to hardware incompatibility with alsa driver or what is going on? Is there a way to connect two programs via a virtual RawMIDI port so that I could test without using the hardware? Any other diagnostics that I could do?
My test programs:
write.cpp:
int main( void )
{
int intstatus;
snd_rawmidi_t *midiout;
if( (intstatus = snd_rawmidi_open(NULL, &midiout, "hw:1,0,1", 0)) ) {
std::cerr << "unable to open MIDI out port: " << snd_strerror(intstatus) << "\n";
exit( 1 );
}
int N = 3000; // 276 bytes gets through ok.
unsigned char msg[N];
for( int a = 0; a < N; a++ ) {
msg[a] = a % 0x80;
}
msg[0] = 0xF0;
msg[N-1] = 0xF7;
ssize_t wrstatus;
if( (wrstatus = snd_rawmidi_write(midiout, msg, N)) < 0 ) {
std::cerr << "unable to write MIDI port: " << snd_strerror(wrstatus) << "\n";
return( -1 );
}
std::cout << "write status = " << wrstatus << "\n";
if( (intstatus = snd_rawmidi_drain( midiout )) ) {
std::cerr << "unable to drain: " << snd_strerror(intstatus) << "\n";
exit( 1 );
}
// Sleep for the amount of time needed for transfer + 10 % extra + 100 ms
usleep( 352*N + 100000 );
snd_rawmidi_status_t *stat;
snd_rawmidi_status_malloc( &stat );
snd_rawmidi_status( midiout, stat );
int err = snd_rawmidi_status_get_xruns( stat );
std::cout << "xruns = " << err << "\n";
snd_rawmidi_close( midiout );
return( 0 );
}
--------------------
read.cpp:
bool quit = false;
void signal_int( int )
{
quit = true;
}
int main( void )
{
int mode = SND_RAWMIDI_NONBLOCK;
int intstat;
std::string portname = "hw:1,0,0";
//std::string portname = "virtual";
snd_rawmidi_t* midiin;
if( (intstat = snd_rawmidi_open(&midiin, NULL, portname.c_str(), mode)) < 0 ) {
std::cerr << "unable to open MIDI port " << portname << ": " << snd_strerror(intstat) << "\n";
exit( 1 );
}
int count = 0;
unsigned char buf[1];
std::cout << std::dec << std::setfill(' ') << std::setw(6) << count << " ";
signal( SIGINT, signal_int );
while( !quit ) {
int read = snd_rawmidi_read( midiin, buf, 1 );
if( read == 0 || read == -EBUSY || read == -EAGAIN ) {
usleep( 320 );
continue;
}
else if( read < 0 ) {
std::cerr << "unable to read MIDI port" << portname << ": " << snd_strerror(read) << "\n";
exit( 1 );
}
std::cout << std::hex << std::setfill('0')
<< "0x" << std::setw(2) << (int)buf[0] << " "
<< std::flush;
count++;
if( count % 8 == 0 ) {
std::cout << "\n";
std::cout << std::dec << std::setfill(' ') << std::setw(6) << count << " "
<< std::flush;
}
}
snd_rawmidi_status_t *stat;
snd_rawmidi_status_malloc( &stat );
snd_rawmidi_status( midiin, stat );
int err = snd_rawmidi_status_get_xruns( stat );
std::cout << "\nxruns = " << err << "\n";
snd_rawmidi_close( midiin );
return( 0 );
}
Thanks.
Taneli
--
Taneli Kalvas
Ph.D., Researcher
Department of Physics, room FL114
P.O. Box 35 (YFL)
40014 University of Jyväskylä, Finland
Mobile: +358-44-314-1602
Fax: +358-14-617-411
Email: taneli.kalvas at jyu.fi
More information about the Alsa-devel
mailing list