Jamoma API  0.6.0.a19
TTSoundfilePlayer.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup dspSoundFileLib
4  *
5  * @brief Jamoma DSP Soundfile Player
6  *
7  * @details
8  *
9  * @authors Timothy Place
10  *
11  * @copyright Copyright © 2010 by 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 "TTSoundfilePlayer.h"
18 
19 #define thisTTClass TTSoundfilePlayer
20 #define thisTTClassName "soundfile.player"
21 #define thisTTClassTags "dspSoundFileLib, audio, soundfile, playback"
22 
23 
24 TT_AUDIO_CONSTRUCTOR,
25 mFilePath(kTTSymEmpty),
26 mTitle(kTTSymEmpty),
27 mAnnotation(kTTSymEmpty),
28 mArtist(kTTSymEmpty),
29 mDate(kTTSymEmpty),
30 mSoundFile(NULL),
31 mPlay(false),
32 mLoop(false),
33 mSeek(0),
34 mSeekInFrames(0),
35 mDuration(0.0),
36 mContinue(false),
37 mNumChannels(0),
38 mNumBufferFrames(0)
39 {
43  addAttribute( Loop, kTypeBoolean);
44  addAttribute( Duration, kTypeFloat64);
45  addAttributeProperty( Duration, readOnly, TTValue(YES));
46  addAttribute( NumChannels, kTypeUInt16);
47  addAttributeProperty( NumChannels, readOnly, TTValue(YES));
48  addAttribute( Title, kTypeSymbol);
49  addAttributeProperty( Title, readOnly, TTValue(YES));
50  addAttribute( Artist, kTypeSymbol);
51  addAttributeProperty( Artist, readOnly, TTValue(YES));
52  addAttribute( Annotation, kTypeSymbol);
53  addAttributeProperty( Annotation, readOnly, TTValue(YES));
54  addAttribute( Date, kTypeSymbol);
55  addAttributeProperty( Date, readOnly, TTValue(YES));
56 
57  addMessage(pause);
58  addMessage(resume);
59  setProcessMethod(processAudio);
60  //setAttributeValue(kTTSym_maxNumChannels, arguments); // This attribute is inherited
61 }
62 
63 
64 TTSoundfilePlayer::~TTSoundfilePlayer()
65 {
66  setAttributeValue(TT("play"), NO);
67  if (mSoundFile)
68  sf_close(mSoundFile);
69 }
70 
71 
72 // takes a POSIX path, e.g. /Users/tim/Music/Demos/whiteandnerdy.aif
74 {
75  TTSymbol potentialFilePath = newValue;
76  SNDFILE* soundfile;
77  const char* textInfo;
78 #ifdef TT_PLATFORM_WIN
79  // There is a bug in libsndfile on Windows where upon return from this function a runtime check fails
80  // because the stack is corrupted around soundfileInfo when sf_open() is called.
81  // We work around this by allocating some extra memory to absorb the overrun. [tap]
82  SF_INFO soundfileInfo[2];
83 #else
84  SF_INFO soundfileInfo[1];
85 #endif
86 
87  memset(&soundfileInfo, 0, sizeof(SF_INFO));
88  //soundfileInfo.format = 0;
89  soundfile = sf_open(potentialFilePath.c_str(), SFM_READ, soundfileInfo);
90 
91  if (soundfile) {
92  SNDFILE* oldSoundFile = mSoundFile;
93 
94  mSoundFile = soundfile;
95  if (oldSoundFile)
96  sf_close(oldSoundFile);
97  memcpy(&mSoundFileInfo, soundfileInfo, sizeof(SF_INFO));
98 
99  mFilePath = potentialFilePath;
100  mPlay = 0;
101  mContinue = 1; //eliminating previous pause state
102 
103  // Now we gather some infos about the sound file
104  textInfo = sf_get_string(soundfile, SF_STR_TITLE);
105  if (textInfo) mTitle = TT(textInfo);
106  else mTitle = kTTSymEmpty;
107  textInfo = sf_get_string(soundfile, SF_STR_ARTIST);
108  if (textInfo) mArtist = TT(textInfo);
109  else mArtist = kTTSymEmpty;
110  textInfo = sf_get_string(soundfile, SF_STR_COMMENT);
111  if (textInfo) mAnnotation = TT(textInfo);
112  else mAnnotation = kTTSymEmpty;
113  textInfo = sf_get_string(soundfile, SF_STR_DATE);
114  if (textInfo) mDate = TT(textInfo);
115  else mDate = kTTSymEmpty;
116  mDuration = mSoundFileInfo.frames / mSoundFileInfo.samplerate;
117 
118  // TODO: fill in things like the NumChannels attr here
119 
120  return kTTErrNone;
121  }
122  else {
123  char errstr[256];
124  sf_error_str (soundfile, errstr, 256);
125  TTLogMessage("cannot open soundfile %s: %s", potentialFilePath.c_str(), errstr);
126  return kTTErrGeneric;
127  }
128 }
129 
130 TTErr TTSoundfilePlayer::setPlay(const TTValue& newValue)
131 {
132  mPlay = newValue;
133  mContinue = 1; //eliminating previous pause state
134  if (mPlay == 0){
135  if (mSoundFile){
136  mSeek = 0;
137  sf_seek(mSoundFile, 0, SEEK_SET);
138  }
139  }
140 return kTTErrNone;
141 }
142 
143 TTErr TTSoundfilePlayer::setSeek(const TTValue& newValue)
144 {
145  if (mSoundFile) {
146  mSeek = newValue;
147  TTLimitMin(mSeek, 0.0);
148  mSeekInFrames = mSeek * sr * 0.001;
149  if (sf_seek(mSoundFile, mSeekInFrames, SEEK_SET) != mSeekInFrames) {
150  char errstr[256];
151  sf_error_str (mSoundFile, errstr, 256);
152  TTLogMessage("error in seek of %s: %s", mFilePath.c_str(), errstr);
153  return kTTErrGeneric;
154  }
155  mContinue = 1; //eliminating previous pause state
156  mPlay = 1;
157  return kTTErrNone;
158  }
159  else
160  return kTTErrGeneric;
161 }
162 
163 TTErr TTSoundfilePlayer::pause()
164 {
165  mContinue = 0;
166  return kTTErrNone;
167 }
168 
169 TTErr TTSoundfilePlayer::resume()
170 {
171  mContinue = 1;
172  return kTTErrNone;
173 }
174 
175 TTErr TTSoundfilePlayer::processAudio(TTAudioSignalArrayPtr inputs, TTAudioSignalArrayPtr outputs)
176 {
177  TTAudioSignal& out = outputs->getSignal(0);
178  TTAudioSignal& outPlayhead = outputs->getSignal(1);
179  TTUInt16 outChannelCount = out.getMaxNumChannelsAsInt();
180  TTUInt16 numFrames = out.getVectorSizeAsInt();
181  TTBoolean bufferNeedsResize = NO;
182  sf_count_t numSamplesRead;
183  TTUInt16 n;
184  TTSampleValuePtr outSample;// outSamplePlayhead;
185  TTUInt16 channel;
186 
187 
188  if (mSoundFile) {
189  // resize of the number of output channels, if needed
190  if (outChannelCount != mSoundFileInfo.channels || !mNumChannels) {
191  mNumChannels = mSoundFileInfo.channels;
193  bufferNeedsResize = YES;
194  out.setNumChannelsWithInt(mNumChannels);
195  outPlayhead.setMaxNumChannels(1);
196  outPlayhead.setNumChannelsWithInt(1);
197  }
198 
199  if (mNumBufferFrames != numFrames) {
200  mNumBufferFrames = numFrames;
201  bufferNeedsResize = YES;
202  }
203  if (bufferNeedsResize)
205 
206  if (!mNumChannels)
207  return TTAudioObjectBase::muteProcess(inputs, outputs);
208 
209  // if there is an input, we want to treat it as a sample-accurate on/off switch for playback
210  //if (inputs->numAudioSignals) {
211  // ; // TODO: implement this
212  //}
213  //else {
214 
215 
216  //mBuffer.assign(mBuffer.size(), 0.0);
217 
218  if (mPlay && mContinue) {
219  numSamplesRead = sf_readf_double(mSoundFile, &mBuffer[0], numFrames);
220  if (numSamplesRead < numFrames) {
221  sf_seek(mSoundFile, mSeekInFrames, SEEK_SET);
222  mPlay = mLoop;
223  }
224  }
225  else
226  mBuffer.assign(mBuffer.size(), 0.0);
227 
228  for (channel=0; channel<mNumChannels; channel++) {
229  outSample = out.mSampleVectors[channel];
230  for (n=0; n<numFrames; n++)
231  outSample[n] = mBuffer[n * mNumChannels + channel];
232  }
233 
234  for (n=0; n<numFrames; n++)
235  outPlayhead.mSampleVectors[0][n] = n; // FIXME: this is a dummy value, replace with a proper playhead position
236  //FIXME: see http://redmine.jamoma.org/issues/578
237  //FIXME: see http://redmine.jamoma.org/issues/547
238  }
239  else { //no soundfile selected, we send out a zero signal on one channel
240  out.setMaxNumChannels(1);
241  out.setNumChannelsWithInt(1);
242  for (n=0; n<numFrames; n++)
243  out.mSampleVectors[0][n] = 0.0;
244  }
245 
246  return kTTErrNone;
247 }
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
SF_INFO mSoundFileInfo
libsndfile metadata for the file we open
TTUInt16 mNumChannels
read-only: number of channels in the open file
SNDFILE * mSoundFile
libsndfile handle for the actual file we open
#define addAttribute(name, type)
A convenience macro to be used by subclasses for registering attributes with a custom getter...
Definition: TTAttribute.h:29
TTBoolean mPlay
is actively playing back the file?
TTUInt16 mNumBufferFrames
number of frames in the buffer to be read from the file at a time
TTFloat64 mDuration
Length of the loaded soundfile - readonly.
#define setProcessMethod(methodName)
A convenience macro to be used by subclasses for setting the process method.
TTErr setAttributeValue(const TTSymbol name, TTValue &value)
Set an attribute value for an object.
Symbol type.
Definition: TTBase.h:282
TTErr muteProcess(TTAudioSignalArrayPtr inputs, TTAudioSignalArrayPtr outputs)
A muted audio processing method, which simply copies zeroes to the output.
16-bit unsigned integer, range is 0 through 65,535.
Definition: TTBase.h:276
#define TT
This macro is defined as a shortcut for doing a lookup in the symbol table.
Definition: TTSymbol.h:155
TTFloat64 mSeek
Cue time start.
TTSymbol mFilePath
full POSIX path to the file, including file name
TTErr setMaxNumChannels(const TTValue &newMaxNumChannels)
Attribute accessor.
64-bit floating point
Definition: TTBase.h:272
#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
TTBoolean mContinue
Pause/Resume flag.
Boolean (1/0) or (true/false) flag.
Definition: TTBase.h:281
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
const char * c_str() const
Return a pointer to the internal string as a C-string.
Definition: TTSymbol.h:77
TTBoolean mLoop
Loop flag.
A simple container for an array of TTAudioSignal pointers.
TTSampleVector mBuffer
buffer of mNumBufferFrames * mNumChannels;
Jamoma DSP Soundfile Player.
void TTFOUNDATION_EXPORT TTLogMessage(TTImmutableCString message,...)
Platform and host independent method for posting log messages.
Definition: TTBase.cpp:534
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
#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
TTErr setFilePath(const TTValue &value)
Setter for the mode attribute.
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34
TTUInt32 sr
Current sample rate being used by this object.