* Copyright 2005-2006, Haiku.
*
* Copyright (c) 2002-2004 Matthijs Hollemans
* Distributed under the terms of the MIT License.
*
* Authors:
* Matthijs Hollemans
*/
#include <stdlib.h>
#include "debug.h"
#include <MidiConsumer.h>
#include <MidiProducer.h>
#include <MidiRoster.h>
#include "protocol.h"
BMidiLocalProducer::BMidiLocalProducer(const char* name)
: BMidiProducer(name)
{
TRACE(("BMidiLocalProducer::BMidiLocalProducer"))
fIsLocal = true;
fRefCount = 1;
BMidiRoster::MidiRoster()->CreateLocal(this);
}
BMidiLocalProducer::~BMidiLocalProducer()
{
TRACE(("BMidiLocalProducer::~BMidiLocalProducer"))
BMidiRoster::MidiRoster()->DeleteLocal(this);
}
void
BMidiLocalProducer::Connected(BMidiConsumer* cons)
{
ASSERT(cons != NULL)
TRACE(("Connected() %" B_PRId32 " to %" B_PRId32 "", ID(), cons->ID()))
}
void
BMidiLocalProducer::Disconnected(BMidiConsumer* cons)
{
ASSERT(cons != NULL)
TRACE(("Disconnected() %" B_PRId32 " from %" B_PRId32 "", ID(), cons->ID()))
}
void
BMidiLocalProducer::SprayData(void* data, size_t length,
bool atomic, bigtime_t time) const
{
SprayEvent(data, length, atomic, time);
}
void
BMidiLocalProducer::SprayNoteOff(uchar channel, uchar note,
uchar velocity, bigtime_t time) const
{
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");
}
}
void
BMidiLocalProducer::SprayNoteOn(uchar channel, uchar note,
uchar velocity, bigtime_t time) const
{
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");
}
}
void
BMidiLocalProducer::SprayKeyPressure(uchar channel, uchar note,
uchar pressure, bigtime_t time) const
{
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");
}
}
void
BMidiLocalProducer::SprayControlChange(uchar channel,
uchar controlNumber, uchar controlValue, bigtime_t time) const
{
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");
}
}
void
BMidiLocalProducer::SprayProgramChange(uchar channel,
uchar programNumber, bigtime_t time) const
{
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");
}
}
void
BMidiLocalProducer::SprayChannelPressure(uchar channel,
uchar pressure, bigtime_t time) const
{
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");
}
}
void
BMidiLocalProducer::SprayPitchBend(uchar channel,
uchar lsb, uchar msb, bigtime_t time) const
{
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 length, bigtime_t time) const
{
SprayEvent(data, length, true, time, true);
}
void
BMidiLocalProducer::SpraySystemCommon(uchar status, uchar data1,
uchar data2, bigtime_t time) const
{
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");
len = 0;
}
SprayEvent(&data, len, true, time);
}
void
BMidiLocalProducer::SpraySystemRealTime(uchar status,
bigtime_t time) const
{
if (status >= B_TIMING_CLOCK)
SprayEvent(&status, 1, true, time);
else
debugger("invalid real time status");
}
void
BMidiLocalProducer::SprayTempoChange(int32 beatsPerMinute,
bigtime_t time) const
{
int32 tempo = 60000000 / beatsPerMinute;
uchar data[6];
data[0] = 0xFF;
data[1] = 0x51;
data[2] = 0x03;
data[3] = tempo >> 16;
data[4] = tempo >> 8;
data[5] = tempo;
SprayEvent(&data, 6, true, time);
}
void BMidiLocalProducer::_Reserved1() { }
void BMidiLocalProducer::_Reserved2() { }
void BMidiLocalProducer::_Reserved3() { }
void BMidiLocalProducer::_Reserved4() { }
void BMidiLocalProducer::_Reserved5() { }
void BMidiLocalProducer::_Reserved6() { }
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) {
size_t buf_size = 20 + length;
if (sysex) {
buf_size += 2;
}
uint8* buffer = (uint8*)malloc(buf_size);
if (buffer != NULL) {
*((uint32*) (buffer + 0)) = fId;
*((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->fId;
#ifdef DEBUG
printf("*** spraying: ");
for (uint32 t = 0; t < buf_size; ++t)
{
printf("%02X, ", buffer[t]);
}
printf("\n");
#endif
write_port(cons->fPort, 0, buffer, buf_size);
}
free(buffer);
}
}
UnlockProducer();
}
}