Jamoma API  0.6.0.a19
TTWavetable.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup dspGeneratorLib
4  *
5  * @brief GeneratorLib: Generate a basic, cycling waveform using a wavetable.
6  *
7  * @details Wavetable is currently limited to using an internal buffer for managing its waveshape. Shape options include sine, triangle and sawtooth.
8  *
9  * @see TTBuffer, TTSampleMatrix, TTMatrix, TTAudioSignal
10  *
11  * @authors Tim Place, Nathan Wolek
12  *
13  * @copyright Copyright © 2003-2013 by Timothy Place & Nathan Wolek @n
14  * This code is licensed under the terms of the "New BSD License" @n
15  * http://creativecommons.org/licenses/BSD/
16  */
17 
18 #include "TTWavetable.h"
19 
20 #define thisTTClass TTWavetable
21 #define thisTTClassName "wavetable"
22 #define thisTTClassTags "dspGeneratorLib, audio, generator, oscillator, buffer"
23 
24 
25 TT_AUDIO_CONSTRUCTOR,
26  mIndex(0.0),
27  mIndexDelta(0.0),
28  mInternalBuffer(1,1),
29  mWavetable(NULL)
30 {
31  TTChannelCount initialMaxNumChannels = arguments;
32 
36  addAttributeWithSetter(Interpolation, kTypeSymbol);
38 
39  addUpdates(SampleRate);
40 
41  // Set Defaults...
42  setAttributeValue("maxNumChannels", initialMaxNumChannels);
43  setAttributeValue("size", 8192);
44  setAttributeValue("mode", kTTSym_sine);
45  setAttributeValue("frequency", 440.0);
46  setAttributeValue("gain", 0.0); // 0 dB
47  setAttributeValue("interpolation", "linear");
48 
49  // Checkout the current SampleMatrix as wavetable...
50  mInternalBuffer.checkOutMatrix(mWavetable);
51 }
52 
53 
54 TTWavetable::~TTWavetable()
55 {
56 }
57 
58 
60 {
61  setAttributeValue("frequency", mFrequency);
62  return kTTErrNone;
63 }
64 
65 
67 {
68  mFrequency = TTClip<TTFloat64>(newValue, 0.0, sr/2.0);
69  mIndexDelta = mFrequency * mSize * srInv;
70  return kTTErrNone;
71 }
72 
73 
75 {
76  // TODO: implement the ability to use an externally defined buffer
77  // would support via mMode == TT("externalBuffer")
78 
79  mMode = newValue[0];
80  //TTValue aReturnWeDontCareAbout;
81 
82  if (mMode != TT("filePath")) {
83 
84  // use fill() to draw the appropriate waveform
85  return mInternalBuffer.fill(newValue);
86 
87  } else {
88 
89  if (newValue.size() > 1) {
90 
91  // use resizeThenLoad() to import a soundfile
92  TTValue soundFilePath = newValue[1];
93  return mInternalBuffer.resizeThenLoad(soundFilePath);
94 
95  } else {
96  return kTTErrWrongNumValues;
97  }
98  }
99 }
100 
101 
103 {
104  mInterpolation = newValue;
105  if (mInterpolation == "linear")
107  else if (mInterpolation == "lfo")
109  else
111  return kTTErrNone;
112 }
113 
114 
116 {
117  mGain = newValue;
118  mLinearGain = TTDecibelsToLinearGain(mGain);
119  return kTTErrNone;
120 }
121 
122 
124 {
125  mSize = newSize;
126  mInternalBuffer.set("lengthInSamples", mSize);
127  return setFrequency(mFrequency); // touch the frequency so that the step size is updated
128  // Q: should resizing the internal buffer cause the waveform to be re-drawn?
129 }
130 
131 
132 // LFO mode only updates values once per vector in order to be as fast as possible
133 // LFO mode cannot be modulated
135 {
136  TTAudioSignal& out = outputs->getSignal(0);
137  TTSampleValue tempSample;
138  TTUInt16 vs = out.getVectorSizeAsInt();
139  TTUInt16 i=0;
140  TTChannelCount numChannels = out.getNumChannelsAsInt();
141  TTChannelCount channel;
142  TTUInt64 p1 = (TTUInt64)mIndex; // playback index
143 
144  // Move the play head
145  mIndex += (mIndexDelta * vs);
146 
147  // Wrap the play head
148  if (mIndex >= mSize)
149  {
150  mIndex -= mSize;
151  mInternalBuffer.checkInMatrix(mWavetable);
152  mInternalBuffer.checkOutMatrix(mWavetable);
153  } else if (mIndex < 0) {
154  mIndex += mSize;
155  mInternalBuffer.checkInMatrix(mWavetable);
156  mInternalBuffer.checkOutMatrix(mWavetable);
157  }
158 
159  // table lookup (no interpolation)
160  // CURRENTLY: this is hard coded to look only at the first channel, and all other channels in the buffer are ignored
161  mWavetable->peek(p1,0,tempSample);
162  tempSample *= mLinearGain;
163 
164  // TODO: in TTBlue 0.2.x this code only assigned the first sample value to save cpu -- should we bring this back as an option?
165  while (vs--) {
166  for (channel=0; channel<numChannels; channel++)
167  out.mSampleVectors[channel][i] = tempSample;
168  i++;
169  }
170 
171  return kTTErrNone;
172 }
173 
174 
176 {
177  TTAudioSignalPtr in; // can't call getSignal if there is no signal! = inputs->getSignal(0);
178  TTAudioSignal& out = outputs->getSignal(0);
179  TTSampleValue *inSample = NULL;
180  TTSampleValue tempSample;
181  TTUInt16 vs = out.getVectorSizeAsInt();
182  TTUInt16 i=0;
183  TTChannelCount numChannels = out.getNumChannelsAsInt();
184  TTChannelCount channel;
185  TTBoolean hasModulation = true;
186 
187  // If the input and output signals are the same, then there really isn't an input signal
188  // In that case we don't modulate the oscillator with it
189  if (inputs->numAudioSignals == 0)
190  hasModulation = false;
191  else {
192  in = &inputs->getSignal(0);
193  inSample = in->mSampleVectors[0];
194  }
195  while (vs--) {
196  TTUInt64 p1 = (TTUInt64)mIndex; // playback index
197 
198  // TODO: all of this access of mIndex and mIndexDelta etc is really going to be dereference pointers in our struct/class
199  // This likely means that the values are not cached (or at least not cached together) in the processors registers
200  // We should copy these to local variables at the vector start and then copy them back at the vector's end
201 
202  // Move the play head
203  mIndex += mIndexDelta;
204 
205  // Apply modulation to the play head
206  if (hasModulation)
207  mIndex += *inSample++ * mSize / sr;
208 
209  // Wrap the play head
210  if (mIndex >= mSize)
211  {
212  mIndex -= mSize;
213  mInternalBuffer.checkInMatrix(mWavetable);
214  mInternalBuffer.checkOutMatrix(mWavetable);
215  } else if (mIndex < 0) {
216  mIndex += mSize;
217  mInternalBuffer.checkInMatrix(mWavetable);
218  mInternalBuffer.checkOutMatrix(mWavetable);
219  }
220 
221  // table lookup (no interpolation)
222  // CURRENTLY: this is hard coded to look only at the first channel, and all other channels in the buffer are ignored
223  mWavetable->peek(p1,0,tempSample);
224  tempSample *= mLinearGain;
225  for (channel=0; channel<numChannels; channel++)
226  out.mSampleVectors[channel][i] = tempSample;
227  i++;
228  }
229 
230  return kTTErrNone;
231 }
232 
233 
235 {
236  TTAudioSignalPtr in; // can't call getSignal if there is no signal! = inputs->getSignal(0);
237  TTAudioSignal& out = outputs->getSignal(0);
238  TTSampleValue *inSample = NULL;
239  TTSampleValue tempSample;
240  TTUInt16 vs = out.getVectorSizeAsInt();
241  TTUInt16 i=0;
242  TTChannelCount numChannels = out.getNumChannelsAsInt();
243  TTChannelCount channel;
244  TTBoolean hasModulation = true;
245 
246  // If the input and output signals are the same, then there really isn't an input signal
247  // In that case we don't modulate the oscillator with it
248  if (inputs->numAudioSignals == 0)
249  hasModulation = false;
250  else {
251  in = &inputs->getSignal(0);
252  inSample = in->mSampleVectors[0];
253  }
254  while (vs--) {
255  // Move the play head
256  mIndex += mIndexDelta;
257 
258  // Apply modulation to the play head
259  if (hasModulation)
260  mIndex += *inSample++ * mSize / sr;
261 
262  // Wrap the play head
263  if (mIndex >= mSize)
264  {
265  mIndex -= mSize;
266  mInternalBuffer.checkInMatrix(mWavetable);
267  mInternalBuffer.checkOutMatrix(mWavetable);
268  } else if (mIndex < 0) {
269  mIndex += mSize;
270  mInternalBuffer.checkInMatrix(mWavetable);
271  mInternalBuffer.checkOutMatrix(mWavetable);
272  }
273 
274  // table lookup (linear interpolation)
275  // CURRENTLY: this is hard coded to look only at the first channel, and all other channels in the buffer are ignored
276  mWavetable->peeki(mIndex,0,tempSample);
277  tempSample *= mLinearGain;
278  for (channel=0; channel<numChannels; channel++)
279  out.mSampleVectors[channel][i] = tempSample;
280  i++;
281  }
282 
283  //mWavetable = contents; // update the class variable
284  return kTTErrNone;
285 }
TTFloat64 TTDecibelsToLinearGain(TTFloat64 value)
Convert decibels into linear ampliude.
bool TTBoolean
Boolean flag, same as Boolean on the Mac.
Definition: TTBase.h:167
std::uint16_t TTUInt16
16 bit unsigned integer
Definition: TTBase.h:176
std::uint64_t TTUInt64
64 bit unsigned integer
Definition: TTBase.h:180
TTErr updateSampleRate(const TTValue &, TTValue &)
This method gets called when the inherited sample-rate attribute is changed.
Definition: TTWavetable.cpp:59
TTErr setGain(const TTValue &value)
Setter for the gain attribute in dB.
TTUInt32 mSize
how many samples in the wave table
Definition: TTWavetable.h:37
size_type size() const noexcept
Return the number of elements.
The wrong number of values were passed to a method or attribute.
Definition: TTBase.h:350
#define setProcessMethod(methodName)
A convenience macro to be used by subclasses for setting the process method.
TTErr setInterpolation(const TTValue &value)
Setter for the interpolation attribute.
TTErr setFrequency(const TTValue &value)
Setter for the frequency attribute in Hz.
Definition: TTWavetable.cpp:66
GeneratorLib: Generate a basic, cycling waveform using a wavetable.
TTErr setAttributeValue(const TTSymbol name, TTValue &value)
Set an attribute value for an object.
Symbol type.
Definition: TTBase.h:282
#define TT
This macro is defined as a shortcut for doing a lookup in the symbol table.
Definition: TTSymbol.h:155
64-bit floating point
Definition: TTBase.h:272
TTErr set(const TTSymbol aName, T aValue)
Set an attribute value for an object.
TTErr setMode(const TTValue &value)
Setter for the mode attribute.
Definition: TTWavetable.cpp:74
TTErr processWithNoInterpolation(TTAudioSignalArrayPtr inputs, TTAudioSignalArrayPtr outputs)
Process method.
The TTAudioSignal class represents N vectors of audio samples for M channels.
Definition: TTAudioSignal.h:57
TTErr setSize(const TTValue &newSize)
Setter for the size attribute.
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.
TTErr processAsLFO(TTAudioSignalArrayPtr, TTAudioSignalArrayPtr outputs)
Process method.
TTErr
Jamoma Error Codes Enumeration of error codes that might be returned by any of the TTBlue functions a...
Definition: TTBase.h:342
TTErr processWithLinearInterpolation(TTAudioSignalArrayPtr inputs, TTAudioSignalArrayPtr outputs)
Process method.
#define addAttributeWithSetter(name, type)
A convenience macro to be used by subclasses for registering attributes with a custom setter...
Definition: TTAttribute.h:47
32-bit unsigned integer, range is 0 through 4,294,967,295.
Definition: TTBase.h:278
TTFloat64 srInv
1.0 over the current sample rate (inverse)
No Error.
Definition: TTBase.h:343
TTSymbol mInterpolation
should be none, linear, or eventually something better...
Definition: TTWavetable.h:36
TTFloat64 TTSampleValue
A value representing a single audio sample.
Definition: TTBase.h:230
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34
TTChannelCount numAudioSignals
The number of audio signal pointers which are actually valid.
#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.