From 5c693588afb767370c9d0869aa0d795c981bc200 Mon Sep 17 00:00:00 2001 From: Milk Brewster Date: Thu, 28 Jun 2018 09:08:07 +0100 Subject: [PATCH] MIDI Channel A/B (#622) * Create midi-channel-ab.c midi-channel-filter.c + bits of midi-split.c = an attempt at a per channel output A/B routing * Update Makefile for ab plugin * Update midi-channel-ab.c fixed incorrect copy/paste * add A/B plugin * Add A/B plugin * Add A/B plugin * Add A/B plugin * Add A/B plugin * Rename and reorder binary options * Fix output order * Fix order(?) * Fix order * More efficient code, floats to booleans, comparison fixes * Revert mistake * Fix midi output port numbers * Fix maker name * Add copyright header line --- source/native-plugins/Makefile | 1 + source/native-plugins/_all.all.c | 2 + source/native-plugins/_all.base.c | 2 + source/native-plugins/_data.all.cpp | 16 ++ source/native-plugins/_data.base.cpp | 16 ++ source/native-plugins/midi-channel-ab.c | 211 ++++++++++++++++++++++++ source/plugin/carla-base.cpp | 1 + 7 files changed, 249 insertions(+) create mode 100644 source/native-plugins/midi-channel-ab.c diff --git a/source/native-plugins/Makefile b/source/native-plugins/Makefile index c2f80235c..f99f0e52d 100644 --- a/source/native-plugins/Makefile +++ b/source/native-plugins/Makefile @@ -28,6 +28,7 @@ OBJS = \ $(OBJDIR)/bypass.c.o \ $(OBJDIR)/lfo.c.o \ $(OBJDIR)/midi-channel-filter.c.o \ + $(OBJDIR)/midi-channel-ab.c.o \ $(OBJDIR)/midi-gain.c.o \ $(OBJDIR)/midi-join.c.o \ $(OBJDIR)/midi-split.c.o \ diff --git a/source/native-plugins/_all.all.c b/source/native-plugins/_all.all.c index 1d102bca7..d10555ae3 100644 --- a/source/native-plugins/_all.all.c +++ b/source/native-plugins/_all.all.c @@ -28,6 +28,7 @@ extern void carla_register_native_plugin_bypass(void); extern void carla_register_native_plugin_lfo(void); extern void carla_register_native_plugin_midichanfilter(void); +extern void carla_register_native_plugin_midichanab(void); extern void carla_register_native_plugin_midigain(void); extern void carla_register_native_plugin_midijoin(void); extern void carla_register_native_plugin_midisplit(void); @@ -61,6 +62,7 @@ void carla_register_all_native_plugins(void) carla_register_native_plugin_bypass(); carla_register_native_plugin_lfo(); carla_register_native_plugin_midichanfilter(); + carla_register_native_plugin_midichanab(); carla_register_native_plugin_midigain(); carla_register_native_plugin_midijoin(); carla_register_native_plugin_midisplit(); diff --git a/source/native-plugins/_all.base.c b/source/native-plugins/_all.base.c index 24f80c4a8..7531f8cf9 100644 --- a/source/native-plugins/_all.base.c +++ b/source/native-plugins/_all.base.c @@ -28,6 +28,7 @@ extern void carla_register_native_plugin_bypass(void); extern void carla_register_native_plugin_lfo(void); extern void carla_register_native_plugin_midichanfilter(void); +extern void carla_register_native_plugin_midichanab(void); extern void carla_register_native_plugin_midigain(void); extern void carla_register_native_plugin_midijoin(void); extern void carla_register_native_plugin_midisplit(void); @@ -52,6 +53,7 @@ void carla_register_all_native_plugins(void) carla_register_native_plugin_bypass(); carla_register_native_plugin_lfo(); carla_register_native_plugin_midichanfilter(); + carla_register_native_plugin_midichanab(); carla_register_native_plugin_midigain(); carla_register_native_plugin_midijoin(); carla_register_native_plugin_midisplit(); diff --git a/source/native-plugins/_data.all.cpp b/source/native-plugins/_data.all.cpp index afa6221c0..71154dcc1 100644 --- a/source/native-plugins/_data.all.cpp +++ b/source/native-plugins/_data.all.cpp @@ -83,6 +83,22 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* copyright */ "GNU GPL v2+", DESCFUNCS }, +{ + /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, + /* hints */ NATIVE_PLUGIN_IS_RTSAFE, + /* supports */ NATIVE_PLUGIN_SUPPORTS_EVERYTHING, + /* audioIns */ 0, + /* audioOuts */ 0, + /* midiIns */ 1, + /* midiOuts */ 2, + /* paramIns */ 0, + /* paramOuts */ 0, + /* name */ "MIDI Channel A/B", + /* label */ "midichanab", + /* maker */ "Milk Brewster", + /* copyright */ "GNU GPL v2+", + DESCFUNCS +}, { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, /* hints */ NATIVE_PLUGIN_IS_RTSAFE, diff --git a/source/native-plugins/_data.base.cpp b/source/native-plugins/_data.base.cpp index 6537677a5..d678a0884 100644 --- a/source/native-plugins/_data.base.cpp +++ b/source/native-plugins/_data.base.cpp @@ -67,6 +67,22 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* copyright */ "GNU GPL v2+", DESCFUNCS }, +{ + /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, + /* hints */ NATIVE_PLUGIN_IS_RTSAFE, + /* supports */ NATIVE_PLUGIN_SUPPORTS_EVERYTHING, + /* audioIns */ 0, + /* audioOuts */ 0, + /* midiIns */ 1, + /* midiOuts */ 2, + /* paramIns */ 0, + /* paramOuts */ 0, + /* name */ "MIDI Channel A/B", + /* label */ "midichanab", + /* maker */ "Milk Brewster", + /* copyright */ "GNU GPL v2+", + DESCFUNCS +}, { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, /* hints */ NATIVE_PLUGIN_IS_RTSAFE, diff --git a/source/native-plugins/midi-channel-ab.c b/source/native-plugins/midi-channel-ab.c new file mode 100644 index 000000000..ac1ec3afb --- /dev/null +++ b/source/native-plugins/midi-channel-ab.c @@ -0,0 +1,211 @@ +/* + * Carla Native Plugins + * Copyright (C) 2012-2018 Filipe Coelho + * Copyright (C) 2018 Milk Brewster + * + * 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 "CarlaNative.h" +#include "CarlaMIDI.h" + +#include +#include +#include + +// ----------------------------------------------------------------------- + +typedef struct { + const NativeHostDescriptor* host; + bool channels[MAX_MIDI_CHANNELS]; +} MidiGainHandle; + +// ----------------------------------------------------------------------- + +static NativePluginHandle midichanab_instantiate(const NativeHostDescriptor* host) +{ + MidiGainHandle* const handle = (MidiGainHandle*)malloc(sizeof(MidiGainHandle)); + + if (handle == NULL) + return NULL; + + handle->host = host; + + memset(handle->channels, 0, MAX_MIDI_CHANNELS); + + return handle; +} + +#define handlePtr ((MidiGainHandle*)handle) + +static void midichanab_cleanup(NativePluginHandle handle) +{ + free(handlePtr); +} + +static uint32_t midichanab_get_parameter_count(NativePluginHandle handle) +{ + return MAX_MIDI_CHANNELS; + + // unused + (void)handle; +} + +static const NativeParameter* midichanab_get_parameter_info(NativePluginHandle handle, uint32_t index) +{ + if (index >= MAX_MIDI_CHANNELS) + return NULL; + + static NativeParameter param; + static const NativeParameterScalePoint scalePoints[2] = { { "Output A", 0 }, { "Output B", 1 } }; + static char paramName[24]; + + param.hints = NATIVE_PARAMETER_IS_ENABLED|NATIVE_PARAMETER_IS_AUTOMABLE|NATIVE_PARAMETER_IS_BOOLEAN|NATIVE_PARAMETER_USES_SCALEPOINTS; + param.name = paramName; + param.unit = NULL; + param.ranges.def = 0; + param.ranges.min = 0; + param.ranges.max = 1; + param.ranges.step = 1; + param.ranges.stepSmall = 1; + param.ranges.stepLarge = 1; + param.scalePointCount = 2; + param.scalePoints = scalePoints; + + snprintf(paramName, 24, "%u", index+1); + + return ¶m; + + // unused + (void)handle; +} + +static float midichanab_get_parameter_value(NativePluginHandle handle, uint32_t index) +{ + if (index >= MAX_MIDI_CHANNELS) + return 0; + + return handlePtr->channels[index] ? 1 : 0; +} + +static void midichanab_set_parameter_value(NativePluginHandle handle, uint32_t index, float value) +{ + if (index >= MAX_MIDI_CHANNELS) + return; + + handlePtr->channels[index] = (value >= 0.5f); +} + +static void midichanab_process(NativePluginHandle handle, float** inBuffer, float** outBuffer, uint32_t frames, const NativeMidiEvent* midiEvents, uint32_t midiEventCount) +{ + const NativeHostDescriptor* const host = handlePtr->host; + const bool* const channels = handlePtr->channels; + NativeMidiEvent tmpEvent; + + for (uint32_t i=0; i < midiEventCount; ++i) + { + const NativeMidiEvent* const midiEvent = &midiEvents[i]; + + const uint8_t status = (uint8_t)MIDI_GET_STATUS_FROM_DATA(midiEvent->data); + + if (MIDI_IS_CHANNEL_MESSAGE(status)) + { + const uint8_t channel = (uint8_t)MIDI_GET_CHANNEL_FROM_DATA(midiEvent->data); + + if (channel >= MAX_MIDI_CHANNELS) + continue; + + if (channels[channel]) + { + memcpy(&tmpEvent, midiEvent, sizeof(NativeMidiEvent)); + ++tmpEvent.port; + host->write_midi_event(host->handle, &tmpEvent); + } + else + { + host->write_midi_event(host->handle, midiEvent); + } + } + else + { + // pass through all non-message events + host->write_midi_event(host->handle, midiEvent); + } + } + + return; + + // unused + (void)inBuffer; + (void)outBuffer; + (void)frames; +} + +// ----------------------------------------------------------------------- + +static const NativePluginDescriptor midichanabDesc = { + .category = NATIVE_PLUGIN_CATEGORY_UTILITY, + .hints = NATIVE_PLUGIN_IS_RTSAFE, + .supports = NATIVE_PLUGIN_SUPPORTS_EVERYTHING, + .audioIns = 0, + .audioOuts = 0, + .midiIns = 1, + .midiOuts = 2, + .paramIns = 0, + .paramOuts = 0, + .name = "MIDI Channel A/B", + .label = "midichanab", + .maker = "Milk Brewster", + .copyright = "GNU GPL v2+", + + .instantiate = midichanab_instantiate, + .cleanup = midichanab_cleanup, + + .get_parameter_count = midichanab_get_parameter_count, + .get_parameter_info = midichanab_get_parameter_info, + .get_parameter_value = midichanab_get_parameter_value, + + .get_midi_program_count = NULL, + .get_midi_program_info = NULL, + + .set_parameter_value = midichanab_set_parameter_value, + .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 = midichanab_process, + + .get_state = NULL, + .set_state = NULL, + + .dispatcher = NULL +}; + +// ----------------------------------------------------------------------- + +void carla_register_native_plugin_midichanab(void); + +void carla_register_native_plugin_midichanab(void) +{ + carla_register_native_plugin(&midichanabDesc); +} + +// ----------------------------------------------------------------------- diff --git a/source/plugin/carla-base.cpp b/source/plugin/carla-base.cpp index 9ca665a81..49d316745 100644 --- a/source/plugin/carla-base.cpp +++ b/source/plugin/carla-base.cpp @@ -63,6 +63,7 @@ struct PluginListManager { if (std::strcmp(desc->label, "lfo" ) == 0 || std::strcmp(desc->label, "midichanfilter" ) == 0 || + std::strcmp(desc->label, "midichanab" ) == 0 || std::strcmp(desc->label, "midigain" ) == 0 || std::strcmp(desc->label, "midijoin" ) == 0 || std::strcmp(desc->label, "midisplit" ) == 0 ||