CSL 5.2

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

SoundFileL.cpp
Go to the documentation of this file.
1 //
2 // SoundFileL.cpp -- sound file class using libsndfile
3 // See the copyright notice and acknowledgment of authors in the file COPYRIGHT
4 //
5
6 #include "SoundFileL.h"
7 #include "math.h"
8 #include "SoundFileMP3.h"
9
10 using namespace csl;
11
12
13 /// Sound file name extensions we recognize - ToDo: should this be in a config file?
14
15 const char * gSndFileExts[] = { "mp3", "wav", "aiff", "aif", "mp4", "m4p", "m4b", "m4a", "aac", "flac", 0 };
16
17 ///< Answer whether the given name looks like a snd file
18
19 bool LSoundFile::isSndfileName(const char * path) {
20 const char * dot = strrchr(path, '.'); // find file name ext
21 if ( ! dot)
22 return false;
23 dot++;
24 if ( ! dot)
25 return false;
26 for (unsigned i = 0; gSndFileExts[i]; i++) {
27 if(strcasestr(dot, gSndFileExts[i]))
28 return true;
29 }
30 return false;
31 }
32
33 ///< Answer the snd file type
34
35 SoundFileFormat LSoundFile::sndfileNameType(const char * path) {
36 const char * lastDot = strrchr(path, '.'); // find the last dot in the name
37 if ( ! lastDot)
38 return kSoundFileFormatOther;
39 lastDot++;
40 if ( ! lastDot)
41 return kSoundFileFormatOther;
42 if (strcasestr(lastDot, "wav")) // guess the file type from the file name
43 return kSoundFileFormatWAV;
44 if (strcasestr(lastDot, "mp3"))
45 return kSoundFileFormatMP3;
46 if (strcasestr(lastDot, "aif"))
47 return kSoundFileFormatAIFF;
48 if (strcasestr(lastDot, "aiff"))
49 return kSoundFileFormatAIFF;
50 if (strcasestr(lastDot, "m4a"))
51 return kSoundFileFormatMP4;
52 if (strcasestr(lastDot, "mp4"))
53 return kSoundFileFormatMP4;
54 if (strcasestr(lastDot, "m4b"))
55 return kSoundFileFormatMP4;
56 if (strcasestr(lastDot, "aac"))
57 return kSoundFileFormatAAC;
58 if (strcasestr(lastDot, "flac"))
59 return kSoundFileFormatFLAC;
60 if (strcasestr(lastDot, "caf"))
61 return kSoundFileFormatCAF;
62 if (strcasestr(lastDot, "ogg"))
63 return kSoundFileFormatOGG;
64 if (strcasestr(lastDot, "shn"))
65 return kSoundFileFormatSHN;
66 if (strcasestr(lastDot, "snd"))
67 return kSoundFileFormatSND;
68 return kSoundFileFormatOther;
69 }
70
71 // Answer the MIME type based on the file name
72
73 const char * LSoundFile::mimeType(const char * path) {
74 SoundFileFormat fmt = LSoundFile::sndfileNameType(path);
75 switch (fmt) {
76 case kSoundFileFormatAIFF: return "audio/x-aiff";
77 case kSoundFileFormatMP3: return "audio/mpeg";
78 case kSoundFileFormatMP4: return "audio/mp4a-latm";
79 case kSoundFileFormatWAV: return "audio/x-wav";
80 default: return "audio/basic";
81 }
82 }
83
84 // Factory method
85
86 LSoundFile * LSoundFile::openSndfile(string tpath, int tstart, int tstop, bool doRead) {
87 const char * fname = tpath.c_str();
88 #ifdef USE_libMAD
89 if (strcasestr(fname, ".mp3")) { // if an MP3
90 return new MP3File(tpath, tstart, tstop);
91 } // if an MP4/AAC
92 #endif
93 #ifdef USE_libFAAD
94 if ((strcasestr(fname, ".mp4")) || (strcasestr(fname, ".m4a"))
95 || (strcasestr(fname, ".m4p")) || (strcasestr(fname, ".aac"))) {
96 return new MP4File(tpath, tstart, tstop);
97 }
98 #endif
99 return new LSoundFile(tpath, tstart, tstop, doRead); // else try LibSndfile
100 }
101
102 LSoundFile * LSoundFile::openSndfile(float maxDurInSecs, string tpath) {
103 const char * fname = tpath.c_str();
104 #ifdef USE_libMAD
105 if (strcasestr(fname, ".mp3")) { // if an MP3
106 return new MP3File(maxDurInSecs, tpath);
107 } // if an MP4/AAC
108 #endif
109 #ifdef USE_libFAAD
110 if ((strcasestr(fname, ".mp4")) || (strcasestr(fname, ".m4a"))
111 || (strcasestr(fname, ".m4p")) || (strcasestr(fname, ".aac"))) {
112 return new MP4File(maxDurInSecs, tpath);
113 }
114 #endif
115 return new LSoundFile(maxDurInSecs, tpath); // else try LibSndfile
116 }
117
118
119 // LSoundFile Constructors
120
121 LSoundFile::LSoundFile(string tpath, int tstart, int tstop, bool doRead, float maxDurInSecs)
122 : Abst_SoundFile(tpath, tstart, tstop),
123 mSFInfo(new SF_INFO),
124 mSndfile(NULL),
125 mMaxDurInSecs (maxDurInSecs) {
126 mSFInfo->format = 0;
127 mNumFrames = 0;
128 #ifdef CSL_USE_SRConv
129 mSRateConv = NULL;
130 #endif
131 if ( ! doRead)
132 return;
133 try {
134 openForRead(); // read and cache whole file
135 setToEnd();
136 } catch (CException & e) {
137 // logMsg(kLogError, "File open exception caught: %s", e.mMessage.c_str());
138 return;
139 }
140 }
141
142 // this version sets maxSize and always reads
143
144 LSoundFile::LSoundFile(float maxDurInSecs, string tpath)
145 : Abst_SoundFile(tpath, -1, -1),
146 mSFInfo(new SF_INFO),
147 mSndfile(NULL),
148 mMaxDurInSecs (maxDurInSecs) {
149 mSFInfo->format = 0;
150 mNumFrames = 0;
151 #ifdef CSL_USE_SRConv
152 mSRateConv = NULL;
153 #endif
154 try {
155 openForRead(); // read and cache whole file
156 setToEnd();
157 } catch (CException & e) {
158 }
159 }
160
161 // Copy constructor -- shares sample buffer
162
163 LSoundFile::LSoundFile(LSoundFile & otherSndFile)
164 : Abst_SoundFile(otherSndFile),
165 mSFInfo(otherSndFile.sfInfo()),
166 mSndfile(otherSndFile.sndFile()) {
167 if ( ! otherSndFile.isCached())
168 logMsg(kLogError, "Cannot copy uncached sound file \"%s\"", mPath.c_str());
169 // logMsg("Open sound file \"%s\"", mPath.c_str());
170 #ifdef CSL_USE_SRConv
171 mSRateConv = NULL;
172 #endif
173 }
174
175 // Clean up data allocated
176
177 LSoundFile::~LSoundFile() {
178 if (mSndfile)
179 sf_close(mSndfile);
180 freeBuffer();
181 delete mSFInfo;
182 #ifdef CSL_USE_SRConv
183 if (mSRateConv)
184 src_delete (mSRateConv);
185 #endif
186 }
187
188 //
189 // set up the receiver's variables based on the file
190 //
191
192 void LSoundFile::initFromSndfile() {
193 mIsValid = (mSndfile != NULL);
194 if ( ! mIsValid) {
195 // logMsg(kLogError, "Cannot open sound file \"%s\"", mPath.c_str());
196 return;
197 }
198 mFrameRate = (unsigned) mSFInfo->samplerate;
199 mNumChannels = (unsigned) mSFInfo->channels;
200 mNumFrames = (unsigned) mSFInfo->frames;
201 if (mMaxDurInSecs > 0.0 && (mNumFrames > (unsigned) (mMaxDurInSecs * mFrameRate))) // truncate if too long
202 mNumFrames = mMaxDurInSecs * mFrameRate;
203 mBase = 0;
204 switch (mSFInfo->format & 0x0f) {
205 case 1: mBytesPerSample = 1; break; // Signed 8 bit
206 case 2: mBytesPerSample = 2; break; // Signed 16 bit
207 case 3: mBytesPerSample = 3; break; // Signed 24 bit
208 case 4: mBytesPerSample = 4; break; // Signed 32 bit
209 case 5: mBytesPerSample = 1; break; // unsigned 8 bit
210 case 6: mBytesPerSample = 4; break; // 32 bit float
211 case 7: mBytesPerSample = 8; break; // 64 bit float
212 }
213 if (mStart > 0) seekTo(mStart);
214 else mStart = 0;
215 if (mStop < 0) mStop = mNumFrames;
216
217 #ifdef CSL_USE_SRConv
218 if (mMode == kSoundFileRead) { // sample rate convertor (SRC) state struct
219 mSRateConv = src_new (CSL_SRC_MODE, mNumChannels, & mSRCReturn);
220 if (mSRateConv == NULL)
221 logMsg (kLogError, "SampleRateConvertor creation error : %s\n", src_strerror (mSRCReturn));
222 }
223 #endif
224 }
225
226 //void LSoundFile::checkBuffer(unsigned numFrames) {
227 // Abst_SoundFile::checkBuffer(numFrames);
228 //#ifdef CSL_USE_SRConv
229 // if ( ! mSRConvBuffer.mAreBuffersAllocated) { // if no SRC buffer allocated
230 // mSRConvBuffer.setSize(1, CGestalt::maxBufferFrames() * mNumChannels);
231 // mSRConvBuffer.allocateBuffers();
232 // }
233 //#endif
234 //}
235
236 ///< answer if file has all of its samples in RAM
237
238 bool LSoundFile::isCached() {
239 return (mWavetable.mNumFrames == mNumFrames);
240 }
241
242 ///< answer if file has X samples in RAM
243
244 bool LSoundFile::isCached(unsigned samps) {
245 return (mWavetable.mNumFrames > (mCurrentFrame + samps));
246 }
247
248 SoundFileFormat LSoundFile::format() {
249 switch (mSFInfo->format) {
250 case SF_FORMAT_WAV:
251 return kSoundFileFormatWAV; break;
252 case SF_FORMAT_AIFF:
253 return kSoundFileFormatAIFF; break;
254 case SF_FORMAT_AU:
255 return kSoundFileFormatSND; break;
256 case SF_FORMAT_RAW:
257 return kSoundFileFormatRaw; break;
258 default:
259 logMsg("Error: Couldn't get the file format.");
260 }
261 return kSoundFileFormatRaw;
262 }
263
264 // ~~~~ Open functions ~~~~
265
266 void LSoundFile::openForRead(bool load) throw (CException) {
267 if (mMode == kSoundFileRead)
268 return;
269 mMode = kSoundFileRead;
270 mSndfile = sf_open(mPath.c_str(), SFM_READ, mSFInfo); // libsndfile open call
271 if (mSndfile != NULL) { // check result
272 this->initFromSndfile();
273 if (load && (mNumFrames <= CGestalt::maxSndFileFrames())) { // read file if size < global max
274 // logMsg("Open/read sound file \"%s\" %d frames %g sec %d channels",
275 // mPath.c_str(), duration(), durationInSecs(), channels());
276 this->readBufferFromFile(mNumFrames); // read entire file, de-interleave
277 }
278 // mCurrentFrame = mStart;
279 // this->setWaveform(mSampleBuffer); // set up oscillator pointers
280 // mWavetable.mDidIAllocateBuffers = true;
281 // if (this->isCached())
282 // logMsg("\t\tSound file cached");
283 }
284 if (mIsValid)
285 this->readTags();
286 }
287
288 void LSoundFile::openForWrite(SoundFileFormat tformat, unsigned tchannels,
289 unsigned rate, unsigned bitDepth) throw (CException) {
290 if (mMode == kSoundFileWrite)
291 return;
292 mMode = kSoundFileWrite;
293 mSFInfo->samplerate = rate;
294 mSFInfo->channels = tchannels;
295 switch (tformat) {
296 case kSoundFileFormatWAV:
297 mSFInfo->format = SF_FORMAT_WAV; break;
298 case kSoundFileFormatAIFF:
299 mSFInfo->format = SF_FORMAT_AIFF; break;
300 case kSoundFileFormatSND:
301 mSFInfo->format = SF_FORMAT_AU; break;
302 case kSoundFileFormatRaw:
303 default:
304 mSFInfo->format = SF_FORMAT_RAW; break;
305 }
306 if (bitDepth == 16)
307 mSFInfo->format = mSFInfo->format | SF_FORMAT_PCM_16;
308 else if (bitDepth == 32)
309 mSFInfo->format = mSFInfo->format | SF_FORMAT_FLOAT;
310 else
311 logMsg("Invalid bitDepth for sound file %s. Use either 16 or 32 bits.", mPath.c_str());
312
313 if ( ! sf_format_check(mSFInfo)) {
314 logMsg(kLogError, "Invalid format for sound file %s", mPath.c_str());
315 mIsValid = false;
316 return;
317 }
318 mSndfile = sf_open(mPath.c_str(), SFM_WRITE, mSFInfo);
319 initFromSndfile();
320 }
321
322 void LSoundFile::openForReadWrite() throw (CException) {
323 mMode = kSoundFileReadWrite;
324 mSndfile = sf_open(mPath.c_str(), SFM_RDWR, mSFInfo);
325 initFromSndfile();
326 }
327
328 void LSoundFile::close() {
329 sf_close(mSndfile);
330 mSndfile = NULL;
331 freeBuffer();
332 }
333
334 // file seek via sf_seek call
335
336 unsigned LSoundFile::seekTo(int position, SeekPosition whence) throw(CException) {
337 int whenceInt;
338 if (this->isCached())
339 return mCurrentFrame;
340 switch (whence) {
341 case kPositionStart: whenceInt = SEEK_SET; break;
342 case kPositionCurrent: whenceInt = SEEK_CUR; break;
343 case kPositionEnd: whenceInt = SEEK_END; break;
344 default:
345 whenceInt = SEEK_CUR;
346 logMsg("Error: Invalid position seek flag. Used kPositionCurrent.");
347 break;
348 } // sf_seek call
349 mCurrentFrame = sf_seek(mSndfile, position, whenceInt);
350 mBase = mCurrentFrame;
351 return mCurrentFrame;
352 }
353
354 ///////////////// next_buffer -- the work is done here //////////
355
356 void LSoundFile::nextBuffer(Buffer &outputBuffer) throw(CException) {
357 unsigned numFrames = outputBuffer.mNumFrames;
358 unsigned currentFrame = mCurrentFrame;
359 DECLARE_SCALABLE_CONTROLS; // declare the scale/offset buffers and values
360 bool atEnd = false;
361
362 if (currentFrame >= (unsigned) mStop) { // if done
363 outputBuffer.zeroBuffers();
364 return;
365 }
366 if (currentFrame + numFrames >= (unsigned) mStop) { // if final window
367 numFrames = mStop - currentFrame;
368 outputBuffer.zeroBuffers();
369 atEnd = true;
370 }
371 if ( ! this->isCached(numFrames)) { // if not playing from cache buffer
372 if (! atEnd)
373 this->readBufferFromFile(numFrames); // read from file
374 }
375 LOAD_SCALABLE_CONTROLS; // load the scaleC and offsetC from the constant or dynamic value
376 if (mRate == 1.0) { // if playing at normal rate
377 if (IS_UNSCALED) { // and there's no scale/offset
378 unsigned numBytes = numFrames * sizeof(sample); // buffer copy loop
379 for (unsigned i = 0; i < outputBuffer.mNumChannels; i++) {
380 SampleBuffer dataOutPtr = mWavetable.monoBuffer(csl_min(i, (mNumChannels - 1))) + currentFrame;
381 memcpy(outputBuffer.monoBuffer(i), dataOutPtr, numBytes);
382 }
383 } else { // do full scaled/offset copy
384 sample samp;
385 for (unsigned i = 0; i < outputBuffer.mNumChannels; i++) {
386 SampleBuffer buffer = outputBuffer.monoBuffer(i); // get pointer to the selected output channel
387 SampleBuffer dPtr = mWavetable.monoBuffer(csl_min(i, (mNumChannels - 1))) + currentFrame;
388
389 for (unsigned i = 0; i < numFrames; i++) { // sample loop
390 samp = (*dPtr++ * scaleValue) + offsetValue; // get and scale the file sample
391 *buffer++ = samp;
392 UPDATE_SCALABLE_CONTROLS; // update the dynamic scale/offset
393 }
394 scalePort->resetPtr();
395 offsetPort->resetPtr();
396 }
397 }
398 currentFrame += numFrames; // incrememnt buf ptr
399 } else { // if mRate != 1.0,
400
401 #ifndef CSL_USE_SRConv // normal case: use wavetable interpolation
402 for (unsigned i = 0; i < mNumChannels; i++)
403 WavetableOscillator::nextBuffer(outputBuffer, i);
404 currentFrame += numFrames; // incrememnt buf ptr
405
406 #else // else use Sample rate convertor
407 int answer; // if we're doing SRC transposition
408 if (this->isCached()) // if playing from cache buffer
409 mSRateData.data_in = mWavetable.monoBuffer(0) + (currentFrame * mNumChannels);
410 else
411 mSRateData.data_in = mWavetable.monoBuffer(0);
412 mSRateData.data_out = mSRateData.data_in; // store for later
413 mSRateData.input_frames = numFrames;
414 mSRateData.output_frames = numFrames;
415 mSRateData.data_out = mSRConvBuffer.monoBuffer(0);
416 mSRateData.end_of_input = 0;
417 mSRateData.src_ratio = mRate;
418 if (answer = src_set_ratio (mSRateConv, mRate)) // set the transposition ratio
419 logMsg (kLogError, "SampleRateConvertor configuration error : %s\n",
420 src_strerror (answer));
421
422 if (answer = src_process (mSRateConv, & mSRateData)) // run SampleRateConvertor
423 logMsg (kLogError, "SampleRateConvertor runtime error : %s\n",
424 src_strerror (answer));
425
426 mSRateData.data_out = mSRConvBuffer.monoBuffer(0); // reset out ptr
427 currentFrame += mSRateData.input_frames_used; // input frames actually read
428 numFrames = mSRateData.output_frames_gen; // output frames actually written
429 #endif
430 }
431 if ((currentFrame >= (unsigned) mStop) && mIsLooping) // if we are past the end of the file...
432 currentFrame = 0; // this will click, have to call nextBuffer() recursively here
433 mCurrentFrame = currentFrame; // store back to member
434 return;
435 }
436
437 // write a CSL buffer to the interleaved output file
438
439 void LSoundFile::writeBuffer(Buffer &inputBuffer) throw(CException) {
440 unsigned numFrames = inputBuffer.mNumFrames;
441 if (mSFInfo->channels > 1) { // interleave stereo-to-mono
442 mWavetable.setSize(1, mNumChannels * numFrames);
443 mWavetable.allocateBuffers();
444 // call interleaver
445 mInterleaver.interleave(inputBuffer, mWavetable.monoBuffer(0),
446 numFrames, mSFInfo->channels);
447 sf_writef_float(mSndfile, mWavetable.monoBuffer(0), numFrames); // libsndfile write
448 } else { // mono file write
449 sf_writef_float(mSndfile, inputBuffer.monoBuffer(0), numFrames); // libsndfile write
450 }
451 mCurrentFrame += numFrames;
452 return;
453 }
454
455 // readBufferFromFile - read some samples from the file into the temp buffer
456
457 void LSoundFile::readBufferFromFile(unsigned numFrames) {
458 sf_count_t numFramesRead;
459 unsigned currentFrame = mCurrentFrame;
460 unsigned myChannels = mSFInfo->channels;
461
462 this->checkBuffer(numFrames); // check my buffer, allocate if necessary
463 SampleBuffer sampleBufferPtr;
464 if ((myChannels > 1)) { // read into temp buffer to multichannel files, then de-interleave
465 SAFE_MALLOC(sampleBufferPtr, sample, (myChannels * numFrames));
466 } else {
467 sampleBufferPtr = mWavetable.monoBuffer(0);
468 }
469 // if we are at the end of the file and not looping
470 if ((currentFrame >= (unsigned) mStop) && !mIsLooping) {
471 memset(sampleBufferPtr, 0, numFrames * myChannels * sizeof(sample));
472 return;
473 }
474 mBase = sf_seek(mSndfile, 0, SEEK_CUR); // get position
475 // libsndfile read function
476 numFramesRead = sf_readf_float(mSndfile, sampleBufferPtr, numFrames);
477 if ((unsigned) numFramesRead != numFrames)
478 logMsg(kLogError, "LSoundFile::readBufferFromFile sf_readf_float requested %d got %d",
479 numFrames, numFramesRead);
480 // mWavetable.mNumFrames = numFrames;
481 mCurrentFrame = 0;
482 // if we are past the end of the file...
483 if ((mBase + numFrames) > (unsigned) mStop) {
484 unsigned numFramesRemaining = numFrames - numFramesRead;
485 SampleBuffer tempBufferPtr = sampleBufferPtr + (numFramesRead * myChannels);
486 if (mIsLooping) { // loop back to start of file
487 while ((unsigned) numFramesRead < numFrames) {
488 currentFrame = sf_seek(mSndfile, 0, SEEK_SET); // libsndfile seek/read function
489 numFramesRead += sf_readf_float(mSndfile, tempBufferPtr, numFramesRemaining);
490 currentFrame += numFramesRead;
491 }
492 } else {
493 unsigned bytesToClear = numFramesRemaining * myChannels * sizeof(sample);
494 memset(tempBufferPtr, 0, bytesToClear);
495 }
496 }
497 if (myChannels > 1) { // auto-de-interleave if multichannel
498 mInterleaver.deinterleave(mWavetable, sampleBufferPtr, numFrames, mNumChannels);
499 SAFE_FREE(sampleBufferPtr);
500 }
501 mCurrentFrame = mStart;
502 }
503
504 #ifdef CSL_USE_SRConv // sample-rate conversion
505
506 #define BUFFER_LEN 4096 /*-(1<<16)-*/
507
508 // fcn prototypes below
509
510 static sf_count_t sample_rate_convert (SNDFILE *infile, SNDFILE *outfile,
511 int converter, double src_ratio, int channels, double * gain);
512
513 static double apply_gain (float * data, long frames, int channels, double max, double gain);
514
515 #endif // SR_Conv
516
517 //-------------------------------------------------------------------------------
518
519 // SF_Virtual structure
520 /*
521 typedef sf_count_t (*sf_vio_get_filelen) (void *user_data) ;
522 typedef sf_count_t (*sf_vio_seek) (sf_count_t offset, int whence, void *user_data) ;
523 typedef sf_count_t (*sf_vio_read) (void *ptr, sf_count_t count, void *user_data) ;
524 typedef sf_count_t (*sf_vio_write) (const void *ptr, sf_count_t count, void *user_data) ;
525 typedef sf_count_t (*sf_vio_tell) (void *user_data) ;
526
527 struct SF_VIRTUAL_IO
528 { sf_vio_get_filelen get_filelen ;
529 sf_vio_seek seek ;
530 sf_vio_read read ;
531 sf_vio_write write ;
532 sf_vio_tell tell ;
533 } ;
534 */
535
536 // Call-back functions for SF_VIRTUAL_IO struct
537
538 //sf_vio_get_filelen lsf_getFileLen(void * vBuffer) {
539 // Buffer * buf = (Buffer *) vfile
540 //}
541 //
542 //sf_vio_seek lsf_seek(sf_count_t offset, int whence, void * vBuffer) {
543 //
544 //}
545 //
546 //sf_vio_tell lsf_tell(void * vBuffer) {
547 //
548 //}
549 //
550 //
551 //sf_vio_read lsf_read(void *ptr, sf_count_t count, void * vBuffer) {
552 //
553 //}
554 //
555 //
556 //sf_vio_write lsf_write(const void *ptr, sf_count_t count, void * vBuffer) {
557 //
558 //}
559
560
561
562 // OLD WAY
563
564 //void LSoundFile::convertRate(char * mTempPath, int fromRate, int toRate) {
565 // SNDFILE *infile, *outfile;
566 // SF_INFO sfinfo;
567 // sf_count_t count;
568 // char tempName[CSL_NAME_LEN];
569 //
570 // double src_ratio = -1.0, gain = 1.0;
571 // int converter;
572 // converter = SRC_SINC_BEST_QUALITY;
573 // logMsg("Convert-rate of \"%s\" from %d to %d", mTempPath, fromRate, toRate);
574 // // create temp name and rename file
575 // sprintf(tempName, "%s.TEMP", mTempPath);
576 // if (rename(mTempPath, tempName) != 0) {
577 // logMsg(kLogError, "Convert-rate cannot rename \"%s\" to \"%s\"", mTempPath, tempName);
578 // perror("SoundFile::convertRate");
579 // return;
580 // }
581 // infile = sf_open(tempName, SFM_READ, &sfinfo);
582 // src_ratio = (double) toRate / (double) fromRate;
583 // sfinfo.samplerate = toRate;
584 // if (src_is_valid_ratio (src_ratio) == 0) {
585 // logMsg (kLogError, "Error: Sample rate change out of valid range.");
586 // sf_close (infile);
587 // return;
588 // }
589 // outfile = sf_open (mTempPath, SFM_WRITE, &sfinfo);
590 // if (outfile == NULL) {
591 // logMsg (kLogError, "Error: Cannot open output file.");
592 // sf_close (infile);
593 // return;
594 // }
595 // sf_command (outfile, SFC_SET_UPDATE_HEADER_AUTO, NULL, SF_TRUE);
596 // sf_command (outfile, SFC_SET_CLIPPING, NULL, SF_TRUE);
597 // do {
598 // count = sample_rate_convert(infile, outfile, converter, src_ratio, sfinfo.channels, &gain);
599 // } while (count < 0);
600 //
601 // logMsg("Convert-rate: output frames %ld", (long) count);
602 // sf_close(infile);
603 // sf_close(outfile);
604 // if (remove(tempName) != 0)
605 // logMsg(kLogError, "Convert-rate cannot remove temp file \"%s\"\n", tempName);
606 //}
607
608 /////////////////////////
609 // These 2 functions are taken from libSampleRate
610 //
611
612 //static sf_count_t sample_rate_convert (SNDFILE *infile, SNDFILE *outfile, int converter,
613 // double src_ratio, int channels, double * gain) {
614 // static float input [BUFFER_LEN];
615 // static float output [BUFFER_LEN];
616 // SRC_STATE * src_state;
617 // SRC_DATA src_data;
618 // int error;
619 // double max = 0.0;
620 // sf_count_t output_count = 0;
621 // sf_seek (infile, 0, SEEK_SET);
622 // sf_seek (outfile, 0, SEEK_SET);
623 //
624 // /* Initialize the sample rate converter. */
625 // if ((src_state = src_new (converter, channels, &error)) == NULL) {
626 // logMsg ("Error : src_new() failed : %s.", src_strerror (error));
627 // exit (1);
628 // };
629 //
630 // src_data.end_of_input = 0; /* Set this later. */
631 //
632 // /* Start with zero to force load in while loop. */
633 // src_data.input_frames = 0;
634 // src_data.data_in = input;
635 // src_data.src_ratio = src_ratio;
636 // src_data.data_out = output;
637 // src_data.output_frames = BUFFER_LEN /channels;
638 //
639 // while (1) {
640 // /* If the input buffer is empty, refill it. */
641 // if (src_data.input_frames == 0) {
642 // src_data.input_frames = sf_readf_float (infile, input, BUFFER_LEN / channels);
643 // src_data.data_in = input;
644 //
645 // /* The last read will not be a full buffer, so snd_of_input. */
646 // if (src_data.input_frames < BUFFER_LEN / channels)
647 // src_data.end_of_input = SF_TRUE;
648 // }
649 //
650 // if ((error = src_process (src_state, &src_data))) {
651 // logMsg ("SRC Error : %s", src_strerror (error));
652 // return (0);
653 // }
654 //
655 // /* Terminate if done. */
656 // if (src_data.end_of_input && src_data.output_frames_gen == 0)
657 // break;
658 //
659 // max = apply_gain (src_data.data_out, src_data.output_frames_gen, channels, max, *gain);
660 //
661 // /* Write output. */
662 // sf_writef_float (outfile, output, src_data.output_frames_gen);
663 // output_count += src_data.output_frames_gen;
664 //
665 // src_data.data_in += src_data.input_frames_used * channels;
666 // src_data.input_frames -= src_data.input_frames_used;
667 // }
668 //
669 // src_state = src_delete (src_state);
670 //
671 // if (max > 1.0) { *gain = 1.0 / max;
672 // logMsg ("Output has clipped. Restarting conversion to prevent clipping.");
673 // output_count = 0;
674 // sf_command (outfile, SFC_FILE_TRUNCATE, &output_count, sizeof (output_count));
675 // return -1;
676 // }
677 //
678 // return output_count;
679 //} /* sample_rate_convert */
680 //
681 //static double apply_gain (float * data, long frames, int channels, double max, double gain) {
682 // for (long k = 0; k < frames * channels; k++) {
683 // double val = (double) data [k];
684 // val *= gain;
685 // data[k] = val;
686 // val = fabs (val);
687 // if (val > max)
688 // max = val;
689 // }
690 // return max;
691 //} /* apply_gain */