Files
haiku-beta6/src/kits/midi2/MidiLocalProducer.cpp
T
mahlzeit a06c9b684a implemented Tempo Change event
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2933 a95241bf-73f2-0310-859d-f6bbb57e9c96
2003-03-17 22:28:13 +00:00

371 lines
8.7 KiB
C++

/*
* Copyright (c) 2002-2003 Matthijs Hollemans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#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"))
isLocal = true;
refCount = 1;
BMidiRoster::MidiRoster()->CreateLocal(this);
}
//------------------------------------------------------------------------------
BMidiLocalProducer::~BMidiLocalProducer()
{
TRACE(("BMidiLocalProducer::~BMidiLocalProducer"))
BMidiRoster::MidiRoster()->DeleteLocal(this);
}
//------------------------------------------------------------------------------
void BMidiLocalProducer::Connected(BMidiConsumer* cons)
{
ASSERT(cons != NULL)
TRACE(("Connected() %ld to %ld", ID(), cons->ID()))
// Do nothing.
}
//------------------------------------------------------------------------------
void BMidiLocalProducer::Disconnected(BMidiConsumer* cons)
{
ASSERT(cons != NULL)
TRACE(("Disconnected() %ld from %ld", ID(), cons->ID()))
// Do nothing.
}
//------------------------------------------------------------------------------
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");
}
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)
{
// 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();
}
}
//------------------------------------------------------------------------------