1 #pragma once
2 
3 #include "util/types.h"
4 
5 class EngineSideChainCompressor {
6   public:
7     EngineSideChainCompressor(const QString& group);
~EngineSideChainCompressor()8     virtual ~EngineSideChainCompressor() { };
9 
setParameters(CSAMPLE threshold,CSAMPLE strength,unsigned int attack_time,unsigned int decay_time)10     void setParameters(CSAMPLE threshold, CSAMPLE strength,
11                        unsigned int attack_time, unsigned int decay_time) {
12         // TODO(owilliams): There is a race condition here because the parameters
13         // are not updated atomically.  This function should instead take a
14         // struct.
15         m_threshold = threshold;
16         m_strength = strength;
17         m_attackTime = attack_time;
18         m_decayTime = decay_time;
19         calculateRates();
20     }
21 
setThreshold(CSAMPLE threshold)22     void setThreshold(CSAMPLE threshold) {
23         m_threshold = threshold;
24         calculateRates();
25     }
26 
setStrength(CSAMPLE strength)27     void setStrength(CSAMPLE strength) {
28         m_strength = strength;
29         calculateRates();
30     }
31 
setAttackTime(unsigned int attack_time)32     void setAttackTime(unsigned int attack_time) {
33         m_attackTime = attack_time;
34         calculateRates();
35     }
36 
setDecayTime(unsigned int decay_time)37     void setDecayTime(unsigned int decay_time) {
38         m_decayTime = decay_time;
39         calculateRates();
40     }
41 
42     /// Forces the above threshold flag to the given value without calculations
43     void setAboveThreshold(bool value);
44 
45     // Every loop, before calling process, first call processKey to feed
46     // the compressor the input key signal.  It is safe to call this function
47     // multiple times for multiple keys, however they will not be summed together
48     // so compression will not be triggered unless at least one buffer would
49     // have triggered alone.
50     void processKey(const CSAMPLE* pIn, const int iBufferSize);
51 
52     // Calculates a new gain value based on the current compression ratio
53     // over the given number of frames and whether the current input is above threshold.
54     double calculateCompressedGain(int frames);
55 
56   private:
57     // Update the attack and decay rates.
58     void calculateRates();
59 
60     // The current ratio the signal is being compressed.  This is the same as m_strength
61     // when the compressor is at maximum engagement (not attacking or decaying).
62     CSAMPLE m_compressRatio;
63 
64     // True if the input signal is above the threshold.
65     bool m_bAboveThreshold;
66 
67     // The sample value above which the compressor is triggered.
68     CSAMPLE m_threshold;
69 
70     // The largest ratio the signal can be compressed.
71     CSAMPLE m_strength;
72 
73     // The length of time, in frames (samples/2), until maximum compression is reached.
74     unsigned int m_attackTime;
75 
76     // The length of time, in frames, until compression is completely off.
77     unsigned int m_decayTime;
78 
79     // These are the delta compression values per sample based on the strengths and timings.
80     CSAMPLE m_attackPerFrame;
81     CSAMPLE m_decayPerFrame;
82 };
83