1 /*
2   Rakarrack Guitar FX
3 
4   Sustainer.C - Simple compressor/sustainer effect with easy interface, minimal controls
5   Copyright (C) 2010 Ryan Billing
6   Author: Ryan Billing
7 
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of version 3 of the GNU General Public License
10   as published by the Free Software Foundation.
11 
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License (version 2) for more details.
16 
17   You should have received a copy of the GNU General Public License (version 2)
18   along with this program; if not, write to the Free Software Foundation,
19   Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
20 
21 */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <math.h>
26 #include "Sustainer.h"
27 
Sustainer(float * efxoutl_,float * efxoutr_,double sample_rate)28 Sustainer::Sustainer (float * efxoutl_, float * efxoutr_, double sample_rate)
29 {
30 	float cSAMPLE_RATE = 1/sample_rate;
31     efxoutl = efxoutl_;
32     efxoutr = efxoutr_;
33 
34     Pvolume = 64;
35     Psustain = 64;
36     fsustain = 0.5f;
37     level = 0.5f;
38 
39     float tmp = 0.01f;  //10 ms decay time on peak detectorS
40     prls = 1.0f - (cSAMPLE_RATE/(cSAMPLE_RATE + tmp));
41 
42     tmp = 0.05f; //50 ms att/rel on compressor
43     calpha =  cSAMPLE_RATE/(cSAMPLE_RATE + tmp);
44     cbeta = 1.0f - calpha;
45     cthresh = 0.25f;
46     cratio = 0.25f;
47 
48     timer = 0;
49     hold = (int) (sample_rate*0.0125);  //12.5ms
50     cleanup ();
51 };
52 
~Sustainer()53 Sustainer::~Sustainer ()
54 {
55 
56 };
57 
58 /*
59  * Cleanup the effect
60  */
61 void
cleanup()62 Sustainer::cleanup ()
63 {
64     compeak = 0.0f;
65     compenv = 0.0f;
66     oldcompenv = 0.0f;
67     cpthresh = cthresh; //dynamic threshold
68 };
69 
70 
71 
72 
73 /*
74  * Effect output
75  */
76 void
out(float * smpsl,float * smpsr,uint32_t period)77 Sustainer::out (float * smpsl, float * smpsr, uint32_t period)
78 {
79     unsigned int i;
80     float auxtempl = 0.0f;
81     float auxtempr = 0.0f;
82     float auxcombi = 0.0f;
83 
84     for (i = 0; i<period; i++) {  //apply compression to auxresampled
85         auxtempl = input * smpsl[i];
86         auxtempr = input * smpsr[i];
87         auxcombi = 0.5f * (auxtempl + auxtempr);
88         if(fabs(auxcombi) > compeak) {
89             compeak = fabs(auxcombi);   //First do peak detection on the signal
90             timer = 0;
91         }
92         if(timer>hold) {
93             compeak *= prls;
94             timer--;
95         }
96         timer++;
97         compenv = cbeta * oldcompenv + calpha * compeak;       //Next average into envelope follower
98         oldcompenv = compenv;
99 
100         if(compenv > cpthresh) {                              //if envelope of signal exceeds thresh, then compress
101             compg = cpthresh + cpthresh*(compenv - cpthresh)/compenv;
102             cpthresh = cthresh + cratio*(compg - cpthresh);   //cpthresh changes dynamically
103             tmpgain = compg/compenv;
104         } else {
105             tmpgain = 1.0f;
106         }
107 
108         if(compenv < cpthresh) cpthresh = compenv;
109         if(cpthresh < cthresh) cpthresh = cthresh;
110 
111         smpsl[i] = auxtempl * tmpgain * level;
112         smpsr[i] = auxtempr * tmpgain * level;
113     };
114     //End compression
115 };
116 
117 
118 /*
119  * Parameter control
120  */
121 
122 
123 void
setpreset(int npreset)124 Sustainer::setpreset (int npreset)
125 {
126     const int PRESET_SIZE = 2;
127     const int NUM_PRESETS = 3;
128     int pdata[PRESET_SIZE];
129     int presets[NUM_PRESETS][PRESET_SIZE] = {
130         //Moderate
131         {79, 54},
132         //Extreme
133         {16, 127},
134         //Mild
135         {120, 15},
136 
137     };
138 
139     if(npreset>NUM_PRESETS-1) {
140         Fpre->ReadPreset(36,npreset-NUM_PRESETS+1, pdata);
141         for (int n = 0; n < PRESET_SIZE; n++)
142             changepar (n, pdata[n]);
143     } else {
144         for (int n = 0; n < PRESET_SIZE; n++)
145             changepar (n, presets[npreset][n]);
146     }
147     Ppreset = npreset;
148 };
149 
150 
151 void
changepar(int npar,int value)152 Sustainer::changepar (int npar, int value)
153 {
154     switch (npar) {
155     case 0:
156         Pvolume = value;
157         level = dB2rap(-30.0f * (1.0f - ((float) Pvolume/127.0f)));
158         break;
159     case 1:
160         Psustain = value;
161         fsustain =  (float) Psustain/127.0f;
162         cratio = 1.25f - fsustain;
163         input = dB2rap (42.0f * fsustain - 6.0f);
164         cthresh = 0.25 + fsustain;
165         break;
166 
167     };
168 };
169 
170 int
getpar(int npar)171 Sustainer::getpar (int npar)
172 {
173     switch (npar) {
174     case 0:
175         return (Pvolume);
176         break;
177     case 1:
178         return (Psustain);
179         break;
180     };
181     return (0);			//in case of bogus parameter number
182 };
183 
184