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