From 78a088fe0245dc59f14d8d6976b1e95ea88443f2 Mon Sep 17 00:00:00 2001 From: mahlzeit Date: Fri, 14 May 2004 14:47:55 +0000 Subject: [PATCH] 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 --- src/servers/midi/PortDrivers.cpp | 245 +++++++++++++++++++------------ 1 file changed, 149 insertions(+), 96 deletions(-) diff --git a/src/servers/midi/PortDrivers.cpp b/src/servers/midi/PortDrivers.cpp index 74df5b4244..c9c3471d70 100644 --- a/src/servers/midi/PortDrivers.cpp +++ b/src/servers/midi/PortDrivers.cpp @@ -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 * * 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; thread_id thread = spawn_thread( - SpawnThread, "MidiDriversProducer", B_URGENT_PRIORITY, this); + SpawnThread, "MidiPortProducer", B_URGENT_PRIORITY, this); resume_thread(thread); } @@ -80,117 +81,169 @@ int32 MidiPortProducer::SpawnThread(void* data) 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) { - if (read(fd, data, 1) != 1) + if (read(fd, &next, 1) != 1) { perror("Error reading data from driver"); return B_ERROR; } - switch (data[0] & 0xF0) + if (haveSysEx) // System Exclusive { - case B_NOTE_OFF: - 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: + if (next < 0x80) // data byte { - size_t msg_size = 4096; - uchar* msg = (uchar*) malloc(msg_size); - size_t count = 0; - - while (read(fd, msg + count, 1) == 1) + sysexBuf[sysexSize++] = next; + if (sysexSize == sysexAlloc) { - // Realtime events may interleave System Exclusives. Any - // non-realtime status byte (not just 0xF7) ends a sysex. + sysexAlloc *= 2; + 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) - { - SpraySystemRealTime(msg[count]); - } - else if (msg[count] >= 0xF0) - { - SpraySystemExclusive(msg, count - 1); + case B_SONG_POSITION: + needed = 2; + msgSize = 3; + break; + + case B_MIDI_TIME_CODE: + 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; - } - else // a normal data byte - { - ++count; - if (count == msg_size) - { - msg_size *= 2; - msg = (uchar*) realloc(msg, msg_size); - } - } } - free(msg); - break; + switch (msgBuf[0]) + { + 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;