Jamoma API  0.6.0.a19
TTSampleMatrix.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup dspLibrary
4  *
5  * @brief Container object that holds some audio in a chunk of memory.
6  *
7  * @see TTMatrix, TTAudioSignal
8  *
9  * @authors Timothy Place & Nathan Wolek
10  *
11  * @copyright Copyright © 2003-2012, Timothy Place & Nathan Wolek @n
12  * This code is licensed under the terms of the "New BSD License" @n
13  * http://creativecommons.org/licenses/BSD/
14  */
15 
16 #include "TTSampleMatrix.h"
17 #include "TTInterpolate.h"
18 //#include "TTSoundfileLoader.h"
19 
20 #define thisTTClass TTSampleMatrix
21 #define thisTTClassName "samplematrix"
22 #define thisTTClassTags "dspLibrary, audio, buffer"
23 
24 TTObjectBasePtr TTSampleMatrix::instantiate(TTSymbol name, TTValue arguments)
25 {
26  return new TTSampleMatrix(arguments);
27 }
28 
29 
30 extern "C" void TTSampleMatrix::registerClass()
31 {
32  TTClassRegister(thisTTClassName, thisTTClassTags, TTSampleMatrix::instantiate);
33 }
34 
35 
36 TTSampleMatrix::TTSampleMatrix(const TTValue& arguments) :
37  TTMatrixBase(arguments),
38  mSampleRate(ttEnvironment->mSampleRate)
39 {
40  this->setTypeWithoutResize(kTypeFloat64);
41  this->setElementCountWithoutResize(1);
42  this->resize();
43  this->mUserCount = 0;
44  this->mBufferPoolStage = kSM_Idle;
45 
49  addAttribute(SampleRate, kTypeUInt32);
50  addAttribute( UserCount, kTypeUInt16);
51  addAttributeProperty( UserCount, readOnly, YES);
52 
53  addMessage(normalize);
55 
56  addMessageWithArguments(getValueAtIndex);
57  registerMessage("peek", (TTMethod)&TTSampleMatrix::getValueAtIndex);
58  registerMessage("peeki", (TTMethod)&TTSampleMatrix::getValueAtIndex);
59 
60  addMessageWithArguments(setValueAtIndex);
62 
64 
65  // TODO: more messages to implement
66  // "readFile" (requires libsndfile straightening-out)
67  // "writeFile" (requires libsndfile straightening-out)
68  // a way to query attributes: for example what is the sr and bpm of an AIFF file?
69 }
70 
71 
72 TTSampleMatrix::~TTSampleMatrix()
73 {
74  ;
75 }
76 
77 
79 {
80  return setColumnCount(newNumChannels);
81 }
82 
83 
84 TTErr TTSampleMatrix::getNumChannels(TTValue& returnedChannelCount)
85 {
86  returnedChannelCount = (int)mNumChannels;
87  return kTTErrNone;
88 }
89 
90 
92 {
93  TTValue newLengthInSamples = TTFloat64(newLength) * mSampleRate;
94  return setRowCount(newLengthInSamples);
95 }
96 
97 
98 TTErr TTSampleMatrix::getLengthInSeconds(TTValue& returnedLength)
99 {
100  returnedLength = (mLengthInSamples / mSampleRate);
101  return kTTErrNone;
102 }
103 
104 
106 {
107  return setRowCount(newLengthInSamples);
108 }
109 
110 
111 TTErr TTSampleMatrix::getLengthInSamples(TTValue& returnedLengthInSamples)
112 {
113  returnedLengthInSamples = (int)mLengthInSamples;
114  return kTTErrNone;
115 }
116 
117 
119 {
120  this->mSampleRate = anotherMatrix.mSampleRate;
121  return TTMatrixBase::adaptTo((TTMatrixBase&)anotherMatrix);
122 }
123 
124 
126 {
127  // could technically exceed 65,535 maximum, but we'll take the chance for now
128  this->mUserCount++;
129  return kTTErrNone;
130 }
131 
132 
134 {
135  if (this->mUserCount > 0)
136  {
137  this->mUserCount--;
138  return kTTErrNone;
139  } else {
140  return kTTErrGeneric;
141  }
142 
143 }
144 
145 TTErr TTSampleMatrix::getValueAtIndex(const TTValue& index, TTValue &output)
146 {
147  TTRowID sampleIndex;
148  TTColumnID sampleChannel = 0;
149  TTSampleValue sampleValue;
150  TTErr err;
151 
152  sampleIndex = index[0];
153  if (index.size() > 1) {
154  sampleChannel = index[1];
155  }
156 
157  err = peek(sampleIndex, sampleChannel, sampleValue);
158  if (!err)
159  output.clear();
160  output.append(sampleValue);
161  return err;
162 }
163 
164 TTErr TTSampleMatrix::peek(const TTRowID index, const TTColumnID channel, TTSampleValue& value)
165 {
166  TTRowID p_index = index;
167  TTColumnID p_channel = channel;
168 
169  TTBoolean weAreNotInBounds = makeInBounds(p_index, p_channel); // out of range values are wrapped
170  get2d(p_index, p_channel, value);
171 
172  if (weAreNotInBounds)
173  {
174  return kTTErrOutOfBounds;
175  } else {
176  return kTTErrNone;
177  }
178 }
179 
180 // a first attempt at interpolation for the SampleMatrix. should be viewed as temporary.
181 // needs to be fleshed out with different options...
182 TTErr TTSampleMatrix::peeki(const TTFloat64 index, const TTColumnID channel, TTSampleValue& value)
183 {
184  // variables needed
185  TTColumnID p_channel = channel;
186  TTFloat64 indexIntegralPart = 0;
187  TTFloat64 indexFractionalPart = modf(index, &indexIntegralPart); // before makeInBounds to get the right value!
188  TTRowID indexThisInteger = TTRowID(indexIntegralPart);
189 
190  TTBoolean weAreNotInBounds = makeInBounds(indexThisInteger, p_channel); // out of range values are wrapped
191 
192  if (weAreNotInBounds)
193  {
194  // no reason to interpolate, just use the first or last value
195  get2d(indexThisInteger, p_channel, value);
196  return kTTErrOutOfBounds; // and report an error (is that what we want?)
197  } else {
198  TTRowID indexNextInteger = indexThisInteger + 1;
199  makeRowIDInBounds(indexNextInteger); //does not allow interpolation between first and last sample
200  // (is that what we want? if not, insert outOfBoundsWrap)
201 
202  TTSampleValue valueThisInteger, valueNextInteger;
203 
204  get2d(indexThisInteger, p_channel, valueThisInteger);
205  get2d(indexNextInteger, p_channel, valueNextInteger);
206 
207  // simple linear interpolation adapted from TTDelay
208  value = TTInterpolateLinear(valueThisInteger, valueNextInteger, indexFractionalPart);
209 
210  return kTTErrNone;
211  }
212 }
213 
214 /** Set the sample value for a given index.
215  The first number passed in the index parameter will be interpreted as the sample index.
216  If there are three numbers passed, then the second number, if passed, will designate the channel index (defaults to zero).
217  The final value will be used as the sample value that will be copied to the designated index.
218 */
220 {
221  TTRowID sampleIndex;
222  TTColumnID sampleChannel = 0;
223  TTSampleValue sampleValue;
224 
225  sampleIndex = index[0];
226  if (index.size() > 2) {
227  sampleChannel = index[1];
228  sampleValue = index[2];
229  } else {
230  sampleValue = index[1];
231  }
232 
233  return poke(sampleIndex, sampleChannel, sampleValue);
234 }
235 
236 TTErr TTSampleMatrix::poke(const TTRowID index, const TTColumnID channel, const TTSampleValue value)
237 {
238  TTRowID p_index = index;
239  TTColumnID p_channel = channel;
240 
241  TTBoolean weAreNotInBounds = makeInBounds(p_index,p_channel); // out of range values are wrapped
242 
243  if (weAreNotInBounds)
244  {
245  // don't go poking around out of bounds
246  return kTTErrOutOfBounds;
247  } else {
248  set2d(p_index, p_channel, value);
249  return kTTErrNone;
250  }
251 }
252 
253 
254 TTErr TTSampleMatrix::fill(const TTValue& value, TTValue& unusedOutput)
255 {
256  TTSymbol fillAlgorithm = value;
257  TTSampleValue tempSample = 0.;
258  TTRowID tempIndex = 0;
259 
260  if (fillAlgorithm == kTTSym_sine) {
261  for (TTColumnID channel=0; channel<mNumChannels; channel++) {
262  for (TTRowID i=0; i<mLengthInSamples; i++)
263  set2d(i, channel, sin(kTTTwoPi * (i / (TTFloat64(mLengthInSamples) - 1.0))));
264  }
265  }
266  else if (fillAlgorithm == kTTSym_sineMod) { // (modulator version: ranges from 0.0 to 1.0, rather than -1.0 to 1.0)
267  for (TTColumnID channel=0; channel<mNumChannels; channel++) {
268  for (TTRowID i=0; i<mLengthInSamples; i++)
269  set2d(i, channel, 0.5 + (0.5 * sin(kTTTwoPi * (i / (TTFloat64(mLengthInSamples) - 1.0)))));
270  }
271  }
272  else if (fillAlgorithm == kTTSym_cosine) {
273  for (TTColumnID channel=0; channel<mNumChannels; channel++) {
274  for (TTRowID i=0; i<mLengthInSamples; i++)
275  set2d(i, channel, cos(kTTTwoPi * (i / (TTFloat64(mLengthInSamples) - 1.0))));
276  }
277  }
278  else if (fillAlgorithm == kTTSym_cosineMod) {
279  for (TTColumnID channel=0; channel<mNumChannels; channel++) {
280  for (TTRowID i=0; i<mLengthInSamples; i++)
281  set2d(i, channel, 0.5 + (0.5 * cos(kTTTwoPi * (i / (TTFloat64(mLengthInSamples) - 1.0)))));
282  }
283  }
284  else if (fillAlgorithm == kTTSym_ramp) {
285  for (TTColumnID channel=0; channel<mNumChannels; channel++) {
286  for (TTRowID i=0; i<mLengthInSamples; i++)
287  set2d(i, channel, -1.0 + (2.0 * (float(i) / mLengthInSamples)));
288  }
289  }
290  else if (fillAlgorithm == kTTSym_rampMod) {
291  for (TTColumnID channel=0; channel<mNumChannels; channel++) {
292  for (TTRowID i=0; i<mLengthInSamples; i++)
293  set2d(i, channel, float(i) / mLengthInSamples);
294  }
295  }
296  else if (fillAlgorithm == kTTSym_sawtooth) {
297  for (TTColumnID channel=0; channel<mNumChannels; channel++) {
298  for (TTRowID i=0; i<mLengthInSamples; i++)
299  set2d(mLengthInSamples-i, channel, -1.0 + (2.0 * (float(i) / mLengthInSamples)));
300  }
301  }
302  else if (fillAlgorithm == kTTSym_sawtoothMod) {
303  for (TTColumnID channel=0; channel<mNumChannels; channel++) {
304  for (TTRowID i=0; i<mLengthInSamples; i++)
305  set2d(mLengthInSamples-i, channel, float(i) / mLengthInSamples);
306  }
307  }
308  else if (fillAlgorithm == kTTSym_triangle) {
309  for (TTColumnID channel=0; channel<mNumChannels; channel++) {
310  tempIndex = 3*mLengthInSamples/4;
311  for (TTRowID i=0; i < mLengthInSamples/4; i++) {
312  tempSample = -1.0 + (4.0 * (float(i) / mLengthInSamples));
313  set2d(i+tempIndex, channel, tempSample);
314  set2d(tempIndex-i, channel, tempSample);
315  }
316  tempIndex = mLengthInSamples/2;
317  for (TTRowID i=0; i < mLengthInSamples/4; i++) {
318  tempSample = 4.0 * (float(i) / mLengthInSamples);
319  set2d(i, channel, tempSample);
320  set2d(tempIndex-i, channel, tempSample);
321  }
322  }
323  }
324  else if (fillAlgorithm == kTTSym_triangleMod) {
325  for (TTColumnID channel=0; channel<mNumChannels; channel++) {
326  for (TTRowID i=0; i < mLengthInSamples/2; i++) {
327  set2d(i, channel, -1.0 + (4.0 * (float(i) / mLengthInSamples)));
328  set2d(mLengthInSamples-i, channel, -1.0 + (4.0 * (float(i) / mLengthInSamples)));
329  }
330  }
331  }
332 
333  return kTTErrNone;
334 }
335 
336 
337 TTErr TTSampleMatrix::load(const TTValue& input, TTValue& unusedOutput)
338 {
339  /* * *
340  Beware this method is still in progress
341  It will eventually work with the TTSoundfileLoader class
342  * * */
343 
344  TTValue inputWithPointerPrepended = input;
345  TTObjectBase* objectBasePtrToSampleMatrix = (TTObjectBase*)(TTPtr(this));
346  inputWithPointerPrepended.prepend(objectBasePtrToSampleMatrix);
347 
348  try {
349 
350  // first instantiate the SoundfileLoader object
351  TTAudioObject fileToLoad("soundfile.loader");
352 
353  // then pass along the updated TTValue to its load() method
354  return fileToLoad.send("load", inputWithPointerPrepended);
355 
356  }
357  catch (...) {
359  }
360 
361 }
362 
363 
365 {
366 
367  TTValue inputWithPointerPrepended = input;
368  TTObjectBase* objectBasePtrToSampleMatrix = (TTObjectBase*)(TTPtr(this));
369  inputWithPointerPrepended.prepend(objectBasePtrToSampleMatrix);
370 
371  try {
372 
373  // first instantiate the SoundfileLoader object
374  TTAudioObject fileToLoad("soundfile.loader");
375 
376  // then pass along the updated TTValue to its load() method
377  return fileToLoad.send("resizeThenLoad", inputWithPointerPrepended);
378  }
379  catch (...) {
381  }
382 
383 }
384 
385 
387 {
388  TTFloat64 normalizeTo = 1.0;
389  TTRowID m = mLengthInSamples; // mFrameLength
390  TTColumnID n = mNumChannels; // mNumChannels
391  TTSampleValuePtr samples = (TTSampleValuePtr)getLockedPointer();
392  TTFloat64 peakValue = 0.0;
393  TTFloat64 scalar;
394 
395  if (aValue.size() && TTFloat64(aValue) > 0.0)
396  normalizeTo = aValue;
397 
398  for (int k=0; k<m*n; k++) {
399  TTFloat64 magnitude = abs(samples[k]);
400 
401  if (magnitude > peakValue)
402  peakValue = magnitude;
403  }
404 
405  scalar = normalizeTo / peakValue;
406 
407  for (int k=0; k<m*n; k++)
408  samples[k] *= scalar;
409 
411  return kTTErrNone;
412 }
T TTInterpolateLinear(const T &x0, const T &x1, const double &delta)
Isolate the fractional part from a double.
Definition: TTInterpolate.h:47
bool TTBoolean
Boolean flag, same as Boolean on the Mac.
Definition: TTBase.h:167
TTBytePtr getLockedPointer()
Return a pointer to the matrix data, and lock the matrix so that others cannot access the data...
Definition: TTMatrixBase.h:547
TTErr setRowCount(const TTValue &aNewRowCount)
Attribute accessor.
Attempted to access memory outside a matrix or array (in a TTMatrix & TTSampleMatrix).
Definition: TTBase.h:355
TTErr decrementUserCount()
Decrease the user count by one.
TTErr send(const TTSymbol aName)
Send a message to this object with no arguments.
Definition: TTObject.cpp:135
#define addAttribute(name, type)
A convenience macro to be used by subclasses for registering attributes with a custom getter...
Definition: TTAttribute.h:29
Couldn't instantiate the Jamoma object requested.
Definition: TTBase.h:356
TTFOUNDATION_EXPORT TTEnvironment * ttEnvironment
The environment object has one instance, which is global in scope.
TTBoolean makeInBounds(TTRowID &i, TTColumnID &j, TTMatrixBaseOutOfBoundsHandler handler=outOfBoundsWrap) const
Make sure an (i,j) pair is within the limits set by RowCount & ColumnCount.
Definition: TTMatrixBase.h:366
size_type size() const noexcept
Return the number of elements.
TTFOUNDATION_EXPORT const TTFloat64 kTTTwoPi
Pre-calculated value of pi * 2.
Definition: TTBase.cpp:24
TTInt32 TTColumnID
Datatype for any number used to indicate a column index within the matrix.
Definition: TTBase.h:216
TTErr normalize(const TTValue &aValue)
Normalize the contents of a buffer.
TTSampleMatrix holds some audio in a chunk of memory.
Base class for all first-class Jamoma objects.
Definition: TTObjectBase.h:109
TTErr setLengthInSeconds(const TTValue &newLength)
Attribute accessor: set the buffer length specified in seconds.
Wrap audio objects for convenience.
TTErr(TTObjectBase::* TTMethod)(const TTSymbol methodName, const TTValue &anInputValue, TTValue &anOutputValue)
A type that can be used to store a pointer to a message for an object.
Definition: TTObjectBase.h:46
TTErr get2d(TTRowID i, TTColumnID j, T &data) const
Get the value of a component located at (i,j) in a 2-dimensional matrix.
Definition: TTMatrixBase.h:422
TTInt32 TTRowID
Datatype for any number used to indicate a row index within a matrix.
Definition: TTBase.h:207
double TTFloat64
64 bit floating point number
Definition: TTBase.h:188
TTErr registerMessage(const TTSymbol name, TTMethod method)
Register a message with this object.
TTErr adaptTo(const TTMatrixBase &anotherMatrix)
Set dimensions, element count, datatype, etc.
16-bit unsigned integer, range is 0 through 65,535.
Definition: TTBase.h:276
void prepend(const TTValue &aValueToPrepend)
Insert another TTValue before the first element.
Definition: TTValue.h:162
void append(const T &anElementValueToAppend)
Insert a single TTElement at the end.
Definition: TTValue.h:243
TTErr setColumnCount(const TTValue &aNewColumnCount)
Attribute accessor.
TTErr adaptTo(const TTSampleMatrix &anotherMatrix)
Set dimensions, element count, datatype, etc.
Container object that holds some audio in a chunk of memory.
void * TTPtr
A generic pointer.
Definition: TTBase.h:248
2-dimensional matrix of compound values with N elements each.
Definition: TTMatrixBase.h:41
64-bit floating point
Definition: TTBase.h:272
TTErr setNumChannels(const TTValue &newNumChannels)
Attribute accessor: set the number of channels for this buffer.
#define addAttributeProperty(attributeName, propertyName, initialValue)
A convenience macro to be used for registering properties of attributes.
Definition: TTAttribute.h:68
The TTSymbol class is used to represent a string and efficiently pass and compare that string...
Definition: TTSymbol.h:26
TTErr incrementUserCount()
Increase the user count by one.
#define addMessageWithArguments(name)
A convenience macro to be used by subclasses for registering messages.
Definition: TTMessage.h:27
void clear()
Clear all values from the vector, leaving with size of 0.
Definition: TTValue.h:131
TTErr set2d(TTRowID i, TTColumnID j, T data)
Set the value of a component located at (i,j) in a 2-dimensional matrix.
Definition: TTMatrixBase.h:481
32-bit signed integer, range is -2,147,483,648 through 2,147,483,647.
Definition: TTBase.h:277
Something went wrong, but what exactly is not known. Typically used for context-specific problems...
Definition: TTBase.h:344
TTErr
Jamoma Error Codes Enumeration of error codes that might be returned by any of the TTBlue functions a...
Definition: TTBase.h:342
void releaseLockedPointer()
Release a locked pointer obtained using getLockedPointer().
Definition: TTMatrixBase.h:556
not currently in use
TTUInt16 mUserCount
how many objects out there are currently using this TTSampleMatrix
#define addMessage(name)
A convenience macro to be used by subclasses for registering messages.
Definition: TTMessage.h:19
TTErr fill(const TTValue &value, TTValue &unusedOutput)
Set the contents of the buffer using a specified algorithm and, if appropriate, coefficients for that...
TTErr resizeThenLoad(const TTValue &input, TTValue &unusedOutput)
First, resize the TTSampleMatrix to match the number of channels and length in seconds found in a sou...
TTErr setValueAtIndex(const TTValue &index, TTValue &unusedOutput)
Set the sample value for a given index.
32-bit unsigned integer, range is 0 through 4,294,967,295.
Definition: TTBase.h:278
No Error.
Definition: TTBase.h:343
TTErr setLengthInSamples(const TTValue &newLengthInSamples)
Attribute accessor: set the buffer length specified as a number of samples.
TTFloat64 TTSampleValue
A value representing a single audio sample.
Definition: TTBase.h:230
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34
Interpolation Utilities.
TTErr load(const TTValue &input, TTValue &unusedOutput)
Load sample values from a soundfile into the TTSampleMatrix.
TTBoolean makeRowIDInBounds(TTRowID &i, TTMatrixBaseOutOfBoundsHandler handler=outOfBoundsWrap) const
Make sure a TTRowID is within the limits set by RowCount.
Definition: TTMatrixBase.h:321
#define addAttributeWithGetterAndSetter(name, type)
A convenience macro to be used by subclasses for registering attributes with a custom getter and sett...
Definition: TTAttribute.h:57