Jamoma API  0.6.0.a19
TTSoundfile.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup dspSoundFileLib
4  *
5  * @brief Provides a common interface to soundfile data
6  *
7  * @details This object provides a common set of attributes and methods for working with soundfiles at a specific filepath.
8  * This allows us to access metadata and copy values in a common way without duplicating code. As with the rest of the
9  * SoundfileLib, it relies on the third-party <a href="http://www.mega-nerd.com/libsndfile/">libsndfile library</a>.@n
10  * Be aware that attributes and metadata are cached when the setFilePath method is called in order to provide efficiency, but this may lead to problems if the file somehow changes after the method call.
11  *
12  * @authors Nathan Wolek
13  *
14  * @copyright Copyright © 2013 by Nathan Wolek @n
15  * This code is licensed under the terms of the "New BSD License" @n
16  * http://creativecommons.org/licenses/BSD/
17  */
18 
19 #include "TTSoundfile.h"
20 #include "TTInterpolate.h"
21 
22 #define thisTTClass TTSoundfile
23 #define thisTTClassName "soundfile"
24 #define thisTTClassTags "dspSoundFileLib, soundfile"
25 
26 TT_AUDIO_CONSTRUCTOR,
27 mFilePath(kTTSymEmpty),
28 mNumChannels(0),
29 mSampleRate(0.0),
30 mLengthInSamples(0),
31 mLengthInSeconds(0.0),
32 mTitle(kTTSymEmpty),
33 mArtist(kTTSymEmpty),
34 mDate(kTTSymEmpty),
35 mAnnotation(kTTSymEmpty),
36 mSoundFile(NULL)
37 {
38  // add the attributes and messages here
40  addAttribute(NumChannels, kTypeInt16);
41  addAttributeProperty(NumChannels, readOnly, TTValue(YES));
42  // need to add the rest of these here...
43  addAttribute(SampleRate, kTypeFloat64);
44  addAttributeProperty(SampleRate, readOnly, TTValue(YES));
45  addAttribute(LengthInSamples, kTypeInt64);
46  addAttributeProperty(LengthInSamples, readOnly, TTValue(YES));
47  addAttribute(LengthInSeconds, kTypeFloat64);
48  addAttributeProperty(LengthInSeconds, readOnly, TTValue(YES));
49  addAttribute(Title, kTypeSymbol);
50  addAttributeProperty(Title, readOnly, TTValue(YES));
51  addAttribute(Artist, kTypeSymbol);
52  addAttributeProperty(Artist, readOnly, TTValue(YES));
54  addAttributeProperty(Date, readOnly, TTValue(YES));
55  addAttribute(Annotation, kTypeSymbol);
56  addAttributeProperty(Annotation, readOnly, TTValue(YES));
57 
58 }
59 
60 TTSoundfile::~TTSoundfile()
61 {
62  // copied from TTSoundfilePlayer, confirm that it is needed
63  if (mSoundFile)
64  sf_close(mSoundFile);
65 }
66 
67 
69 {
70  TTSymbol potentialFilePath = newValue;
71  SNDFILE* soundfile;
72  const char* textInfo;
73 #ifdef TT_PLATFORM_WIN
74  // There is a bug in libsndfile on Windows where upon return from this function a runtime check fails
75  // because the stack is corrupted around soundfileInfo when sf_open() is called.
76  // We work around this by allocating some extra memory to absorb the overrun.
77  // [tap - old comment from soundfileplayer]
78  SF_INFO soundfileInfo[2];
79 #else
80  SF_INFO soundfileInfo[1];
81 #endif
82 
83  memset(&soundfileInfo, 0, sizeof(SF_INFO));
84  //soundfileInfo.format = 0;
85  soundfile = sf_open(potentialFilePath.c_str(), SFM_READ, soundfileInfo);
86 
87  if (soundfile) { // if the filepath was valid
88 
89  // swap out the old for the new, but hold onto the old for a moment
90  SNDFILE* oldSoundFile = mSoundFile;
91  mSoundFile = soundfile;
92 
93  // if there was an old file, we can now close it
94  if (oldSoundFile)
95  sf_close(oldSoundFile);
96 
97  // copy the metadata to our local variable
98  memcpy(&mSoundFileInfo, soundfileInfo, sizeof(SF_INFO));
99 
100  /* copy additional data to local variables */
101  // filepath
102  mFilePath = potentialFilePath;
103 
104  // number of channels
105  mNumChannels = mSoundFileInfo.channels;
106 
107  // sample rate
108  mSampleRate = mSoundFileInfo.samplerate;
109 
110  // duration in samples
111  mLengthInSamples = mSoundFileInfo.frames;
112 
113  // duration in seconds
115 
116  // copy specific metadata pieces to separate TTSymbols
117  // in transfer from player, made this little pattern into a macro
118  #define SF_STRING_TO_TTSYMBOL(sf_info_piece, local_ttsymbol) \
119  textInfo = sf_get_string(soundfile, sf_info_piece); \
120  if (textInfo) { \
121  local_ttsymbol = TT(textInfo); \
122  } \
123  else local_ttsymbol = kTTSymEmpty;
124 
125  // title
126  SF_STRING_TO_TTSYMBOL(SF_STR_TITLE, mTitle);
127  // artist
128  SF_STRING_TO_TTSYMBOL(SF_STR_ARTIST, mArtist);
129  // date
130  SF_STRING_TO_TTSYMBOL(SF_STR_DATE, mDate);
131  // comment
132  SF_STRING_TO_TTSYMBOL(SF_STR_COMMENT, mAnnotation);
133 
134 
135  return kTTErrNone;
136 
137  } else { // if the filepath was invalid
138  char errstr[256];
139  sf_error_str(soundfile, errstr, 256);
140  TTLogMessage("cannot open soundfile %s: %s", potentialFilePath.c_str(), errstr);
141 
142  return kTTErrInvalidFilepath;
143 
144  }
145 
146 }
147 
148 TTErr TTSoundfile::peek(const TTRowID frame, const TTColumnID channel, TTSampleValue& value)
149 {
150  TTSampleVector temp_value;
151  sf_count_t seekInFrames;
152  sf_count_t numSamplesRead;
153 
154  seekInFrames = sf_seek(mSoundFile, frame, SEEK_SET);
155 
156  if (seekInFrames == -1) {
157  return kTTErrGeneric;
158  }
159 
160  temp_value.resize(mNumChannels);
161 
162  numSamplesRead = sf_readf_double(mSoundFile, &temp_value[0], 1);
163 
164  if (numSamplesRead != 1) {
165  return kTTErrGeneric;
166  }
167 
168  value = temp_value[channel];
169  return kTTErrNone;
170 
171 }
172 
173 TTErr TTSoundfile::peeki(const TTFloat64 frame, const TTColumnID channel, TTSampleValue& value)
174 {
175  // variables needed
176  TTColumnID p_channel = channel;
177  TTFloat64 indexIntegralPart = TTInt32(frame);
178  TTFloat64 indexFractionalPart = frame - indexIntegralPart; // before makeInBounds to get the right value!
179  TTRowID indexThisInteger = TTRowID(indexIntegralPart);
180  TTRowID indexNextInteger = indexThisInteger + 1;
181 
182  TTSampleValue valueThisInteger, valueNextInteger;
183 
184  peek(indexThisInteger, p_channel, valueThisInteger);
185  peek(indexNextInteger, p_channel, valueNextInteger);
186 
187  // simple linear interpolation adapted from TTDelay
188  value = TTInterpolateLinear(valueThisInteger, valueNextInteger, indexFractionalPart);
189 
190  return kTTErrNone;
191 
192 
193 }
T TTInterpolateLinear(const T &x0, const T &x1, const double &delta)
Isolate the fractional part from a double.
Definition: TTInterpolate.h:47
Couldn't resolve the filepath as submitted.
Definition: TTBase.h:357
#define addAttribute(name, type)
A convenience macro to be used by subclasses for registering attributes with a custom getter...
Definition: TTAttribute.h:29
TTSymbol mDate
date if metadata is present in the file
Definition: TTSoundfile.h:41
TTFloat64 mSampleRate
samples per second
Definition: TTSoundfile.h:36
TTSymbol mArtist
artist if metadata is present in the file
Definition: TTSoundfile.h:40
TTInt32 TTColumnID
Datatype for any number used to indicate a column index within the matrix.
Definition: TTBase.h:216
TTErr peek(const TTRowID frame, const TTColumnID channel, TTSampleValue &value)
Get the value stored at a specified frame and channel.
TTInt32 TTRowID
Datatype for any number used to indicate a row index within a matrix.
Definition: TTBase.h:207
Symbol type.
Definition: TTBase.h:282
double TTFloat64
64 bit floating point number
Definition: TTBase.h:188
TTColumnID mNumChannels
channels in the file
Definition: TTSoundfile.h:35
16-bit signed integer, range is −32,768 through 32,767.
Definition: TTBase.h:275
64-bit floating point
Definition: TTBase.h:272
std::vector< TTSampleValue > TTSampleVector
A TTSampleVector is simply a pointer to the first of an array of TTSampleValues.
Definition: TTBase.h:233
#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
TTSymbol mTitle
title if metadata is present in the file
Definition: TTSoundfile.h:39
TTSymbol mAnnotation
comments if metadata is present in the file
Definition: TTSoundfile.h:42
TTRowID mLengthInSamples
length in samples
Definition: TTSoundfile.h:37
const char * c_str() const
Return a pointer to the internal string as a C-string.
Definition: TTSymbol.h:77
std::int32_t TTInt32
32 bit signed integer
Definition: TTBase.h:177
64-bit signed integer, ragne is −9,223,372,036,854,775,808 through 9,223,372,036,854,775,807
Definition: TTBase.h:279
Provides a common interface to soundfile data.
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
TTErr setFilePath(const TTValue &newValue)
Atribute accessor.
Definition: TTSoundfile.cpp:68
TTErr peeki(const TTFloat64 frame, const TTColumnID channel, TTSampleValue &value)
Interpolate a value using a floating-point frame and integer channel.
No Error.
Definition: TTBase.h:343
TTFloat64 mLengthInSeconds
length in seconds
Definition: TTSoundfile.h:38
TTSymbol mFilePath
full POSIX path to the file, including file name
Definition: TTSoundfile.h:34
TTFloat64 TTSampleValue
A value representing a single audio sample.
Definition: TTBase.h:230
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34
Interpolation Utilities.