Jamoma API  0.6.0.a19
TTHalfband5.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup dspFilterLib
4  *
5  * @brief #TTHalfband5 is a 5-Pole Halfband filter built up from a 2-path allpass structure.
6  *
7  * @details
8  *
9  * @authors Timothy Place, Trond Lossius
10  *
11  * @copyright Copyright © 2010, Timothy Place @n
12  * This code is licensed under the terms of the "New BSD License" @n
13  * http://creativecommons.org/licenses/BSD/
14  */
15 
16 
17 #include "TTHalfband5.h"
18 
19 #define thisTTClass TTHalfband5
20 #define thisTTClassName "halfband.5"
21 #define thisTTClassTags "dspFilterLib, audio, processor, filter, lowpass, highpass"
22 
23 #ifdef TT_PLATFORM_WIN
24 #include <Algorithm>
25 #endif
26 
27 TT_AUDIO_CONSTRUCTOR,
28  mF0("allpass.1b"),
29  mF1("allpass.1b"),
30  mDelay("allpass.1a"),
31  mR0("allpass.1a"),
32  mR1("allpass.1a")
33 {
34  TTChannelCount initialMaxNumChannels = arguments;
35 
37  addMessage(clear);
38  addUpdates(MaxNumChannels);
39 
40  setAttributeValue(kTTSym_maxNumChannels, initialMaxNumChannels);
41  setAttributeValue(TT("mode"), TT("lowpass"));
42 
43  // for the simple 1-sample delay, we set alpha (the feedback coefficient) to zero
44  mDelay.set("alpha", 0.0);
45 
46  // -60 db attenuation, stopband starts at fs * 0.37
47  //mF0->setAttributeValue(TT("alpha"), 0.1413486);
48  //mF1->setAttributeValue(TT("alpha"), 0.5899948);
49  //mR0->setAttributeValue(TT("alpha"), 0.1413486);
50  //mR1->setAttributeValue(TT("alpha"), 0.5899948);
51 
52  // -83 db attenuation, stopband starts at f_s * 0.42
53  mF0.set("alpha", 0.117266261862726);
54  mF1.set("alpha", 0.549470222366184);
55  mR0.set("alpha", 0.117266261862726);
56  mR1.set("alpha", 0.549470222366184);
57 }
58 
59 
60 TTHalfband5::~TTHalfband5()
61 {
62 }
63 
64 
65 TTErr TTHalfband5::updateMaxNumChannels(const TTValue& oldMaxNumChannels, TTValue&)
66 {
67  mRSwitch.resize(mMaxNumChannels);
68  mRSwitch.assign(mMaxNumChannels, 0.0);
69 
70  mY0.resize(mMaxNumChannels);
71  mY0.assign(mMaxNumChannels, 0.0);
72  mY1.resize(mMaxNumChannels);
73  mY1.assign(mMaxNumChannels, 0.0);
74 
75  // update internal filters
76  mF0.set(kTTSym_maxNumChannels, mMaxNumChannels);
77  mF1.set(kTTSym_maxNumChannels, mMaxNumChannels);
78  mR0.set(kTTSym_maxNumChannels, mMaxNumChannels);
79  mR1.set(kTTSym_maxNumChannels, mMaxNumChannels);
80  mDelay.set(kTTSym_maxNumChannels, mMaxNumChannels);
81 
82  clear();
83  return kTTErrNone;
84 }
85 
86 
87 TTErr TTHalfband5::clear()
88 {
89  mF0.send(kTTSym_clear);
90  mF1.send(kTTSym_clear);
91  mR0.send(kTTSym_clear);
92  mR1.send(kTTSym_clear);
93  mDelay.send(kTTSym_clear);
94  return kTTErrNone;
95 }
96 
97 
98 TTErr TTHalfband5::setMode(const TTValue& newValue)
99 {
100  TTSymbol newMode = newValue;
101 
102  if (newMode == TT("upsample")) {
103  mMode = TT("upsample");
104  setCalculateMethod(calculateUpsample);
105  setProcessMethod(processUpsample);
106  }
107  else if (newMode == TT("downsample")) { // downsample
108  mMode = TT("downsample");
109  setCalculateMethod(calculateDownsample);
110  setProcessMethod(processDownsample);
111  }
112  else if (newMode == TT("highpass")) {
113  mMode = TT("highpass");
114  setCalculateMethod(calculateHighpass);
115  setProcessMethod(processHighpass);
116  }
117  else { // lowpass
118  mMode = TT("lowpass");
119  setCalculateMethod(calculateLowpass);
120  setProcessMethod(processLowpass);
121  }
122  return kTTErrNone;
123 }
124 
125 
126 TTErr TTHalfband5::calculateLowpass(const TTFloat64& x, TTFloat64& y, TTPtrSizedInt channel)
127 {
128  TTFloat64 outputFromTopPath;
129  TTFloat64 outputFromBottomPathDelay;
130  TTFloat64 outputFromBottomPath;
131 
132  TTBASE(mF0, TTAllpass1b)->calculateValue(x, outputFromTopPath, channel);
133 
134  TTBASE(mDelay, TTAllpass1a)->calculateValue(x, outputFromBottomPathDelay, channel);
135  TTBASE(mF1, TTAllpass1b)->calculateValue(outputFromBottomPathDelay, outputFromBottomPath, channel);
136 
137  y = (outputFromTopPath + outputFromBottomPath) * 0.5;
138  return kTTErrNone;
139 }
140 
141 
142 TTErr TTHalfband5::calculateHighpass(const TTFloat64& x, TTFloat64& y, TTPtrSizedInt channel)
143 {
144  TTFloat64 outputFromTopPath;
145  TTFloat64 outputFromBottomPathDelay;
146  TTFloat64 outputFromBottomPath;
147 
148  TTBASE(mF0, TTAllpass1b)->calculateValue(x, outputFromTopPath, channel);
149 
150  TTBASE(mDelay, TTAllpass1a)->calculateValue(x, outputFromBottomPathDelay, channel);
151  TTBASE(mF1, TTAllpass1b)->calculateValue(outputFromBottomPathDelay, outputFromBottomPath, channel);
152 
153  // the only difference between the lowpass and highpass is the sign of the bottom path in this calculation
154  y = (outputFromTopPath - outputFromBottomPath) * 0.5;
155  return kTTErrNone;
156 }
157 
158 
159 // for every second input sample, we calculate an output sample
160 TTErr TTHalfband5::calculateDownsample(const TTFloat64& x, TTFloat64& y, TTPtrSizedInt channel)
161 {
162 #define VERSION_WITH_DELAY_FACTORED_OUT 1
163 #if VERSION_WITH_DELAY_FACTORED_OUT
164  if (mRSwitch[channel]) {
165  TTFloat64 temp;
166 
167  TTBASE(mR0, TTAllpass1a)->calculateValue(x, temp, channel);
168  y = (temp + mY1[channel]) * 0.5;
169  mRSwitch[channel] = 0;
170  }
171  else {
172  TTBASE(mR1, TTAllpass1a)->calculateValue(x, mY1[channel], channel);
173  mRSwitch[channel] = 1;
174  }
175 #else
176  // This version has the delay in place, but tests in Max/AudioGraph show that both
177  // versions of this algorithm work equally well, as stated by the F.H. book
178  // (and unlike my findings for the upsampling algorithm which requires the delay).
179 
180  TTBASE(mDelay, TTAllpass1a)->calculateValue(x, mY1[channel], channel);
181  if (mRSwitch[channel]) {
182  TTFloat64 outputFromTopPath;
183  TTFloat64 outputFromBottomPath;
184 
185  TTBASE(mR0, TTAllpass1a)->calculateValue(x, outputFromTopPath, channel);
186  TTBASE(mR1, TTAllpass1a)->calculateValue(mY1[channel], outputFromBottomPath, channel);
187  mY0[channel] = (outputFromTopPath + outputFromBottomPath) * 0.5;
188 
189  mRSwitch[channel] = 0;
190  }
191  else
192  mRSwitch[channel] = 1;
193 
194  y = mY0[channel];
195 #endif
196  return kTTErrNone;
197 }
198 
199 
200 // for every second output sample, we calculate from a given input sample
201 TTErr TTHalfband5::calculateUpsample(const TTFloat64& x, TTFloat64& y, TTPtrSizedInt channel)
202 {
203  TTFloat64 temp;
204 
205  if (mRSwitch[channel]) {
206  TTBASE(mR0, TTAllpass1a)->calculateValue(x, mY0[channel], channel);
207  TTBASE(mR1, TTAllpass1a)->calculateValue(x, mY1[channel], channel);
208  mRSwitch[channel] = 0;
209  }
210  else {
211  mRSwitch[channel] = 1;
212  }
213 
214  TTBASE(mDelay, TTAllpass1a)->calculateValue(mY1[channel], temp, channel);
215  y = (mY0[channel] + temp) * 0.5;
216 
217  return kTTErrNone;
218 }
219 
220 
221 TTErr TTHalfband5::processLowpass(TTAudioSignalArrayPtr inputs, TTAudioSignalArrayPtr outputs)
222 {
223  TT_WRAP_CALCULATE_METHOD(calculateLowpass);
224 }
225 
226 
227 TTErr TTHalfband5::processHighpass(TTAudioSignalArrayPtr inputs, TTAudioSignalArrayPtr outputs)
228 {
229  TT_WRAP_CALCULATE_METHOD(calculateHighpass);
230 }
231 
232 
233 TTErr TTHalfband5::processDownsample(TTAudioSignalArrayPtr inputs, TTAudioSignalArrayPtr outputs)
234 {
235  TTAudioSignal& in = inputs->getSignal(0);
236  TTAudioSignal& out = outputs->getSignal(0);
237  TTSampleValue* inSample;
238  TTSampleValue* outSample;
239  TTChannelCount numchannels = TTAudioSignal::getMinChannelCount(in, out);
240  TTPtrSizedInt channel;
241  TTUInt16 targetVectorSize = in.getVectorSizeAsInt() / 2;
242  //TTErr err;
243 
244  out.changeVectorSize(targetVectorSize);
245  out.setSampleRate(in.getSampleRate() / 2);
246  for (channel=0; channel<numchannels; channel++) {
247  TTUInt16 n = targetVectorSize;
248 
249  inSample = in.mSampleVectors[channel];
250  outSample = out.mSampleVectors[channel];
251 
252  while (n--) {
253  calculateDownsample(*inSample, *outSample, channel);
254  inSample++;
255  calculateDownsample(*inSample, *outSample, channel);
256  inSample++;
257  outSample++;
258  }
259  }
260  return kTTErrNone;
261 }
262 
263 
264 TTErr TTHalfband5::processUpsample(TTAudioSignalArrayPtr inputs, TTAudioSignalArrayPtr outputs)
265 {
266  TTAudioSignal& in = inputs->getSignal(0);
267  TTAudioSignal& out = outputs->getSignal(0);
268  TTSampleValue* inSample;
269  TTSampleValue* outSample;
270  TTChannelCount numchannels = TTAudioSignal::getMinChannelCount(in, out);
271  TTPtrSizedInt channel;
272  TTUInt16 targetVectorSize = in.getVectorSizeAsInt() * 2;
273  TTErr err;
274 
275  err = out.changeVectorSize(targetVectorSize);
276  if (!err) {
277  out.setSampleRate(in.getSampleRate() * 2);
278  for (channel=0; channel<numchannels; channel++) {
279  TTUInt16 n = in.getVectorSizeAsInt();
280 
281  inSample = in.mSampleVectors[channel];
282  outSample = out.mSampleVectors[channel];
283 
284  while (n--) {
285  calculateUpsample(*inSample, *outSample, channel);
286  outSample++;
287  calculateUpsample(*inSample, *outSample, channel);
288  outSample++;
289  inSample++;
290  }
291  }
292  }
293  return kTTErrNone;
294 }
295 
std::uint16_t TTUInt16
16 bit unsigned integer
Definition: TTBase.h:176
TTErr send(const TTSymbol aName)
Send a message to this object with no arguments.
Definition: TTObject.cpp:135
TTAudioObject mF1
filter1 (in the lower path, second block)
Definition: TTHalfband5.h:36
TTChannelCount mMaxNumChannels
This is the maximum number of channels that can be guaranteed to work.
TTSampleVector mY0
resampling path0 output (for each channel)
Definition: TTHalfband5.h:41
TTAudioObject mR1
resampling filter1 (in the lower path, second block)
Definition: TTHalfband5.h:39
#define TTBASE(instance_, class_)
Macro to access the actual C++ class that is contained inside of the TTObject as a pointer...
Definition: TTObject.h:211
#define setProcessMethod(methodName)
A convenience macro to be used by subclasses for setting the process method.
Symbol type.
Definition: TTBase.h:282
double TTFloat64
64 bit floating point number
Definition: TTBase.h:188
TTAudioObject mF0
filter0 (in the upper path)
Definition: TTHalfband5.h:35
#define TT
This macro is defined as a shortcut for doing a lookup in the symbol table.
Definition: TTSymbol.h:155
#define setCalculateMethod(methodName)
A convenience macro to be used by subclasses for setting the calculate method.
TTSymbol mMode
Attribute: lowpass or highpass.
Definition: TTHalfband5.h:43
TTAudioObject mR0
resampling filter0 (in the upper path)
Definition: TTHalfband5.h:38
TTErr set(const TTSymbol aName, T aValue)
Set an attribute value for an object.
The TTSymbol class is used to represent a string and efficiently pass and compare that string...
Definition: TTSymbol.h:26
TTSampleVector mY1
resampling path1 output (for each channel)
Definition: TTHalfband5.h:42
A first-order building-block allpass filter.
Definition: TTAllpass1a.h:25
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
TTSampleVector mRSwitch
resampling switch (so we know which path to calculate)
Definition: TTHalfband5.h:40
TTSampleValue ** mSampleVectors
An array of pointers to the first sample in each vector. Declared Public for fast access...
Definition: TTAudioSignal.h:74
TTUInt16 TTChannelCount
Data type used when counting the number of channels in multi-channel audio signals and processes...
Definition: TTAudioSignal.h:31
A simple container for an array of TTAudioSignal pointers.
long TTPtrSizedInt
An integer that is the same size as a pointer.
Definition: TTBase.h:240
TTAudioObject mDelay
delay (in the lower path, first block)
Definition: TTHalfband5.h:37
A first-order building-block allpass filter.
Definition: TTAllpass1b.h:25
TTErr
Jamoma Error Codes Enumeration of error codes that might be returned by any of the TTBlue functions a...
Definition: TTBase.h:342
#define addAttributeWithSetter(name, type)
A convenience macro to be used by subclasses for registering attributes with a custom setter...
Definition: TTAttribute.h:47
#define addMessage(name)
A convenience macro to be used by subclasses for registering messages.
Definition: TTMessage.h:19
No Error.
Definition: TTBase.h:343
TTHalfband5 is a 5-Pole Halfband filter built up from a 2-path allpass structure. ...
TTFloat64 TTSampleValue
A value representing a single audio sample.
Definition: TTBase.h:230
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34
#define addUpdates(updateName)
An 'update' is a message sent to a subclass instance from its parent class.
Definition: TTMessage.h:44