| @@ -895,7 +895,12 @@ private: | |||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| struct carla_v3_output_event_list : v3_event_list_cpp { | struct carla_v3_output_event_list : v3_event_list_cpp { | ||||
| v3_event* const events; | |||||
| uint16_t numEvents; | |||||
| carla_v3_output_event_list() | carla_v3_output_event_list() | ||||
| : events(new v3_event[kPluginMaxMidiEvents]), | |||||
| numEvents(0) | |||||
| { | { | ||||
| query_interface = v3_query_interface_static<v3_event_list_iid>; | query_interface = v3_query_interface_static<v3_event_list_iid>; | ||||
| ref = v3_ref_static; | ref = v3_ref_static; | ||||
| @@ -905,6 +910,11 @@ struct carla_v3_output_event_list : v3_event_list_cpp { | |||||
| list.add_event = add_event; | list.add_event = add_event; | ||||
| } | } | ||||
| ~carla_v3_output_event_list() | |||||
| { | |||||
| delete[] events; | |||||
| } | |||||
| private: | private: | ||||
| static uint32_t V3_API get_event_count(void*) | static uint32_t V3_API get_event_count(void*) | ||||
| { | { | ||||
| @@ -920,10 +930,13 @@ private: | |||||
| return V3_NOT_IMPLEMENTED; | return V3_NOT_IMPLEMENTED; | ||||
| } | } | ||||
| static v3_result V3_API add_event(void*, v3_event*) | |||||
| static v3_result V3_API add_event(void* const self, v3_event* const event) | |||||
| { | { | ||||
| carla_debug("TODO %s", __PRETTY_FUNCTION__); | |||||
| return V3_NOT_IMPLEMENTED; | |||||
| carla_v3_output_event_list* const me = *static_cast<carla_v3_output_event_list**>(self); | |||||
| if (me->numEvents >= kPluginMaxMidiEvents) | |||||
| return V3_NOMEM; | |||||
| std::memcpy(&me->events[me->numEvents++], event, sizeof(v3_event)); | |||||
| return V3_OK; | |||||
| } | } | ||||
| CARLA_DECLARE_NON_COPYABLE(carla_v3_output_event_list) | CARLA_DECLARE_NON_COPYABLE(carla_v3_output_event_list) | ||||
| @@ -3016,15 +3029,6 @@ public: | |||||
| } // End of Plugin processing (no events) | } // End of Plugin processing (no events) | ||||
| // ------------------------------------------------------------------------------------------------------------ | |||||
| // MIDI Output | |||||
| if (pData->event.portOut != nullptr) | |||||
| { | |||||
| // TODO | |||||
| } // End of MIDI Output | |||||
| fFirstActive = false; | fFirstActive = false; | ||||
| // ------------------------------------------------------------------------------------------------------------ | // ------------------------------------------------------------------------------------------------------------ | ||||
| @@ -3131,6 +3135,67 @@ public: | |||||
| v3_cpp_obj(fV3.processor)->process(fV3.processor, &processData); | v3_cpp_obj(fV3.processor)->process(fV3.processor, &processData); | ||||
| } CARLA_SAFE_EXCEPTION("process"); | } CARLA_SAFE_EXCEPTION("process"); | ||||
| // ------------------------------------------------------------------------------------------------------------ | |||||
| // Handle MIDI output | |||||
| int32_t minPortOutOffset = 0; | |||||
| if (fEvents.eventOutputs != nullptr) | |||||
| { | |||||
| uint8_t midiData[3], midiSize; | |||||
| for (uint32_t i=0; i < fEvents.eventOutputs->numEvents; ++i) | |||||
| { | |||||
| v3_event& v3event(fEvents.eventOutputs->events[i]); | |||||
| if (v3event.bus_index != 0) | |||||
| continue; | |||||
| switch (v3event.type) | |||||
| { | |||||
| case V3_EVENT_NOTE_OFF: | |||||
| midiData[0] = MIDI_STATUS_NOTE_OFF | (v3event.note_off.channel & MIDI_CHANNEL_BIT); | |||||
| midiData[1] = v3event.note_off.pitch; | |||||
| midiData[2] = carla_fixedValue<uint8_t>(0, | |||||
| MAX_MIDI_VALUE - 1, | |||||
| v3event.note_off.velocity * MAX_MIDI_VALUE); | |||||
| midiSize = 3; | |||||
| break; | |||||
| case V3_EVENT_NOTE_ON: | |||||
| midiData[0] = MIDI_STATUS_NOTE_ON | (v3event.note_on.channel & MIDI_CHANNEL_BIT); | |||||
| midiData[1] = v3event.note_on.pitch; | |||||
| midiData[2] = carla_fixedValue<uint8_t>(0, | |||||
| MAX_MIDI_VALUE - 1, | |||||
| v3event.note_on.velocity * MAX_MIDI_VALUE); | |||||
| midiSize = 3; | |||||
| break; | |||||
| case V3_EVENT_POLY_PRESSURE: | |||||
| midiData[0] = MIDI_STATUS_POLYPHONIC_AFTERTOUCH | (v3event.poly_pressure.channel & MIDI_CHANNEL_BIT); | |||||
| midiData[1] = v3event.poly_pressure.pitch; | |||||
| midiData[2] = carla_fixedValue<uint8_t>(0, | |||||
| MAX_MIDI_VALUE - 1, | |||||
| v3event.poly_pressure.pressure * MAX_MIDI_VALUE); | |||||
| midiSize = 3; | |||||
| break; | |||||
| case V3_EVENT_LEGACY_MIDI_CC_OUT: | |||||
| midiData[0] = MIDI_STATUS_CONTROL_CHANGE | (v3event.midi_cc_out.channel & MIDI_CHANNEL_BIT); | |||||
| midiData[1] = v3event.midi_cc_out.cc_number; | |||||
| midiData[2] = v3event.midi_cc_out.value; | |||||
| midiSize = 3; | |||||
| break; | |||||
| default: | |||||
| continue; | |||||
| } | |||||
| if (! pData->event.portOut->writeMidiEvent(static_cast<uint32_t>(v3event.sample_offset), | |||||
| midiSize, | |||||
| midiData)) | |||||
| break; | |||||
| minPortOutOffset = v3event.sample_offset; | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------ | // ------------------------------------------------------------------------------------------------------------ | ||||
| // Handle parameter outputs | // Handle parameter outputs | ||||
| @@ -3157,7 +3222,7 @@ public: | |||||
| channel = pData->param.data[i].midiChannel; | channel = pData->param.data[i].midiChannel; | ||||
| param = static_cast<uint16_t>(pData->param.data[i].mappedControlIndex); | param = static_cast<uint16_t>(pData->param.data[i].mappedControlIndex); | ||||
| pData->event.portOut->writeControlEvent(queue->offset, | |||||
| pData->event.portOut->writeControlEvent(std::max(minPortOutOffset, queue->offset), | |||||
| channel, | channel, | ||||
| kEngineControlEventTypeParameter, | kEngineControlEventTypeParameter, | ||||
| param, | param, | ||||
| @@ -4168,6 +4233,9 @@ private: | |||||
| if (eventInputs != nullptr) | if (eventInputs != nullptr) | ||||
| eventInputs->numEvents = 0; | eventInputs->numEvents = 0; | ||||
| if (eventOutputs != nullptr) | |||||
| eventOutputs->numEvents = 0; | |||||
| } | } | ||||
| void prepare() | void prepare() | ||||