Browse Source

Rework some plugin MIDI code, closes #134

tags/1.9.5
falkTX 10 years ago
parent
commit
29f8bbf13f
9 changed files with 371 additions and 353 deletions
  1. +14
    -10
      source/backend/plugin/BridgePlugin.cpp
  2. +68
    -78
      source/backend/plugin/DssiPlugin.cpp
  3. +66
    -47
      source/backend/plugin/FluidSynthPlugin.cpp
  4. +22
    -20
      source/backend/plugin/JucePlugin.cpp
  5. +19
    -24
      source/backend/plugin/LinuxSamplerPlugin.cpp
  6. +35
    -31
      source/backend/plugin/Lv2Plugin.cpp
  7. +66
    -65
      source/backend/plugin/NativePlugin.cpp
  8. +65
    -68
      source/backend/plugin/VstPlugin.cpp
  9. +16
    -10
      source/includes/CarlaMIDI.h

+ 14
- 10
source/backend/plugin/BridgePlugin.cpp View File

@@ -966,7 +966,7 @@ public:
CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS);

uint8_t data1, data2, data3;
data1 = static_cast<uint8_t>((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT));
data1 = uint8_t((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT));
data2 = note.note;
data3 = note.velo;

@@ -990,7 +990,7 @@ public:

bool allNotesOffSent = false;

for (uint32_t i=0, numEvents = pData->event.portIn->getEventCount(); i < numEvents; ++i)
for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i)
{
const EngineEvent& event(pData->event.portIn->getEvent(i));

@@ -1124,11 +1124,9 @@ public:
if (midiEvent.size == 0 || midiEvent.size >= MAX_MIDI_VALUE)
continue;

uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data));
uint8_t channel = event.channel;
const uint8_t* const midiData(midiEvent.size > EngineMidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data);

if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0)
status = MIDI_STATUS_NOTE_OFF;
uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiData));

if (status == MIDI_STATUS_CHANNEL_PRESSURE && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0)
continue;
@@ -1139,20 +1137,26 @@ public:
if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0)
continue;

// Fix bad note-off
if (status == MIDI_STATUS_NOTE_ON && midiData[2] == 0)
status = MIDI_STATUS_NOTE_OFF;

fShmRtControl.writeOpcode(kPluginBridgeRtMidiEvent);
fShmRtControl.writeUInt(event.time);
fShmRtControl.writeByte(midiEvent.port);
fShmRtControl.writeByte(midiEvent.size);

for (uint8_t j=0; j < midiEvent.size; ++j)
fShmRtControl.writeByte(midiEvent.data[j]);
fShmRtControl.writeByte(uint8_t(midiData[0] | (event.channel & MIDI_CHANNEL_BIT)));

for (uint8_t j=1; j < midiEvent.size; ++j)
fShmRtControl.writeByte(midiData[j]);

fShmRtControl.commitWrite();

if (status == MIDI_STATUS_NOTE_ON)
pData->postponeRtEvent(kPluginPostRtEventNoteOn, channel, midiEvent.data[1], midiEvent.data[2]);
pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, midiData[1], midiData[2]);
else if (status == MIDI_STATUS_NOTE_OFF)
pData->postponeRtEvent(kPluginPostRtEventNoteOff, channel, midiEvent.data[1], 0.0f);
pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, midiData[1], 0.0f);
} break;
}
}


+ 68
- 78
source/backend/plugin/DssiPlugin.cpp View File

@@ -1092,6 +1092,7 @@ public:
}

ulong midiEventCount = 0;
carla_zeroStruct<snd_seq_event_t>(fMidiEvents, kPluginMaxMidiEvents);

// --------------------------------------------------------------------------------------------------------
// Check if needs reset
@@ -1101,7 +1102,6 @@ public:
if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
{
midiEventCount = MAX_MIDI_CHANNELS*2;
carla_zeroStruct<snd_seq_event_t>(fMidiEvents, midiEventCount);

for (uchar i=0, k=MAX_MIDI_CHANNELS; i < MAX_MIDI_CHANNELS; ++i)
{
@@ -1117,7 +1117,6 @@ public:
else if (pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS)
{
midiEventCount = MAX_MIDI_NOTE;
carla_zeroStruct<snd_seq_event_t>(fMidiEvents, midiEventCount);

for (uchar i=0; i < MAX_MIDI_NOTE; ++i)
{
@@ -1156,13 +1155,12 @@ public:

CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS);

snd_seq_event_t& midiEvent(fMidiEvents[midiEventCount++]);
carla_zeroStruct<snd_seq_event_t>(midiEvent);
snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]);

midiEvent.type = (note.velo > 0) ? SND_SEQ_EVENT_NOTEON : SND_SEQ_EVENT_NOTEOFF;
midiEvent.data.note.channel = static_cast<uchar>(note.channel);
midiEvent.data.note.note = note.note;
midiEvent.data.note.velocity = note.velo;
seqEvent.type = (note.velo > 0) ? SND_SEQ_EVENT_NOTEON : SND_SEQ_EVENT_NOTEOFF;
seqEvent.data.note.channel = static_cast<uchar>(note.channel);
seqEvent.data.note.note = note.note;
seqEvent.data.note.velocity = note.velo;
}

pData->extNotes.mutex.unlock();
@@ -1177,7 +1175,6 @@ public:
#endif
const bool isSampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0;

uint32_t numEvents = pData->event.portIn->getEventCount();
uint32_t startTime = 0;
uint32_t timeOffset = 0;
uint32_t nextBankId;
@@ -1187,7 +1184,7 @@ public:
else
nextBankId = 0;

for (uint32_t i=0; i < numEvents; ++i)
for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i)
{
const EngineEvent& event(pData->event.portIn->getEvent(i));

@@ -1319,15 +1316,14 @@ public:
if (midiEventCount >= kPluginMaxMidiEvents)
continue;

snd_seq_event_t& midiEvent(fMidiEvents[midiEventCount++]);
carla_zeroStruct<snd_seq_event_t>(midiEvent);
snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]);

midiEvent.time.tick = isSampleAccurate ? startTime : event.time;
seqEvent.time.tick = isSampleAccurate ? startTime : event.time;

midiEvent.type = SND_SEQ_EVENT_CONTROLLER;
midiEvent.data.control.channel = event.channel;
midiEvent.data.control.param = ctrlEvent.param;
midiEvent.data.control.value = int8_t(ctrlEvent.value*127.0f);
seqEvent.type = SND_SEQ_EVENT_CONTROLLER;
seqEvent.data.control.channel = event.channel;
seqEvent.data.control.param = ctrlEvent.param;
seqEvent.data.control.value = int8_t(ctrlEvent.value*127.0f);
}
break;
} // case kEngineControlEventTypeParameter
@@ -1361,14 +1357,13 @@ public:
if (midiEventCount >= kPluginMaxMidiEvents)
continue;

snd_seq_event_t& midiEvent(fMidiEvents[midiEventCount++]);
carla_zeroStruct<snd_seq_event_t>(midiEvent);
snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]);

midiEvent.time.tick = isSampleAccurate ? startTime : event.time;
seqEvent.time.tick = isSampleAccurate ? startTime : event.time;

midiEvent.type = SND_SEQ_EVENT_CONTROLLER;
midiEvent.data.control.channel = event.channel;
midiEvent.data.control.param = MIDI_CONTROL_ALL_SOUND_OFF;
seqEvent.type = SND_SEQ_EVENT_CONTROLLER;
seqEvent.data.control.channel = event.channel;
seqEvent.data.control.param = MIDI_CONTROL_ALL_SOUND_OFF;
}
break;

@@ -1386,16 +1381,13 @@ public:
if (midiEventCount >= kPluginMaxMidiEvents)
continue;

snd_seq_event_t& midiEvent(fMidiEvents[midiEventCount++]);
carla_zeroStruct<snd_seq_event_t>(midiEvent);
snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]);

midiEvent.time.tick = isSampleAccurate ? startTime : event.time;
seqEvent.time.tick = isSampleAccurate ? startTime : event.time;

midiEvent.type = SND_SEQ_EVENT_CONTROLLER;
midiEvent.data.control.channel = event.channel;
midiEvent.data.control.param = MIDI_CONTROL_ALL_NOTES_OFF;

midiEventCount += 1;
seqEvent.type = SND_SEQ_EVENT_CONTROLLER;
seqEvent.data.control.channel = event.channel;
seqEvent.data.control.param = MIDI_CONTROL_ALL_NOTES_OFF;
}
break;
} // switch (ctrlEvent.type)
@@ -1406,103 +1398,101 @@ public:
if (midiEventCount >= kPluginMaxMidiEvents)
continue;

const EngineMidiEvent& engineEvent(event.midi);
const EngineMidiEvent& midiEvent(event.midi);

if (midiEvent.size > EngineMidiEvent::kDataSize)
continue;

uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(engineEvent.data));
uint8_t channel = event.channel;
uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data));

// Fix bad note-off (per DSSI spec)
if (MIDI_IS_STATUS_NOTE_ON(status) && engineEvent.data[2] == 0)
if (status == MIDI_STATUS_NOTE_ON && midiEvent.data[2] == 0)
status = MIDI_STATUS_NOTE_OFF;

snd_seq_event_t& midiEvent(fMidiEvents[midiEventCount]);
carla_zeroStruct<snd_seq_event_t>(midiEvent);
snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]);

midiEvent.time.tick = isSampleAccurate ? startTime : event.time;
seqEvent.time.tick = isSampleAccurate ? startTime : event.time;

switch (status)
{
case MIDI_STATUS_NOTE_OFF: {
const uint8_t note = engineEvent.data[1];
const uint8_t note = midiEvent.data[1];

midiEvent.type = SND_SEQ_EVENT_NOTEOFF;
midiEvent.data.note.channel = channel;
midiEvent.data.note.note = note;
seqEvent.type = SND_SEQ_EVENT_NOTEOFF;
seqEvent.data.note.channel = event.channel;
seqEvent.data.note.note = note;

pData->postponeRtEvent(kPluginPostRtEventNoteOff, channel, note, 0.0f);
pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, note, 0.0f);
break;
}

case MIDI_STATUS_NOTE_ON: {
const uint8_t note = engineEvent.data[1];
const uint8_t velo = engineEvent.data[2];
const uint8_t note = midiEvent.data[1];
const uint8_t velo = midiEvent.data[2];

midiEvent.type = SND_SEQ_EVENT_NOTEON;
midiEvent.data.note.channel = channel;
midiEvent.data.note.note = note;
midiEvent.data.note.velocity = velo;
seqEvent.type = SND_SEQ_EVENT_NOTEON;
seqEvent.data.note.channel = event.channel;
seqEvent.data.note.note = note;
seqEvent.data.note.velocity = velo;

pData->postponeRtEvent(kPluginPostRtEventNoteOn, channel, note, velo);
pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, note, velo);
break;
}

case MIDI_STATUS_POLYPHONIC_AFTERTOUCH:
if (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH)
{
const uint8_t note = engineEvent.data[1];
const uint8_t pressure = engineEvent.data[2];
const uint8_t note = midiEvent.data[1];
const uint8_t pressure = midiEvent.data[2];

midiEvent.type = SND_SEQ_EVENT_KEYPRESS;
midiEvent.data.note.channel = channel;
midiEvent.data.note.note = note;
midiEvent.data.note.velocity = pressure;
seqEvent.type = SND_SEQ_EVENT_KEYPRESS;
seqEvent.data.note.channel = event.channel;
seqEvent.data.note.note = note;
seqEvent.data.note.velocity = pressure;
}
break;

case MIDI_STATUS_CONTROL_CHANGE:
if (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES)
{
const uint8_t control = engineEvent.data[1];
const uint8_t value = engineEvent.data[2];
const uint8_t control = midiEvent.data[1];
const uint8_t value = midiEvent.data[2];

midiEvent.type = SND_SEQ_EVENT_CONTROLLER;
midiEvent.data.control.channel = channel;
midiEvent.data.control.param = control;
midiEvent.data.control.value = value;
seqEvent.type = SND_SEQ_EVENT_CONTROLLER;
seqEvent.data.control.channel = event.channel;
seqEvent.data.control.param = control;
seqEvent.data.control.value = value;
}
break;

case MIDI_STATUS_CHANNEL_PRESSURE:
if (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE)
{
const uint8_t pressure = engineEvent.data[1];
const uint8_t pressure = midiEvent.data[1];

midiEvent.type = SND_SEQ_EVENT_CHANPRESS;
midiEvent.data.control.channel = channel;
midiEvent.data.control.value = pressure;
seqEvent.type = SND_SEQ_EVENT_CHANPRESS;
seqEvent.data.control.channel = event.channel;
seqEvent.data.control.value = pressure;
}
break;

case MIDI_STATUS_PITCH_WHEEL_CONTROL:
if (pData->options & PLUGIN_OPTION_SEND_PITCHBEND)
{
const uint8_t lsb = engineEvent.data[1];
const uint8_t msb = engineEvent.data[2];
const uint8_t lsb = midiEvent.data[1];
const uint8_t msb = midiEvent.data[2];

midiEvent.type = SND_SEQ_EVENT_PITCHBEND;
midiEvent.data.control.channel = channel;
midiEvent.data.control.value = ((msb << 7) | lsb) - 8192;
seqEvent.type = SND_SEQ_EVENT_PITCHBEND;
seqEvent.data.control.channel = event.channel;
seqEvent.data.control.value = ((msb << 7) | lsb) - 8192;
}
break;

default:
continue;
--midiEventCount;
break;
} // switch (status)

midiEventCount += 1;
break;
} // case kEngineEventTypeMidi
} break;
} // switch (event.type)
}

@@ -1946,7 +1936,7 @@ public:
#if 0
uint8_t midiData[4];
midiData[0] = 0;
midiData[1] = static_cast<uint8_t>(MIDI_STATUS_NOTE_ON + channel);
midiData[1] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT));
midiData[2] = note;
midiData[3] = velo;

@@ -1965,7 +1955,7 @@ public:
#if 0
uint8_t midiData[4];
midiData[0] = 0;
midiData[1] = static_cast<uint8_t>(MIDI_STATUS_NOTE_OFF + channel);
midiData[1] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT));
midiData[2] = note;
midiData[3] = 0;



+ 66
- 47
source/backend/plugin/FluidSynthPlugin.cpp View File

@@ -1074,7 +1074,6 @@ public:
#ifndef BUILD_BRIDGE
bool allNotesOffSent = false;
#endif
uint32_t time, nEvents = pData->event.portIn->getEventCount();
uint32_t timeOffset = 0;

uint32_t nextBankIds[MAX_MIDI_CHANNELS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0 };
@@ -1082,20 +1081,20 @@ public:
if (pData->midiprog.current >= 0 && pData->midiprog.count > 0 && pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS)
nextBankIds[pData->ctrlChannel] = pData->midiprog.data[pData->midiprog.current].bank;

for (uint32_t i=0; i < nEvents; ++i)
for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i)
{
const EngineEvent& event(pData->event.portIn->getEvent(i));

time = event.time;
if (event.time >= frames)
continue;

CARLA_SAFE_ASSERT_CONTINUE(time < frames);
CARLA_SAFE_ASSERT_BREAK(time >= timeOffset);
CARLA_ASSERT_INT2(event.time >= timeOffset, event.time, timeOffset);

if (time > timeOffset)
if (event.time > timeOffset)
{
if (processSingle(audioOut, time - timeOffset, timeOffset))
if (processSingle(audioOut, event.time - timeOffset, timeOffset))
{
timeOffset = time;
timeOffset = event.time;

if (pData->midiprog.current >= 0 && pData->midiprog.count > 0 && pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS)
nextBankIds[pData->ctrlChannel] = pData->midiprog.data[pData->midiprog.current].bank;
@@ -1215,6 +1214,7 @@ public:
const uint32_t bankId(nextBankIds[event.channel]);
const uint32_t progId(ctrlEvent.param);

// TODO int32_t midiprog.find(bank, prog)
for (uint32_t k=0; k < pData->midiprog.count; ++k)
{
if (pData->midiprog.data[k].bank == bankId && pData->midiprog.data[k].program == progId)
@@ -1265,66 +1265,85 @@ public:
break;
}

case kEngineEventTypeMidi:
{
case kEngineEventTypeMidi: {
const EngineMidiEvent& midiEvent(event.midi);

uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data));
uint8_t channel = event.channel;
if (midiEvent.size > EngineMidiEvent::kDataSize)
continue;

uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data));

// Fix bad note-off
if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0)
if (status == MIDI_STATUS_NOTE_ON && midiEvent.data[2] == 0)
status = MIDI_STATUS_NOTE_OFF;

if (MIDI_IS_STATUS_NOTE_OFF(status))
switch (status)
{
case MIDI_STATUS_NOTE_OFF: {
const uint8_t note = midiEvent.data[1];

fluid_synth_noteoff(fSynth, channel, note);
fluid_synth_noteoff(fSynth, event.channel, note);

pData->postponeRtEvent(kPluginPostRtEventNoteOff, channel, note, 0.0f);
pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, note, 0.0f);
break;
}
else if (MIDI_IS_STATUS_NOTE_ON(status))
{
case MIDI_STATUS_NOTE_ON: {
const uint8_t note = midiEvent.data[1];
const uint8_t velo = midiEvent.data[2];

fluid_synth_noteon(fSynth, channel, note, velo);
fluid_synth_noteon(fSynth, event.channel, note, velo);

pData->postponeRtEvent(kPluginPostRtEventNoteOn, channel, note, velo);
pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, note, velo);
break;
}
else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) && (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) != 0)
{
//const uint8_t note = midiEvent.data[1];
//const uint8_t pressure = midiEvent.data[2];

// TODO, not in fluidsynth API
}
else if (MIDI_IS_STATUS_CONTROL_CHANGE(status) && (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0)
{
const uint8_t control = midiEvent.data[1];
const uint8_t value = midiEvent.data[2];
case MIDI_STATUS_POLYPHONIC_AFTERTOUCH:
if (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH)
{
//const uint8_t note = midiEvent.data[1];
//const uint8_t pressure = midiEvent.data[2];

fluid_synth_cc(fSynth, channel, control, value);
}
else if (MIDI_IS_STATUS_CHANNEL_PRESSURE(status) && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) != 0)
{
const uint8_t pressure = midiEvent.data[1];
// not in fluidsynth API
}
break;

fluid_synth_channel_pressure(fSynth, channel, pressure);;
}
else if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) != 0)
{
const uint8_t lsb = midiEvent.data[1];
const uint8_t msb = midiEvent.data[2];
const int value = ((msb << 7) | lsb);
case MIDI_STATUS_CONTROL_CHANGE:
if (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES)
{
const uint8_t control = midiEvent.data[1];
const uint8_t value = midiEvent.data[2];

fluid_synth_pitch_bend(fSynth, channel, value);
}
fluid_synth_cc(fSynth, event.channel, control, value);
}
break;

break;
}
}
case MIDI_STATUS_CHANNEL_PRESSURE:
if (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE)
{
const uint8_t pressure = midiEvent.data[1];

fluid_synth_channel_pressure(fSynth, event.channel, pressure);;
}
break;

case MIDI_STATUS_PITCH_WHEEL_CONTROL:
if (pData->options & PLUGIN_OPTION_SEND_PITCHBEND)
{
const uint8_t lsb = midiEvent.data[1];
const uint8_t msb = midiEvent.data[2];
const int value = ((msb << 7) | lsb);

fluid_synth_pitch_bend(fSynth, event.channel, value);
}
break;

default:
continue;
break;
} // switch (status)
} break;
} // switch (event.type)
}

pData->postRtEvents.trySplice();


+ 22
- 20
source/backend/plugin/JucePlugin.cpp View File

@@ -609,7 +609,7 @@ public:
CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS);

uint8_t midiEvent[3];
midiEvent[0] = static_cast<uint8_t>((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT));
midiEvent[0] = uint8_t((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT));
midiEvent[1] = note.note;
midiEvent[2] = note.velo;

@@ -627,7 +627,6 @@ public:
#ifndef BUILD_BRIDGE
bool allNotesOffSent = false;
#endif
uint32_t numEvents = pData->event.portIn->getEventCount();
uint32_t nextBankId;

if (pData->midiprog.current >= 0 && pData->midiprog.count > 0)
@@ -635,7 +634,7 @@ public:
else
nextBankId = 0;

for (uint32_t i=0; i < numEvents; ++i)
for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i)
{
const EngineEvent& event(pData->event.portIn->getEvent(i));

@@ -746,8 +745,8 @@ public:
if ((pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0 && ctrlEvent.param <= 0x5F)
{
uint8_t midiData[3];
midiData[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE + i);
midiData[1] = static_cast<uint8_t>(ctrlEvent.param);
midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
midiData[1] = uint8_t(ctrlEvent.param);
midiData[2] = uint8_t(ctrlEvent.value*127.0f);

fMidiBuffer.addEvent(midiData, 3, static_cast<int>(event.time));
@@ -782,7 +781,7 @@ public:
if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
{
uint8_t midiData[3];
midiData[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE + i);
midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
midiData[1] = MIDI_CONTROL_ALL_SOUND_OFF;
midiData[2] = 0;

@@ -802,7 +801,7 @@ public:
#endif

uint8_t midiData[3];
midiData[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE + i);
midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
midiData[1] = MIDI_CONTROL_ALL_NOTES_OFF;
midiData[2] = 0;

@@ -813,16 +812,12 @@ public:
break;
} // case kEngineEventTypeControl

case kEngineEventTypeMidi:
{
case kEngineEventTypeMidi: {
const EngineMidiEvent& midiEvent(event.midi);

uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data));
uint8_t channel = event.channel;
const uint8_t* const midiData(midiEvent.size > EngineMidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data);

// Fix bad note-off
if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0)
status = MIDI_STATUS_NOTE_OFF;
uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiData));

if (status == MIDI_STATUS_CHANNEL_PRESSURE && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0)
continue;
@@ -833,15 +828,22 @@ public:
if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0)
continue;

fMidiBuffer.addEvent(midiEvent.data, midiEvent.size, static_cast<int>(event.time));
// Fix bad note-off
if (status == MIDI_STATUS_NOTE_ON && midiData[2] == 0)
status = MIDI_STATUS_NOTE_OFF;

// put back channel in data
uint8_t midiData2[midiEvent.size];
midiData2[0] = uint8_t(status | (event.channel & MIDI_CHANNEL_BIT));
std::memcpy(midiData2+1, midiData+1, static_cast<std::size_t>(midiEvent.size-1));

fMidiBuffer.addEvent(midiData2, midiEvent.size, static_cast<int>(event.time));

if (status == MIDI_STATUS_NOTE_ON)
pData->postponeRtEvent(kPluginPostRtEventNoteOn, channel, midiEvent.data[1], midiEvent.data[2]);
pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, midiData[1], midiData[2]);
else if (status == MIDI_STATUS_NOTE_OFF)
pData->postponeRtEvent(kPluginPostRtEventNoteOff, channel, midiEvent.data[1], 0.0f);

break;
} // case kEngineEventTypeMidi
pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, midiData[1], 0.0f);
} break;
} // switch (event.type)
}



+ 19
- 24
source/backend/plugin/LinuxSamplerPlugin.cpp View File

@@ -799,11 +799,10 @@ public:
#endif
bool sampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0;

uint32_t nEvents = pData->event.portIn->getEventCount();
uint32_t startTime = 0;
uint32_t timeOffset = 0;

for (uint32_t i=0; i < nEvents; ++i)
for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i)
{
const EngineEvent& event(pData->event.portIn->getEvent(i));

@@ -982,42 +981,38 @@ public:
break;
}

case kEngineEventTypeMidi:
{
case kEngineEventTypeMidi: {
const EngineMidiEvent& midiEvent(event.midi);

uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data));
uint8_t channel = event.channel;
const uint8_t* const midiData(midiEvent.size > EngineMidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data);

// Fix bad note-off
if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0)
status = MIDI_STATUS_NOTE_OFF;
uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiData));

if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) && (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) == 0)
if (status == MIDI_STATUS_CHANNEL_PRESSURE && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0)
continue;
if (MIDI_IS_STATUS_CONTROL_CHANGE(status) && (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) == 0)
if (status == MIDI_STATUS_CONTROL_CHANGE && (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) == 0)
continue;
if (MIDI_IS_STATUS_CHANNEL_PRESSURE(status) && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0)
if (status == MIDI_STATUS_POLYPHONIC_AFTERTOUCH && (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) == 0)
continue;
if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0)
if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0)
continue;

// put back channel in data
uint8_t data[EngineMidiEvent::kDataSize];
std::memcpy(data, event.midi.data, EngineMidiEvent::kDataSize);
// Fix bad note-off
if (status == MIDI_STATUS_NOTE_ON && midiData[2] == 0)
status = MIDI_STATUS_NOTE_OFF;

if (status < 0xF0 && channel < MAX_MIDI_CHANNELS)
data[0] = uint8_t(data[0] + channel);
// put back channel in data
uint8_t midiData2[midiEvent.size];
midiData2[0] = uint8_t(status | (event.channel & MIDI_CHANNEL_BIT));
std::memcpy(midiData2+1, midiData+1, static_cast<std::size_t>(midiEvent.size-1));

fMidiInputPort->DispatchRaw(data, static_cast<int32_t>(sampleAccurate ? startTime : event.time));
fMidiInputPort->DispatchRaw(midiData2, static_cast<int32_t>(sampleAccurate ? startTime : event.time));

if (status == MIDI_STATUS_NOTE_ON)
pData->postponeRtEvent(kPluginPostRtEventNoteOn, channel, data[1], data[2]);
pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, midiData[1], midiData[2]);
else if (status == MIDI_STATUS_NOTE_OFF)
pData->postponeRtEvent(kPluginPostRtEventNoteOff, channel,data[1], 0.0f);

break;
}
pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, midiData[1], 0.0f);
} break;
}
}



+ 35
- 31
source/backend/plugin/Lv2Plugin.cpp View File

@@ -2517,7 +2517,7 @@ public:

if (pData->needsReset)
{
uint8_t midiData[3] = { 0 };
uint8_t midiData[3] = { 0, 0, 0 };

if (fEventsIn.ctrl != nullptr && (fEventsIn.ctrl->type & CARLA_EVENT_TYPE_MIDI) != 0)
{
@@ -2527,7 +2527,7 @@ public:
{
for (uint8_t i=0; i < MAX_MIDI_CHANNELS; ++i)
{
midiData[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE + i);
midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (i & MIDI_CHANNEL_BIT));
midiData[1] = MIDI_CONTROL_ALL_NOTES_OFF;

if (fEventsIn.ctrl->type & CARLA_EVENT_DATA_ATOM)
@@ -2539,7 +2539,7 @@ public:
else if (fEventsIn.ctrl->type & CARLA_EVENT_DATA_MIDI_LL)
lv2midi_put_event(&evInMidiStates[j], 0.0, 3, midiData);

midiData[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE + i);
midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (i & MIDI_CHANNEL_BIT));
midiData[1] = MIDI_CONTROL_ALL_SOUND_OFF;

if (fEventsIn.ctrl->type & CARLA_EVENT_DATA_ATOM)
@@ -2556,7 +2556,7 @@ public:
{
for (uint8_t k=0; k < MAX_MIDI_NOTE; ++k)
{
midiData[0] = static_cast<uint8_t>(MIDI_STATUS_NOTE_OFF + pData->ctrlChannel);
midiData[0] = uint8_t(MIDI_STATUS_NOTE_OFF | (pData->ctrlChannel & MIDI_CHANNEL_BIT));
midiData[1] = k;

if (fEventsIn.ctrl->type & CARLA_EVENT_DATA_ATOM)
@@ -2796,7 +2796,7 @@ public:
CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS);

uint8_t midiEvent[3];
midiEvent[0] = static_cast<uint8_t>((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT));
midiEvent[0] = uint8_t((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT));
midiEvent[1] = note.note;
midiEvent[2] = note.velo;

@@ -2825,7 +2825,6 @@ public:
#endif
bool isSampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0;

uint32_t numEvents = (fEventsIn.ctrl->port != nullptr) ? fEventsIn.ctrl->port->getEventCount() : 0;
uint32_t startTime = 0;
uint32_t timeOffset = 0;
uint32_t nextBankId;
@@ -2835,6 +2834,8 @@ public:
else
nextBankId = 0;

const uint32_t numEvents = (fEventsIn.ctrl->port != nullptr) ? fEventsIn.ctrl->port->getEventCount() : 0;

for (uint32_t i=0; i < numEvents; ++i)
{
const EngineEvent& event(fEventsIn.ctrl->port->getEvent(i));
@@ -2984,8 +2985,8 @@ public:
if ((pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0 && ctrlEvent.param <= 0x5F)
{
uint8_t midiData[3];
midiData[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE + i);
midiData[1] = static_cast<uint8_t>(ctrlEvent.param);
midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
midiData[1] = uint8_t(ctrlEvent.param);
midiData[2] = uint8_t(ctrlEvent.value*127.0f);

const uint32_t mtime(isSampleAccurate ? startTime : event.time);
@@ -3031,7 +3032,7 @@ public:
const uint32_t mtime(isSampleAccurate ? startTime : event.time);

uint8_t midiData[3];
midiData[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE + i);
midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
midiData[1] = MIDI_CONTROL_ALL_SOUND_OFF;
midiData[2] = 0;

@@ -3060,7 +3061,7 @@ public:
const uint32_t mtime(isSampleAccurate ? startTime : event.time);

uint8_t midiData[3];
midiData[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE + i);
midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
midiData[1] = MIDI_CONTROL_ALL_NOTES_OFF;
midiData[2] = 0;

@@ -3078,17 +3079,12 @@ public:
break;
} // case kEngineEventTypeControl

case kEngineEventTypeMidi:
{
case kEngineEventTypeMidi: {
const EngineMidiEvent& midiEvent(event.midi);

uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data));
uint8_t channel = event.channel;
uint32_t mtime = isSampleAccurate ? startTime : event.time;
const uint8_t* const midiData(midiEvent.size > EngineMidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data);

// Fix bad note-off (per LV2 spec)
if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0)
status = MIDI_STATUS_NOTE_OFF;
uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiData));

if (status == MIDI_STATUS_CHANNEL_PRESSURE && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0)
continue;
@@ -3099,24 +3095,32 @@ public:
if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0)
continue;

const uint32_t j = fEventsIn.ctrlIndex;
// Fix bad note-off (per LV2 spec)
if (status == MIDI_STATUS_NOTE_ON && midiData[2] == 0)
status = MIDI_STATUS_NOTE_OFF;

const uint32_t j = fEventsIn.ctrlIndex;
const uint32_t mtime = isSampleAccurate ? startTime : event.time;

// put back channel in data
uint8_t midiData2[midiEvent.size];
midiData2[0] = uint8_t(status | (event.channel & MIDI_CHANNEL_BIT));
std::memcpy(midiData2+1, midiData+1, static_cast<std::size_t>(midiEvent.size-1));

if (fEventsIn.ctrl->type & CARLA_EVENT_DATA_ATOM)
lv2_atom_buffer_write(&evInAtomIters[j], mtime, 0, CARLA_URI_MAP_ID_MIDI_EVENT, midiEvent.size, midiEvent.data);
lv2_atom_buffer_write(&evInAtomIters[j], mtime, 0, CARLA_URI_MAP_ID_MIDI_EVENT, midiEvent.size, midiData2);

else if (fEventsIn.ctrl->type & CARLA_EVENT_DATA_EVENT)
lv2_event_write(&evInEventIters[j], mtime, 0, CARLA_URI_MAP_ID_MIDI_EVENT, midiEvent.size, midiEvent.data);
lv2_event_write(&evInEventIters[j], mtime, 0, CARLA_URI_MAP_ID_MIDI_EVENT, midiEvent.size, midiData2);

else if (fEventsIn.ctrl->type & CARLA_EVENT_DATA_MIDI_LL)
lv2midi_put_event(&evInMidiStates[j], mtime, midiEvent.size, midiEvent.data);
lv2midi_put_event(&evInMidiStates[j], mtime, midiEvent.size, midiData2);

if (status == MIDI_STATUS_NOTE_ON)
pData->postponeRtEvent(kPluginPostRtEventNoteOn, channel, midiEvent.data[1], midiEvent.data[2]);
pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, midiData[1], midiData[2]);
else if (status == MIDI_STATUS_NOTE_OFF)
pData->postponeRtEvent(kPluginPostRtEventNoteOff, channel, midiEvent.data[1], 0.0f);

break;
} // case kEngineEventTypeMidi
pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, midiData[1], 0.0f);
} break;
} // switch (event.type)
}

@@ -3773,7 +3777,7 @@ public:
if (pData->osc.data.target != nullptr)
{
uint8_t midiData[4] = { 0, 0, 0, 0 };
midiData[1] = static_cast<uint8_t>(MIDI_STATUS_NOTE_ON + channel);
midiData[1] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT));
midiData[2] = note;
midiData[3] = velo;
osc_send_midi(pData->osc.data, midiData);
@@ -3787,7 +3791,7 @@ public:
midiEv.event.time.frames = 0;
midiEv.event.body.type = CARLA_URI_MAP_ID_MIDI_EVENT;
midiEv.event.body.size = 3;
midiEv.data[0] = static_cast<uint8_t>(MIDI_STATUS_NOTE_ON + channel);
midiEv.data[0] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT));
midiEv.data[1] = note;
midiEv.data[2] = velo;

@@ -3807,7 +3811,7 @@ public:
if (pData->osc.data.target != nullptr)
{
uint8_t midiData[4] = { 0, 0, 0, 0 };
midiData[1] = static_cast<uint8_t>(MIDI_STATUS_NOTE_OFF + channel);
midiData[1] = uint8_t(MIDI_STATUS_NOTE_OFF | (channel & MIDI_CHANNEL_BIT));
midiData[2] = note;
osc_send_midi(pData->osc.data, midiData);
}
@@ -3820,7 +3824,7 @@ public:
midiEv.event.time.frames = 0;
midiEv.event.body.type = CARLA_URI_MAP_ID_MIDI_EVENT;
midiEv.event.body.size = 3;
midiEv.data[0] = static_cast<uint8_t>(MIDI_STATUS_NOTE_OFF + channel);
midiEv.data[0] = uint8_t(MIDI_STATUS_NOTE_OFF | (channel & MIDI_CHANNEL_BIT));
midiEv.data[1] = note;
midiEv.data[2] = 0;



+ 66
- 65
source/backend/plugin/NativePlugin.cpp View File

@@ -1302,32 +1302,32 @@ public:
{
if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
{
fMidiEventCount = MAX_MIDI_CHANNELS*2;

for (uint8_t k=0, i=MAX_MIDI_CHANNELS; k < MAX_MIDI_CHANNELS; ++k)
{
fMidiEvents[k].data[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE + k);
fMidiEvents[k].data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (k & MIDI_CHANNEL_BIT));
fMidiEvents[k].data[1] = MIDI_CONTROL_ALL_NOTES_OFF;
fMidiEvents[k].data[2] = 0;
fMidiEvents[k].size = 3;

fMidiEvents[k+i].data[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE + k);
fMidiEvents[k+i].data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (k & MIDI_CHANNEL_BIT));
fMidiEvents[k+i].data[1] = MIDI_CONTROL_ALL_SOUND_OFF;
fMidiEvents[k+i].data[2] = 0;
fMidiEvents[k+i].size = 3;
}

fMidiEventCount = MAX_MIDI_CHANNELS*2;
}
else if (pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS)
{
fMidiEventCount = MAX_MIDI_NOTE;

for (uint8_t k=0; k < MAX_MIDI_NOTE; ++k)
{
fMidiEvents[k].data[0] = static_cast<uint8_t>(MIDI_STATUS_NOTE_OFF + pData->ctrlChannel);
fMidiEvents[k].data[0] = uint8_t(MIDI_STATUS_NOTE_OFF | (pData->ctrlChannel & MIDI_CHANNEL_BIT));
fMidiEvents[k].data[1] = k;
fMidiEvents[k].data[2] = 0;
fMidiEvents[k].size = 3;
}

fMidiEventCount = MAX_MIDI_NOTE;
}

pData->needsReset = false;
@@ -1372,19 +1372,18 @@ public:
{
ExternalMidiNote note = { 0, 0, 0 };

//for (RtLinkedList<ExternalMidiNote>::Itenerator it = pData->extNotes.data.begin(); it.valid(); it.next())
while (fMidiEventCount < kPluginMaxMidiEvents*2 && ! pData->extNotes.data.isEmpty())
for (; fMidiEventCount < kPluginMaxMidiEvents*2 && ! pData->extNotes.data.isEmpty();)
{
note = pData->extNotes.data.getFirst(note, true);

CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS);

fMidiEvents[fMidiEventCount].data[0] = static_cast<uint8_t>((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT));
fMidiEvents[fMidiEventCount].data[1] = note.note;
fMidiEvents[fMidiEventCount].data[2] = note.velo;
fMidiEvents[fMidiEventCount].size = 3;
NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]);

fMidiEventCount += 1;
nativeEvent.data[0] = uint8_t((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT));
nativeEvent.data[1] = note.note;
nativeEvent.data[2] = note.velo;
nativeEvent.size = 3;
}

pData->extNotes.mutex.unlock();
@@ -1399,31 +1398,30 @@ public:
#endif
bool sampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0;

uint32_t time, nEvents = pData->event.portIn->getEventCount();
uint32_t startTime = 0;
uint32_t timeOffset = 0;
uint32_t nextBankId = 0;
uint32_t nextBankId;

if (pData->midiprog.current >= 0 && pData->midiprog.count > 0)
nextBankId = pData->midiprog.data[pData->midiprog.current].bank;
else
nextBankId = 0;

for (uint32_t i=0; i < nEvents; ++i)
for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i)
{
const EngineEvent& event(pData->event.portIn->getEvent(i));

time = event.time;

if (time >= frames)
if (event.time >= frames)
continue;

CARLA_ASSERT_INT2(time >= timeOffset, time, timeOffset);
CARLA_ASSERT_INT2(event.time >= timeOffset, event.time, timeOffset);

if (time > timeOffset && sampleAccurate)
if (event.time > timeOffset && sampleAccurate)
{
if (processSingle(audioIn, audioOut, cvIn, cvOut, time - timeOffset, timeOffset))
if (processSingle(audioIn, audioOut, cvIn, cvOut, event.time - timeOffset, timeOffset))
{
startTime = 0;
timeOffset = time;
timeOffset = event.time;

if (pData->midiprog.current >= 0 && pData->midiprog.count > 0)
nextBankId = pData->midiprog.data[pData->midiprog.current].bank;
@@ -1538,14 +1536,14 @@ public:
if (fMidiEventCount >= kPluginMaxMidiEvents*2)
continue;

fMidiEvents[fMidiEventCount].port = 0;
fMidiEvents[fMidiEventCount].time = sampleAccurate ? startTime : time;
fMidiEvents[fMidiEventCount].data[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE + event.channel);
fMidiEvents[fMidiEventCount].data[1] = static_cast<uint8_t>(ctrlEvent.param);
fMidiEvents[fMidiEventCount].data[2] = uint8_t(ctrlEvent.value*127.0f);
fMidiEvents[fMidiEventCount].size = 3;
NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]);
carla_zeroStruct(nativeEvent);

fMidiEventCount += 1;
nativeEvent.time = sampleAccurate ? startTime : event.time;
nativeEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
nativeEvent.data[1] = uint8_t(ctrlEvent.param);
nativeEvent.data[2] = uint8_t(ctrlEvent.value*127.0f);
nativeEvent.size = 3;
}
break;
}
@@ -1586,14 +1584,15 @@ public:
if (fMidiEventCount >= kPluginMaxMidiEvents*2)
continue;

fMidiEvents[fMidiEventCount].port = 0;
fMidiEvents[fMidiEventCount].time = sampleAccurate ? startTime : time;
fMidiEvents[fMidiEventCount].data[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE + event.channel);
fMidiEvents[fMidiEventCount].data[1] = MIDI_CONTROL_ALL_SOUND_OFF;
fMidiEvents[fMidiEventCount].data[2] = 0;
fMidiEvents[fMidiEventCount].size = 3;
NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]);
carla_zeroStruct(nativeEvent);

fMidiEventCount += 1;
nativeEvent.port = 0;
nativeEvent.time = sampleAccurate ? startTime : event.time;
nativeEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
nativeEvent.data[1] = MIDI_CONTROL_ALL_SOUND_OFF;
nativeEvent.data[2] = 0;
nativeEvent.size = 3;
}
break;

@@ -1611,14 +1610,14 @@ public:
if (fMidiEventCount >= kPluginMaxMidiEvents*2)
continue;

fMidiEvents[fMidiEventCount].port = 0;
fMidiEvents[fMidiEventCount].time = sampleAccurate ? startTime : time;
fMidiEvents[fMidiEventCount].data[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE + event.channel);
fMidiEvents[fMidiEventCount].data[1] = MIDI_CONTROL_ALL_NOTES_OFF;
fMidiEvents[fMidiEventCount].data[2] = 0;
fMidiEvents[fMidiEventCount].size = 3;
NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]);
carla_zeroStruct(nativeEvent);

fMidiEventCount += 1;
nativeEvent.time = sampleAccurate ? startTime : event.time;
nativeEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
nativeEvent.data[1] = MIDI_CONTROL_ALL_NOTES_OFF;
nativeEvent.data[2] = 0;
nativeEvent.size = 3;
}
break;
}
@@ -1631,41 +1630,43 @@ public:

const EngineMidiEvent& midiEvent(event.midi);

uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data));
uint8_t channel = event.channel;
if (midiEvent.size > 4)
continue;
static_assert(4 <= EngineMidiEvent::kDataSize, "Incorrect data");

uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data));

if (MIDI_IS_STATUS_CHANNEL_PRESSURE(status) && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0)
if (status == MIDI_STATUS_CHANNEL_PRESSURE && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0)
continue;
if (MIDI_IS_STATUS_CONTROL_CHANGE(status) && (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) == 0)
if (status == MIDI_STATUS_CONTROL_CHANGE && (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) == 0)
continue;
if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) && (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) == 0)
if (status == MIDI_STATUS_POLYPHONIC_AFTERTOUCH && (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) == 0)
continue;
if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0)
if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0)
continue;

// Fix bad note-off
if (status == MIDI_STATUS_NOTE_ON && midiEvent.data[2] == 0)
status = MIDI_STATUS_NOTE_OFF;

fMidiEvents[fMidiEventCount].port = 0;
fMidiEvents[fMidiEventCount].time = sampleAccurate ? startTime : time;
fMidiEvents[fMidiEventCount].size = midiEvent.size;
NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]);
carla_zeroStruct(nativeEvent);

fMidiEvents[fMidiEventCount].data[0] = static_cast<uint8_t>(status + channel);
fMidiEvents[fMidiEventCount].data[1] = midiEvent.data[1];
fMidiEvents[fMidiEventCount].data[2] = midiEvent.data[2];
fMidiEvents[fMidiEventCount].data[3] = midiEvent.data[3];
nativeEvent.port = midiEvent.port;
nativeEvent.time = sampleAccurate ? startTime : event.time;
nativeEvent.size = midiEvent.size;

fMidiEventCount += 1;
nativeEvent.data[0] = uint8_t(status | (event.channel & MIDI_CHANNEL_BIT));
nativeEvent.data[1] = midiEvent.size >= 2 ? midiEvent.data[1] : 0;
nativeEvent.data[2] = midiEvent.size >= 3 ? midiEvent.data[2] : 0;
nativeEvent.data[3] = midiEvent.size == 4 ? midiEvent.data[3] : 0;

if (status == MIDI_STATUS_NOTE_ON)
pData->postponeRtEvent(kPluginPostRtEventNoteOn, channel, midiEvent.data[1], midiEvent.data[2]);
pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, midiEvent.data[1], midiEvent.data[2]);
else if (status == MIDI_STATUS_NOTE_OFF)
pData->postponeRtEvent(kPluginPostRtEventNoteOff, channel, midiEvent.data[1], 0.0f);

break;
}
}
pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, midiEvent.data[1], 0.0f);
} break;
} // switch (event.type)
}

pData->postRtEvents.trySplice();


+ 65
- 68
source/backend/plugin/VstPlugin.cpp View File

@@ -47,6 +47,8 @@ const uint PLUGIN_HAS_COCKOS_EXTENSIONS = 0x2000;
const uint PLUGIN_USES_OLD_VSTSDK = 0x4000;
const uint PLUGIN_WANTS_MIDI_INPUT = 0x8000;

static const int32_t kVstMidiEventSize = static_cast<int32_t>(sizeof(VstMidiEvent));

// -----------------------------------------------------

class VstPlugin : public CarlaPlugin,
@@ -1083,13 +1085,13 @@ public:
for (uint8_t i=0, k=MAX_MIDI_CHANNELS; i < MAX_MIDI_CHANNELS; ++i)
{
fMidiEvents[k].type = kVstMidiType;
fMidiEvents[k].byteSize = static_cast<int32_t>(sizeof(VstMidiEvent));
fMidiEvents[k].midiData[0] = static_cast<char>(MIDI_STATUS_CONTROL_CHANGE + k);
fMidiEvents[k].byteSize = kVstMidiEventSize;
fMidiEvents[k].midiData[0] = char(MIDI_STATUS_CONTROL_CHANGE | (k & MIDI_CHANNEL_BIT));
fMidiEvents[k].midiData[1] = MIDI_CONTROL_ALL_NOTES_OFF;

fMidiEvents[k+i].type = kVstMidiType;
fMidiEvents[k+i].byteSize = static_cast<int32_t>(sizeof(VstMidiEvent));
fMidiEvents[k+i].midiData[0] = static_cast<char>(MIDI_STATUS_CONTROL_CHANGE + k);
fMidiEvents[k+i].byteSize = kVstMidiEventSize;
fMidiEvents[k+i].midiData[0] = char(MIDI_STATUS_CONTROL_CHANGE | (k & MIDI_CHANNEL_BIT));
fMidiEvents[k+i].midiData[1] = MIDI_CONTROL_ALL_SOUND_OFF;
}
}
@@ -1100,9 +1102,9 @@ public:
for (uint8_t i=0; i < MAX_MIDI_NOTE; ++i)
{
fMidiEvents[i].type = kVstMidiType;
fMidiEvents[i].byteSize = static_cast<int32_t>(sizeof(VstMidiEvent));
fMidiEvents[i].midiData[0] = static_cast<char>(MIDI_STATUS_NOTE_OFF + pData->ctrlChannel);
fMidiEvents[i].midiData[1] = static_cast<char>(i);
fMidiEvents[i].byteSize = kVstMidiEventSize;
fMidiEvents[i].midiData[0] = char(MIDI_STATUS_NOTE_OFF | (pData->ctrlChannel & MIDI_CHANNEL_BIT));
fMidiEvents[i].midiData[1] = char(i);
}
}

@@ -1193,13 +1195,13 @@ public:

CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS);

fMidiEvents[fMidiEventCount].type = kVstMidiType;
fMidiEvents[fMidiEventCount].byteSize = static_cast<int32_t>(sizeof(VstMidiEvent));
fMidiEvents[fMidiEventCount].midiData[0] = static_cast<char>((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT));
fMidiEvents[fMidiEventCount].midiData[1] = static_cast<char>(note.note);
fMidiEvents[fMidiEventCount].midiData[2] = static_cast<char>(note.velo);
VstMidiEvent& vstMidiEvent(fMidiEvents[fMidiEventCount++]);

++fMidiEventCount;
vstMidiEvent.type = kVstMidiType;
vstMidiEvent.byteSize = kVstMidiEventSize;
vstMidiEvent.midiData[0] = char((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT));
vstMidiEvent.midiData[1] = char(note.note);
vstMidiEvent.midiData[2] = char(note.velo);
}

pData->extNotes.mutex.unlock();
@@ -1214,11 +1216,10 @@ public:
#endif
bool isSampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0;

uint32_t numEvents = pData->event.portIn->getEventCount();
uint32_t startTime = 0;
uint32_t timeOffset = 0;

for (uint32_t i=0; i < numEvents; ++i)
for (uint32_t i=0, numEvents = pData->event.portIn->getEventCount(); i < numEvents; ++i)
{
const EngineEvent& event(pData->event.portIn->getEvent(i));

@@ -1350,16 +1351,15 @@ public:
if (fMidiEventCount >= kPluginMaxMidiEvents*2)
continue;

carla_zeroStruct<VstMidiEvent>(fMidiEvents[fMidiEventCount]);

fMidiEvents[fMidiEventCount].type = kVstMidiType;
fMidiEvents[fMidiEventCount].byteSize = static_cast<int32_t>(sizeof(VstMidiEvent));
fMidiEvents[fMidiEventCount].midiData[0] = static_cast<char>(MIDI_STATUS_CONTROL_CHANGE + event.channel);
fMidiEvents[fMidiEventCount].midiData[1] = static_cast<char>(ctrlEvent.param);
fMidiEvents[fMidiEventCount].midiData[2] = char(ctrlEvent.value*127.0f);
fMidiEvents[fMidiEventCount].deltaFrames = static_cast<int32_t>(isSampleAccurate ? startTime : event.time);
VstMidiEvent& vstMidiEvent(fMidiEvents[fMidiEventCount++]);
carla_zeroStruct(vstMidiEvent);

++fMidiEventCount;
vstMidiEvent.type = kVstMidiType;
vstMidiEvent.byteSize = kVstMidiEventSize;
vstMidiEvent.deltaFrames = static_cast<int32_t>(isSampleAccurate ? startTime : event.time);
vstMidiEvent.midiData[0] = char(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
vstMidiEvent.midiData[1] = char(ctrlEvent.param);
vstMidiEvent.midiData[2] = char(ctrlEvent.value*127.0f);
}

break;
@@ -1386,15 +1386,14 @@ public:
if (fMidiEventCount >= kPluginMaxMidiEvents*2)
continue;

carla_zeroStruct<VstMidiEvent>(fMidiEvents[fMidiEventCount]);

fMidiEvents[fMidiEventCount].type = kVstMidiType;
fMidiEvents[fMidiEventCount].byteSize = static_cast<int32_t>(sizeof(VstMidiEvent));
fMidiEvents[fMidiEventCount].midiData[0] = static_cast<char>(MIDI_STATUS_CONTROL_CHANGE + event.channel);
fMidiEvents[fMidiEventCount].midiData[1] = MIDI_CONTROL_ALL_SOUND_OFF;
fMidiEvents[fMidiEventCount].deltaFrames = static_cast<int32_t>(isSampleAccurate ? startTime : event.time);
VstMidiEvent& vstMidiEvent(fMidiEvents[fMidiEventCount++]);
carla_zeroStruct(vstMidiEvent);

++fMidiEventCount;
vstMidiEvent.type = kVstMidiType;
vstMidiEvent.byteSize = kVstMidiEventSize;
vstMidiEvent.deltaFrames = static_cast<int32_t>(isSampleAccurate ? startTime : event.time);
vstMidiEvent.midiData[0] = char(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
vstMidiEvent.midiData[1] = MIDI_CONTROL_ALL_SOUND_OFF;
}
break;

@@ -1412,15 +1411,14 @@ public:
if (fMidiEventCount >= kPluginMaxMidiEvents*2)
continue;

carla_zeroStruct<VstMidiEvent>(fMidiEvents[fMidiEventCount]);
VstMidiEvent& vstMidiEvent(fMidiEvents[fMidiEventCount++]);
carla_zeroStruct(vstMidiEvent);

fMidiEvents[fMidiEventCount].type = kVstMidiType;
fMidiEvents[fMidiEventCount].byteSize = static_cast<int32_t>(sizeof(VstMidiEvent));
fMidiEvents[fMidiEventCount].midiData[0] = static_cast<char>(MIDI_STATUS_CONTROL_CHANGE + event.channel);
fMidiEvents[fMidiEventCount].midiData[1] = MIDI_CONTROL_ALL_NOTES_OFF;
fMidiEvents[fMidiEventCount].deltaFrames = static_cast<int32_t>(isSampleAccurate ? startTime : event.time);

++fMidiEventCount;
vstMidiEvent.type = kVstMidiType;
vstMidiEvent.byteSize = kVstMidiEventSize;
vstMidiEvent.deltaFrames = static_cast<int32_t>(isSampleAccurate ? startTime : event.time);
vstMidiEvent.midiData[0] = char(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
vstMidiEvent.midiData[1] = MIDI_CONTROL_ALL_NOTES_OFF;
}
break;
} // switch (ctrlEvent.type)
@@ -1433,12 +1431,11 @@ public:

const EngineMidiEvent& midiEvent(event.midi);

uint8_t status = static_cast<uint8_t>(MIDI_GET_STATUS_FROM_DATA(midiEvent.data));
uint8_t channel = event.channel;
if (midiEvent.size > 3)
continue;
static_assert(3 <= EngineMidiEvent::kDataSize, "Incorrect data");

// Fix bad note-off (per VST spec)
if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0)
status = MIDI_STATUS_NOTE_OFF;
uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data));

if (status == MIDI_STATUS_CHANNEL_PRESSURE && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0)
continue;
@@ -1449,24 +1446,25 @@ public:
if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0)
continue;

carla_zeroStruct<VstMidiEvent>(fMidiEvents[fMidiEventCount]);
// Fix bad note-off
if (status == MIDI_STATUS_NOTE_ON && midiEvent.data[2] == 0)
status = MIDI_STATUS_NOTE_OFF;

fMidiEvents[fMidiEventCount].type = kVstMidiType;
fMidiEvents[fMidiEventCount].byteSize = static_cast<int32_t>(sizeof(VstMidiEvent));
fMidiEvents[fMidiEventCount].midiData[0] = static_cast<char>(status + channel);
fMidiEvents[fMidiEventCount].midiData[1] = static_cast<char>(midiEvent.data[1]);
fMidiEvents[fMidiEventCount].midiData[2] = static_cast<char>(midiEvent.data[2]);
fMidiEvents[fMidiEventCount].deltaFrames = static_cast<int32_t>(isSampleAccurate ? startTime : event.time);
VstMidiEvent& vstMidiEvent(fMidiEvents[fMidiEventCount++]);
carla_zeroStruct(vstMidiEvent);

++fMidiEventCount;
vstMidiEvent.type = kVstMidiType;
vstMidiEvent.byteSize = kVstMidiEventSize;
vstMidiEvent.deltaFrames = static_cast<int32_t>(isSampleAccurate ? startTime : event.time);
vstMidiEvent.midiData[0] = char(status | (event.channel & MIDI_CHANNEL_BIT));
vstMidiEvent.midiData[1] = char(midiEvent.size >= 2 ? midiEvent.data[1] : 0);
vstMidiEvent.midiData[2] = char(midiEvent.size >= 3 ? midiEvent.data[2] : 0);

if (status == MIDI_STATUS_NOTE_ON)
pData->postponeRtEvent(kPluginPostRtEventNoteOn, channel, midiEvent.data[1], midiEvent.data[2]);
pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, midiEvent.data[1], midiEvent.data[2]);
else if (status == MIDI_STATUS_NOTE_OFF)
pData->postponeRtEvent(kPluginPostRtEventNoteOff, channel, midiEvent.data[1], 0.0f);

break;
} // case kEngineEventTypeMidi
pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, midiEvent.data[1], 0.0f);
} break;
} // switch (event.type)
}

@@ -1497,18 +1495,17 @@ public:
if (fMidiEvents[k].type == 0)
break;

CARLA_SAFE_ASSERT_CONTINUE(fMidiEvents[k].deltaFrames >= 0);
CARLA_SAFE_ASSERT_CONTINUE(fMidiEvents[k].midiData[0] != 0);
const VstMidiEvent& vstMidiEvent(fMidiEvents[k]);

const uint8_t status(static_cast<uint8_t>(fMidiEvents[k].midiData[0]));
const uint8_t channel(static_cast<uint8_t>(status < MIDI_STATUS_BIT ? status & MIDI_CHANNEL_BIT : 0));
CARLA_SAFE_ASSERT_CONTINUE(vstMidiEvent.deltaFrames >= 0);
CARLA_SAFE_ASSERT_CONTINUE(vstMidiEvent.midiData[0] != 0);

uint8_t midiData[3];
midiData[0] = static_cast<uint8_t>(fMidiEvents[k].midiData[0]);
midiData[1] = static_cast<uint8_t>(fMidiEvents[k].midiData[1]);
midiData[2] = static_cast<uint8_t>(fMidiEvents[k].midiData[2]);
midiData[0] = static_cast<uint8_t>(vstMidiEvent.midiData[0]);
midiData[1] = static_cast<uint8_t>(vstMidiEvent.midiData[1]);
midiData[2] = static_cast<uint8_t>(vstMidiEvent.midiData[2]);

pData->event.portOut->writeMidiEvent(static_cast<uint32_t>(fMidiEvents[k].deltaFrames), channel, 0, 3, midiData);
pData->event.portOut->writeMidiEvent(static_cast<uint32_t>(vstMidiEvent.deltaFrames), MIDI_GET_CHANNEL_FROM_DATA(midiData), 0, 3, midiData);
}

} // End of MIDI Output
@@ -1740,7 +1737,7 @@ public:

uint8_t midiData[4];
midiData[0] = 0;
midiData[1] = static_cast<uint8_t>(MIDI_STATUS_NOTE_ON + channel);
midiData[1] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT));
midiData[2] = note;
midiData[3] = velo;

@@ -1759,7 +1756,7 @@ public:

uint8_t midiData[4];
midiData[0] = 0;
midiData[1] = static_cast<uint8_t>(MIDI_STATUS_NOTE_OFF + channel);
midiData[1] = uint8_t(MIDI_STATUS_NOTE_OFF | (channel & MIDI_CHANNEL_BIT));
midiData[2] = note;
midiData[3] = 0;



+ 16
- 10
source/includes/CarlaMIDI.h View File

@@ -1,6 +1,6 @@
/*
* Carla common MIDI code
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -35,17 +35,23 @@
#define MIDI_STATUS_CHANNEL_PRESSURE 0xD0 // pressure (0-127), none
#define MIDI_STATUS_PITCH_WHEEL_CONTROL 0xE0 // LSB (0-127), MSB (0-127)

#define MIDI_IS_STATUS_NOTE_OFF(status) (((status) < MIDI_STATUS_BIT) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_NOTE_OFF)
#define MIDI_IS_STATUS_NOTE_ON(status) (((status) < MIDI_STATUS_BIT) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_NOTE_ON)
#define MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) (((status) < MIDI_STATUS_BIT) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_POLYPHONIC_AFTERTOUCH)
#define MIDI_IS_STATUS_CONTROL_CHANGE(status) (((status) < MIDI_STATUS_BIT) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_CONTROL_CHANGE)
#define MIDI_IS_STATUS_PROGRAM_CHANGE(status) (((status) < MIDI_STATUS_BIT) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_PROGRAM_CHANGE)
#define MIDI_IS_STATUS_CHANNEL_PRESSURE(status) (((status) < MIDI_STATUS_BIT) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_CHANNEL_PRESSURE)
#define MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) (((status) < MIDI_STATUS_BIT) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_PITCH_WHEEL_CONTROL)
// MIDI Message type
#define MIDI_IS_CHANNEL_MESSAGE(status) ((status) >= MIDI_STATUS_NOTE_OFF && (status) < MIDI_STATUS_BIT)
#define MIDI_IS_SYSTEM_MESSAGE(status) ((status) >= MIDI_STATUS_BIT && (status) <= 0xFF)
#define MIDI_IS_OSC_MESSAGE(status) ((status) == '/' || (status) == '#')

// MIDI Channel message type
#define MIDI_IS_STATUS_NOTE_OFF(status) (MIDI_IS_CHANNEL_MESSAGE(status) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_NOTE_OFF)
#define MIDI_IS_STATUS_NOTE_ON(status) (MIDI_IS_CHANNEL_MESSAGE(status) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_NOTE_ON)
#define MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) (MIDI_IS_CHANNEL_MESSAGE(status) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_POLYPHONIC_AFTERTOUCH)
#define MIDI_IS_STATUS_CONTROL_CHANGE(status) (MIDI_IS_CHANNEL_MESSAGE(status) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_CONTROL_CHANGE)
#define MIDI_IS_STATUS_PROGRAM_CHANGE(status) (MIDI_IS_CHANNEL_MESSAGE(status) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_PROGRAM_CHANGE)
#define MIDI_IS_STATUS_CHANNEL_PRESSURE(status) (MIDI_IS_CHANNEL_MESSAGE(status) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_CHANNEL_PRESSURE)
#define MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) (MIDI_IS_CHANNEL_MESSAGE(status) && ((status) & MIDI_STATUS_BIT) == MIDI_STATUS_PITCH_WHEEL_CONTROL)

// MIDI Utils
#define MIDI_GET_STATUS_FROM_DATA(data) ((data[0] < MIDI_STATUS_BIT) ? data[0] & MIDI_STATUS_BIT : data[0])
#define MIDI_GET_CHANNEL_FROM_DATA(data) ((data[0] < MIDI_STATUS_BIT) ? data[0] & MIDI_CHANNEL_BIT : 0)
#define MIDI_GET_STATUS_FROM_DATA(data) (MIDI_IS_CHANNEL_MESSAGE(data[0]) ? data[0] & MIDI_STATUS_BIT : data[0])
#define MIDI_GET_CHANNEL_FROM_DATA(data) (MIDI_IS_CHANNEL_MESSAGE(data[0]) ? data[0] & MIDI_CHANNEL_BIT : 0)

// Control Change Messages List
#define MIDI_CONTROL_BANK_SELECT 0x00 // 0-127, MSB


Loading…
Cancel
Save