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