1 /*
2  * Copyright (C) 2014 Guitarix project MOD project
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  * --------------------------------------------------------------------------
18  */
19 
20 
21 #include <cstdlib>
22 #include <cmath>
23 #include <iostream>
24 #include <cstring>
25 #include <unistd.h>
26 
27 ///////////////////////// MACRO SUPPORT ////////////////////////////////
28 
29 #define __rt_func __attribute__((section(".rt.text")))
30 #define __rt_data __attribute__((section(".rt.data")))
31 
32 ///////////////////////// FAUST SUPPORT ////////////////////////////////
33 
34 #define FAUSTFLOAT float
35 #ifndef N_
36 #define N_(String) (String)
37 #endif
38 #define max(x, y) (((x) > (y)) ? (x) : (y))
39 #define min(x, y) (((x) < (y)) ? (x) : (y))
40 
41 #define always_inline inline __attribute__((always_inline))
42 
43 #ifndef signbit
44 #define signbit(x) std::signbit(x)
45 #endif
46 
mydsp_faustpower2_f(T x)47 template<class T> inline T mydsp_faustpower2_f(T x) {return (x * x);}
mydsp_faustpower3_f(T x)48 template<class T> inline T mydsp_faustpower3_f(T x) {return ((x * x) * x);}
mydsp_faustpower4_f(T x)49 template<class T> inline T mydsp_faustpower4_f(T x) {return (((x * x) * x) * x);}
mydsp_faustpower5_f(T x)50 template<class T> inline T mydsp_faustpower5_f(T x) {return ((((x * x) * x) * x) * x);}
mydsp_faustpower6_f(T x)51 template<class T> inline T mydsp_faustpower6_f(T x) {return (((((x * x) * x) * x) * x) * x);}
52 
53 ////////////////////////////// LOCAL INCLUDES //////////////////////////
54 
55 #include "gx_sceleton.h"        // define struct PortIndex
56 #include "gx_pluginlv2.h"   // define struct PluginLV2
57 #include "sceleton.cc"    // dsp class generated by faust -> dsp2cc
58 
59 ////////////////////////////// PLUG-IN CLASS ///////////////////////////
60 
61 namespace sceleton {
62 
63 class Gx_sceleton_
64 {
65 private:
66   // pointer to buffer
67   float*          output;
68   float*          input;
69   float*          output1;
70   float*          input1;
71   // pointer to dsp class
72   PluginLV2*      sceleton;
73 
74   // bypass ramping
75   float*          bypass;
76   uint32_t        bypass_;
77 
78   bool            needs_ramp_down;
79   bool            needs_ramp_up;
80   float           ramp_down;
81   float           ramp_up;
82   float           ramp_up_step;
83   float           ramp_down_step;
84   bool            bypassed;
85 
86   // private functions
87   inline void run_dsp_(uint32_t n_samples);
88   inline void connect_(uint32_t port,void* data);
89   inline void init_dsp_(uint32_t rate);
90   inline void connect_all__ports(uint32_t port, void* data);
91   inline void activate_f();
92   inline void clean_up();
93   inline void deactivate_f();
94 
95 public:
96   // LV2 Descriptor
97   static const LV2_Descriptor descriptor;
98   // static wrapper to private functions
99   static void deactivate(LV2_Handle instance);
100   static void cleanup(LV2_Handle instance);
101   static void run(LV2_Handle instance, uint32_t n_samples);
102   static void activate(LV2_Handle instance);
103   static void connect_port(LV2_Handle instance, uint32_t port, void* data);
104   static LV2_Handle instantiate(const LV2_Descriptor* descriptor,
105                                 double rate, const char* bundle_path,
106                                 const LV2_Feature* const* features);
107   Gx_sceleton_();
108   ~Gx_sceleton_();
109 };
110 
111 // constructor
Gx_sceleton_()112 Gx_sceleton_::Gx_sceleton_() :
113   output(NULL),
114   input(NULL),
115   sceleton(sceleton::plugin()),
116   bypass(0),
117   bypass_(2),
118   needs_ramp_down(false),
119   needs_ramp_up(false),
120   bypassed(false) {};
121 
122 // destructor
~Gx_sceleton_()123 Gx_sceleton_::~Gx_sceleton_()
124 {
125   // just to be sure the plug have given free the allocated mem
126   // it didn't hurd if the mem is already given free by clean_up()
127   if (sceleton->activate_plugin !=0)
128     sceleton->activate_plugin(false, sceleton);
129   // delete DSP class
130   sceleton->delete_instance(sceleton);
131 };
132 
133 ///////////////////////// PRIVATE CLASS  FUNCTIONS /////////////////////
134 
init_dsp_(uint32_t rate)135 void Gx_sceleton_::init_dsp_(uint32_t rate)
136 {
137   // set values for internal ramping
138   ramp_down_step = 32 * (256 * rate) / 48000;
139   ramp_up_step = ramp_down_step;
140   ramp_down = ramp_down_step;
141   ramp_up = 0.0;
142 
143   sceleton->set_samplerate(rate, sceleton); // init the DSP class
144 }
145 
146 // connect the Ports used by the plug-in class
connect_(uint32_t port,void * data)147 void Gx_sceleton_::connect_(uint32_t port,void* data)
148 {
149   switch ((PortIndex)port)
150     {
151     case EFFECTS_OUTPUT:
152       output = static_cast<float*>(data);
153       break;
154     case EFFECTS_INPUT:
155       input = static_cast<float*>(data);
156       break;
157     case EFFECTS_OUTPUT1:
158       output1 = static_cast<float*>(data);
159       break;
160     case EFFECTS_INPUT1:
161       input1 = static_cast<float*>(data);
162       break;
163     case BYPASS:
164       bypass = static_cast<float*>(data); // , 0.0, 0.0, 1.0, 1.0
165       break;
166     default:
167       break;
168     }
169 }
170 
activate_f()171 void Gx_sceleton_::activate_f()
172 {
173   // allocate the internal DSP mem
174   if (sceleton->activate_plugin !=0)
175     sceleton->activate_plugin(true, sceleton);
176 }
177 
clean_up()178 void Gx_sceleton_::clean_up()
179 {
180   // delete the internal DSP mem
181   if (sceleton->activate_plugin !=0)
182     sceleton->activate_plugin(false, sceleton);
183 }
184 
deactivate_f()185 void Gx_sceleton_::deactivate_f()
186 {
187   // delete the internal DSP mem
188   if (sceleton->activate_plugin !=0)
189     sceleton->activate_plugin(false, sceleton);
190 }
191 
run_dsp_(uint32_t n_samples)192 void Gx_sceleton_::run_dsp_(uint32_t n_samples)
193 {
194   FAUSTFLOAT buf[n_samples];
195   FAUSTFLOAT buf1[n_samples];
196   // do inplace processing at default
197   memcpy(output, input, n_samples*sizeof(float));
198   memcpy(output1, input1, n_samples*sizeof(float));
199   // check if bypass is pressed
200   if (bypass_ != static_cast<uint32_t>(*(bypass))) {
201     bypass_ = static_cast<uint32_t>(*(bypass));
202     if (!bypass_) {
203       needs_ramp_down = true;
204       needs_ramp_up = false;
205     } else {
206       needs_ramp_down = false;
207       needs_ramp_up = true;
208       bypassed = false;
209     }
210   }
211 
212   if (needs_ramp_down || needs_ramp_up) {
213        memcpy(buf, input, n_samples*sizeof(float));
214        memcpy(buf1, input1, n_samples*sizeof(float));
215   }
216 
217   if (!bypassed) {
218      sceleton->stereo_audio(static_cast<int>(n_samples), output, output1, output, output1, sceleton);
219   }
220 
221   // check if ramping is needed
222   if (needs_ramp_down) {
223     float fade = 0;
224     for (uint32_t i=0; i<n_samples; i++) {
225       if (ramp_down >= 0.0) {
226         --ramp_down;
227       }
228       fade = max(0.0,ramp_down) /ramp_down_step ;
229       output[i] = output[i] * fade + buf[i] * (1.0 - fade);
230       output1[i] = output1[i] * fade + buf1[i] * (1.0 - fade);
231     }
232 
233     if (ramp_down <= 0.0) {
234       // when ramped down, clear buffer from sceleton class
235       sceleton->clear_state(sceleton);
236       needs_ramp_down = false;
237       bypassed = true;
238       ramp_down = ramp_down_step;
239       ramp_up = 0.0;
240     } else {
241       ramp_up = ramp_down;
242     }
243 
244   } else if (needs_ramp_up) {
245     float fade = 0;
246     for (uint32_t i=0; i<n_samples; i++) {
247       if (ramp_up < ramp_up_step) {
248         ++ramp_up ;
249       }
250       fade = min(ramp_up_step,ramp_up) /ramp_up_step ;
251       output[i] = output[i] * fade + buf[i] * (1.0 - fade);
252       output1[i] = output1[i] * fade + buf1[i] * (1.0 - fade);
253     }
254 
255     if (ramp_up >= ramp_up_step) {
256       needs_ramp_up = false;
257       ramp_up = 0.0;
258       ramp_down = ramp_down_step;
259     } else {
260       ramp_down = ramp_up;
261     }
262   }
263 
264 }
265 
connect_all__ports(uint32_t port,void * data)266 void Gx_sceleton_::connect_all__ports(uint32_t port, void* data)
267 {
268   // connect the Ports used by the plug-in class
269   connect_(port,data);
270   // connect the Ports used by the DSP class
271   sceleton->connect_ports(port,  data, sceleton);
272 }
273 
274 ////////////////////// STATIC CLASS  FUNCTIONS  ////////////////////////
275 
276 LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)277 Gx_sceleton_::instantiate(const LV2_Descriptor* descriptor,
278                             double rate, const char* bundle_path,
279                             const LV2_Feature* const* features)
280 {
281   // init the plug-in class
282   Gx_sceleton_ *self = new Gx_sceleton_();
283   if (!self) {
284     return NULL;
285   }
286 
287   self->init_dsp_((uint32_t)rate);
288 
289   return (LV2_Handle)self;
290 }
291 
connect_port(LV2_Handle instance,uint32_t port,void * data)292 void Gx_sceleton_::connect_port(LV2_Handle instance,
293                                    uint32_t port, void* data)
294 {
295   // connect all ports
296   static_cast<Gx_sceleton_*>(instance)->connect_all__ports(port, data);
297 }
298 
activate(LV2_Handle instance)299 void Gx_sceleton_::activate(LV2_Handle instance)
300 {
301   // allocate needed mem
302   static_cast<Gx_sceleton_*>(instance)->activate_f();
303 }
304 
run(LV2_Handle instance,uint32_t n_samples)305 void Gx_sceleton_::run(LV2_Handle instance, uint32_t n_samples)
306 {
307   // run dsp
308   static_cast<Gx_sceleton_*>(instance)->run_dsp_(n_samples);
309 }
310 
deactivate(LV2_Handle instance)311 void Gx_sceleton_::deactivate(LV2_Handle instance)
312 {
313   // free allocated mem
314   static_cast<Gx_sceleton_*>(instance)->deactivate_f();
315 }
316 
cleanup(LV2_Handle instance)317 void Gx_sceleton_::cleanup(LV2_Handle instance)
318 {
319   // well, clean up after us
320   Gx_sceleton_* self = static_cast<Gx_sceleton_*>(instance);
321   self->clean_up();
322   delete self;
323 }
324 
325 const LV2_Descriptor Gx_sceleton_::descriptor =
326 {
327   GXPLUGIN_URI "#_sceleton_",
328   Gx_sceleton_::instantiate,
329   Gx_sceleton_::connect_port,
330   Gx_sceleton_::activate,
331   Gx_sceleton_::run,
332   Gx_sceleton_::deactivate,
333   Gx_sceleton_::cleanup,
334   NULL
335 };
336 
337 
338 } // end namespace sceleton
339 
340 ////////////////////////// LV2 SYMBOL EXPORT ///////////////////////////
341 
342 extern "C"
343 LV2_SYMBOL_EXPORT
344 const LV2_Descriptor*
lv2_descriptor(uint32_t index)345 lv2_descriptor(uint32_t index)
346 {
347   switch (index)
348     {
349     case 0:
350       return &sceleton::Gx_sceleton_::descriptor;
351     default:
352       return NULL;
353     }
354 }
355 
356 ///////////////////////////// FIN //////////////////////////////////////
357