[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