diff --git a/source/backend/carla_native.h b/source/backend/carla_native.h index 38a6eb11d..8e3ed65c3 100644 --- a/source/backend/carla_native.h +++ b/source/backend/carla_native.h @@ -39,21 +39,6 @@ extern "C" { typedef void* HostHandle; typedef void* PluginHandle; -const uint32_t PLUGIN_IS_RTSAFE = 1 << 0; -const uint32_t PLUGIN_IS_SYNTH = 1 << 1; -const uint32_t PLUGIN_HAS_GUI = 1 << 2; -const uint32_t PLUGIN_USES_SINGLE_THREAD = 1 << 3; - -const uint32_t PARAMETER_IS_OUTPUT = 1 << 0; -const uint32_t PARAMETER_IS_ENABLED = 1 << 1; -const uint32_t PARAMETER_IS_AUTOMABLE = 1 << 2; -const uint32_t PARAMETER_IS_BOOLEAN = 1 << 3; -const uint32_t PARAMETER_IS_INTEGER = 1 << 4; -const uint32_t PARAMETER_IS_LOGARITHMIC = 1 << 5; -const uint32_t PARAMETER_USES_SAMPLE_RATE = 1 << 6; -const uint32_t PARAMETER_USES_SCALEPOINTS = 1 << 7; -const uint32_t PARAMETER_USES_CUSTOM_TEXT = 1 << 8; - typedef enum _PluginCategory { PLUGIN_CATEGORY_NONE = 0, //!< Null plugin category. PLUGIN_CATEGORY_SYNTH = 1, //!< A synthesizer or generator. @@ -66,6 +51,25 @@ typedef enum _PluginCategory { PLUGIN_CATEGORY_OTHER = 8 //!< Misc plugin (used to check if the plugin has a category). } PluginCategory; +typedef enum _PluginHints { + PLUGIN_IS_RTSAFE = 1 << 0, + PLUGIN_IS_SYNTH = 1 << 1, + PLUGIN_HAS_GUI = 1 << 2, + PLUGIN_USES_SINGLE_THREAD = 1 << 3 +} PluginHints; + +typedef enum _ParameterHints { + PARAMETER_IS_OUTPUT = 1 << 0, + PARAMETER_IS_ENABLED = 1 << 1, + PARAMETER_IS_AUTOMABLE = 1 << 2, + PARAMETER_IS_BOOLEAN = 1 << 3, + PARAMETER_IS_INTEGER = 1 << 4, + PARAMETER_IS_LOGARITHMIC = 1 << 5, + PARAMETER_USES_SAMPLE_RATE = 1 << 6, + PARAMETER_USES_SCALEPOINTS = 1 << 7, + PARAMETER_USES_CUSTOM_TEXT = 1 << 8 +} ParameterHints; + typedef struct _ParameterScalePoint { const char* label; float value; @@ -85,7 +89,7 @@ typedef struct _ParameterRanges { #define PARAMETER_RANGES_DEFAULT_STEP_LARGE 0.1f typedef struct _Parameter { - uint32_t hints; + ParameterHints hints; const char* name; const char* unit; ParameterRanges ranges; @@ -145,7 +149,7 @@ typedef struct _HostDescriptor { typedef struct _PluginDescriptor { const PluginCategory category; - const uint32_t hints; + const PluginHints hints; const uint32_t audioIns; const uint32_t audioOuts; const uint32_t midiIns; diff --git a/source/backend/native/bypass.c b/source/backend/native/bypass.c index 2bc953875..5b5088bf3 100644 --- a/source/backend/native/bypass.c +++ b/source/backend/native/bypass.c @@ -17,8 +17,6 @@ #include "carla_native.h" -#include // for memcpy - static PluginHandle bypass_instantiate(const PluginDescriptor* _this_, HostDescriptor* host) { // dummy, return non-NULL @@ -37,8 +35,6 @@ static void bypass_process(PluginHandle handle, float** inBuffer, float** outBuf for (uint32_t i=0; i < frames; i++) *in++ = *out++; - //memcpy(out, in, sizeof(float)*frames); - return; // unused @@ -51,19 +47,20 @@ static void bypass_process(PluginHandle handle, float** inBuffer, float** outBuf static const PluginDescriptor bypassDesc = { .category = PLUGIN_CATEGORY_NONE, - .hints = /*PLUGIN_IS_RTSAFE*/0, + .hints = PLUGIN_IS_RTSAFE, .audioIns = 1, .audioOuts = 1, .midiIns = 0, .midiOuts = 0, .parameterIns = 0, .parameterOuts = 0, - .name = "ByPass", - .label = "bypass", - .maker = "falkTX", - .copyright = "GNU GPL v2+", + .name = "ByPass", + .label = "bypass", + .maker = "falkTX", + .copyright = "GNU GPL v2+", .instantiate = bypass_instantiate, + .cleanup = NULL, .get_parameter_count = NULL, .get_parameter_info = NULL, @@ -86,7 +83,6 @@ static const PluginDescriptor bypassDesc = { .activate = NULL, .deactivate = NULL, - .cleanup = NULL, .process = bypass_process }; diff --git a/source/backend/native/midi-split.c b/source/backend/native/midi-split.c new file mode 100644 index 000000000..16eb7b825 --- /dev/null +++ b/source/backend/native/midi-split.c @@ -0,0 +1,130 @@ +/* + * Carla Native Plugins + * Copyright (C) 2012-2013 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 COPYING file + */ + +#include "carla_midi.h" +#include "carla_native.h" + +#include + +typedef struct _MidiSplitHandle { + HostDescriptor* host; +} MidiSplitHandle; + +static PluginHandle midiSplit_instantiate(const PluginDescriptor* _this_, HostDescriptor* host) +{ + MidiSplitHandle* const handle = (MidiSplitHandle*)malloc(sizeof(MidiSplitHandle)); + + if (handle) + { + handle->host = host; + return handle; + } + + return NULL; + + // unused + (void)_this_; +} + +static void midiSplit_cleanup(PluginHandle handle) +{ + free((MidiSplitHandle*)handle); +} + +static void midiSplit_process(PluginHandle handle, float** inBuffer, float** outBuffer, uint32_t frames, uint32_t midiEventCount, const MidiEvent* midiEvents) +{ + HostDescriptor* const host = ((MidiSplitHandle*)handle)->host; + MidiEvent tmpEvent; + + for (uint32_t i=0; i < midiEventCount; i++) + { + const MidiEvent* const midiEvent = &midiEvents[i]; + + const uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent->data); + const uint8_t channel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent->data); + + if (channel >= MAX_MIDI_CHANNELS) + continue; + + tmpEvent.port = channel; + tmpEvent.time = midiEvent->time; + tmpEvent.data[0] = status; + tmpEvent.data[1] = midiEvent->data[1]; + tmpEvent.data[2] = midiEvent->data[2]; + + host->write_midi_event(host, &tmpEvent); + } + + return; + + // unused + (void)inBuffer; + (void)outBuffer; + (void)frames; +} + +// ----------------------------------------------------------------------- + +static const PluginDescriptor midiSplitDesc = { + .category = PLUGIN_CATEGORY_UTILITY, + .hints = PLUGIN_IS_RTSAFE, + .audioIns = 0, + .audioOuts = 0, + .midiIns = 1, + .midiOuts = 16, + .parameterIns = 0, + .parameterOuts = 0, + .name = "MIDI Split", + .label = "midiSplit", + .maker = "falkTX", + .copyright = "GNU GPL v2+", + + .instantiate = midiSplit_instantiate, + .cleanup = midiSplit_cleanup, + + .get_parameter_count = NULL, + .get_parameter_info = NULL, + .get_parameter_value = NULL, + .get_parameter_text = NULL, + + .get_midi_program_count = NULL, + .get_midi_program_info = NULL, + + .set_parameter_value = NULL, + .set_midi_program = NULL, + .set_custom_data = NULL, + + .ui_show = NULL, + .ui_idle = NULL, + + .ui_set_parameter_value = NULL, + .ui_set_midi_program = NULL, + .ui_set_custom_data = NULL, + + .activate = NULL, + .deactivate = NULL, + .process = midiSplit_process +}; + +// ----------------------------------------------------------------------- + +void carla_register_native_plugin_midiSplit() +{ + carla_register_native_plugin(&midiSplitDesc); +} + +// ----------------------------------------------------------------------- diff --git a/source/backend/native/midi-split.cpp b/source/backend/native/midi-split.cpp deleted file mode 100644 index 5b0ad8327..000000000 --- a/source/backend/native/midi-split.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Carla Native Plugins - * Copyright (C) 2012 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 COPYING file - */ - -#include "carla_native.hpp" - -#include - -class MidiSplitPlugin : public PluginDescriptorClass -{ -public: - MidiSplitPlugin(const HostDescriptor* const host) - : PluginDescriptorClass(host) - { - } - - ~MidiSplitPlugin() - { - } - -protected: - // ------------------------------------------------------------------- - // Plugin process calls - - void process(float**, float**, const uint32_t, const uint32_t midiEventCount, const MidiEvent* const midiEvents) - { - for (uint32_t i=0; i < midiEventCount; i++) - { - memcpy(&m_midiEvent, &midiEvents[i], sizeof(MidiEvent)); - - const uint8_t status = m_midiEvent.data[0] & 0xF0; - const uint8_t channel = status & 0x0F; - - CARLA_ASSERT(channel < 16); - - if (channel >= 16) - continue; - - m_midiEvent.port = channel; - m_midiEvent.data[0] = status; - - writeMidiEvent(&m_midiEvent); - } - } - - // ------------------------------------------------------------------- - -private: - MidiEvent m_midiEvent; - - PluginDescriptorClassEND(MidiSplitPlugin) - - CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MidiSplitPlugin) -}; - -// ----------------------------------------------------------------------- - -static const PluginDescriptor midiSplitDesc = { - /* category */ PLUGIN_CATEGORY_UTILITY, - /* hints */ PLUGIN_IS_RTSAFE, - /* audioIns */ 0, - /* audioOuts */ 0, - /* midiIns */ 1, - /* midiOuts */ 16, - /* paramIns */ 0, - /* paramOuts */ 0, - /* name */ "MIDI Split", - /* label */ "midiSplit", - /* maker */ "falkTX", - /* copyright */ "GNU GPL v2+", - PluginDescriptorFILL(MidiSplitPlugin) -}; - -// ----------------------------------------------------------------------- - -void carla_register_native_plugin_midiSplit() -{ - carla_register_native_plugin(&midiSplitDesc); -} - -// ----------------------------------------------------------------------- diff --git a/source/backend/native/midi-through.c b/source/backend/native/midi-through.c new file mode 100644 index 000000000..416cd8b1c --- /dev/null +++ b/source/backend/native/midi-through.c @@ -0,0 +1,113 @@ +/* + * Carla Native Plugins + * Copyright (C) 2012-2013 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 COPYING file + */ + +#include "carla_midi.h" +#include "carla_native.h" + +#include + +typedef struct _MidiThroughHandle { + HostDescriptor* host; +} MidiThroughHandle; + +static PluginHandle midiThrough_instantiate(const PluginDescriptor* _this_, HostDescriptor* host) +{ + MidiThroughHandle* const handle = (MidiThroughHandle*)malloc(sizeof(MidiThroughHandle)); + + if (handle) + { + handle->host = host; + return handle; + } + + return NULL; + + // unused + (void)_this_; +} + +static void midiThrough_cleanup(PluginHandle handle) +{ + free((MidiThroughHandle*)handle); +} + +static void midiThrough_process(PluginHandle handle, float** inBuffer, float** outBuffer, uint32_t frames, uint32_t midiEventCount, const MidiEvent* midiEvents) +{ + HostDescriptor* const host = ((MidiThroughHandle*)handle)->host; + + for (uint32_t i=0; i < midiEventCount; i++) + host->write_midi_event(host, &midiEvents[i]); + + return; + + // unused + (void)inBuffer; + (void)outBuffer; + (void)frames; +} + +// ----------------------------------------------------------------------- + +static const PluginDescriptor midiThroughDesc = { + .category = PLUGIN_CATEGORY_NONE, + .hints = PLUGIN_IS_RTSAFE, + .audioIns = 0, + .audioOuts = 0, + .midiIns = 1, + .midiOuts = 1, + .parameterIns = 0, + .parameterOuts = 0, + .name = "MIDI Through", + .label = "midiThrough", + .maker = "falkTX", + .copyright = "GNU GPL v2+", + + .instantiate = midiThrough_instantiate, + .cleanup = midiThrough_cleanup, + + .get_parameter_count = NULL, + .get_parameter_info = NULL, + .get_parameter_value = NULL, + .get_parameter_text = NULL, + + .get_midi_program_count = NULL, + .get_midi_program_info = NULL, + + .set_parameter_value = NULL, + .set_midi_program = NULL, + .set_custom_data = NULL, + + .ui_show = NULL, + .ui_idle = NULL, + + .ui_set_parameter_value = NULL, + .ui_set_midi_program = NULL, + .ui_set_custom_data = NULL, + + .activate = NULL, + .deactivate = NULL, + .process = midiThrough_process +}; + +// ----------------------------------------------------------------------- + +void carla_register_native_plugin_midiThrough() +{ + carla_register_native_plugin(&midiThroughDesc); +} + +// ----------------------------------------------------------------------- diff --git a/source/backend/native/zynaddsubfx.cpp b/source/backend/native/zynaddsubfx.cpp index 57944c632..a7f111607 100644 --- a/source/backend/native/zynaddsubfx.cpp +++ b/source/backend/native/zynaddsubfx.cpp @@ -1,6 +1,6 @@ /* * Carla Native Plugins - * Copyright (C) 2012 Filipe Coelho + * Copyright (C) 2012-2013 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 @@ -9,7 +9,7 @@ * * 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 + * 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 COPYING file @@ -25,7 +25,9 @@ #include "zynaddsubfx/Misc/Master.h" #include "zynaddsubfx/Misc/Util.h" -//Dummy variables and functions for linking purposes +#include + +// Dummy variables and functions for linking purposes class WavFile; namespace Nio { bool start(void){return 1;} @@ -46,10 +48,9 @@ public: }; ZynAddSubFxPlugin(const HostDescriptor* const host) - : PluginDescriptorClass(host) + : PluginDescriptorClass(host), + m_master(new Master) { - m_master = new Master; - // refresh banks m_master->bank.rescanforbanks(); @@ -67,7 +68,7 @@ public: if (insName.empty() || insName[0] == '\0' || insName[0] == ' ') continue; - ProgramInfo pInfo = { i, instrument, CarlaString(insName.c_str()) }; + ProgramInfo pInfo(i, instrument, insName.c_str()); m_programs.push_back(pInfo); } } @@ -127,6 +128,8 @@ protected: float getParameterValue(const uint32_t index) { + CARLA_ASSERT(index < getParameterCount()); + switch (index) { #if 0 @@ -168,9 +171,15 @@ protected: void setParameterValue(const uint32_t index, const float value) { + CARLA_ASSERT(index < getParameterCount()); + switch (index) { } + + return; + + // unused, TODO Q_UNUSED(value); } @@ -181,7 +190,7 @@ protected: if (program >= BANK_SIZE) return; - const std::string bankdir = m_master->bank.banks[bank].dir; + const std::string bankdir(m_master->bank.banks[bank].dir); if (! bankdir.empty()) { @@ -204,11 +213,17 @@ protected: void process(float**, float** const outBuffer, const uint32_t frames, const uint32_t midiEventCount, const MidiEvent* const midiEvents) { + if (pthread_mutex_trylock(&m_master->mutex) != 0) + { + carla_zeroFloat(outBuffer[0], frames); + carla_zeroFloat(outBuffer[1], frames); + return; + } + uint32_t fromFrame = 0; uint32_t eventIndex = 0; uint32_t nextEventFrame = 0; uint32_t toFrame = 0; - pthread_mutex_lock(&m_master->mutex); do { // Find the time of the next event, if any @@ -237,26 +252,26 @@ protected: // Now process any event(s) at the current timing point while (eventIndex < midiEventCount && midiEvents[eventIndex].time == toFrame) { - uint8_t status = midiEvents[eventIndex].data[0]; - uint8_t channel = status & 0x0F; + const uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvents[eventIndex].data); + const uint8_t channel = MIDI_GET_CHANNEL_FROM_DATA(midiEvents[eventIndex].data); if (MIDI_IS_STATUS_NOTE_OFF(status)) { - uint8_t note = midiEvents[eventIndex].data[1]; + const uint8_t note = midiEvents[eventIndex].data[1]; m_master->noteOff(channel, note); } else if (MIDI_IS_STATUS_NOTE_ON(status)) { - uint8_t note = midiEvents[eventIndex].data[1]; - uint8_t velo = midiEvents[eventIndex].data[2]; + const uint8_t note = midiEvents[eventIndex].data[1]; + const uint8_t velo = midiEvents[eventIndex].data[2]; m_master->noteOn(channel, note, velo); } else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status)) { - uint8_t note = midiEvents[eventIndex].data[1]; - uint8_t pressure = midiEvents[eventIndex].data[2]; + const uint8_t note = midiEvents[eventIndex].data[1]; + const uint8_t pressure = midiEvents[eventIndex].data[2]; m_master->polyphonicAftertouch(channel, note, pressure); } @@ -277,10 +292,18 @@ private: uint32_t bank; uint32_t prog; CarlaString name; + + ProgramInfo(uint32_t bank_, uint32_t prog_, const char* name_) + : bank(bank_), + prog(prog_), + name(name_) {} + + ProgramInfo() = delete; }; + std::vector m_programs; - Master* m_master; + Master* const m_master; public: static int s_instanceCount; @@ -299,8 +322,8 @@ public: config.cfg.SampleRate = synth->samplerate; config.cfg.GzipCompression = 0; - sprng(time(NULL)); - denormalkillbuf = new float [synth->buffersize]; + sprng(std::time(nullptr)); + denormalkillbuf = new float[synth->buffersize]; for (int i=0; i < synth->buffersize; i++) denormalkillbuf[i] = (RND - 0.5f) * 1e-16; } @@ -321,6 +344,8 @@ public: synth = nullptr; } } + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ZynAddSubFxPlugin) }; int ZynAddSubFxPlugin::s_instanceCount = 0; diff --git a/source/includes/carla_midi.h b/source/includes/carla_midi.h index 7cecbee8b..e72ab76bb 100644 --- a/source/includes/carla_midi.h +++ b/source/includes/carla_midi.h @@ -1,6 +1,6 @@ /* * Carla common MIDI code - * Copyright (C) 2012 Filipe Coelho + * Copyright (C) 2012-2013 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 @@ -37,6 +37,10 @@ #define MIDI_IS_STATUS_AFTERTOUCH(status) (((status) & 0xF0) == MIDI_STATUS_AFTERTOUCH) #define MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) (((status) & 0xF0) == MIDI_STATUS_PITCH_WHEEL_CONTROL) +// MIDI Utils +#define MIDI_GET_STATUS_FROM_DATA(data) ((data[0]) & 0xF0) +#define MIDI_GET_CHANNEL_FROM_DATA(data) ((data[0]) & 0x0F) + // Control Change Messages List #define MIDI_CONTROL_BANK_SELECT 0x00 // 0-127, MSB #define MIDI_CONTROL_MODULATION_WHEEL 0x01 // 0-127, MSB