Milestone 2 is complete. You can now send and receive MIDI events.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2874 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
7a618fe9a9
commit
e4fa49727a
@ -4,8 +4,6 @@
|
||||
|
||||
#include <MidiEndpoint.h>
|
||||
|
||||
class BMidiDispatcher;
|
||||
|
||||
class BMidiConsumer : public BMidiEndpoint
|
||||
{
|
||||
public:
|
||||
@ -75,7 +73,7 @@ public:
|
||||
uchar channel, uchar lsb, uchar msb, bigtime_t time);
|
||||
|
||||
virtual void SystemExclusive(
|
||||
void* data, size_t dataLength, bigtime_t time);
|
||||
void* data, size_t length, bigtime_t time);
|
||||
|
||||
virtual void SystemCommon(
|
||||
uchar status, uchar data1, uchar data2, bigtime_t time);
|
||||
@ -92,8 +90,8 @@ protected:
|
||||
|
||||
private:
|
||||
|
||||
friend class BMidiDispatcher;
|
||||
friend class BMidiRoster;
|
||||
friend int32 _midi_event_thread(void*);
|
||||
|
||||
virtual void _Reserved1();
|
||||
virtual void _Reserved2();
|
||||
@ -103,12 +101,14 @@ private:
|
||||
virtual void _Reserved6();
|
||||
virtual void _Reserved7();
|
||||
virtual void _Reserved8();
|
||||
|
||||
BMidiDispatcher* fDispatcher;
|
||||
bigtime_t fTimeout;
|
||||
void* fTimeoutData;
|
||||
|
||||
int32 fCurrentProducer;
|
||||
|
||||
int32 EventThread();
|
||||
|
||||
bigtime_t timeout;
|
||||
void* timeoutData;
|
||||
int32 currentProducer;
|
||||
thread_id thread;
|
||||
|
||||
uint32 _reserved[1];
|
||||
};
|
||||
|
||||
|
@ -89,7 +89,7 @@ public:
|
||||
uchar channel, uchar lsb, uchar msb, bigtime_t time = 0) const;
|
||||
|
||||
void SpraySystemExclusive(
|
||||
void* data, size_t dataLength, bigtime_t time = 0) const;
|
||||
void* data, size_t length, bigtime_t time = 0) const;
|
||||
|
||||
void SpraySystemCommon(
|
||||
uchar status, uchar data1, uchar data2, bigtime_t time = 0) const;
|
||||
@ -106,7 +106,9 @@ protected:
|
||||
|
||||
private:
|
||||
|
||||
//void SprayEvent(BMidiEvent* event, size_t length) const;
|
||||
void SprayEvent(
|
||||
const void* data, size_t length, bool atomic, bigtime_t time,
|
||||
bool sysex = false) const;
|
||||
|
||||
virtual void _Reserved1();
|
||||
virtual void _Reserved2();
|
||||
|
@ -14,10 +14,9 @@ const char* BMidiEndpoint::Name() const
|
||||
{
|
||||
const char* str = NULL;
|
||||
|
||||
// It seems reasonable to assume that the pointer
|
||||
// returned by BString::String() can change when the
|
||||
// string is modified, e.g. to allocate more space.
|
||||
// That's why we need to lock here too.
|
||||
// It seems reasonable to assume that the pointer returned by
|
||||
// BString::String() can change when the string is modified,
|
||||
// e.g. to allocate more space. That's why we lock here too.
|
||||
|
||||
if (LockLooper())
|
||||
{
|
||||
|
@ -2,6 +2,8 @@
|
||||
* Copyright (c) 2002-2003 Matthijs Hollemans
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "MidiConsumer.h"
|
||||
#include "MidiRoster.h"
|
||||
@ -9,6 +11,13 @@
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
int32 _midi_event_thread(void* data)
|
||||
{
|
||||
return ((BMidiLocalConsumer*) data)->EventThread();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
BMidiLocalConsumer::BMidiLocalConsumer(const char* name)
|
||||
: BMidiConsumer(name)
|
||||
{
|
||||
@ -16,6 +25,13 @@ BMidiLocalConsumer::BMidiLocalConsumer(const char* name)
|
||||
|
||||
isLocal = true;
|
||||
refCount = 1;
|
||||
timeout = (bigtime_t) -1;
|
||||
timeoutData = NULL;
|
||||
|
||||
port = create_port(1, "MidiEventPort");
|
||||
thread = spawn_thread(
|
||||
_midi_event_thread, "MidiEventThread", B_REAL_TIME_PRIORITY, this);
|
||||
resume_thread(thread);
|
||||
|
||||
BMidiRoster::MidiRoster()->CreateLocal(this);
|
||||
}
|
||||
@ -27,6 +43,11 @@ BMidiLocalConsumer::~BMidiLocalConsumer()
|
||||
TRACE(("BMidiLocalConsumer::~BMidiLocalConsumer"))
|
||||
|
||||
BMidiRoster::MidiRoster()->DeleteLocal(this);
|
||||
|
||||
delete_port(port);
|
||||
|
||||
status_t result;
|
||||
wait_for_thread(thread, &result);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -62,22 +83,22 @@ void BMidiLocalConsumer::SetLatency(bigtime_t latency_)
|
||||
|
||||
int32 BMidiLocalConsumer::GetProducerID(void)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
return 0;
|
||||
return currentProducer;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void BMidiLocalConsumer::SetTimeout(bigtime_t when, void* data)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
timeout = when;
|
||||
timeoutData = data;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void BMidiLocalConsumer::Timeout(void* data)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -85,7 +106,134 @@ void BMidiLocalConsumer::Timeout(void* data)
|
||||
void BMidiLocalConsumer::Data(
|
||||
uchar* data, size_t length, bool atomic, bigtime_t time)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
if (atomic)
|
||||
{
|
||||
switch (data[0] & 0xF0)
|
||||
{
|
||||
case B_NOTE_OFF:
|
||||
{
|
||||
if (length == 3)
|
||||
{
|
||||
NoteOff(data[0] & 0x0F, data[1], data[2], time);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case B_NOTE_ON:
|
||||
{
|
||||
if (length == 3)
|
||||
{
|
||||
NoteOn(data[0] & 0x0F, data[1], data[2], time);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case B_KEY_PRESSURE:
|
||||
{
|
||||
if (length == 3)
|
||||
{
|
||||
KeyPressure(data[0] & 0x0F, data[1], data[2], time);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case B_CONTROL_CHANGE:
|
||||
{
|
||||
if (length == 3)
|
||||
{
|
||||
ControlChange(data[0] & 0x0F, data[1], data[2], time);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case B_PROGRAM_CHANGE:
|
||||
{
|
||||
if (length == 2)
|
||||
{
|
||||
ProgramChange(data[0] & 0x0F, data[1], time);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case B_CHANNEL_PRESSURE:
|
||||
{
|
||||
if (length == 2)
|
||||
{
|
||||
ChannelPressure(data[0] & 0x0F, data[1], time);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case B_PITCH_BEND:
|
||||
{
|
||||
if (length == 3)
|
||||
{
|
||||
PitchBend(data[0] & 0x0F, data[1], data[2], time);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xF0:
|
||||
{
|
||||
switch (data[0])
|
||||
{
|
||||
case B_SYS_EX_START:
|
||||
{
|
||||
if (data[length - 1] == B_SYS_EX_END)
|
||||
{
|
||||
SystemExclusive(data + 1, length - 2, time);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case B_TUNE_REQUEST:
|
||||
case B_SYS_EX_END:
|
||||
{
|
||||
if (length == 1)
|
||||
{
|
||||
SystemCommon(data[0], 0, 0, time);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case B_CABLE_MESSAGE:
|
||||
case B_MIDI_TIME_CODE:
|
||||
case B_SONG_SELECT:
|
||||
{
|
||||
if (length == 2)
|
||||
{
|
||||
SystemCommon(data[0], data[1], 0, time);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case B_SONG_POSITION:
|
||||
{
|
||||
if (length == 3)
|
||||
{
|
||||
SystemCommon(data[0], data[1], data[2], time);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case B_TIMING_CLOCK:
|
||||
case B_START:
|
||||
case B_CONTINUE:
|
||||
case B_STOP:
|
||||
case B_ACTIVE_SENSING:
|
||||
case B_SYSTEM_RESET:
|
||||
{
|
||||
if (length == 1)
|
||||
{
|
||||
SystemRealTime(data[0], time);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -93,7 +241,7 @@ void BMidiLocalConsumer::Data(
|
||||
void BMidiLocalConsumer::NoteOff(
|
||||
uchar channel, uchar note, uchar velocity, bigtime_t time)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -101,7 +249,7 @@ void BMidiLocalConsumer::NoteOff(
|
||||
void BMidiLocalConsumer::NoteOn(
|
||||
uchar channel, uchar note, uchar velocity, bigtime_t time)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -109,7 +257,7 @@ void BMidiLocalConsumer::NoteOn(
|
||||
void BMidiLocalConsumer::KeyPressure(
|
||||
uchar channel, uchar note, uchar pressure, bigtime_t time)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -117,7 +265,7 @@ void BMidiLocalConsumer::KeyPressure(
|
||||
void BMidiLocalConsumer::ControlChange(
|
||||
uchar channel, uchar controlNumber, uchar controlValue, bigtime_t time)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -125,7 +273,7 @@ void BMidiLocalConsumer::ControlChange(
|
||||
void BMidiLocalConsumer::ProgramChange(
|
||||
uchar channel, uchar programNumber, bigtime_t time)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -133,7 +281,7 @@ void BMidiLocalConsumer::ProgramChange(
|
||||
void BMidiLocalConsumer::ChannelPressure(
|
||||
uchar channel, uchar pressure, bigtime_t time)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -141,15 +289,15 @@ void BMidiLocalConsumer::ChannelPressure(
|
||||
void BMidiLocalConsumer::PitchBend(
|
||||
uchar channel, uchar lsb, uchar msb, bigtime_t time)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void BMidiLocalConsumer::SystemExclusive(
|
||||
void* data, size_t dataLength, bigtime_t time)
|
||||
void* data, size_t length, bigtime_t time)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -157,28 +305,28 @@ void BMidiLocalConsumer::SystemExclusive(
|
||||
void BMidiLocalConsumer::SystemCommon(
|
||||
uchar statusByte, uchar data1, uchar data2, bigtime_t time)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void BMidiLocalConsumer::SystemRealTime(uchar statusByte, bigtime_t time)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void BMidiLocalConsumer::TempoChange(int32 bpm, bigtime_t time)
|
||||
void BMidiLocalConsumer::TempoChange(int32 beatsPerMinute, bigtime_t time)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void BMidiLocalConsumer::AllNotesOff(bool justChannel, bigtime_t time)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -193,3 +341,67 @@ void BMidiLocalConsumer::_Reserved7() { }
|
||||
void BMidiLocalConsumer::_Reserved8() { }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
int32 BMidiLocalConsumer::EventThread()
|
||||
{
|
||||
int32 msg_code;
|
||||
ssize_t msg_size;
|
||||
ssize_t buf_size = 100;
|
||||
uint8* buffer = (uint8*) malloc(buf_size);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (timeout == (bigtime_t) -1)
|
||||
{
|
||||
msg_size = port_buffer_size(port);
|
||||
}
|
||||
else // have timeout
|
||||
{
|
||||
msg_size = port_buffer_size_etc(port, B_ABSOLUTE_TIMEOUT, timeout);
|
||||
if (msg_size == B_TIMED_OUT)
|
||||
{
|
||||
Timeout(timeoutData);
|
||||
timeout = (bigtime_t) -1;
|
||||
timeoutData = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (msg_size < 0) { break; } // error reading port
|
||||
|
||||
if (msg_size > buf_size)
|
||||
{
|
||||
buffer = (uint8*) realloc(buffer, msg_size);
|
||||
buf_size = msg_size;
|
||||
}
|
||||
|
||||
read_port(port, &msg_code, buffer, msg_size);
|
||||
|
||||
if (msg_size > 20) // minimum valid size
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("*** received: ");
|
||||
for (int32 t = 0; t < msg_size; ++t)
|
||||
{
|
||||
printf("%02X, ", ((uint8*) buffer)[t]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
currentProducer = *((uint32*) (buffer + 0));
|
||||
int32 targetId = *((uint32*) (buffer + 4));
|
||||
bigtime_t time = *((bigtime_t*) (buffer + 8));
|
||||
bool atomic = *((bool*) (buffer + 16));
|
||||
|
||||
if (targetId == id) // only if we are the destination
|
||||
{
|
||||
Data((uchar*) (buffer + 20), msg_size - 20, atomic, time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -2,6 +2,8 @@
|
||||
* Copyright (c) 2002-2003 Matthijs Hollemans
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "MidiConsumer.h"
|
||||
#include "MidiProducer.h"
|
||||
@ -55,7 +57,7 @@ void BMidiLocalProducer::Disconnected(BMidiConsumer* cons)
|
||||
void BMidiLocalProducer::SprayData(
|
||||
void* data, size_t length, bool atomic, bigtime_t time) const
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
SprayEvent(data, length, atomic, time);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -63,7 +65,19 @@ void BMidiLocalProducer::SprayData(
|
||||
void BMidiLocalProducer::SprayNoteOff(
|
||||
uchar channel, uchar note, uchar velocity, bigtime_t time) const
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
if (channel < 16)
|
||||
{
|
||||
uchar data[3];
|
||||
data[0] = B_NOTE_OFF + channel;
|
||||
data[1] = note;
|
||||
data[2] = velocity;
|
||||
|
||||
SprayEvent(&data, 3, true, time);
|
||||
}
|
||||
else
|
||||
{
|
||||
debugger("invalid MIDI channel");
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -71,7 +85,19 @@ void BMidiLocalProducer::SprayNoteOff(
|
||||
void BMidiLocalProducer::SprayNoteOn(
|
||||
uchar channel, uchar note, uchar velocity, bigtime_t time) const
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
if (channel < 16)
|
||||
{
|
||||
uchar data[3];
|
||||
data[0] = B_NOTE_ON + channel;
|
||||
data[1] = note;
|
||||
data[2] = velocity;
|
||||
|
||||
SprayEvent(&data, 3, true, time);
|
||||
}
|
||||
else
|
||||
{
|
||||
debugger("invalid MIDI channel");
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -79,7 +105,19 @@ void BMidiLocalProducer::SprayNoteOn(
|
||||
void BMidiLocalProducer::SprayKeyPressure(
|
||||
uchar channel, uchar note, uchar pressure, bigtime_t time) const
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
if (channel < 16)
|
||||
{
|
||||
uchar data[3];
|
||||
data[0] = B_KEY_PRESSURE + channel;
|
||||
data[1] = note;
|
||||
data[2] = pressure;
|
||||
|
||||
SprayEvent(&data, 3, true, time);
|
||||
}
|
||||
else
|
||||
{
|
||||
debugger("invalid MIDI channel");
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -88,7 +126,19 @@ void BMidiLocalProducer::SprayControlChange(
|
||||
uchar channel, uchar controlNumber, uchar controlValue,
|
||||
bigtime_t time) const
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
if (channel < 16)
|
||||
{
|
||||
uchar data[3];
|
||||
data[0] = B_CONTROL_CHANGE + channel;
|
||||
data[1] = controlNumber;
|
||||
data[2] = controlValue;
|
||||
|
||||
SprayEvent(&data, 3, true, time);
|
||||
}
|
||||
else
|
||||
{
|
||||
debugger("invalid MIDI channel");
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -96,7 +146,18 @@ void BMidiLocalProducer::SprayControlChange(
|
||||
void BMidiLocalProducer::SprayProgramChange(
|
||||
uchar channel, uchar programNumber, bigtime_t time) const
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
if (channel < 16)
|
||||
{
|
||||
uchar data[2];
|
||||
data[0] = B_PROGRAM_CHANGE + channel;
|
||||
data[1] = programNumber;
|
||||
|
||||
SprayEvent(&data, 2, true, time);
|
||||
}
|
||||
else
|
||||
{
|
||||
debugger("invalid MIDI channel");
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -104,7 +165,18 @@ void BMidiLocalProducer::SprayProgramChange(
|
||||
void BMidiLocalProducer::SprayChannelPressure(
|
||||
uchar channel, uchar pressure, bigtime_t time) const
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
if (channel < 16)
|
||||
{
|
||||
uchar data[2];
|
||||
data[0] = B_CHANNEL_PRESSURE + channel;
|
||||
data[1] = pressure;
|
||||
|
||||
SprayEvent(&data, 2, true, time);
|
||||
}
|
||||
else
|
||||
{
|
||||
debugger("invalid MIDI channel");
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -112,39 +184,82 @@ void BMidiLocalProducer::SprayChannelPressure(
|
||||
void BMidiLocalProducer::SprayPitchBend(
|
||||
uchar channel, uchar lsb, uchar msb, bigtime_t time) const
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
if (channel < 16)
|
||||
{
|
||||
uchar data[3];
|
||||
data[0] = B_PITCH_BEND + channel;
|
||||
data[1] = lsb;
|
||||
data[2] = msb;
|
||||
|
||||
SprayEvent(&data, 3, true, time);
|
||||
}
|
||||
else
|
||||
{
|
||||
debugger("invalid MIDI channel");
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void BMidiLocalProducer::SpraySystemExclusive(
|
||||
void* data, size_t dataLength, bigtime_t time) const
|
||||
void* data, size_t length, bigtime_t time) const
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
SprayEvent(data, length, true, time, true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void BMidiLocalProducer::SpraySystemCommon(
|
||||
uchar statusByte, uchar data1, uchar data2, bigtime_t time) const
|
||||
uchar status, uchar data1, uchar data2, bigtime_t time) const
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
size_t len;
|
||||
uchar data[3];
|
||||
data[0] = status;
|
||||
data[1] = data1;
|
||||
data[2] = data2;
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case B_TUNE_REQUEST:
|
||||
case B_SYS_EX_END:
|
||||
len = 1; break;
|
||||
|
||||
case B_CABLE_MESSAGE:
|
||||
case B_MIDI_TIME_CODE:
|
||||
case B_SONG_SELECT:
|
||||
len = 2; break;
|
||||
|
||||
case B_SONG_POSITION:
|
||||
len = 3; break;
|
||||
|
||||
default:
|
||||
debugger("invalid system common status");
|
||||
}
|
||||
|
||||
SprayEvent(&data, len, true, time);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void BMidiLocalProducer::SpraySystemRealTime(
|
||||
uchar statusByte, bigtime_t time) const
|
||||
uchar status, bigtime_t time) const
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
if (status >= B_TIMING_CLOCK)
|
||||
{
|
||||
SprayEvent(&status, 1, true, time);
|
||||
}
|
||||
else
|
||||
{
|
||||
debugger("invalid real time status");
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void BMidiLocalProducer::SprayTempoChange(
|
||||
int32 bpm, bigtime_t time) const
|
||||
int32 beatsPerMinute, bigtime_t time) const
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
// This method does nothing, just like the BeOS R5 Midi Kit.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -159,3 +274,69 @@ void BMidiLocalProducer::_Reserved7() { }
|
||||
void BMidiLocalProducer::_Reserved8() { }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void BMidiLocalProducer::SprayEvent(
|
||||
const void* data, size_t length, bool atomic, bigtime_t time,
|
||||
bool sysex) const
|
||||
{
|
||||
if (LockProducer())
|
||||
{
|
||||
if (CountConsumers() > 0)
|
||||
{
|
||||
// We don't just send the MIDI event data to all connected
|
||||
// consumers, we also send a header. The header contains our
|
||||
// ID (4 bytes), the consumer's ID (4 bytes), the performance
|
||||
// time (8 bytes), whether the data is atomic (1 byte), and
|
||||
// padding (3 bytes). The MIDI event data follows the header.
|
||||
|
||||
size_t buf_size = 20 + length;
|
||||
if (sysex) { buf_size += 2; } // add 0xF0 and 0xF7 markers
|
||||
|
||||
uint8* buffer = (uint8*) malloc(buf_size);
|
||||
if (buffer != NULL)
|
||||
{
|
||||
*((uint32*) (buffer + 0)) = id;
|
||||
*((bigtime_t*) (buffer + 8)) = time;
|
||||
*((uint32*) (buffer + 16)) = 0;
|
||||
*((bool*) (buffer + 16)) = atomic;
|
||||
|
||||
if (sysex)
|
||||
{
|
||||
*((uint8*) (buffer + 20)) = B_SYS_EX_START;
|
||||
if (data != NULL)
|
||||
{
|
||||
memcpy(buffer + 21, data, length);
|
||||
}
|
||||
*((uint8*) (buffer + buf_size - 1)) = B_SYS_EX_END;
|
||||
}
|
||||
else if (data != NULL)
|
||||
{
|
||||
memcpy(buffer + 20, data, length);
|
||||
}
|
||||
|
||||
for (int32 t = 0; t < CountConsumers(); ++t)
|
||||
{
|
||||
BMidiConsumer* cons = ConsumerAt(t);
|
||||
*((uint32*) (buffer + 4)) = cons->id;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("*** spraying: ");
|
||||
for (int32 t = 0; t < buf_size; ++t)
|
||||
{
|
||||
printf("%02X, ", buffer[t]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
write_port(cons->port, 0, buffer, buf_size);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
UnlockProducer();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user