| @@ -740,7 +740,7 @@ public: | |||
| /*! | |||
| * Process all the post-poned events. | |||
| * This function must be called from the main thread (ie, idleGui()) if PLUGIN_USES_SINGLE_THREAD is set. | |||
| * This function must be called from the main thread (ie, idle()) if PLUGIN_USES_SINGLE_THREAD is set. | |||
| */ | |||
| void postRtEventsRun(); | |||
| @@ -48,306 +48,6 @@ CARLA_BACKEND_START_NAMESPACE | |||
| } // Fix editor indentation | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // Fallback data | |||
| static const EngineEvent kFallbackEngineEvent = { kEngineEventTypeNull, 0, 0, {{ kEngineControlEventTypeNull, 0, 0.0f }} }; | |||
| // ----------------------------------------------------------------------- | |||
| // Carla Engine port (Abstract) | |||
| CarlaEnginePort::CarlaEnginePort(const CarlaEngine& engine, const bool isInputPort) noexcept | |||
| : fEngine(engine), | |||
| fIsInput(isInputPort) | |||
| { | |||
| carla_debug("CarlaEnginePort::CarlaEnginePort(%s)", bool2str(isInputPort)); | |||
| } | |||
| CarlaEnginePort::~CarlaEnginePort() noexcept | |||
| { | |||
| carla_debug("CarlaEnginePort::~CarlaEnginePort()"); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Carla Engine Audio port | |||
| CarlaEngineAudioPort::CarlaEngineAudioPort(const CarlaEngine& engine, const bool isInputPort) noexcept | |||
| : CarlaEnginePort(engine, isInputPort), | |||
| fBuffer(nullptr) | |||
| { | |||
| carla_debug("CarlaEngineAudioPort::CarlaEngineAudioPort(%s)", bool2str(isInputPort)); | |||
| } | |||
| CarlaEngineAudioPort::~CarlaEngineAudioPort() noexcept | |||
| { | |||
| carla_debug("CarlaEngineAudioPort::~CarlaEngineAudioPort()"); | |||
| } | |||
| void CarlaEngineAudioPort::initBuffer() noexcept | |||
| { | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Carla Engine CV port | |||
| CarlaEngineCVPort::CarlaEngineCVPort(const CarlaEngine& engine, const bool isInputPort) noexcept | |||
| : CarlaEnginePort(engine, isInputPort), | |||
| fBuffer(nullptr) | |||
| { | |||
| carla_debug("CarlaEngineCVPort::CarlaEngineCVPort(%s)", bool2str(isInputPort)); | |||
| } | |||
| CarlaEngineCVPort::~CarlaEngineCVPort() noexcept | |||
| { | |||
| carla_debug("CarlaEngineCVPort::~CarlaEngineCVPort()"); | |||
| } | |||
| void CarlaEngineCVPort::initBuffer() noexcept | |||
| { | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Carla Engine Event port | |||
| CarlaEngineEventPort::CarlaEngineEventPort(const CarlaEngine& engine, const bool isInputPort) noexcept | |||
| : CarlaEnginePort(engine, isInputPort), | |||
| fBuffer(nullptr), | |||
| fProcessMode(engine.getProccessMode()) | |||
| { | |||
| carla_debug("CarlaEngineEventPort::CarlaEngineEventPort(%s)", bool2str(isInputPort)); | |||
| if (fProcessMode == ENGINE_PROCESS_MODE_PATCHBAY) | |||
| fBuffer = new EngineEvent[kMaxEngineEventInternalCount]; | |||
| } | |||
| CarlaEngineEventPort::~CarlaEngineEventPort() noexcept | |||
| { | |||
| carla_debug("CarlaEngineEventPort::~CarlaEngineEventPort()"); | |||
| if (fProcessMode == ENGINE_PROCESS_MODE_PATCHBAY) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,); | |||
| delete[] fBuffer; | |||
| fBuffer = nullptr; | |||
| } | |||
| } | |||
| void CarlaEngineEventPort::initBuffer() noexcept | |||
| { | |||
| if (fProcessMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || fProcessMode == ENGINE_PROCESS_MODE_BRIDGE) | |||
| fBuffer = fEngine.getInternalEventBuffer(fIsInput); | |||
| else if (fProcessMode == ENGINE_PROCESS_MODE_PATCHBAY && ! fIsInput) | |||
| carla_zeroStruct<EngineEvent>(fBuffer, kMaxEngineEventInternalCount); | |||
| } | |||
| uint32_t CarlaEngineEventPort::getEventCount() const noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fIsInput, 0); | |||
| CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, 0); | |||
| CARLA_SAFE_ASSERT_RETURN(fProcessMode != ENGINE_PROCESS_MODE_SINGLE_CLIENT && fProcessMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS, 0); | |||
| uint32_t i=0; | |||
| for (; i < kMaxEngineEventInternalCount; ++i) | |||
| { | |||
| if (fBuffer[i].type == kEngineEventTypeNull) | |||
| break; | |||
| } | |||
| return i; | |||
| } | |||
| const EngineEvent& CarlaEngineEventPort::getEvent(const uint32_t index) const noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fIsInput, kFallbackEngineEvent); | |||
| CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, kFallbackEngineEvent); | |||
| CARLA_SAFE_ASSERT_RETURN(fProcessMode != ENGINE_PROCESS_MODE_SINGLE_CLIENT && fProcessMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS, kFallbackEngineEvent); | |||
| CARLA_SAFE_ASSERT_RETURN(index < kMaxEngineEventInternalCount, kFallbackEngineEvent); | |||
| return fBuffer[index]; | |||
| } | |||
| const EngineEvent& CarlaEngineEventPort::getEventUnchecked(const uint32_t index) const noexcept | |||
| { | |||
| return fBuffer[index]; | |||
| } | |||
| bool CarlaEngineEventPort::writeControlEvent(const uint32_t time, const uint8_t channel, const EngineControlEventType type, const uint16_t param, const float value) noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(! fIsInput, false); | |||
| CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false); | |||
| CARLA_SAFE_ASSERT_RETURN(fProcessMode != ENGINE_PROCESS_MODE_SINGLE_CLIENT && fProcessMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS, false); | |||
| CARLA_SAFE_ASSERT_RETURN(type != kEngineControlEventTypeNull, false); | |||
| CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS, false); | |||
| CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.0f); | |||
| if (type == kEngineControlEventTypeParameter) { | |||
| CARLA_SAFE_ASSERT(! MIDI_IS_CONTROL_BANK_SELECT(param)); | |||
| } | |||
| // FIXME? should not fix range if midi-program | |||
| const float fixedValue(carla_fixValue<float>(0.0f, 1.0f, value)); | |||
| for (uint32_t i=0; i < kMaxEngineEventInternalCount; ++i) | |||
| { | |||
| EngineEvent& event(fBuffer[i]); | |||
| if (event.type != kEngineEventTypeNull) | |||
| continue; | |||
| event.type = kEngineEventTypeControl; | |||
| event.time = time; | |||
| event.channel = channel; | |||
| event.ctrl.type = type; | |||
| event.ctrl.param = param; | |||
| event.ctrl.value = fixedValue; | |||
| return true; | |||
| } | |||
| carla_stderr2("CarlaEngineEventPort::writeControlEvent() - buffer full"); | |||
| return false; | |||
| } | |||
| bool CarlaEngineEventPort::writeControlEvent(const uint32_t time, const uint8_t channel, const EngineControlEvent& ctrl) noexcept | |||
| { | |||
| return writeControlEvent(time, channel, ctrl.type, ctrl.param, ctrl.value); | |||
| } | |||
| bool CarlaEngineEventPort::writeMidiEvent(const uint32_t time, const uint8_t channel, const uint8_t port, const uint8_t size, const uint8_t* const data) noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(! fIsInput, false); | |||
| CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false); | |||
| CARLA_SAFE_ASSERT_RETURN(fProcessMode != ENGINE_PROCESS_MODE_SINGLE_CLIENT && fProcessMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS, false); | |||
| CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS, false); | |||
| CARLA_SAFE_ASSERT_RETURN(size > 0 && size <= EngineMidiEvent::kDataSize, false); | |||
| CARLA_SAFE_ASSERT_RETURN(data != nullptr, false); | |||
| for (uint32_t i=0; i < kMaxEngineEventInternalCount; ++i) | |||
| { | |||
| EngineEvent& event(fBuffer[i]); | |||
| if (event.type != kEngineEventTypeNull) | |||
| continue; | |||
| event.type = kEngineEventTypeMidi; | |||
| event.time = time; | |||
| event.channel = channel; | |||
| event.midi.port = port; | |||
| event.midi.size = size; | |||
| event.midi.data[0] = uint8_t(MIDI_GET_STATUS_FROM_DATA(data)); | |||
| uint8_t j=1; | |||
| for (; j < size; ++j) | |||
| event.midi.data[j] = data[j]; | |||
| for (; j < EngineMidiEvent::kDataSize; ++j) | |||
| event.midi.data[j] = 0; | |||
| return true; | |||
| } | |||
| carla_stderr2("CarlaEngineEventPort::writeMidiEvent() - buffer full"); | |||
| return false; | |||
| } | |||
| bool CarlaEngineEventPort::writeMidiEvent(const uint32_t time, const uint8_t size, const uint8_t* const data) noexcept | |||
| { | |||
| return writeMidiEvent(time, uint8_t(MIDI_GET_CHANNEL_FROM_DATA(data)), 0, size, data); | |||
| } | |||
| bool CarlaEngineEventPort::writeMidiEvent(const uint32_t time, const uint8_t channel, const EngineMidiEvent& midi) noexcept | |||
| { | |||
| return writeMidiEvent(time, channel, midi.port, midi.size, midi.data); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Carla Engine client (Abstract) | |||
| CarlaEngineClient::CarlaEngineClient(const CarlaEngine& engine) | |||
| : fEngine(engine), | |||
| fActive(false), | |||
| fLatency(0) | |||
| { | |||
| carla_debug("CarlaEngineClient::CarlaEngineClient()"); | |||
| } | |||
| CarlaEngineClient::~CarlaEngineClient() | |||
| { | |||
| CARLA_SAFE_ASSERT(! fActive); | |||
| carla_debug("CarlaEngineClient::~CarlaEngineClient()"); | |||
| } | |||
| void CarlaEngineClient::activate() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT(! fActive); | |||
| carla_debug("CarlaEngineClient::activate()"); | |||
| fActive = true; | |||
| } | |||
| void CarlaEngineClient::deactivate() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT(fActive); | |||
| carla_debug("CarlaEngineClient::deactivate()"); | |||
| fActive = false; | |||
| } | |||
| bool CarlaEngineClient::isActive() const noexcept | |||
| { | |||
| return fActive; | |||
| } | |||
| bool CarlaEngineClient::isOk() const noexcept | |||
| { | |||
| return true; | |||
| } | |||
| uint32_t CarlaEngineClient::getLatency() const noexcept | |||
| { | |||
| return fLatency; | |||
| } | |||
| void CarlaEngineClient::setLatency(const uint32_t samples) noexcept | |||
| { | |||
| fLatency = samples; | |||
| } | |||
| CarlaEnginePort* CarlaEngineClient::addPort(const EnginePortType portType, const char* const name, const bool isInput) /*noexcept*/ | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', nullptr); | |||
| carla_debug("CarlaEngineClient::addPort(%i:%s, \"%s\", %s)", portType, EnginePortType2Str(portType), name, bool2str(isInput)); | |||
| CarlaEnginePort* ret = nullptr; | |||
| try { | |||
| switch (portType) | |||
| { | |||
| case kEnginePortTypeNull: | |||
| break; | |||
| case kEnginePortTypeAudio: | |||
| ret = new CarlaEngineAudioPort(fEngine, isInput); | |||
| case kEnginePortTypeCV: | |||
| ret = new CarlaEngineCVPort(fEngine, isInput); | |||
| case kEnginePortTypeEvent: | |||
| ret = new CarlaEngineEventPort(fEngine, isInput); | |||
| } | |||
| } | |||
| catch(...) { | |||
| return nullptr; | |||
| } | |||
| if (ret != nullptr) | |||
| return ret; | |||
| carla_stderr("CarlaEngineClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput)); | |||
| return nullptr; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Carla Engine | |||
| @@ -0,0 +1,115 @@ | |||
| /* | |||
| * Carla Plugin Host | |||
| * Copyright (C) 2011-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 | |||
| * published by the Free Software Foundation; either version 2 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #include "CarlaEngineInternal.hpp" | |||
| #include "CarlaEngineUtils.hpp" | |||
| // ----------------------------------------------------------------------- | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| #if 0 | |||
| } // Fix editor indentation | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // Carla Engine client (Abstract) | |||
| CarlaEngineClient::CarlaEngineClient(const CarlaEngine& engine) | |||
| : fEngine(engine), | |||
| fActive(false), | |||
| fLatency(0) | |||
| { | |||
| carla_debug("CarlaEngineClient::CarlaEngineClient()"); | |||
| } | |||
| CarlaEngineClient::~CarlaEngineClient() | |||
| { | |||
| CARLA_SAFE_ASSERT(! fActive); | |||
| carla_debug("CarlaEngineClient::~CarlaEngineClient()"); | |||
| } | |||
| void CarlaEngineClient::activate() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT(! fActive); | |||
| carla_debug("CarlaEngineClient::activate()"); | |||
| fActive = true; | |||
| } | |||
| void CarlaEngineClient::deactivate() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT(fActive); | |||
| carla_debug("CarlaEngineClient::deactivate()"); | |||
| fActive = false; | |||
| } | |||
| bool CarlaEngineClient::isActive() const noexcept | |||
| { | |||
| return fActive; | |||
| } | |||
| bool CarlaEngineClient::isOk() const noexcept | |||
| { | |||
| return true; | |||
| } | |||
| uint32_t CarlaEngineClient::getLatency() const noexcept | |||
| { | |||
| return fLatency; | |||
| } | |||
| void CarlaEngineClient::setLatency(const uint32_t samples) noexcept | |||
| { | |||
| fLatency = samples; | |||
| } | |||
| CarlaEnginePort* CarlaEngineClient::addPort(const EnginePortType portType, const char* const name, const bool isInput) /*noexcept*/ | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', nullptr); | |||
| carla_debug("CarlaEngineClient::addPort(%i:%s, \"%s\", %s)", portType, EnginePortType2Str(portType), name, bool2str(isInput)); | |||
| CarlaEnginePort* ret = nullptr; | |||
| try { | |||
| switch (portType) | |||
| { | |||
| case kEnginePortTypeNull: | |||
| break; | |||
| case kEnginePortTypeAudio: | |||
| ret = new CarlaEngineAudioPort(fEngine, isInput); | |||
| case kEnginePortTypeCV: | |||
| ret = new CarlaEngineCVPort(fEngine, isInput); | |||
| case kEnginePortTypeEvent: | |||
| ret = new CarlaEngineEventPort(fEngine, isInput); | |||
| } | |||
| } | |||
| catch(...) { | |||
| return nullptr; | |||
| } | |||
| if (ret != nullptr) | |||
| return ret; | |||
| carla_stderr("CarlaEngineClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput)); | |||
| return nullptr; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| CARLA_BACKEND_END_NAMESPACE | |||
| @@ -0,0 +1,285 @@ | |||
| /* | |||
| * Carla Plugin Host | |||
| * Copyright (C) 2011-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 | |||
| * published by the Free Software Foundation; either version 2 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #include "CarlaEngineInternal.hpp" | |||
| #include "CarlaMIDI.h" | |||
| #include "CarlaMathUtils.hpp" | |||
| // ----------------------------------------------------------------------- | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| #if 0 | |||
| } // Fix editor indentation | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // EngineControlEvent | |||
| void EngineControlEvent::dumpToMidiData(const uint8_t channel, uint8_t& size, uint8_t data[3]) const noexcept | |||
| { | |||
| size = 0; | |||
| switch (type) | |||
| { | |||
| case kEngineControlEventTypeNull: | |||
| break; | |||
| case kEngineControlEventTypeParameter: | |||
| if (param >= MAX_MIDI_VALUE) | |||
| { | |||
| // out of bounds. do nothing | |||
| } | |||
| else if (MIDI_IS_CONTROL_BANK_SELECT(param)) | |||
| { | |||
| size = 3; | |||
| data[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE | (channel & MIDI_CHANNEL_BIT)); | |||
| data[1] = MIDI_CONTROL_BANK_SELECT; | |||
| data[2] = uint8_t(carla_fixValue<float>(0.0f, float(MAX_MIDI_VALUE-1), value)); | |||
| } | |||
| else | |||
| { | |||
| size = 3; | |||
| data[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE | (channel & MIDI_CHANNEL_BIT)); | |||
| data[1] = static_cast<uint8_t>(param); | |||
| data[2] = uint8_t(carla_fixValue<float>(0.0f, 1.0f, value) * float(MAX_MIDI_VALUE-1)); | |||
| } | |||
| break; | |||
| case kEngineControlEventTypeMidiBank: | |||
| size = 3; | |||
| data[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE | (channel & MIDI_CHANNEL_BIT)); | |||
| data[1] = MIDI_CONTROL_BANK_SELECT; | |||
| data[2] = uint8_t(carla_fixValue<uint16_t>(0, MAX_MIDI_VALUE-1, param)); | |||
| break; | |||
| case kEngineControlEventTypeMidiProgram: | |||
| size = 2; | |||
| data[0] = static_cast<uint8_t>(MIDI_STATUS_PROGRAM_CHANGE | (channel & MIDI_CHANNEL_BIT)); | |||
| data[1] = uint8_t(carla_fixValue<uint16_t>(0, MAX_MIDI_VALUE-1, param)); | |||
| break; | |||
| case kEngineControlEventTypeAllSoundOff: | |||
| size = 2; | |||
| data[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE | (channel & MIDI_CHANNEL_BIT)); | |||
| data[1] = MIDI_CONTROL_ALL_SOUND_OFF; | |||
| break; | |||
| case kEngineControlEventTypeAllNotesOff: | |||
| size = 2; | |||
| data[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE | (channel & MIDI_CHANNEL_BIT)); | |||
| data[1] = MIDI_CONTROL_ALL_NOTES_OFF; | |||
| break; | |||
| } | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // EngineEvent | |||
| void EngineEvent::fillFromMidiData(const uint8_t size, const uint8_t* const data) noexcept | |||
| { | |||
| if (size == 0 || data == nullptr || data[0] < MIDI_STATUS_NOTE_OFF) | |||
| { | |||
| type = kEngineEventTypeNull; | |||
| channel = 0; | |||
| return; | |||
| } | |||
| // get channel | |||
| channel = uint8_t(MIDI_GET_CHANNEL_FROM_DATA(data)); | |||
| // get status | |||
| const uint8_t midiStatus(uint8_t(MIDI_GET_STATUS_FROM_DATA(data))); | |||
| if (midiStatus == MIDI_STATUS_CONTROL_CHANGE) | |||
| { | |||
| type = kEngineEventTypeControl; | |||
| const uint8_t midiControl(data[1]); | |||
| if (MIDI_IS_CONTROL_BANK_SELECT(midiControl)) | |||
| { | |||
| CARLA_SAFE_ASSERT_INT(size == 3, size); | |||
| const uint8_t midiBank(data[2]); | |||
| ctrl.type = kEngineControlEventTypeMidiBank; | |||
| ctrl.param = midiBank; | |||
| ctrl.value = 0.0f; | |||
| } | |||
| else if (midiControl == MIDI_CONTROL_ALL_SOUND_OFF) | |||
| { | |||
| CARLA_SAFE_ASSERT_INT(size == 2, size); | |||
| ctrl.type = kEngineControlEventTypeAllSoundOff; | |||
| ctrl.param = 0; | |||
| ctrl.value = 0.0f; | |||
| } | |||
| else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF) | |||
| { | |||
| CARLA_SAFE_ASSERT_INT(size == 2, size); | |||
| ctrl.type = kEngineControlEventTypeAllNotesOff; | |||
| ctrl.param = 0; | |||
| ctrl.value = 0.0f; | |||
| } | |||
| else | |||
| { | |||
| CARLA_SAFE_ASSERT_INT2(size == 3, size, midiControl); | |||
| const uint8_t midiValue(carla_fixValue<uint8_t>(0, 127, data[2])); // ensures 0.0<->1.0 value range | |||
| ctrl.type = kEngineControlEventTypeParameter; | |||
| ctrl.param = midiControl; | |||
| ctrl.value = float(midiValue)/127.0f; | |||
| } | |||
| } | |||
| else if (midiStatus == MIDI_STATUS_PROGRAM_CHANGE) | |||
| { | |||
| CARLA_SAFE_ASSERT_INT2(size == 2, size, data[1]); | |||
| type = kEngineEventTypeControl; | |||
| const uint8_t midiProgram(data[1]); | |||
| ctrl.type = kEngineControlEventTypeMidiProgram; | |||
| ctrl.param = midiProgram; | |||
| ctrl.value = 0.0f; | |||
| } | |||
| else | |||
| { | |||
| type = kEngineEventTypeMidi; | |||
| midi.port = 0; | |||
| midi.size = size; | |||
| if (size > EngineMidiEvent::kDataSize) | |||
| { | |||
| midi.dataExt = data; | |||
| std::memset(midi.data, 0, sizeof(uint8_t)*EngineMidiEvent::kDataSize); | |||
| } | |||
| else | |||
| { | |||
| midi.data[0] = midiStatus; | |||
| uint8_t i=1; | |||
| for (; i < midi.size; ++i) | |||
| midi.data[i] = data[i]; | |||
| for (; i < EngineMidiEvent::kDataSize; ++i) | |||
| midi.data[i] = 0; | |||
| midi.dataExt = nullptr; | |||
| } | |||
| } | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // EngineOptions | |||
| EngineOptions::EngineOptions() noexcept | |||
| #ifdef CARLA_OS_LINUX | |||
| : processMode(ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS), | |||
| transportMode(ENGINE_TRANSPORT_MODE_JACK), | |||
| #else | |||
| : processMode(ENGINE_PROCESS_MODE_CONTINUOUS_RACK), | |||
| transportMode(ENGINE_TRANSPORT_MODE_INTERNAL), | |||
| #endif | |||
| forceStereo(false), | |||
| preferPluginBridges(false), | |||
| preferUiBridges(true), | |||
| uisAlwaysOnTop(true), | |||
| maxParameters(MAX_DEFAULT_PARAMETERS), | |||
| uiBridgesTimeout(4000), | |||
| audioNumPeriods(2), | |||
| audioBufferSize(512), | |||
| audioSampleRate(44100), | |||
| audioDevice(nullptr), | |||
| binaryDir(nullptr), | |||
| resourceDir(nullptr), | |||
| frontendWinId(0) {} | |||
| EngineOptions::~EngineOptions() noexcept | |||
| { | |||
| if (audioDevice != nullptr) | |||
| { | |||
| delete[] audioDevice; | |||
| audioDevice = nullptr; | |||
| } | |||
| if (binaryDir != nullptr) | |||
| { | |||
| delete[] binaryDir; | |||
| binaryDir = nullptr; | |||
| } | |||
| if (resourceDir != nullptr) | |||
| { | |||
| delete[] resourceDir; | |||
| resourceDir = nullptr; | |||
| } | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // EngineTimeInfoBBT | |||
| EngineTimeInfoBBT::EngineTimeInfoBBT() noexcept | |||
| : bar(0), | |||
| beat(0), | |||
| tick(0), | |||
| barStartTick(0.0), | |||
| beatsPerBar(0.0f), | |||
| beatType(0.0f), | |||
| ticksPerBeat(0.0), | |||
| beatsPerMinute(0.0) {} | |||
| // ----------------------------------------------------------------------- | |||
| // EngineTimeInfo | |||
| EngineTimeInfo::EngineTimeInfo() noexcept | |||
| : playing(false), | |||
| frame(0), | |||
| usecs(0), | |||
| valid(0x0) {} | |||
| void EngineTimeInfo::clear() noexcept | |||
| { | |||
| playing = false; | |||
| frame = 0; | |||
| usecs = 0; | |||
| valid = 0x0; | |||
| } | |||
| bool EngineTimeInfo::operator==(const EngineTimeInfo& timeInfo) const noexcept | |||
| { | |||
| if (timeInfo.playing != playing || timeInfo.frame != frame || timeInfo.valid != valid) | |||
| return false; | |||
| if ((valid & kValidBBT) == 0) | |||
| return true; | |||
| if (timeInfo.bbt.beatsPerMinute != bbt.beatsPerMinute) | |||
| return false; | |||
| return true; | |||
| } | |||
| bool EngineTimeInfo::operator!=(const EngineTimeInfo& timeInfo) const noexcept | |||
| { | |||
| return !operator==(timeInfo); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| CARLA_BACKEND_END_NAMESPACE | |||
| @@ -29,258 +29,6 @@ CARLA_BACKEND_START_NAMESPACE | |||
| } // Fix editor indentation | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // EngineControlEvent | |||
| void EngineControlEvent::dumpToMidiData(const uint8_t channel, uint8_t& size, uint8_t data[3]) const noexcept | |||
| { | |||
| size = 0; | |||
| switch (type) | |||
| { | |||
| case kEngineControlEventTypeNull: | |||
| break; | |||
| case kEngineControlEventTypeParameter: | |||
| if (param >= MAX_MIDI_VALUE) | |||
| { | |||
| // out of bounds. do nothing | |||
| } | |||
| else if (MIDI_IS_CONTROL_BANK_SELECT(param)) | |||
| { | |||
| size = 3; | |||
| data[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE | (channel & MIDI_CHANNEL_BIT)); | |||
| data[1] = MIDI_CONTROL_BANK_SELECT; | |||
| data[2] = uint8_t(carla_fixValue<float>(0.0f, float(MAX_MIDI_VALUE-1), value)); | |||
| } | |||
| else | |||
| { | |||
| size = 3; | |||
| data[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE | (channel & MIDI_CHANNEL_BIT)); | |||
| data[1] = static_cast<uint8_t>(param); | |||
| data[2] = uint8_t(carla_fixValue<float>(0.0f, 1.0f, value) * float(MAX_MIDI_VALUE-1)); | |||
| } | |||
| break; | |||
| case kEngineControlEventTypeMidiBank: | |||
| size = 3; | |||
| data[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE | (channel & MIDI_CHANNEL_BIT)); | |||
| data[1] = MIDI_CONTROL_BANK_SELECT; | |||
| data[2] = uint8_t(carla_fixValue<uint16_t>(0, MAX_MIDI_VALUE-1, param)); | |||
| break; | |||
| case kEngineControlEventTypeMidiProgram: | |||
| size = 2; | |||
| data[0] = static_cast<uint8_t>(MIDI_STATUS_PROGRAM_CHANGE | (channel & MIDI_CHANNEL_BIT)); | |||
| data[1] = uint8_t(carla_fixValue<uint16_t>(0, MAX_MIDI_VALUE-1, param)); | |||
| break; | |||
| case kEngineControlEventTypeAllSoundOff: | |||
| size = 2; | |||
| data[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE | (channel & MIDI_CHANNEL_BIT)); | |||
| data[1] = MIDI_CONTROL_ALL_SOUND_OFF; | |||
| break; | |||
| case kEngineControlEventTypeAllNotesOff: | |||
| size = 2; | |||
| data[0] = static_cast<uint8_t>(MIDI_STATUS_CONTROL_CHANGE | (channel & MIDI_CHANNEL_BIT)); | |||
| data[1] = MIDI_CONTROL_ALL_NOTES_OFF; | |||
| break; | |||
| } | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // EngineEvent | |||
| void EngineEvent::fillFromMidiData(const uint8_t size, const uint8_t* const data) noexcept | |||
| { | |||
| if (size == 0 || data == nullptr || data[0] < MIDI_STATUS_NOTE_OFF) | |||
| { | |||
| type = kEngineEventTypeNull; | |||
| channel = 0; | |||
| return; | |||
| } | |||
| // get channel | |||
| channel = uint8_t(MIDI_GET_CHANNEL_FROM_DATA(data)); | |||
| // get status | |||
| const uint8_t midiStatus(uint8_t(MIDI_GET_STATUS_FROM_DATA(data))); | |||
| if (midiStatus == MIDI_STATUS_CONTROL_CHANGE) | |||
| { | |||
| type = kEngineEventTypeControl; | |||
| const uint8_t midiControl(data[1]); | |||
| if (MIDI_IS_CONTROL_BANK_SELECT(midiControl)) | |||
| { | |||
| CARLA_SAFE_ASSERT_INT(size == 3, size); | |||
| const uint8_t midiBank(data[2]); | |||
| ctrl.type = kEngineControlEventTypeMidiBank; | |||
| ctrl.param = midiBank; | |||
| ctrl.value = 0.0f; | |||
| } | |||
| else if (midiControl == MIDI_CONTROL_ALL_SOUND_OFF) | |||
| { | |||
| CARLA_SAFE_ASSERT_INT(size == 2, size); | |||
| ctrl.type = kEngineControlEventTypeAllSoundOff; | |||
| ctrl.param = 0; | |||
| ctrl.value = 0.0f; | |||
| } | |||
| else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF) | |||
| { | |||
| CARLA_SAFE_ASSERT_INT(size == 2, size); | |||
| ctrl.type = kEngineControlEventTypeAllNotesOff; | |||
| ctrl.param = 0; | |||
| ctrl.value = 0.0f; | |||
| } | |||
| else | |||
| { | |||
| CARLA_SAFE_ASSERT_INT2(size == 3, size, midiControl); | |||
| const uint8_t midiValue(carla_fixValue<uint8_t>(0, 127, data[2])); // ensures 0.0<->1.0 value range | |||
| ctrl.type = kEngineControlEventTypeParameter; | |||
| ctrl.param = midiControl; | |||
| ctrl.value = float(midiValue)/127.0f; | |||
| } | |||
| } | |||
| else if (midiStatus == MIDI_STATUS_PROGRAM_CHANGE) | |||
| { | |||
| CARLA_SAFE_ASSERT_INT2(size == 2, size, data[1]); | |||
| type = kEngineEventTypeControl; | |||
| const uint8_t midiProgram(data[1]); | |||
| ctrl.type = kEngineControlEventTypeMidiProgram; | |||
| ctrl.param = midiProgram; | |||
| ctrl.value = 0.0f; | |||
| } | |||
| else | |||
| { | |||
| type = kEngineEventTypeMidi; | |||
| midi.port = 0; | |||
| midi.size = size; | |||
| if (size > EngineMidiEvent::kDataSize) | |||
| { | |||
| midi.dataExt = data; | |||
| std::memset(midi.data, 0, sizeof(uint8_t)*EngineMidiEvent::kDataSize); | |||
| } | |||
| else | |||
| { | |||
| midi.data[0] = midiStatus; | |||
| uint8_t i=1; | |||
| for (; i < midi.size; ++i) | |||
| midi.data[i] = data[i]; | |||
| for (; i < EngineMidiEvent::kDataSize; ++i) | |||
| midi.data[i] = 0; | |||
| midi.dataExt = nullptr; | |||
| } | |||
| } | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // EngineOptions | |||
| EngineOptions::EngineOptions() noexcept | |||
| #ifdef CARLA_OS_LINUX | |||
| : processMode(ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS), | |||
| transportMode(ENGINE_TRANSPORT_MODE_JACK), | |||
| #else | |||
| : processMode(ENGINE_PROCESS_MODE_CONTINUOUS_RACK), | |||
| transportMode(ENGINE_TRANSPORT_MODE_INTERNAL), | |||
| #endif | |||
| forceStereo(false), | |||
| preferPluginBridges(false), | |||
| preferUiBridges(true), | |||
| uisAlwaysOnTop(true), | |||
| maxParameters(MAX_DEFAULT_PARAMETERS), | |||
| uiBridgesTimeout(4000), | |||
| audioNumPeriods(2), | |||
| audioBufferSize(512), | |||
| audioSampleRate(44100), | |||
| audioDevice(nullptr), | |||
| binaryDir(nullptr), | |||
| resourceDir(nullptr), | |||
| frontendWinId(0) {} | |||
| EngineOptions::~EngineOptions() noexcept | |||
| { | |||
| if (audioDevice != nullptr) | |||
| { | |||
| delete[] audioDevice; | |||
| audioDevice = nullptr; | |||
| } | |||
| if (binaryDir != nullptr) | |||
| { | |||
| delete[] binaryDir; | |||
| binaryDir = nullptr; | |||
| } | |||
| if (resourceDir != nullptr) | |||
| { | |||
| delete[] resourceDir; | |||
| resourceDir = nullptr; | |||
| } | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // EngineTimeInfoBBT | |||
| EngineTimeInfoBBT::EngineTimeInfoBBT() noexcept | |||
| : bar(0), | |||
| beat(0), | |||
| tick(0), | |||
| barStartTick(0.0), | |||
| beatsPerBar(0.0f), | |||
| beatType(0.0f), | |||
| ticksPerBeat(0.0), | |||
| beatsPerMinute(0.0) {} | |||
| // ----------------------------------------------------------------------- | |||
| // EngineTimeInfo | |||
| EngineTimeInfo::EngineTimeInfo() noexcept | |||
| : playing(false), | |||
| frame(0), | |||
| usecs(0), | |||
| valid(0x0) {} | |||
| void EngineTimeInfo::clear() noexcept | |||
| { | |||
| playing = false; | |||
| frame = 0; | |||
| usecs = 0; | |||
| valid = 0x0; | |||
| } | |||
| bool EngineTimeInfo::operator==(const EngineTimeInfo& timeInfo) const noexcept | |||
| { | |||
| if (timeInfo.playing != playing || timeInfo.frame != frame || timeInfo.valid != valid) | |||
| return false; | |||
| if ((valid & kValidBBT) == 0) | |||
| return true; | |||
| if (timeInfo.bbt.beatsPerMinute != bbt.beatsPerMinute) | |||
| return false; | |||
| return true; | |||
| } | |||
| bool EngineTimeInfo::operator!=(const EngineTimeInfo& timeInfo) const noexcept | |||
| { | |||
| return !operator==(timeInfo); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // EngineRackBuffers | |||
| @@ -37,7 +37,7 @@ extern int CarlaPluginSetOscBridgeInfo(CarlaPlugin* const plugin, const PluginBr | |||
| // ----------------------------------------------------------------------- | |||
| CarlaEngineOsc::CarlaEngineOsc(CarlaEngine* const engine) | |||
| CarlaEngineOsc::CarlaEngineOsc(CarlaEngine* const engine) noexcept | |||
| : fEngine(engine), | |||
| fServerTCP(nullptr), | |||
| fServerUDP(nullptr) | |||
| @@ -46,7 +46,7 @@ CarlaEngineOsc::CarlaEngineOsc(CarlaEngine* const engine) | |||
| carla_debug("CarlaEngineOsc::CarlaEngineOsc(%p)", engine); | |||
| } | |||
| CarlaEngineOsc::~CarlaEngineOsc() | |||
| CarlaEngineOsc::~CarlaEngineOsc() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT(fName.isEmpty()); | |||
| CARLA_SAFE_ASSERT(fServerPathTCP.isEmpty()); | |||
| @@ -58,7 +58,7 @@ CarlaEngineOsc::~CarlaEngineOsc() | |||
| // ----------------------------------------------------------------------- | |||
| void CarlaEngineOsc::init(const char* const name) | |||
| void CarlaEngineOsc::init(const char* const name) noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fName.isEmpty(),); | |||
| CARLA_SAFE_ASSERT_RETURN(fServerPathTCP.isEmpty(),); | |||
| @@ -106,18 +106,38 @@ void CarlaEngineOsc::init(const char* const name) | |||
| CARLA_SAFE_ASSERT(fServerUDP != nullptr); | |||
| } | |||
| void CarlaEngineOsc::idle() const | |||
| void CarlaEngineOsc::idle() const noexcept | |||
| { | |||
| if (fServerTCP != nullptr) { | |||
| while (lo_server_recv_noblock(fServerTCP, 0) != 0) {} | |||
| if (fServerTCP != nullptr) | |||
| { | |||
| for (;;) | |||
| { | |||
| try { | |||
| if (lo_server_recv_noblock(fServerTCP, 0) == 0) | |||
| break; | |||
| } | |||
| catch(...) { | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| if (fServerUDP != nullptr) { | |||
| while (lo_server_recv_noblock(fServerUDP, 0) != 0) {} | |||
| if (fServerUDP != nullptr) | |||
| { | |||
| for (;;) | |||
| { | |||
| try { | |||
| if (lo_server_recv_noblock(fServerUDP, 0) == 0) | |||
| break; | |||
| } | |||
| catch(...) { | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| void CarlaEngineOsc::close() | |||
| void CarlaEngineOsc::close() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT(fName.isNotEmpty()); | |||
| CARLA_SAFE_ASSERT(fServerPathTCP.isNotEmpty()); | |||
| @@ -130,15 +150,23 @@ void CarlaEngineOsc::close() | |||
| if (fServerTCP != nullptr) | |||
| { | |||
| lo_server_del_method(fServerTCP, nullptr, nullptr); | |||
| lo_server_free(fServerTCP); | |||
| try { | |||
| lo_server_del_method(fServerTCP, nullptr, nullptr); | |||
| } catch(...) {} | |||
| try { | |||
| lo_server_free(fServerTCP); | |||
| } catch(...) {} | |||
| fServerTCP = nullptr; | |||
| } | |||
| if (fServerUDP != nullptr) | |||
| { | |||
| lo_server_del_method(fServerUDP, nullptr, nullptr); | |||
| lo_server_free(fServerUDP); | |||
| try { | |||
| lo_server_del_method(fServerUDP, nullptr, nullptr); | |||
| } catch(...) {} | |||
| try { | |||
| lo_server_free(fServerUDP); | |||
| } catch(...) {} | |||
| fServerUDP = nullptr; | |||
| } | |||
| @@ -57,12 +57,12 @@ CARLA_BACKEND_START_NAMESPACE | |||
| class CarlaEngineOsc | |||
| { | |||
| public: | |||
| CarlaEngineOsc(CarlaEngine* const engine); | |||
| ~CarlaEngineOsc(); | |||
| CarlaEngineOsc(CarlaEngine* const engine) noexcept; | |||
| ~CarlaEngineOsc() noexcept; | |||
| void init(const char* const name); | |||
| void idle() const; | |||
| void close(); | |||
| void init(const char* const name) noexcept; | |||
| void idle() const noexcept; | |||
| void close() noexcept; | |||
| // ------------------------------------------------------------------- | |||
| @@ -76,9 +76,9 @@ public: | |||
| return fServerPathUDP; | |||
| } | |||
| #ifndef BUILD_BRIDGE | |||
| // ------------------------------------------------------------------- | |||
| #ifndef BUILD_BRIDGE | |||
| bool isControlRegistered() const noexcept | |||
| { | |||
| return (fControlData.target != nullptr); | |||
| @@ -0,0 +1,249 @@ | |||
| /* | |||
| * Carla Plugin Host | |||
| * Copyright (C) 2011-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 | |||
| * published by the Free Software Foundation; either version 2 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #include "CarlaEngineInternal.hpp" | |||
| #include "CarlaMathUtils.hpp" | |||
| #include "CarlaMIDI.h" | |||
| // ----------------------------------------------------------------------- | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| #if 0 | |||
| } // Fix editor indentation | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // Fallback data | |||
| static const EngineEvent kFallbackEngineEvent = { kEngineEventTypeNull, 0, 0, {{ kEngineControlEventTypeNull, 0, 0.0f }} }; | |||
| // ----------------------------------------------------------------------- | |||
| // Carla Engine port (Abstract) | |||
| CarlaEnginePort::CarlaEnginePort(const CarlaEngine& engine, const bool isInputPort) noexcept | |||
| : fEngine(engine), | |||
| fIsInput(isInputPort) | |||
| { | |||
| carla_debug("CarlaEnginePort::CarlaEnginePort(%s)", bool2str(isInputPort)); | |||
| } | |||
| CarlaEnginePort::~CarlaEnginePort() noexcept | |||
| { | |||
| carla_debug("CarlaEnginePort::~CarlaEnginePort()"); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Carla Engine Audio port | |||
| CarlaEngineAudioPort::CarlaEngineAudioPort(const CarlaEngine& engine, const bool isInputPort) noexcept | |||
| : CarlaEnginePort(engine, isInputPort), | |||
| fBuffer(nullptr) | |||
| { | |||
| carla_debug("CarlaEngineAudioPort::CarlaEngineAudioPort(%s)", bool2str(isInputPort)); | |||
| } | |||
| CarlaEngineAudioPort::~CarlaEngineAudioPort() noexcept | |||
| { | |||
| carla_debug("CarlaEngineAudioPort::~CarlaEngineAudioPort()"); | |||
| } | |||
| void CarlaEngineAudioPort::initBuffer() noexcept | |||
| { | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Carla Engine CV port | |||
| CarlaEngineCVPort::CarlaEngineCVPort(const CarlaEngine& engine, const bool isInputPort) noexcept | |||
| : CarlaEnginePort(engine, isInputPort), | |||
| fBuffer(nullptr) | |||
| { | |||
| carla_debug("CarlaEngineCVPort::CarlaEngineCVPort(%s)", bool2str(isInputPort)); | |||
| } | |||
| CarlaEngineCVPort::~CarlaEngineCVPort() noexcept | |||
| { | |||
| carla_debug("CarlaEngineCVPort::~CarlaEngineCVPort()"); | |||
| } | |||
| void CarlaEngineCVPort::initBuffer() noexcept | |||
| { | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Carla Engine Event port | |||
| CarlaEngineEventPort::CarlaEngineEventPort(const CarlaEngine& engine, const bool isInputPort) noexcept | |||
| : CarlaEnginePort(engine, isInputPort), | |||
| fBuffer(nullptr), | |||
| fProcessMode(engine.getProccessMode()) | |||
| { | |||
| carla_debug("CarlaEngineEventPort::CarlaEngineEventPort(%s)", bool2str(isInputPort)); | |||
| if (fProcessMode == ENGINE_PROCESS_MODE_PATCHBAY) | |||
| fBuffer = new EngineEvent[kMaxEngineEventInternalCount]; | |||
| } | |||
| CarlaEngineEventPort::~CarlaEngineEventPort() noexcept | |||
| { | |||
| carla_debug("CarlaEngineEventPort::~CarlaEngineEventPort()"); | |||
| if (fProcessMode == ENGINE_PROCESS_MODE_PATCHBAY) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,); | |||
| delete[] fBuffer; | |||
| fBuffer = nullptr; | |||
| } | |||
| } | |||
| void CarlaEngineEventPort::initBuffer() noexcept | |||
| { | |||
| if (fProcessMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || fProcessMode == ENGINE_PROCESS_MODE_BRIDGE) | |||
| fBuffer = fEngine.getInternalEventBuffer(fIsInput); | |||
| else if (fProcessMode == ENGINE_PROCESS_MODE_PATCHBAY && ! fIsInput) | |||
| carla_zeroStruct<EngineEvent>(fBuffer, kMaxEngineEventInternalCount); | |||
| } | |||
| uint32_t CarlaEngineEventPort::getEventCount() const noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fIsInput, 0); | |||
| CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, 0); | |||
| CARLA_SAFE_ASSERT_RETURN(fProcessMode != ENGINE_PROCESS_MODE_SINGLE_CLIENT && fProcessMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS, 0); | |||
| uint32_t i=0; | |||
| for (; i < kMaxEngineEventInternalCount; ++i) | |||
| { | |||
| if (fBuffer[i].type == kEngineEventTypeNull) | |||
| break; | |||
| } | |||
| return i; | |||
| } | |||
| const EngineEvent& CarlaEngineEventPort::getEvent(const uint32_t index) const noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fIsInput, kFallbackEngineEvent); | |||
| CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, kFallbackEngineEvent); | |||
| CARLA_SAFE_ASSERT_RETURN(fProcessMode != ENGINE_PROCESS_MODE_SINGLE_CLIENT && fProcessMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS, kFallbackEngineEvent); | |||
| CARLA_SAFE_ASSERT_RETURN(index < kMaxEngineEventInternalCount, kFallbackEngineEvent); | |||
| return fBuffer[index]; | |||
| } | |||
| const EngineEvent& CarlaEngineEventPort::getEventUnchecked(const uint32_t index) const noexcept | |||
| { | |||
| return fBuffer[index]; | |||
| } | |||
| bool CarlaEngineEventPort::writeControlEvent(const uint32_t time, const uint8_t channel, const EngineControlEventType type, const uint16_t param, const float value) noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(! fIsInput, false); | |||
| CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false); | |||
| CARLA_SAFE_ASSERT_RETURN(fProcessMode != ENGINE_PROCESS_MODE_SINGLE_CLIENT && fProcessMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS, false); | |||
| CARLA_SAFE_ASSERT_RETURN(type != kEngineControlEventTypeNull, false); | |||
| CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS, false); | |||
| CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.0f); | |||
| if (type == kEngineControlEventTypeParameter) { | |||
| CARLA_SAFE_ASSERT(! MIDI_IS_CONTROL_BANK_SELECT(param)); | |||
| } | |||
| // FIXME? should not fix range if midi-program | |||
| const float fixedValue(carla_fixValue<float>(0.0f, 1.0f, value)); | |||
| for (uint32_t i=0; i < kMaxEngineEventInternalCount; ++i) | |||
| { | |||
| EngineEvent& event(fBuffer[i]); | |||
| if (event.type != kEngineEventTypeNull) | |||
| continue; | |||
| event.type = kEngineEventTypeControl; | |||
| event.time = time; | |||
| event.channel = channel; | |||
| event.ctrl.type = type; | |||
| event.ctrl.param = param; | |||
| event.ctrl.value = fixedValue; | |||
| return true; | |||
| } | |||
| carla_stderr2("CarlaEngineEventPort::writeControlEvent() - buffer full"); | |||
| return false; | |||
| } | |||
| bool CarlaEngineEventPort::writeControlEvent(const uint32_t time, const uint8_t channel, const EngineControlEvent& ctrl) noexcept | |||
| { | |||
| return writeControlEvent(time, channel, ctrl.type, ctrl.param, ctrl.value); | |||
| } | |||
| bool CarlaEngineEventPort::writeMidiEvent(const uint32_t time, const uint8_t channel, const uint8_t port, const uint8_t size, const uint8_t* const data) noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(! fIsInput, false); | |||
| CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false); | |||
| CARLA_SAFE_ASSERT_RETURN(fProcessMode != ENGINE_PROCESS_MODE_SINGLE_CLIENT && fProcessMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS, false); | |||
| CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS, false); | |||
| CARLA_SAFE_ASSERT_RETURN(size > 0 && size <= EngineMidiEvent::kDataSize, false); | |||
| CARLA_SAFE_ASSERT_RETURN(data != nullptr, false); | |||
| for (uint32_t i=0; i < kMaxEngineEventInternalCount; ++i) | |||
| { | |||
| EngineEvent& event(fBuffer[i]); | |||
| if (event.type != kEngineEventTypeNull) | |||
| continue; | |||
| event.type = kEngineEventTypeMidi; | |||
| event.time = time; | |||
| event.channel = channel; | |||
| event.midi.port = port; | |||
| event.midi.size = size; | |||
| event.midi.data[0] = uint8_t(MIDI_GET_STATUS_FROM_DATA(data)); | |||
| uint8_t j=1; | |||
| for (; j < size; ++j) | |||
| event.midi.data[j] = data[j]; | |||
| for (; j < EngineMidiEvent::kDataSize; ++j) | |||
| event.midi.data[j] = 0; | |||
| return true; | |||
| } | |||
| carla_stderr2("CarlaEngineEventPort::writeMidiEvent() - buffer full"); | |||
| return false; | |||
| } | |||
| bool CarlaEngineEventPort::writeMidiEvent(const uint32_t time, const uint8_t size, const uint8_t* const data) noexcept | |||
| { | |||
| return writeMidiEvent(time, uint8_t(MIDI_GET_CHANNEL_FROM_DATA(data)), 0, size, data); | |||
| } | |||
| bool CarlaEngineEventPort::writeMidiEvent(const uint32_t time, const uint8_t channel, const EngineMidiEvent& midi) noexcept | |||
| { | |||
| return writeMidiEvent(time, channel, midi.port, midi.size, midi.data); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| CARLA_BACKEND_END_NAMESPACE | |||
| @@ -23,7 +23,7 @@ CARLA_BACKEND_START_NAMESPACE | |||
| // ----------------------------------------------------------------------- | |||
| CarlaEngineThread::CarlaEngineThread(CarlaEngine* const engine) | |||
| CarlaEngineThread::CarlaEngineThread(CarlaEngine* const engine) noexcept | |||
| : CarlaThread("CarlaEngineThread"), | |||
| fEngine(engine) | |||
| { | |||
| @@ -31,14 +31,14 @@ CarlaEngineThread::CarlaEngineThread(CarlaEngine* const engine) | |||
| carla_debug("CarlaEngineThread::CarlaEngineThread(%p)", engine); | |||
| } | |||
| CarlaEngineThread::~CarlaEngineThread() | |||
| CarlaEngineThread::~CarlaEngineThread() noexcept | |||
| { | |||
| carla_debug("CarlaEngineThread::~CarlaEngineThread()"); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| void CarlaEngineThread::run() | |||
| void CarlaEngineThread::run() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fEngine != nullptr,); | |||
| CARLA_SAFE_ASSERT(fEngine->isRunning()); | |||
| @@ -71,7 +71,14 @@ void CarlaEngineThread::run() | |||
| if (oscRegisted || ! needsSingleThread) | |||
| { | |||
| if (! needsSingleThread) | |||
| plugin->postRtEventsRun(); | |||
| { | |||
| try { | |||
| plugin->postRtEventsRun(); | |||
| } | |||
| catch (...) { | |||
| carla_stderr2("Caught exception during postRtEventsRun()"); | |||
| } | |||
| } | |||
| if (hasUi || oscRegisted) | |||
| { | |||
| @@ -28,15 +28,16 @@ CARLA_BACKEND_START_NAMESPACE | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // CarlaEngineThread | |||
| class CarlaEngineThread : public CarlaThread | |||
| { | |||
| public: | |||
| CarlaEngineThread(CarlaEngine* const engine); | |||
| ~CarlaEngineThread() override; | |||
| CarlaEngineThread(CarlaEngine* const engine) noexcept; | |||
| ~CarlaEngineThread() noexcept override; | |||
| protected: | |||
| void run() override; | |||
| void run() noexcept override; | |||
| private: | |||
| CarlaEngine* const fEngine; | |||
| @@ -188,6 +188,13 @@ private: \ | |||
| static void operator delete(void*); | |||
| #endif | |||
| /* Define CARLA_CATCH_MSG */ | |||
| #define CARLA_CATCH_MSG(msg, after) \ | |||
| catch(...) { \ | |||
| carla_stderr2("Caught exception: " msg); \ | |||
| after \ | |||
| } | |||
| /* Define EXTERN_C */ | |||
| #ifdef __cplusplus | |||
| # define EXTERN_C extern "C" | |||
| @@ -0,0 +1,61 @@ | |||
| /* | |||
| * Carla Tests | |||
| * Copyright (C) 2013-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 | |||
| * published by the Free Software Foundation; either version 2 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #include "CarlaDefines.h" | |||
| #include "CarlaUtils.hpp" | |||
| struct Struct1 { | |||
| Struct1() noexcept {} | |||
| ~Struct1() noexcept {} | |||
| void throwHere() | |||
| { | |||
| throw 1; | |||
| } | |||
| }; | |||
| struct Struct2 { | |||
| Struct2() { throw 2; } | |||
| ~Struct2() noexcept {} | |||
| void throwHere() | |||
| { | |||
| throw 3; | |||
| } | |||
| }; | |||
| int main() | |||
| { | |||
| Struct1 a; | |||
| Struct2* b = nullptr; | |||
| try { | |||
| a.throwHere(); | |||
| } CARLA_CATCH_MSG("Struct1 throw", carla_stdout("after text1 here");) | |||
| try { | |||
| b = new Struct2; | |||
| } CARLA_CATCH_MSG("Struct2 throw", carla_stdout("after text2 here");) | |||
| if (b != nullptr) | |||
| { | |||
| delete b; | |||
| b = nullptr; | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -69,6 +69,10 @@ Engine: Engine.cpp | |||
| env LD_LIBRARY_PATH=../backend valgrind --leak-check=full ./$@ | |||
| # ../modules/juce_audio_basics.a ../modules/juce_core.a \ | |||
| Exception: Exception.cpp | |||
| $(CXX) $< $(PEDANTIC_CXX_FLAGS) -o $@ | |||
| # valgrind ./$@ | |||
| EngineEvents: EngineEvents.cpp | |||
| $(CXX) $< $(PEDANTIC_CXX_FLAGS) -L../backend -lcarla_standalone2 -o $@ | |||
| env LD_LIBRARY_PATH=../backend valgrind ./$@ | |||