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:
mahlzeit 2003-03-09 16:10:30 +00:00
parent 7a618fe9a9
commit e4fa49727a
5 changed files with 445 additions and 51 deletions

View File

@ -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];
};

View File

@ -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();

View File

@ -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())
{

View File

@ -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;
}
//------------------------------------------------------------------------------

View File

@ -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();
}
}
//------------------------------------------------------------------------------