SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
audiocompressorsnd.h
Go to the documentation of this file.
1 // Copyright (C) 2019 F4EXB //
3 // written by Edouard Griffiths //
4 // //
5 // Audio compressor based on sndfilter by Sean Connelly (@voidqk) //
6 // https://github.com/voidqk/sndfilter //
7 // //
8 // Sample by sample interface to facilitate integration in SDRangel modulators. //
9 // Uses mono samples (just floats) //
10 // //
11 // This program is free software; you can redistribute it and/or modify //
12 // it under the terms of the GNU General Public License as published by //
13 // the Free Software Foundation as version 3 of the License, or //
14 // (at your option) any later version. //
15 // //
16 // This program is distributed in the hope that it will be useful, //
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
19 // GNU General Public License V3 for more details. //
20 // //
21 // You should have received a copy of the GNU General Public License //
22 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
24 
25 #ifndef SDRBASE_AUDIO_AUDIOCOMPRESSORSND_H_
26 #define SDRBASE_AUDIO_AUDIOCOMPRESSORSND_H_
27 
28 #define _USE_MATH_DEFINES
29 #include <math.h>
30 
31 // maximum number of samples in the delay buffer
32 #define AUDIOCOMPRESSORSND_SF_COMPRESSOR_MAXDELAY 1024
33 
34 // samples per update; the compressor works by dividing the input chunks into even smaller sizes,
35 // and performs heavier calculations after each mini-chunk to adjust the final envelope
36 #define AUDIOCOMPRESSORSND_SF_COMPRESSOR_SPU 32
37 
38 // not sure what this does exactly, but it is part of the release curve
39 #define AUDIOCOMPRESSORSND_SF_COMPRESSOR_SPACINGDB 5.0f
40 
41 // the "chunk" size as defined in original sndfilter library
42 #define AUDIOCOMPRESSORSND_SF_COMPRESSOR_CHUNKSIZE 128
43 
44 #include "export.h"
45 
47 {
48 public:
51 
52  void initDefault(int rate)
53  {
54  m_rate = rate;
55  m_pregain = 0.000f;
56  m_threshold = -24.000f;
57  m_knee = 30.000f;
58  m_ratio = 12.000f;
59  m_attack = 0.003f;
60  m_release = 0.250f;
61  m_predelay = 0.006f;
62  m_releasezone1 = 0.090f;
63  m_releasezone2 = 0.160f;
64  m_releasezone3 = 0.420f;
65  m_releasezone4 = 0.980f;
66  m_postgain = 0.000f;
67  m_wet = 1.000f;
68  initState();
69  }
70 
71  void initSimple(
72  int rate, // input sample rate (samples per second)
73  float pregain, // dB, amount to boost the signal before applying compression [0 to 100]
74  float threshold, // dB, level where compression kicks in [-100 to 0]
75  float knee, // dB, width of the knee [0 to 40]
76  float ratio, // unitless, amount to inversely scale the output when applying comp [1 to 20]
77  float attack, // seconds, length of the attack phase [0 to 1]
78  float release // seconds, length of the release phase [0 to 1]
79  )
80  {
81  m_rate = rate;
82  m_pregain = pregain;
83  m_threshold = threshold;
84  m_knee = knee;
85  m_ratio = ratio;
86  m_attack = attack;
87  m_release = release;
88  m_predelay = 0.006f;
89  m_releasezone1 = 0.090f;
90  m_releasezone2 = 0.160f;
91  m_releasezone3 = 0.420f;
92  m_releasezone4 = 0.980f;
93  m_postgain = 0.000f;
94  m_wet = 1.000f;
95  initState();
96  }
97 
98  void initState();
99  float compress(float sample);
100 
101  float m_rate;
102  float m_pregain;
103  float m_threshold;
104  float m_knee;
105  float m_ratio;
106  float m_attack;
107  float m_release;
108  float m_predelay;
113  float m_postgain;
114  float m_wet;
115 
116 private:
117  static inline float db2lin(float db){ // dB to linear
118  return powf(10.0f, 0.05f * db);
119  }
120 
121  static inline float lin2db(float lin){ // linear to dB
122  return 20.0f * log10f(lin);
123  }
124 
125  // for more information on the knee curve, check out the compressor-curve.html demo + source code
126  // included in this repo
127  static inline float kneecurve(float x, float k, float linearthreshold){
128  return linearthreshold + (1.0f - expf(-k * (x - linearthreshold))) / k;
129  }
130 
131  static inline float kneeslope(float x, float k, float linearthreshold){
132  return k * x / ((k * linearthreshold + 1.0f) * expf(k * (x - linearthreshold)) - 1);
133  }
134 
135  static inline float compcurve(float x, float k, float slope, float linearthreshold,
136  float linearthresholdknee, float threshold, float knee, float kneedboffset){
137  if (x < linearthreshold)
138  return x;
139  if (knee <= 0.0f) // no knee in curve
140  return db2lin(threshold + slope * (lin2db(x) - threshold));
141  if (x < linearthresholdknee)
142  return kneecurve(x, k, linearthreshold);
143  return db2lin(kneedboffset + slope * (lin2db(x) - threshold - knee));
144  }
145 
146  // for more information on the adaptive release curve, check out adaptive-release-curve.html demo +
147  // source code included in this repo
148  static inline float adaptivereleasecurve(float x, float a, float b, float c, float d){
149  // a*x^3 + b*x^2 + c*x + d
150  float x2 = x * x;
151  return a * x2 * x + b * x2 + c * x + d;
152  }
153 
154  static inline float clampf(float v, float min, float max){
155  return v < min ? min : (v > max ? max : v);
156  }
157 
158  static inline float absf(float v){
159  return v < 0.0f ? -v : v;
160  }
161 
162  static inline float fixf(float v, float def){
163  // fix NaN and infinity values that sneak in... not sure why this is needed, but it is
164  if (isnan(v) || isinf(v))
165  return def;
166  return v;
167  }
168 
170  { // sf_compressor_state_st
171  // user can read the metergain state variable after processing a chunk to see how much dB the
172  // compressor would have liked to compress the sample; the meter values aren't used to shape the
173  // sound in any way, only used for output if desired
174  float metergain;
175 
176  // everything else shouldn't really be mucked with unless you read the algorithm and feel
177  // comfortable
179  float threshold;
180  float knee;
183  float slope;
186  float wet;
187  float dry;
188  float k;
191  float mastergain;
192  float a; // adaptive release polynomial coefficients
193  float b;
194  float c;
195  float d;
196  float detectoravg;
197  float compgain;
202  float delaybuf[AUDIOCOMPRESSORSND_SF_COMPRESSOR_MAXDELAY]; // predelay buffer
203 
204  // populate the compressor state with advanced parameters
205  void sf_advancecomp(
206  // these parameters are the same as the simple version above:
207  int rate, float pregain, float threshold, float knee, float ratio, float attack, float release,
208  // these are the advanced parameters:
209  float predelay, // seconds, length of the predelay buffer [0 to 1]
210  float releasezone1, // release zones should be increasing between 0 and 1, and are a fraction
211  float releasezone2, // of the release time depending on the input dB -- these parameters define
212  float releasezone3, // the adaptive release curve, which is discussed in further detail in the
213  float releasezone4, // demo: adaptive-release-curve.html
214  float postgain, // dB, amount of gain to apply after compression [0 to 100]
215  float wet // amount to apply the effect [0 completely dry to 1 completely wet]
216  );
217  };
218 
219  static void sf_compressor_process(CompressorState *state, int size, float *input, float *output);
220 
225 };
226 
227 
228 
229 
230 #endif // SDRBASE_AUDIO_AUDIOCOMPRESSORSND_H_
#define AUDIOCOMPRESSORSND_SF_COMPRESSOR_MAXDELAY
static float kneecurve(float x, float k, float linearthreshold)
#define AUDIOCOMPRESSORSND_SF_COMPRESSOR_CHUNKSIZE
void initSimple(int rate, float pregain, float threshold, float knee, float ratio, float attack, float release)
CompressorState m_compressorState
static float absf(float v)
static float fixf(float v, float def)
static float adaptivereleasecurve(float x, float a, float b, float c, float d)
static float compcurve(float x, float k, float slope, float linearthreshold, float linearthresholdknee, float threshold, float knee, float kneedboffset)
static float lin2db(float lin)
static float kneeslope(float x, float k, float linearthreshold)
static float clampf(float v, float min, float max)
static float db2lin(float db)
void initDefault(int rate)
#define SDRBASE_API
Definition: export.h:40
T max(const T &x, const T &y)
Definition: framework.h:446
T min(const T &x, const T &y)
Definition: framework.h:440