8 #include "SoundFileMP3.h"
13 #define strcasestr strstr
19 const char * fname = tpath.c_str();
21 if (strcasestr(fname,
".mp3")) {
22 return new MP3File(tpath, tstart, tstop);
26 if ((strcasestr(fname,
".mp4")) || (strcasestr(fname,
".m4a"))
27 || (strcasestr(fname,
".m4p")) || (strcasestr(fname,
".aac"))) {
28 return new MP4File(tpath, tstart, tstop);
31 return new LSoundFile(tpath, tstart, tstop, doRead);
35 const char * fname = tpath.c_str();
37 if (strcasestr(fname,
".mp3")) {
38 return new MP3File(maxDurInSecs, tpath);
42 if ((strcasestr(fname,
".mp4")) || (strcasestr(fname,
".m4a"))
43 || (strcasestr(fname,
".m4p")) || (strcasestr(fname,
".aac"))) {
44 return new MP4File(maxDurInSecs, tpath);
57 mMaxDurInSecs (maxDurInSecs) {
80 mMaxDurInSecs (maxDurInSecs) {
97 mSFInfo(otherSndFile.sfInfo()),
98 mSndfile(otherSndFile.sndFile()) {
102 #ifdef CSL_USE_SRConv
114 #ifdef CSL_USE_SRConv
116 src_delete (mSRateConv);
136 switch (
mSFInfo->format & 0x0f) {
149 #ifdef CSL_USE_SRConv
151 mSRateConv = src_new (CSL_SRC_MODE,
mNumChannels, & mSRCReturn);
152 if (mSRateConv == NULL)
153 logMsg (
kLogError,
"SampleRateConvertor creation error : %s\n", src_strerror (mSRCReturn));
191 logMsg(
"Error: Couldn't get the file format.");
202 mSndfile = sf_open(mPath.c_str(), SFM_READ, mSFInfo);
203 if (mSndfile != NULL) {
204 this->initFromSndfile();
208 this->readBufferFromFile(mNumFrames);
221 unsigned rate,
unsigned bitDepth)
throw (
CException) {
225 mSFInfo->samplerate = rate;
226 mSFInfo->channels = tchannels;
229 mSFInfo->format = SF_FORMAT_WAV;
break;
231 mSFInfo->format = SF_FORMAT_AIFF;
break;
233 mSFInfo->format = SF_FORMAT_AU;
break;
236 mSFInfo->format = SF_FORMAT_RAW;
break;
239 mSFInfo->format = mSFInfo->format | SF_FORMAT_PCM_16;
240 else if (bitDepth == 32)
241 mSFInfo->format = mSFInfo->format | SF_FORMAT_FLOAT;
243 logMsg(
"Invalid bitDepth for sound file %s. Use either 16 or 32 bits.", mPath.c_str());
245 if ( ! sf_format_check(mSFInfo)) {
250 mSndfile = sf_open(mPath.c_str(), SFM_WRITE, mSFInfo);
270 if (this->isCached())
271 return mCurrentFrame;
277 whenceInt = SEEK_CUR;
278 logMsg(
"Error: Invalid position seek flag. Used kPositionCurrent.");
281 mCurrentFrame = sf_seek(mSndfile, position, whenceInt);
282 mBase = mCurrentFrame;
283 return mCurrentFrame;
289 unsigned numFrames = outputBuffer.mNumFrames;
290 unsigned currentFrame = mCurrentFrame;
294 if (currentFrame >= (
unsigned) mStop) {
295 outputBuffer.zeroBuffers();
298 if (currentFrame + numFrames >= (
unsigned) mStop) {
299 numFrames = mStop - currentFrame;
300 outputBuffer.zeroBuffers();
303 if ( ! this->isCached(numFrames)) {
305 this->readBufferFromFile(numFrames);
310 unsigned numBytes = numFrames *
sizeof(
sample);
311 for (
unsigned i = 0; i < outputBuffer.mNumChannels; i++) {
312 SampleBuffer dataOutPtr = mWavetable.buffer(
csl_min(i, (mNumChannels - 1))) + currentFrame;
313 memcpy(outputBuffer.buffer(i), dataOutPtr, numBytes);
317 for (
unsigned i = 0; i < outputBuffer.mNumChannels; i++) {
321 for (
unsigned i = 0; i < numFrames; i++) {
322 samp = (*dPtr++ * scaleValue) + offsetValue;
326 scalePort->resetPtr();
327 offsetPort->resetPtr();
330 currentFrame += numFrames;
333 #ifndef CSL_USE_SRConv // normal case: use wavetable interpolation
334 for (
unsigned i = 0; i < mNumChannels; i++)
336 currentFrame += numFrames;
338 #else // else use Sample rate convertor
340 if (this->isCached())
341 mSRateData.data_in = mWavetable.buffer(0) + (currentFrame * mNumChannels);
343 mSRateData.data_in = mWavetable.buffer(0);
344 mSRateData.data_out = mSRateData.data_in;
345 mSRateData.input_frames = numFrames;
346 mSRateData.output_frames = numFrames;
347 mSRateData.data_out = mSRConvBuffer.buffer(0);
348 mSRateData.end_of_input = 0;
349 mSRateData.src_ratio = mRate;
350 if (answer = src_set_ratio (mSRateConv, mRate))
352 src_strerror (answer));
354 if (answer = src_process (mSRateConv, & mSRateData))
356 src_strerror (answer));
358 mSRateData.data_out = mSRConvBuffer.buffer(0);
359 currentFrame += mSRateData.input_frames_used;
360 numFrames = mSRateData.output_frames_gen;
363 if ((currentFrame >= (
unsigned) mStop) && mIsLooping)
365 mCurrentFrame = currentFrame;
372 unsigned numFrames = inputBuffer.mNumFrames;
373 if (mSFInfo->channels > 1) {
374 mWavetable.setSize(1, mNumChannels * numFrames);
375 mWavetable.allocateBuffers();
377 mInterleaver.interleave(inputBuffer, mWavetable.buffer(0),
378 numFrames, mSFInfo->channels);
379 sf_writef_float(mSndfile, mWavetable.buffer(0), numFrames);
381 sf_writef_float(mSndfile, inputBuffer.buffer(0), numFrames);
383 mCurrentFrame += numFrames;
388 unsigned maxFrames = inputBuffer.mNumFrames;
389 if (maxFrames > toFrame)
391 unsigned numFrames = maxFrames - fromFrame;
392 if (mSFInfo->channels > 1) {
393 mWavetable.setSize(1, mNumChannels * numFrames);
394 mWavetable.allocateBuffers();
396 mInterleaver.interleave(inputBuffer, mWavetable.buffer(0) + fromFrame,
397 numFrames, mSFInfo->channels);
398 sf_writef_float(mSndfile, mWavetable.buffer(0), numFrames);
400 sf_writef_float(mSndfile, inputBuffer.buffer(0) + fromFrame, numFrames);
402 mCurrentFrame += numFrames;
409 sf_count_t numFramesRead;
411 unsigned myChannels =
mSFInfo->channels;
415 if ((myChannels > 1)) {
422 memset(sampleBufferPtr, 0, numFrames * myChannels *
sizeof(
sample));
427 numFramesRead = sf_readf_float(
mSndfile, sampleBufferPtr, numFrames);
428 if ((
unsigned) numFramesRead != numFrames)
429 logMsg(
kLogError,
"LSoundFile::readBufferFromFile sf_readf_float requested %d got %d",
430 numFrames, numFramesRead);
434 if ((
mBase + numFrames) > (
unsigned) mStop) {
435 unsigned numFramesRemaining = numFrames - numFramesRead;
436 SampleBuffer tempBufferPtr = sampleBufferPtr + (numFramesRead * myChannels);
438 while ((
unsigned) numFramesRead < numFrames) {
439 currentFrame = sf_seek(
mSndfile, 0, SEEK_SET);
440 numFramesRead += sf_readf_float(
mSndfile, tempBufferPtr, numFramesRemaining);
441 currentFrame += numFramesRead;
444 unsigned bytesToClear = numFramesRemaining * myChannels *
sizeof(
sample);
445 memset(tempBufferPtr, 0, bytesToClear);
448 if (myChannels > 1) {
455 #ifdef CSL_USE_SRConv // sample-rate conversion
457 #define BUFFER_LEN 4096
461 static sf_count_t sample_rate_convert (SNDFILE *infile, SNDFILE *outfile,
462 int converter,
double src_ratio,
int channels,
double * gain);
464 static double apply_gain (
float * data,
long frames,
int channels,
double max,
double gain);
sample * SampleBuffer
1-channel buffer data type, vector of (sample)
#define UPDATE_SCALABLE_CONTROLS
void logMsg(const char *format,...)
These are the public logging messages.
SeekPosition
Enumeration for seek flags.
#define kSoundFileFormatAIFF
unsigned mNumFrames
num frames used in each buffer
unsigned mNumFrames
sample frames
SF_INFO * mSFInfo
libsndfile sf-info struct
float mMaxDurInSecs
max size to read from file. In seconds so it can deal with varying sample rates.
void readBufferFromFile(unsigned numFrames)
read a buffer from the file (possibly all of it)
AdditiveInstrument.h – Sum-of-sines synthesis instrument class.
SoundFileMode mMode
r/w mode
static unsigned maxSndFileFrames()
the max num frames that can be cached
bool isCached()
answer if file has all of its samples in RAM
#define kSoundFileRead
Sound file constants.
unsigned mFrameRate
trigger ignored here
unsigned mBase
starting frame in file of buffer
#define kSoundFileReadWrite
virtual void setToEnd()
set to end position
void nextBuffer(Buffer &outB)
UGen operations.
virtual SampleBuffer buffer(unsigned bufNum)
convenience accessors for sample buffers
SoundFileFormat format()
get format
virtual void nextBuffer(Buffer &outputBuffer, unsigned outBufNum)
really compute the next buffer given an offset base channel; this is called by nextBuffer, possibly multiple times
void openForWrite(SoundFileFormat format=kSoundFileFormatAIFF, unsigned channels=1, unsigned rate=44100, unsigned bitDepth=16)
Open a file for writing. Default values are some common format.
virtual void openForRead(bool load=true)
open file and get stats Open a file for write. Default values are some common format.
void close()
close file seek to some position
#define kSoundFileFormatRaw
void deinterleave(Buffer &output, SampleBuffer samples, unsigned numFrames, unsigned numChannels)
De-interleave = copy from interleaved SampleBuffer to CSL Buffer object.
void writeBuffer(Buffer &inputBuffer)
write a buffer of data into the file
bool mIsValid
is my file valid?
static LSoundFile * openSndfile(string path, int start=-1, int stop=-1, bool doRead=true)
Factory methods.
#define kSoundFileFormatSND
Interleaver mInterleaver
File IO interleaver/deinterleaver.
unsigned mBytesPerSample
the # of bytes per sample
unsigned mCurrentFrame
where I currently am in the buffer
float sample
(could be changed to int, or double)
unsigned mNumChannels
my "expected" number of output channels
#define kSoundFileFormatWAV
virtual void freeBuffer()
free the file cache
void openForReadWrite()
open r/w
bool mIsLooping
am i looping start-stop?
void initFromSndfile()
read SF header
int mStop
starting/ending frames (or -1 if not used)
Buffer mWavetable
the stored wave form
#define LOAD_SCALABLE_CONTROLS
Load the scale/offset-related values at the start.
Buffer – the multi-channel sample buffer class (passed around between generators and IO guys)...
LSoundFile(std::string path, int start=-1, int stop=-1, bool doRead=true, float maxDurInSecs=0.0)
Constructor with defaults.
void checkBuffer(unsigned numFrames)
allocate buffer lazily
unsigned seekTo(int position, SeekPosition whence=kPositionStart)
seek to some position relative to "whence"
Here's the abstract sound file reader/writer class, a sample player UGen. The concrete subclasses rep...
Here's the sound file reader/writer class; it assumes libSndFile and interleaved sample buffers...
SNDFILE * mSndfile
libsndfile handle
#define SAFE_MALLOC(ptr, type, len)
Useful Macros.
Base class of CSL exceptions (written upper-case). Has a string message.
#define DECLARE_SCALABLE_CONTROLS
Macros for all the Scalable UnitGenerators (note that these don't end with ";")