Added Christian Packmann's code for parsing raw MIDI streams.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7578 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
mahlzeit
2004-05-14 14:47:55 +00:00
parent e16d0060fe
commit 78a088fe02
+149 -96
View File
@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2003 Matthijs Hollemans * Copyright (c) 2003-2004 Matthijs Hollemans
* Copyright (c) 2004 Christian Packmann
* Copyright (c) 2003 Jerome Leveque * Copyright (c) 2003 Jerome Leveque
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
@@ -57,7 +58,7 @@ MidiPortProducer::MidiPortProducer(int fd_, const char *name = NULL)
keepRunning = true; keepRunning = true;
thread_id thread = spawn_thread( thread_id thread = spawn_thread(
SpawnThread, "MidiDriversProducer", B_URGENT_PRIORITY, this); SpawnThread, "MidiPortProducer", B_URGENT_PRIORITY, this);
resume_thread(thread); resume_thread(thread);
} }
@@ -80,117 +81,169 @@ int32 MidiPortProducer::SpawnThread(void* data)
int32 MidiPortProducer::GetData() int32 MidiPortProducer::GetData()
{ {
uchar data[3]; uint8 msgBuf[3];
uint8* sysexBuf;
uint8* msgPtr;
size_t msgSize;
size_t needed = 0;
uint8 runningStatus = 0;
bool haveSysEx = false;
size_t sysexAlloc;
size_t sysexSize;
uint8 next;
while (keepRunning) while (keepRunning)
{ {
if (read(fd, data, 1) != 1) if (read(fd, &next, 1) != 1)
{ {
perror("Error reading data from driver"); perror("Error reading data from driver");
return B_ERROR; return B_ERROR;
} }
switch (data[0] & 0xF0) if (haveSysEx) // System Exclusive
{ {
case B_NOTE_OFF: if (next < 0x80) // data byte
read(fd, data + 1, 2);
SprayNoteOff(data[0] & 0x0F, data[1], data[2]);
break;
case B_NOTE_ON:
read(fd, data + 1, 2);
SprayNoteOn(data[0] & 0x0F, data[1], data[2]);
break;
case B_KEY_PRESSURE:
read(fd, data + 1, 2);
SprayKeyPressure(data[0] & 0x0F, data[1], data[2]);
break;
case B_CONTROL_CHANGE:
read(fd, data + 1, 2);
SprayControlChange(data[0] & 0x0F, data[1], data[2]);
break;
case B_PROGRAM_CHANGE:
read(fd, data + 1, 1);
SprayProgramChange(data[0] & 0x0F, data[1]);
break;
case B_CHANNEL_PRESSURE:
read(fd, data + 1, 1);
SprayChannelPressure(data[0] & 0x0F, data[1]);
break;
case B_PITCH_BEND:
read(fd, data + 1, 2);
SprayPitchBend(data[0] & 0x0F, data[1], data[2]);
break;
}
switch (data[0])
{
case B_SYS_EX_START:
{ {
size_t msg_size = 4096; sysexBuf[sysexSize++] = next;
uchar* msg = (uchar*) malloc(msg_size); if (sysexSize == sysexAlloc)
size_t count = 0;
while (read(fd, msg + count, 1) == 1)
{ {
// Realtime events may interleave System Exclusives. Any sysexAlloc *= 2;
// non-realtime status byte (not just 0xF7) ends a sysex. sysexBuf = (uint8*) realloc(sysexBuf, sysexAlloc);
}
continue;
}
else if (next < 0xF8) // end of sysex
{
SpraySystemExclusive(sysexBuf, sysexSize);
haveSysEx = false;
}
}
if ((next & 0xF8) == 0xF8) // System Realtime
{
SpraySystemRealTime(next);
}
else if ((next & 0xF0) == 0xF0) // System Common
{
runningStatus = 0;
msgBuf[0] = next;
msgPtr = msgBuf + 1;
switch (next)
{
case B_SYS_EX_START:
sysexAlloc = 4096;
sysexBuf = (uint8*) malloc(sysexAlloc);
sysexBuf[0] = next;
sysexSize = 1;
haveSysEx = true;
break;
if (msg[count] >= 0xF8) case B_SONG_POSITION:
{ needed = 2;
SpraySystemRealTime(msg[count]); msgSize = 3;
} break;
else if (msg[count] >= 0xF0)
{ case B_MIDI_TIME_CODE:
SpraySystemExclusive(msg, count - 1); case B_SONG_SELECT:
case B_CABLE_MESSAGE:
needed = 1;
msgSize = 2;
break;
case B_TUNE_REQUEST:
case B_SYS_EX_END:
SpraySystemCommon(next, 0, 0);
break;
}
}
else if ((next & 0x80) == 0x80) // Voice message
{
runningStatus = next;
msgBuf[0] = next;
msgPtr = msgBuf + 1;
switch (next & 0xF0)
{
case B_NOTE_OFF:
case B_NOTE_ON:
case B_KEY_PRESSURE:
case B_CONTROL_CHANGE:
case B_PITCH_BEND:
needed = 2;
msgSize = 3;
break;
case B_PROGRAM_CHANGE:
case B_CHANNEL_PRESSURE:
needed = 1;
msgSize = 2;
break;
}
}
else if (needed > 0) // Data bytes to complete message
{
*msgPtr++ = next;
if (--needed == 0)
{
switch (msgBuf[0] & 0xF0)
{
case B_NOTE_OFF:
SprayNoteOff(msgBuf[0] & 0x0F, msgBuf[1], msgBuf[2]);
break;
case B_NOTE_ON:
SprayNoteOn(msgBuf[0] & 0x0F, msgBuf[1], msgBuf[2]);
break;
case B_KEY_PRESSURE:
SprayKeyPressure(msgBuf[0] & 0x0F, msgBuf[1], msgBuf[2]);
break;
case B_CONTROL_CHANGE:
SprayControlChange(msgBuf[0] & 0x0F, msgBuf[1], msgBuf[2]);
break;
case B_PROGRAM_CHANGE:
SprayProgramChange(msgBuf[0] & 0x0F, msgBuf[1]);
break;
case B_CHANNEL_PRESSURE:
SprayChannelPressure(msgBuf[0] & 0x0F, msgBuf[1]);
break;
case B_PITCH_BEND:
SprayPitchBend(msgBuf[0] & 0x0F, msgBuf[1], msgBuf[2]);
break; break;
}
else // a normal data byte
{
++count;
if (count == msg_size)
{
msg_size *= 2;
msg = (uchar*) realloc(msg, msg_size);
}
}
} }
free(msg); switch (msgBuf[0])
break; {
case B_SONG_POSITION:
SpraySystemCommon(msgBuf[0], msgBuf[1], msgBuf[2]);
break;
case B_MIDI_TIME_CODE:
case B_SONG_SELECT:
case B_CABLE_MESSAGE:
SpraySystemCommon(msgBuf[0], msgBuf[1], 0);
break;
}
} }
case B_TUNE_REQUEST:
case B_SYS_EX_END:
SpraySystemCommon(data[0], 0, 0);
break;
case B_MIDI_TIME_CODE:
case B_SONG_SELECT:
case B_CABLE_MESSAGE:
read(fd, data + 1, 1);
SpraySystemCommon(data[0], data[1], 0);
break;
case B_SONG_POSITION:
read(fd, data + 1, 2);
SpraySystemCommon(data[0], data[1], data[2]);
break;
case B_TIMING_CLOCK:
case B_START:
case B_CONTINUE:
case B_STOP:
case B_ACTIVE_SENSING:
case B_SYSTEM_RESET:
SpraySystemRealTime(data[0]);
break;
} }
else if (runningStatus != 0) // Repeated voice command
{
msgBuf[0] = runningStatus;
msgBuf[1] = next;
msgPtr = msgBuf + 2;
needed = msgSize - 2;
}
}
if (haveSysEx)
{
free(sysexBuf);
} }
return B_OK; return B_OK;