1 #include "gx_plugin.h"
2 #include <cmath>
3 #include <stdlib.h>
4
5 namespace pluginlib {
6 namespace reversedelay {
7
8 #define N_(x) (x)
9
10 class ReverseDelay : public PluginDef {
11 private:
12 float sample_rate;
13 float *buffer;
14 unsigned int counter;
15 unsigned int buf_size;
16
17 unsigned int cur_buf_size;
18 float feedback_buf;
19
20 //Params
21 float time, feedback, window, drywet;
22 //Params buffs
23 float time_old, window_old;
24
25 //Indicator
26 float buf_indication;
27
28 class overlap_window
29 {
30 private:
31 float val;
32 float step;
33 float acc;
34 unsigned int active_samples;
35 unsigned int full_samples;
36 unsigned int counter;
37
38 public:
overlap_window()39 overlap_window() {
40 val = 0;
41 step = 0;
42 acc = 0;
43 active_samples = 0;
44 full_samples = 0;
45 counter = 0;
46 }
set_coef(float t,unsigned int full_samples)47 void set_coef(float t /* 0..1 */, unsigned int full_samples) {
48 set_full(0, full_samples, t*full_samples);
49 }
set_full(float min_val,unsigned int full_samples,unsigned int active_samples)50 bool set_full(float min_val, unsigned int full_samples, unsigned int active_samples) {
51 if(active_samples >= full_samples) return false;
52
53 acc = min_val;
54 val = min_val;
55 this->full_samples = full_samples;
56 this->active_samples = active_samples;
57 counter = 0;
58 step = (1 - min_val)/(active_samples/2);
59
60 return true;
61 }
get()62 float get() {
63 if(counter >= 0 && counter < active_samples/2) {
64 acc += step;
65 counter++;
66 return acc;
67 }
68 else if(counter >= active_samples/2 && counter <= full_samples - active_samples/2) {
69 counter++;
70 return 1;
71 }
72 else if(counter > full_samples - active_samples/2 && counter < full_samples) {
73 acc -= step;
74 counter++;
75 return acc;
76 }
77 else if(counter >= full_samples) {
78 float ret_val = acc;
79 acc = val;
80 counter = 0;
81 return ret_val;
82 }
83 return 1;
84 }
85 };
86
87 overlap_window ow;
88
reverse_delay_line_impl(float in,float * buf,unsigned int * counter,unsigned int length)89 static float reverse_delay_line_impl(float in, float* buf, unsigned int* counter, unsigned int length)
90 {
91 float out = 0;
92
93 //Read data
94 if(*counter < length - 1)
95 {
96 unsigned int read_counter = length - 1 - (*counter);
97 out = buf[read_counter];
98 }
99
100 //Write data
101 *(buf + (*counter)) = in;
102 (*counter)++;
103 if ((*counter) > length-1)
104 (*counter) = 0;
105
106 return (out);
107 }
108
109 public:
110 ReverseDelay();
111 static void init(unsigned int samplingFreq, PluginDef *plugin);
112 static void process(int count, float *input, float *output, PluginDef *plugin);
113 static int registerparam(const ParamReg& reg);
114 static int uiloader(const UiBuilder& builder, int form);
115 static void del_instance(PluginDef *plugin);
116 };
117
ReverseDelay()118 ReverseDelay::ReverseDelay():
119 PluginDef(),
120 sample_rate(0) {
121 version = PLUGINDEF_VERSION;
122 id = "reversedelay";
123 name = N_("ReverseDelay");
124 category = N_("Echo / Delay");
125 mono_audio = process;
126 set_samplerate = init;
127 register_params = registerparam;
128 load_ui = uiloader;
129 delete_instance = del_instance;
130
131 buffer = NULL;
132 counter = 0;
133 buf_size = 0;
134 cur_buf_size = 0;
135 feedback_buf = 0;
136 time_old = 0;
137 window_old = 0;
138
139 buf_indication = 0;
140 }
141
registerparam(const ParamReg & reg)142 int ReverseDelay::registerparam(const ParamReg& reg) {
143 ReverseDelay& self = *static_cast<ReverseDelay*>(reg.plugin);
144 reg.registerFloatVar("reversedelay.time", N_("Time (ms)"), "S", N_("Delay time in milliseconds"), &self.time, 500, 200, 2000, 1, 0);
145 reg.registerFloatVar("reversedelay.feedback", N_("Feedback"), "S", N_("Feedback"), &self.feedback, 0, 0, 1, 0.05, 0);
146 reg.registerFloatVar("reversedelay.window", N_("Window (%)"), "S", N_("Crossfade between delayed chunks in percents"), &self.window, 50, 0, 100, 1, 0);
147 reg.registerFloatVar("reversedelay.drywet", N_("Dry/Wet"), "S", N_("Dry/Wet"), &self.drywet, 0.5, 0, 1, 0.05, 0);
148
149 reg.registerFloatVar("reversedelay.buf_indication", "", "SNO", "", &self.buf_indication, 0.0, 0.0, 1.0, 0.01, 0);
150 self.buf_indication = 0;
151
152 return 0;
153 }
154
init(unsigned int samplingFreq,PluginDef * plugin)155 void ReverseDelay::init(unsigned int samplingFreq, PluginDef *plugin) {
156 ReverseDelay& self = *static_cast<ReverseDelay*>(plugin);
157 self.sample_rate = samplingFreq;
158
159 float* old_buf = self.buffer;
160
161 //Provide dual buf size, with 2 seconds length for every part
162 unsigned int new_buf_size = (unsigned int)(samplingFreq * 2 * 2);
163
164 float *new_buf = new float[new_buf_size];
165 for (size_t i = 0; i < new_buf_size; i++)
166 new_buf[i] = 0.0f;
167
168 // Assign new pointer and size
169 self.buffer = new_buf;
170 self.buf_size = new_buf_size;
171
172 // Delete old buffer
173 if (old_buf != NULL)
174 delete [] old_buf;
175 }
176
process(int count,float * input,float * output,PluginDef * plugin)177 void ReverseDelay::process(int count, float *input, float *output, PluginDef *plugin) {
178 ReverseDelay& self = *static_cast<ReverseDelay*>(plugin);
179
180 //Update params
181 if(self.time_old != self.time) {
182 self.cur_buf_size = (self.time/1000.0)*self.sample_rate;
183 self.counter = 0;
184 self.ow.set_coef((self.window)/(100.0 + 1.0), self.cur_buf_size/2); //Avoid to pass 1
185
186 self.time_old = self.time;
187 self.window_old = self.window;
188 }
189 else if(self.window_old != self.window) {
190 self.ow.set_coef((self.window)/(100.0 + 1.0), self.cur_buf_size/2);
191 self.window_old = self.window;
192 }
193
194 for (int i = 0; i < count; ++i) {
195 float in = input[i];
196 float out = 0;
197
198 //Update indicator
199 self.buf_indication = ((float)self.counter)/self.cur_buf_size;
200
201 //Process
202 out = reverse_delay_line_impl(in + self.feedback_buf * self.feedback, self.buffer, &self.counter, self.cur_buf_size);
203 self.feedback_buf = out;
204
205 out*= self.ow.get();
206
207 out = out* self.drywet + in* (1 - self.drywet);
208 output[i] = out;
209 }
210 }
211
uiloader(const UiBuilder & b,int form)212 int ReverseDelay::uiloader(const UiBuilder& b, int form) {
213 if (form & UI_FORM_GLADE) {
214 b.load_glade_file("reversedelay_ui.glade");
215 return 0;
216 }
217 if (!(form & UI_FORM_STACK)) {
218 return -1;
219 }
220 b.openHorizontalhideBox("");
221 {
222 b.create_master_slider("reversedelay.drywet",N_("Dry/Wet"));
223 }
224 b.closeBox();
225 b.openHorizontalBox("");
226 {
227 b.create_small_rackknob("reversedelay.time",N_("Time (ms)"));
228
229 b.openVerticalBox("");
230 b.insertSpacer();
231 b.create_port_display("reversedelay.buf_indication", N_("Buf state"));
232 b.insertSpacer();
233 b.closeBox();
234
235 b.create_small_rackknob("reversedelay.feedback",N_("Feedback"));
236 b.create_small_rackknob("reversedelay.window",N_("Window (%)"));
237 b.create_small_rackknobr("reversedelay.drywet",N_("Dry/Wet"));
238
239 }
240 b.closeBox();
241 return 0;
242 }
243
del_instance(PluginDef * plugin)244 void ReverseDelay::del_instance(PluginDef *plugin)
245 {
246 ReverseDelay& self = *static_cast<ReverseDelay*>(plugin);
247 delete [] self.buffer;
248 delete static_cast<ReverseDelay*>(plugin);
249 }
250
251
252 #if true
253
plugin()254 PluginDef *plugin() {
255 return new ReverseDelay;
256 }
257
258 #else
259
260 extern "C" __attribute__ ((visibility ("default"))) int
get_gx_plugin(unsigned int idx,PluginDef ** pplugin)261 get_gx_plugin(unsigned int idx, PluginDef **pplugin)
262 {
263 const int count = 1;
264 if (!pplugin) {
265 return count;
266 }
267 switch (idx) {
268 case 0: *pplugin = new ReverseDelay; return count;
269 default: *pplugin = 0; return -1;
270 }
271 }
272
273 #endif
274
275 } // end namespace reverse_delay
276 } // end namespace pluginlib
277