1 /*
2  * Carla Native Plugins
3  * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com>
4  * Copyright (C) 2018 Milk Brewster <code@milkmiruku.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * For a full copy of the GNU General Public License see the doc/GPL.txt file.
17  */
18 
19 #include "CarlaNative.h"
20 #include "CarlaMIDI.h"
21 
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 // -----------------------------------------------------------------------
27 
28 typedef struct {
29     const NativeHostDescriptor* host;
30     bool channels[MAX_MIDI_CHANNELS];
31 } MidiGainHandle;
32 
33 // -----------------------------------------------------------------------
34 
midichanab_instantiate(const NativeHostDescriptor * host)35 static NativePluginHandle midichanab_instantiate(const NativeHostDescriptor* host)
36 {
37     MidiGainHandle* const handle = (MidiGainHandle*)malloc(sizeof(MidiGainHandle));
38 
39     if (handle == NULL)
40         return NULL;
41 
42     handle->host = host;
43 
44     memset(handle->channels, 0, MAX_MIDI_CHANNELS);
45 
46     return handle;
47 }
48 
49 #define handlePtr ((MidiGainHandle*)handle)
50 
midichanab_cleanup(NativePluginHandle handle)51 static void midichanab_cleanup(NativePluginHandle handle)
52 {
53     free(handlePtr);
54 }
55 
midichanab_get_parameter_count(NativePluginHandle handle)56 static uint32_t midichanab_get_parameter_count(NativePluginHandle handle)
57 {
58     return MAX_MIDI_CHANNELS;
59 
60     // unused
61     (void)handle;
62 }
63 
midichanab_get_parameter_info(NativePluginHandle handle,uint32_t index)64 static const NativeParameter* midichanab_get_parameter_info(NativePluginHandle handle, uint32_t index)
65 {
66     if (index >= MAX_MIDI_CHANNELS)
67         return NULL;
68 
69     static NativeParameter param;
70     static const NativeParameterScalePoint scalePoints[2] = { { "Output A", 0 }, { "Output B", 1 } };
71     static char paramName[24];
72 
73     param.hints = NATIVE_PARAMETER_IS_ENABLED|NATIVE_PARAMETER_IS_AUTOMABLE|NATIVE_PARAMETER_IS_BOOLEAN|NATIVE_PARAMETER_USES_SCALEPOINTS;
74     param.name  = paramName;
75     param.unit  = NULL;
76     param.ranges.def       = 0;
77     param.ranges.min       = 0;
78     param.ranges.max       = 1;
79     param.ranges.step      = 1;
80     param.ranges.stepSmall = 1;
81     param.ranges.stepLarge = 1;
82     param.scalePointCount  = 2;
83     param.scalePoints      = scalePoints;
84 
85     snprintf(paramName, 24, "%u", index+1);
86 
87     return &param;
88 
89     // unused
90     (void)handle;
91 }
92 
midichanab_get_parameter_value(NativePluginHandle handle,uint32_t index)93 static float midichanab_get_parameter_value(NativePluginHandle handle, uint32_t index)
94 {
95     if (index >= MAX_MIDI_CHANNELS)
96         return 0;
97 
98     return handlePtr->channels[index] ? 1 : 0;
99 }
100 
midichanab_set_parameter_value(NativePluginHandle handle,uint32_t index,float value)101 static void midichanab_set_parameter_value(NativePluginHandle handle, uint32_t index, float value)
102 {
103     if (index >= MAX_MIDI_CHANNELS)
104         return;
105 
106     handlePtr->channels[index] = (value >= 0.5f);
107 }
108 
109 // FIXME for v3.0, use const for the input buffer
midichanab_process(NativePluginHandle handle,float ** inBuffer,float ** outBuffer,uint32_t frames,const NativeMidiEvent * midiEvents,uint32_t midiEventCount)110 static void midichanab_process(NativePluginHandle handle,
111                                float** inBuffer, float** outBuffer, uint32_t frames,
112                                const NativeMidiEvent* midiEvents, uint32_t midiEventCount)
113 {
114     const NativeHostDescriptor* const host     = handlePtr->host;
115     const bool*                 const channels = handlePtr->channels;
116     NativeMidiEvent tmpEvent;
117 
118     for (uint32_t i=0; i < midiEventCount; ++i)
119     {
120         const NativeMidiEvent* const midiEvent = &midiEvents[i];
121 
122         const uint8_t status = (uint8_t)MIDI_GET_STATUS_FROM_DATA(midiEvent->data);
123 
124         if (MIDI_IS_CHANNEL_MESSAGE(status))
125         {
126             const uint8_t channel = (uint8_t)MIDI_GET_CHANNEL_FROM_DATA(midiEvent->data);
127 
128             if (channel >= MAX_MIDI_CHANNELS)
129                 continue;
130 
131             if (channels[channel])
132             {
133                 memcpy(&tmpEvent, midiEvent, sizeof(NativeMidiEvent));
134                 ++tmpEvent.port;
135                 host->write_midi_event(host->handle, &tmpEvent);
136             }
137             else
138             {
139                 host->write_midi_event(host->handle, midiEvent);
140             }
141         }
142         else
143         {
144             // pass through all non-message events
145             host->write_midi_event(host->handle, midiEvent);
146         }
147     }
148 
149     return;
150 
151     // unused
152     (void)inBuffer;
153     (void)outBuffer;
154     (void)frames;
155 }
156 
157 // -----------------------------------------------------------------------
158 
159 static const NativePluginDescriptor midichanabDesc = {
160     .category  = NATIVE_PLUGIN_CATEGORY_UTILITY,
161     .hints     = NATIVE_PLUGIN_IS_RTSAFE,
162     .supports  = NATIVE_PLUGIN_SUPPORTS_EVERYTHING,
163     .audioIns  = 0,
164     .audioOuts = 0,
165     .cvIns     = 0,
166     .cvOuts    = 0,
167     .midiIns   = 1,
168     .midiOuts  = 2,
169     .paramIns  = 0,
170     .paramOuts = 0,
171     .name      = "MIDI Channel A/B",
172     .label     = "midichanab",
173     .maker     = "Milk Brewster",
174     .copyright = "GNU GPL v2+",
175 
176     .instantiate = midichanab_instantiate,
177     .cleanup     = midichanab_cleanup,
178 
179     .get_parameter_count = midichanab_get_parameter_count,
180     .get_parameter_info  = midichanab_get_parameter_info,
181     .get_parameter_value = midichanab_get_parameter_value,
182 
183     .get_midi_program_count = NULL,
184     .get_midi_program_info  = NULL,
185 
186     .set_parameter_value = midichanab_set_parameter_value,
187     .set_midi_program    = NULL,
188     .set_custom_data     = NULL,
189 
190     .ui_show = NULL,
191     .ui_idle = NULL,
192 
193     .ui_set_parameter_value = NULL,
194     .ui_set_midi_program    = NULL,
195     .ui_set_custom_data     = NULL,
196 
197     .activate   = NULL,
198     .deactivate = NULL,
199     .process    = midichanab_process,
200 
201     .get_state = NULL,
202     .set_state = NULL,
203 
204     .dispatcher = NULL
205 };
206 
207 // -----------------------------------------------------------------------
208 
209 void carla_register_native_plugin_midichanab(void);
210 
carla_register_native_plugin_midichanab(void)211 void carla_register_native_plugin_midichanab(void)
212 {
213     carla_register_native_plugin(&midichanabDesc);
214 }
215 
216 // -----------------------------------------------------------------------
217