1 /* abGate - LV2 Noise Gate Plugin
2 *
3 * Copyright 2011 Antanas Bružas
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 3 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 #include <stdlib.h>
20 #include <lv2.h>
21 #include <cmath>
22
23 #include "gate_const.h"
24
25 #define CLOSED 1
26 #define ATTACK 2
27 #define OPENED 3
28 #define DECAY 4
29
30 static LV2_Descriptor *gateDescriptor = NULL;
31
32 class Gate {
33 public:
Gate()34 Gate() {
35 state = CLOSED;
36 gate = 0;
37 holding = 0;
38 }
~Gate()39 ~Gate() {
40 }
41
42 float *switch_button, *threshold, *attack, *hold, *decay, *range, sample_rate, gate, *output;
43 const float *input;
44 int state, holding;
45 };
46
instantiateGate(const LV2_Descriptor * descriptor,double s_rate,const char * path,const LV2_Feature * const * features)47 static LV2_Handle instantiateGate(const LV2_Descriptor *descriptor, double s_rate, const char *path, const LV2_Feature * const * features) {
48 Gate *plugin_data = new Gate;
49 plugin_data->sample_rate = s_rate;
50 return (LV2_Handle) plugin_data;
51 }
52
connectPortGate(LV2_Handle instance,uint32_t port,void * data)53 static void connectPortGate(LV2_Handle instance, uint32_t port, void *data) {
54 Gate *plugin = (Gate *) instance;
55
56 switch (port) {
57 case p_switch:
58 plugin->switch_button = (float*) data;
59 break;
60 case p_threshold:
61 plugin->threshold = (float*) data;
62 break;
63 case p_attack:
64 plugin->attack = (float*) data;
65 break;
66 case p_hold:
67 plugin->hold = (float*) data;
68 break;
69 case p_decay:
70 plugin->decay = (float*) data;
71 break;
72 case p_gaterange:
73 plugin->range = (float*) data;
74 break;
75 case p_input:
76 plugin->input = (const float*) data;
77 break;
78 case p_output:
79 plugin->output = (float*) data;
80 break;
81 }
82 }
83
runGate(LV2_Handle instance,uint32_t sample_count)84 static void runGate(LV2_Handle instance, uint32_t sample_count) {
85
86 Gate *plugin_data = (Gate *) instance;
87
88 float * const output = plugin_data->output;
89 const float * const input = plugin_data->input;
90
91 // Checking bypass state
92 float switch_button = *(plugin_data->switch_button);
93 switch_button = switch_button < 0 ? 0 : switch_button;
94 switch_button = switch_button > 1 ? 1 : switch_button;
95
96 bool active = switch_button > 0;
97 if (active) {
98
99 // Getting port values
100 const float threshold = *(plugin_data->threshold);
101 const float attack = *(plugin_data->attack);
102 const float hold = *(plugin_data->hold);
103 const float decay = *(plugin_data->decay);
104 const float range = *(plugin_data->range);
105
106 const float sample_rate = plugin_data->sample_rate;
107
108 const float threshold_value = pow(10, threshold * 0.05);
109 const float attack_coef = 1000 / (attack * sample_rate);
110 const int hold_samples = round(hold * sample_rate * 0.001);
111 const float decay_coef = 1000 / (decay * sample_rate);
112 const float range_coef = range > -90 ? pow(10, range * 0.05) : 0;
113
114 int state = plugin_data->state;
115 float gate = plugin_data->gate;
116 int holding = plugin_data->holding;
117
118 for (uint32_t i = 0; i < sample_count; ++i) {
119
120 // Counting input dB
121 float sample = input[i];
122 float abs_sample = fabs(sample);
123
124 switch (state) {
125 case CLOSED:
126 case DECAY:
127 if (abs_sample >= threshold_value) {
128 state = ATTACK;
129 }
130 break;
131 case ATTACK:
132 break;
133 case OPENED:
134 if (abs_sample >= threshold_value) {
135 holding = hold_samples;
136 } else if (holding <= 0) {
137 state = DECAY;
138 } else {
139 holding--;
140 }
141 break;
142 default:
143 // shouldn't happen
144 state = CLOSED;
145 }
146
147 // handle attack/decay in a second pass to avoid unnecessary one-sample delay
148 switch (state) {
149 case CLOSED:
150 output[i] = sample * range_coef;
151 break;
152 case DECAY:
153 gate -= decay_coef;
154 if (gate <= 0) {
155 gate = 0;
156 state = CLOSED;
157 }
158 output[i] = sample * (range_coef * (1 - gate) + gate);
159 break;
160 case ATTACK:
161 gate += attack_coef;
162 if (gate >= 1) {
163 gate = 1;
164 state = OPENED;
165 holding = hold_samples;
166 }
167 output[i] = sample * (range_coef * (1 - gate) + gate);
168 break;
169 case OPENED:
170 output[i] = sample;
171 break;
172 }
173 }
174
175 plugin_data->gate = gate;
176 plugin_data->state = state;
177 plugin_data->holding = holding;
178 } else {
179 // Bypassing
180 if (output != input) {
181 for (uint32_t i = 0; i < sample_count; ++i) {
182 output[i] = input[i];
183 }
184 }
185 }
186 }
187
cleanupGate(LV2_Handle instance)188 static void cleanupGate(LV2_Handle instance) {
189 Gate *plugin_data = (Gate *) instance;
190 delete plugin_data;
191 }
192
init()193 static void init() {
194
195 gateDescriptor = (LV2_Descriptor *) malloc(sizeof(LV2_Descriptor));
196 gateDescriptor->URI = p_uri;
197 gateDescriptor->instantiate = instantiateGate;
198 gateDescriptor->connect_port = connectPortGate;
199 gateDescriptor->activate = NULL;
200 gateDescriptor->run = runGate;
201 gateDescriptor->deactivate = NULL;
202 gateDescriptor->cleanup = cleanupGate;
203 gateDescriptor->extension_data = NULL;
204 }
205
206 LV2_SYMBOL_EXPORT
lv2_descriptor(uint32_t index)207 const LV2_Descriptor *lv2_descriptor(uint32_t index) {
208
209 if (!gateDescriptor) {
210 init();
211 }
212
213 switch (index) {
214 case 0:
215 return gateDescriptor;
216 default:
217 return NULL;
218 }
219 }
220