Jamoma API  0.6.0.a19
TTLimiter.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup dspEffectsLib
4  *
5  * @brief #TTLimiter implements a lookahead limiter processor for controlling the dynamics of an input.
6  *
7  * @details The way this works is by buffering the input, and delaying it by N samples. That way we are able to see what the output will be some amount of time prior to actually outputting it, and adjust the gain accordingly. @n
8  * @n
9  * After some preprocessing to adjust gain and filter DC offsets on the input, we have an analysis stage. The analysis stage looks at the sample value for each channel at the input, and then uses the hottest sample to calculate the gain adjust that needs to be applied. @n
10  * @n
11  * The release attribute (specified in seconds) determines how long it takes for a gain reduction to "wear off" once the amplitude level of the input has been reduced.
12  *
13  * @authors Tim Place, Trond Lossius
14  *
15  * @copyright Copyright © 2008, Tim Place @n
16  * This code is licensed under the terms of the "New BSD License" @n
17  * http://creativecommons.org/licenses/BSD/
18  */
19 
20 
21 #include "TTLimiter.h"
22 
23 #define thisTTClass TTLimiter
24 #define thisTTClassName "limiter"
25 #define thisTTClassTags "dspEffectsLib, audio, processor, dynamics, limiter"
26 
27 
28 TT_AUDIO_CONSTRUCTOR,
29  recover(0.0),
30  lookaheadBufferIndex(0),
31  lookaheadBuffer(NULL),
32  gain(NULL),
33  last(0.0),
34  dcBlocker(kTTSym_dcblock),
35  preamp(kTTSym_gain),
36  maxBufferSize(512),
37  attrMode(TT("exponential"))
38 {
39  TTChannelCount initialMaxNumChannels = arguments;
40 
41  // register our attributes
43  registerAttribute(TT("postamp"), kTypeFloat64, &attrPostamp, (TTGetterMethod)&TTLimiter::getPostamp, (TTSetterMethod)&TTLimiter::setPostamp);
44  registerAttribute(TT("threshold"), kTypeFloat64, &attrThreshold, (TTGetterMethod)&TTLimiter::getThreshold, (TTSetterMethod)&TTLimiter::setThreshold);
45  registerAttribute(TT("lookahead"), kTypeUInt32, &attrLookahead, (TTSetterMethod)&TTLimiter::setLookahead);
46  registerAttribute(TT("release"), kTypeFloat64, &attrRelease, (TTSetterMethod)&TTLimiter::setRelease);
47  registerAttribute(TT("mode"), kTypeSymbol, &attrMode, (TTSetterMethod)&TTLimiter::setMode);
48  registerAttribute(TT("dcBlocker"), kTypeBoolean, &attrDCBlocker, (TTSetterMethod)&TTLimiter::setDCBlocker);
49 
50  // register for notifications from the parent class so we can allocate memory as required
51  addUpdates(MaxNumChannels);
52  // register for notifications from the parent class so we can update the release/recover values
53  addUpdates(SampleRate);
54 
55  // clear the history
56  addMessage(clear);
57 
58  // Set Defaults...
59  setAttributeValue(kTTSym_maxNumChannels, initialMaxNumChannels);
60  setAttributeValue("threshold", 0.0);
61  setAttributeValue("preamp", 0.0);
62  setAttributeValue("postamp", 0.0);
63  setAttributeValue("lookahead", 100);
64  setAttributeValue("mode", "exponential");
65  setAttributeValue("release", 1000.0);
66  setAttributeValue("dcBlocker", YES);
67  setAttributeValue("bypass", NO);
68 
69  clear();
70  setProcessMethod(processAudio);
71 }
72 
73 
74 TTLimiter::~TTLimiter()
75 {
76  short i;
77 
78  for (i=0; i<mMaxNumChannels; i++)
79  delete [] lookaheadBuffer[i];
80  delete [] lookaheadBuffer;
81  delete [] gain;
82 }
83 
84 
85 // TODO: These message receiver args should be reversed -- this is a change that should be applied throughout TTBlue
87 {
88  TTChannelCount channel;
89  TTChannelCount numChannels = oldMaxNumChannels;
90 
91  if (lookaheadBuffer) {
92  for (channel=0; channel<numChannels; channel++)
93  delete [] lookaheadBuffer[channel];
94  delete [] lookaheadBuffer;
95  }
96  delete gain;
97 
98  gain = new TTSampleValue[maxBufferSize];
99  lookaheadBuffer = new TTSampleValuePtr[mMaxNumChannels];
100  for (channel=0; channel<mMaxNumChannels; channel++)
102 
103  clear();
104 
105  dcBlocker.set(kTTSym_maxNumChannels, mMaxNumChannels);
106  preamp.set(kTTSym_maxNumChannels, mMaxNumChannels);
107 
108  return kTTErrNone;
109 }
110 
111 
113 {
114  setRecover();
115  return kTTErrNone;
116 }
117 
118 
120 {
121  return preamp.set("gain", newValue);
122 }
123 
125 {
126  return preamp.get("gain", value);
127 }
128 
129 
131 {
133  return kTTErrNone;
134 }
135 
137 {
139  return kTTErrNone;
140 }
141 
142 
144 {
146  return kTTErrNone;
147 }
148 
150 {
152  return kTTErrNone;
153 }
154 
155 
157 {
158  attrLookahead = TTClip(TTUInt32(newValue), TTUInt32(1), maxBufferSize-1);
160  return kTTErrNone;
161 }
162 
163 
165 {
166  attrRelease = newValue;
167  setRecover();
168  return kTTErrNone;
169 }
170 
171 
173 {
174  attrMode = newValue;
175  if (attrMode == "linear")
176  isLinear = true;
177  else
178  isLinear = false;
179  setRecover();
180  return kTTErrNone;
181 }
182 
183 
185 {
186  attrDCBlocker = newValue;
187  return dcBlocker.set("bypass", !attrDCBlocker);
188 }
189 
190 
192 {
193  TTUInt32 i;
194  TTUInt32 channel;
195 
196  for (i=0; i<maxBufferSize; i++) {
197  for (channel=0; channel < mMaxNumChannels; channel++)
198  lookaheadBuffer[channel][i] = 0.0;
199  gain[i] = 1.0; // gain is shared across channels
200  }
201 
202  lookaheadBufferIndex = 0; // was bp
203  last = 1.0;
204  setRecover();
205 
206  dcBlocker.send("clear");
207  return kTTErrNone;
208 }
209 
210 
211 // set variables related to the time it takes for the limiter to recover from a peak in the audio
212 // it is based on the release time attr, which is specified in seconds
214 {
215  recover = 1000.0 / (attrRelease * sr);
216  if (attrMode == "linear")
217  recover = recover * 0.5;
218  else
219  recover = recover * 0.707;
220 }
221 
222 
224 {
225  TTAudioSignal& in = inputs->getSignal(0);
226  TTAudioSignal& out = outputs->getSignal(0);
227  TTUInt16 vs = in.getVectorSizeAsInt();
228  TTUInt16 i, j;
229  TTSampleValue tempSample;
230  TTSampleValue hotSample;
231  TTFloat64 maybe,
232  curgain,
233  newgain,
234  inc,
235  acc;
236  TTInt16 flag,
237  lookaheadBufferPlayback,
238  ind;
239  TTUInt16 numchannels = TTAudioSignal::getMinChannelCount(in, out);
240  TTUInt16 channel;
241 
242  // Pre-Process the input
243  dcBlocker.process(in, out); // filter out DC-Offsets (unless it is bypassed)
244  preamp.process(out, in); // copy output back to input for the rest of this process
245 
246  for (i=0; i<vs; i++) {
247  hotSample = 0.0;
248 
249  // Analysis Stage ...
250  for (channel=0; channel<numchannels; channel++) {
251  tempSample = in.mSampleVectors[channel][i];
252  lookaheadBuffer[channel][lookaheadBufferIndex] = tempSample * attrPostamp;
253  tempSample = fabs(tempSample);
254  if (tempSample > hotSample)
255  hotSample = tempSample;
256  }
257 
258  if (isLinear)
259  tempSample = last + recover;
260  else {
261  if (last > 0.01)
262  tempSample = last + recover * last;
263  else
264  tempSample = last + recover;
265  }
266 
267  if (tempSample > attrThreshold)
268  maybe = attrThreshold;
269  else
270  maybe = tempSample;
271  gain[lookaheadBufferIndex] = maybe;
272 
273  lookaheadBufferPlayback = lookaheadBufferIndex - attrLookahead;
274  if (lookaheadBufferPlayback < 0)
275  lookaheadBufferPlayback += attrLookahead;
276 
277  // Process Stage ...
278  // this ***very slow*** : with a lookahead of 100, and vs = 64, we loop 640 times!
279  if (hotSample * maybe > attrThreshold) {
280  curgain = attrThreshold / hotSample;
281  inc = (attrThreshold - curgain);
282  acc = 0;
283  flag = 0;
284  for (j=0; flag==0 && j<attrLookahead; j++) {
285  ind = lookaheadBufferIndex - j;
286  if (ind<0)
287  ind += maxBufferSize;
288 
289  if (isLinear) //TODO: can't we move this condition outside the loop? isLinear won't change during a vs [NP]
290  newgain = curgain + inc * acc;
291  else
292  newgain = curgain + inc * (acc * acc);
293 
294  if (newgain < gain[ind])
295  gain[ind] = newgain;
296  else
297  flag = 1;
298  acc = acc + lookaheadInv;
299  }
300  }
301 
302  // Actual application of the gain
303  for (channel=0; channel<numchannels; channel++) {
304  out.mSampleVectors[channel][i] = lookaheadBuffer[channel][lookaheadBufferPlayback] * gain[lookaheadBufferPlayback];
305  }
306 
307  last = gain[lookaheadBufferIndex];
308  lookaheadBufferIndex++;
309  if (lookaheadBufferIndex >= attrLookahead)
310  lookaheadBufferIndex = 0;
311  }
312  return kTTErrNone;
313 }
TTFloat64 TTDecibelsToLinearGain(TTFloat64 value)
Convert decibels into linear ampliude.
TTErr(TTObjectBase::* TTSetterMethod)(const TTAttribute &attribute, const TTValue &value)
A type that can be used to store a pointer to a message for an object.
Definition: TTObjectBase.h:78
TTErr setLookahead(TTValue &newValue)
Setter for the lookahead attribute, value is in samples.
Definition: TTLimiter.cpp:156
TTBoolean isLinear
is attrMode set to linear?
Definition: TTLimiter.h:51
std::uint16_t TTUInt16
16 bit unsigned integer
Definition: TTBase.h:176
TTErr setThreshold(const TTValue &value)
Setter for the threshold attribute.
Definition: TTLimiter.cpp:143
TTFloat64 TTLinearGainToDecibels(const TTFloat64 value)
Convert linear amplitude into deciBels.
TTErr send(const TTSymbol aName)
Send a message to this object with no arguments.
Definition: TTObject.cpp:135
TTErr getPostamp(TTValue &value)
Getter for the threshold attribute.
Definition: TTLimiter.cpp:136
TTErr setPreamp(TTValue &value)
Setter for the threshold attribute.
Definition: TTLimiter.cpp:119
TTErr getPreamp(TTValue &value)
Getter for the threshold attribute.
Definition: TTLimiter.cpp:124
TTErr setDCBlocker(TTValue &newValue)
Setter for the dcblocker attribute.
Definition: TTLimiter.cpp:184
TTChannelCount mMaxNumChannels
This is the maximum number of channels that can be guaranteed to work.
TTAudioObject dcBlocker
TTDCBlock object
Definition: TTLimiter.h:53
TTFloat64 lookaheadInv
reciprocal (inverse) of the lookahead attribute
Definition: TTLimiter.h:46
TTUInt32 maxBufferSize
TODO: make this settable.
Definition: TTLimiter.h:56
TTErr setPostamp(const TTValue &value)
Setter for the threshold attribute.
Definition: TTLimiter.cpp:130
#define setProcessMethod(methodName)
A convenience macro to be used by subclasses for setting the process method.
TTSymbol attrMode
may be one of two symbols: "linear" or "exponential".
Definition: TTLimiter.h:58
TTLimiter implements a lookahead limiter processor for controlling the dynamics of an input...
Symbol type.
Definition: TTBase.h:282
double TTFloat64
64 bit floating point number
Definition: TTBase.h:188
#define TT
This macro is defined as a shortcut for doing a lookup in the symbol table.
Definition: TTSymbol.h:155
TTErr updateMaxNumChannels(const TTValue &oldMaxNumChannels, TTValue &)
Override the setter for the inherited maxNumChannels attribute.
Definition: TTLimiter.cpp:86
std::int16_t TTInt16
16 bit signed integer
Definition: TTBase.h:175
TTErr get(const TTSymbol aName, T &aReturnedValue) const
Get an attribute value for an object.
TTFloat64 attrRelease
number of seconds for the release to recover after a peak in the audio signal.
Definition: TTLimiter.h:59
TTFloat64 attrThreshold
linear amplitude threshold at which the limiting should kick in (attr setter used dB)...
Definition: TTLimiter.h:61
void setRecover()
Private utility used by the audio processing routine.
Definition: TTLimiter.cpp:213
64-bit floating point
Definition: TTBase.h:272
TTErr processAudio(TTAudioSignalArrayPtr inputs, TTAudioSignalArrayPtr outputs)
Standard audio processing method as used by TTBlue objects.
Definition: TTLimiter.cpp:223
TTErr set(const TTSymbol aName, T aValue)
Set an attribute value for an object.
Boolean (1/0) or (true/false) flag.
Definition: TTBase.h:281
static TTChannelCount getMinChannelCount(const TTAudioSignal &signal1, const TTAudioSignal &signal2)
Use this class method to determine the least number of channels the two signals have in common...
The TTAudioSignal class represents N vectors of audio samples for M channels.
Definition: TTAudioSignal.h:57
TTSampleValue ** mSampleVectors
An array of pointers to the first sample in each vector. Declared Public for fast access...
Definition: TTAudioSignal.h:74
TTErr setMode(TTValue &newValue)
Setter for the mode attribute.
Definition: TTLimiter.cpp:172
TTUInt16 TTChannelCount
Data type used when counting the number of channels in multi-channel audio signals and processes...
Definition: TTAudioSignal.h:31
TTBoolean attrDCBlocker
If toggled to NO, the internal DC Blocker will be turned off.
Definition: TTLimiter.h:57
TTFloat64 attrPostamp
linear gain scaling factor after the limiting (attr setter used dB).
Definition: TTLimiter.h:63
A simple container for an array of TTAudioSignal pointers.
TTErr
Jamoma Error Codes Enumeration of error codes that might be returned by any of the TTBlue functions a...
Definition: TTBase.h:342
TTUInt32 attrLookahead
number of samples by which to look forward.
Definition: TTLimiter.h:60
std::uint32_t TTUInt32
32 bit unsigned integer
Definition: TTBase.h:178
TTErr getThreshold(TTValue &value)
Getter for the threshold attribute.
Definition: TTLimiter.cpp:149
#define addMessage(name)
A convenience macro to be used by subclasses for registering messages.
Definition: TTMessage.h:19
TTErr setRelease(TTValue &newValue)
Setter for the release attribute.
Definition: TTLimiter.cpp:164
32-bit unsigned integer, range is 0 through 4,294,967,295.
Definition: TTBase.h:278
No Error.
Definition: TTBase.h:343
TTAudioObject preamp
TTGain object to apply preamp
Definition: TTLimiter.h:54
TTErr clear()
Clear the history: reset the limiter.
Definition: TTLimiter.cpp:191
TTErr(TTObjectBase::* TTGetterMethod)(const TTAttribute &attribute, TTValue &value)
A type that can be used to store a pointer to a message for an object.
Definition: TTObjectBase.h:73
TTSampleValue ** lookaheadBuffer
keep a lookahead buffer for each channel
Definition: TTLimiter.h:48
TTFloat64 TTSampleValue
A value representing a single audio sample.
Definition: TTBase.h:230
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34
TTErr updateSampleRate(const TTValue &oldSampleRate, TTValue &)
Receives notifications when there are changes to the inherited sr attribute.
Definition: TTLimiter.cpp:112
#define addUpdates(updateName)
An 'update' is a message sent to a subclass instance from its parent class.
Definition: TTMessage.h:44
TTUInt32 sr
Current sample rate being used by this object.