/* * Carla Plugin Host * Copyright (C) 2011-2014 Filipe Coelho * * 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 "CarlaEngine.hpp" #include "CarlaMIDI.h" #include "CarlaUtils.hpp" // ----------------------------------------------------------------------- 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 isInput) : fEngine(engine), fIsInput(isInput) { carla_debug("CarlaEnginePort::CarlaEnginePort(%s)", bool2str(isInput)); } CarlaEnginePort::~CarlaEnginePort() { carla_debug("CarlaEnginePort::~CarlaEnginePort()"); } // ----------------------------------------------------------------------- // Carla Engine Audio port CarlaEngineAudioPort::CarlaEngineAudioPort(const CarlaEngine& engine, const bool isInput) : CarlaEnginePort(engine, isInput), fBuffer(nullptr) { carla_debug("CarlaEngineAudioPort::CarlaEngineAudioPort(%s)", bool2str(isInput)); } CarlaEngineAudioPort::~CarlaEngineAudioPort() { carla_debug("CarlaEngineAudioPort::~CarlaEngineAudioPort()"); } void CarlaEngineAudioPort::initBuffer() { } // ----------------------------------------------------------------------- // Carla Engine CV port CarlaEngineCVPort::CarlaEngineCVPort(const CarlaEngine& engine, const bool isInput) : CarlaEnginePort(engine, isInput), fBuffer(nullptr), fProcessMode(engine.getProccessMode()) { carla_debug("CarlaEngineCVPort::CarlaEngineCVPort(%s)", bool2str(isInput)); if (fProcessMode != ENGINE_PROCESS_MODE_SINGLE_CLIENT && fProcessMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS) fBuffer = new float[engine.getBufferSize()]; } CarlaEngineCVPort::~CarlaEngineCVPort() { carla_debug("CarlaEngineCVPort::~CarlaEngineCVPort()"); if (fProcessMode != ENGINE_PROCESS_MODE_SINGLE_CLIENT && fProcessMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS) { CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,); delete[] fBuffer; fBuffer = nullptr; } } void CarlaEngineCVPort::initBuffer() { CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,); CARLA_SAFE_ASSERT_RETURN(fProcessMode != ENGINE_PROCESS_MODE_SINGLE_CLIENT && fProcessMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS,); carla_zeroFloat(fBuffer, fEngine.getBufferSize()); } void CarlaEngineCVPort::setBufferSize(const uint32_t bufferSize) { CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,); CARLA_SAFE_ASSERT_RETURN(fProcessMode != ENGINE_PROCESS_MODE_SINGLE_CLIENT && fProcessMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS,); delete[] fBuffer; fBuffer = new float[bufferSize]; } // ----------------------------------------------------------------------- // Carla Engine Event port CarlaEngineEventPort::CarlaEngineEventPort(const CarlaEngine& engine, const bool isInput) : CarlaEnginePort(engine, isInput), fBuffer(nullptr), fProcessMode(engine.getProccessMode()) { carla_debug("CarlaEngineEventPort::CarlaEngineEventPort(%s)", bool2str(isInput)); if (fProcessMode == ENGINE_PROCESS_MODE_PATCHBAY) fBuffer = new EngineEvent[EngineEvent::kMaxInternalCount]; } CarlaEngineEventPort::~CarlaEngineEventPort() { carla_debug("CarlaEngineEventPort::~CarlaEngineEventPort()"); if (fProcessMode == ENGINE_PROCESS_MODE_PATCHBAY) { CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,); delete[] fBuffer; fBuffer = nullptr; } } void CarlaEngineEventPort::initBuffer() { 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(fBuffer, EngineEvent::kMaxInternalCount); } 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 < EngineEvent::kMaxInternalCount; ++i) { if (fBuffer[i].type == kEngineEventTypeNull) break; } return i; } const EngineEvent& CarlaEngineEventPort::getEvent(const uint32_t index) 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 < EngineEvent::kMaxInternalCount, kFallbackEngineEvent); return fBuffer[index]; } const EngineEvent& CarlaEngineEventPort::getEventUnchecked(const uint32_t index) 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) { 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)); } const float fixedValue(carla_fixValue(0.0f, 1.0f, value)); for (uint32_t i=0; i < EngineEvent::kMaxInternalCount; ++i) { if (fBuffer[i].type != kEngineEventTypeNull) continue; EngineEvent& event(fBuffer[i]); 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) { 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) { 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 < EngineEvent::kMaxInternalCount; ++i) { if (fBuffer[i].type != kEngineEventTypeNull) continue; EngineEvent& event(fBuffer[i]); 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) { 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) { return writeMidiEvent(time, channel, midi.port, midi.size, midi.data); } // ----------------------------------------------------------------------- CARLA_BACKEND_END_NAMESPACE