diff options
author | Robert Jonsson <spamatica@gmail.com> | 2010-10-13 19:34:22 +0000 |
---|---|---|
committer | Robert Jonsson <spamatica@gmail.com> | 2010-10-13 19:34:22 +0000 |
commit | 8a2c2824a59d7644e13bc52c9a0ecbd641f21f95 (patch) | |
tree | 064ad3f2bf8daab0ad27b128abd86a9bbdb1e496 /muse2/muse/audioconvert.cpp | |
parent | a27706d9629e8b592cca4659f865b70adef24e6d (diff) |
new branch muse2, first checkin
Diffstat (limited to 'muse2/muse/audioconvert.cpp')
-rw-r--r-- | muse2/muse/audioconvert.cpp | 886 |
1 files changed, 886 insertions, 0 deletions
diff --git a/muse2/muse/audioconvert.cpp b/muse2/muse/audioconvert.cpp new file mode 100644 index 00000000..878bc8e7 --- /dev/null +++ b/muse2/muse/audioconvert.cpp @@ -0,0 +1,886 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: audioconvert.cpp,v 1.1.1.1 2009/12/28 16:07:33 terminator356 Exp $ +// +// (C) Copyright 1999-2009 Werner Schweer (ws@seh.de) +// +// Audio converter module created by Tim terminator356 +//========================================================= + +#include <math.h> + +#include "wave.h" +#include "globals.h" +#include "audioconvert.h" +#include "eventbase.h" + +//#define AUDIOCONVERT_DEBUG +//#define AUDIOCONVERT_DEBUG_PRC + +//--------------------------------------------------------- +// AudioConvertMap +//--------------------------------------------------------- + +void AudioConvertMap::remapEvents(const EventList* el) +{ + +} + +iAudioConvertMap AudioConvertMap::addEvent(EventBase* eb) +{ + iAudioConvertMap iacm = getConverter(eb); + if(iacm == end()) + { + AudioConverter* cv = 0; + if(!eb->sndFile().isNull()) + cv = new SRCAudioConverter(eb->sndFile().channels(), SRC_SINC_MEDIUM_QUALITY); + + // Use insert with hint for speed. + return insert(iacm, std::pair<EventBase*, AudioConverter*> (eb, cv)); + } + else + // Adopt a policy of returning an already existing item to enforce no-duplicates. + return iacm; +} + +void AudioConvertMap::removeEvent(EventBase* eb) +{ + iAudioConvertMap iacm = find(eb); + if(iacm != end()) + { + AudioConverter* cv = iacm->second; + if(cv) + delete cv; + erase(iacm); + } +} + +iAudioConvertMap AudioConvertMap::getConverter(EventBase* eb) +{ + return find(eb); +} + +//--------------------------------------------------------- +// AudioConverter +//--------------------------------------------------------- + +AudioConverter::AudioConverter() +{ + #ifdef AUDIOCONVERT_DEBUG + printf("AudioConverter::AudioConverter this:%p\n", this); + #endif + + _refCount = 1; + _sfCurFrame = 0; +} + +AudioConverter::~AudioConverter() +{ + #ifdef AUDIOCONVERT_DEBUG + printf("AudioConverter::~AudioConverter this:%p\n", this); + #endif +} + +AudioConverter* AudioConverter::reference() +{ + _refCount += 1; + #ifdef AUDIOCONVERT_DEBUG + printf("AudioConverter::reference this:%p current refcount:%d\n", this, _refCount); + #endif + return this; +} + +AudioConverter* AudioConverter::release(AudioConverter* cv) +{ + if(!cv) + return 0; + //if(cv->incRefCount(-1) <= 0) + cv->_refCount -= 1; + #ifdef AUDIOCONVERT_DEBUG + printf("AudioConverter::release converter:%p current refcount:%d\n", cv, cv->_refCount); + #endif + if(cv->_refCount <= 0) + { + #ifdef AUDIOCONVERT_DEBUG + printf("AudioConverter::release deleting converter:%p\n", cv); + #endif + delete cv; + cv = 0; + } + return cv; +} + +//off_t AudioConverter::readAudio(SndFileR& f, off_t sfCurFrame, unsigned offset, float** buffer, int channel, int n, bool doSeek, bool overwrite) +off_t AudioConverter::readAudio(SndFileR& f, unsigned offset, float** buffer, int channel, int n, bool doSeek, bool overwrite) +{ + if(f.isNull()) + return _sfCurFrame; + + // Added by Tim. p3.3.17 + //#ifdef AUDIOCONVERT_DEBUG_PRC + //printf("AudioConverter::process %s audConv:%p sfCurFrame:%ld offset:%u channel:%d fchan:%d n:%d\n", + // f.name().latin1(), this, sfCurFrame, offset, channel, f.channels(), n); + //#endif + + off_t frame = offset; // _spos is added before the call. + unsigned fsrate = f.samplerate(); + bool resample = isValid() && ((unsigned)sampleRate != fsrate); + + // No resampling needed? + if(!resample) + { + // Sample rates are the same. Just a regular seek + read, no conversion. + _sfCurFrame = f.seek(frame, 0); + return _sfCurFrame + f.read(channel, buffer, n, overwrite); + } + + // Is a 'transport' seek requested? (Not to be requested with every read! Should only be for 'first read' seeks, or positional 'transport' seeks.) + // Due to the support of sound file references in MusE, seek must ALWAYS be done before read, as before, + // except now we alter the seek position if sample rate conversion is being used and remember the seek positions. + if(doSeek) + { + // Sample rates are different. Seek to a calculated 'sample rate ratio factored' position. + + double srcratio = (double)fsrate / (double)sampleRate; + //long inSize = long((double)frames * _src_ratio) + 1 // From MusE-2 file converter. + off_t newfr = (off_t)floor(((double)frame * srcratio)); // From simplesynth. + + _sfCurFrame = f.seek(newfr, 0); + + // Added by Tim. p3.3.17 + //#ifdef AUDIOCONVERT_DEBUG_PRC + //printf("AudioConverter::process Seek frame:%ld converted to frame:%ld sfCurFrame:%ld\n", frame, newfr, sfCurFrame); + //#endif + + // Reset the converter. Its current state is meaningless now. + reset(); + } + else + { + // No seek requested. + // Added by Tim. p3.3.17 + //#ifdef AUDIOCONVERT_DEBUG_PRC + //printf("AudioConverter::process No 'transport' seek, rates different. Seeking to sfCurFrame:%ld\n", sfCurFrame); + //#endif + + // Sample rates are different. We can't just tell seek to go to an absolute calculated position, + // since the last position can vary - it might not be what the calculated position is. + // We must use the last position left by SRC conversion, ie. let the file position progress on its own. + _sfCurFrame = f.seek(_sfCurFrame, 0); + } + + /* + int fchan = f.channels(); + long outFrames = n; + long outSize = outFrames * fchan; + float outbuffer[outSize]; + */ + + //sfCurFrame = process(f, sfCurFrame, offset, &outbuffer[0], channel, n); +// sfCurFrame = process(f, sfCurFrame, outbuffer, channel, n); + //sfCurFrame = process(f, sfCurFrame, buffer, channel, n, overwrite); + _sfCurFrame = process(f, buffer, channel, n, overwrite); + + /* + float* poutbuf = &outbuffer[0]; + if(fchan == channel) + { + if(overwrite) + //for (size_t i = 0; i < rn; ++i) + for (int i = 0; i < n; ++i) + { + for(int ch = 0; ch < channel; ++ch) + *(buffer[ch] + i) = *poutbuf++; + } + else + //for(size_t i = 0; i < rn; ++i) + for(int i = 0; i < n; ++i) + { + for(int ch = 0; ch < channel; ++ch) + *(buffer[ch] + i) += *poutbuf++; + } + } + else if((fchan == 2) && (channel == 1)) + { + // stereo to mono + if(overwrite) + //for(size_t i = 0; i < rn; ++i) + for(int i = 0; i < n; ++i) + *(buffer[0] + i) = poutbuf[i + i] + poutbuf[i + i + 1]; + else + //for(size_t i = 0; i < rn; ++i) + for(int i = 0; i < n; ++i) + *(buffer[0] + i) += poutbuf[i + i] + poutbuf[i + i + 1]; + } + else if((fchan == 1) && (channel == 2)) + { + // mono to stereo + if(overwrite) + //for(size_t i = 0; i < rn; ++i) + for(int i = 0; i < n; ++i) + { + float data = *poutbuf++; + *(buffer[0]+i) = data; + *(buffer[1]+i) = data; + } + else + //for(size_t i = 0; i < rn; ++i) + for(int i = 0; i < n; ++i) + { + float data = *poutbuf++; + *(buffer[0]+i) += data; + *(buffer[1]+i) += data; + } + } + else + { + #ifdef AUDIOCONVERT_DEBUG + printf("AudioConverter::readAudio Channel mismatch: source chans:%d -> dst chans:%d\n", fchan, channel); + #endif + } + */ + + return _sfCurFrame; +} + +//--------------------------------------------------------- +// SRCAudioConverter +//--------------------------------------------------------- + +SRCAudioConverter::SRCAudioConverter(int channels, int type) : AudioConverter() +{ + #ifdef AUDIOCONVERT_DEBUG + printf("SRCAudioConverter::SRCAudioConverter this:%p channels:%d type:%d\n", this, channels, type); + #endif + + _type = type; + _src_state = 0; + _channels = channels; + + int srcerr; + #ifdef AUDIOCONVERT_DEBUG + printf("SRCAudioConverter::SRCaudioConverter Creating samplerate converter type:%d with %d channels\n", _type, _channels); + #endif + _src_state = src_new(_type, _channels, &srcerr); + if(!_src_state) + printf("SRCAudioConverter::SRCaudioConverter Creation of samplerate converter type:%d with %d channels failed:%s\n", _type, _channels, src_strerror(srcerr)); +} + +SRCAudioConverter::~SRCAudioConverter() +{ + #ifdef AUDIOCONVERT_DEBUG + printf("SRCAudioConverter::~SRCAudioConverter this:%p\n", this); + #endif + if(_src_state) + src_delete(_src_state); +} + +void SRCAudioConverter::setChannels(int ch) +{ + #ifdef AUDIOCONVERT_DEBUG + printf("SRCAudioConverter::setChannels this:%p channels:%d\n", this, ch); + #endif + if(_src_state) + src_delete(_src_state); + _src_state = 0; + + _channels = ch; + int srcerr; + #ifdef AUDIOCONVERT_DEBUG + printf("SRCAudioConverter::setChannels Creating samplerate converter type:%d with %d channels\n", _type, ch); + #endif + _src_state = src_new(_type, ch, &srcerr); + if(!_src_state) + printf("SRCAudioConverter::setChannels of samplerate converter type:%d with %d channels failed:%s\n", _type, ch, src_strerror(srcerr)); + return; +} + +void SRCAudioConverter::reset() +{ + if(!_src_state) + return; + #ifdef AUDIOCONVERT_DEBUG + printf("SRCAudioConverter::reset this:%p\n", this); + #endif + int srcerr = src_reset(_src_state); + if(srcerr != 0) + printf("SRCAudioConverter::reset Converter reset failed: %s\n", src_strerror(srcerr)); + return; +} + +//off_t SRCAudioConverter::process(SndFileR& f, off_t sfCurFrame, float** buffer, int channel, int n, bool overwrite) +off_t SRCAudioConverter::process(SndFileR& f, float** buffer, int channel, int n, bool overwrite) +{ + //return src_process(_src_state, sd); + + if(f.isNull()) + //return; + return _sfCurFrame; + + // Added by Tim. p3.3.17 + //#ifdef AUDIOCONVERT_DEBUG_PRC + //printf("AudioConverter::process %s audConv:%p sfCurFrame:%ld offset:%u channel:%d fchan:%d n:%d\n", + // f.name().latin1(), this, sfCurFrame, offset, channel, f.channels(), n); + //#endif + +// off_t frame = offset; // _spos is added before the call. + unsigned fsrate = f.samplerate(); + //bool resample = src_state && ((unsigned)sampleRate != fsrate); +// bool resample = isValid() && ((unsigned)sampleRate != fsrate); + + if((sampleRate == 0) || (fsrate == 0)) + { + #ifdef AUDIOCONVERT_DEBUG + printf("SRCAudioConverter::process Error: sampleRate or file samplerate is zero!\n"); + #endif + return _sfCurFrame; + } + + SRC_DATA srcdata; + int fchan = f.channels(); + // Ratio is defined as output sample rate over input samplerate. + double srcratio = (double)sampleRate / (double)fsrate; + // Extra input compensation. + long inComp = 1; + + long outFrames = n; + //long outSize = outFrames * channel; + long outSize = outFrames * fchan; + + //long inSize = long(outSize * srcratio) + 1 // From MusE-2 file converter. + //long inSize = (long)floor(((double)outSize / srcratio)); // From simplesynth. + //long inFrames = (long)floor(((double)outFrames / srcratio)); // From simplesynth. + long inFrames = (long)ceil(((double)outFrames / srcratio)) + inComp; // From simplesynth. + //long inFrames = (long)floor(double(outFrames * sfinfo.samplerate) / double(sampleRate)); // From simplesynth. + + long inSize = inFrames * fchan; + //long inSize = inFrames * channel; + + // Start with buffers at expected sizes. We won't need anything larger than this, but add 4 for good luck. + float inbuffer[inSize + 4]; + float outbuffer[outSize]; + + //size_t sfTotalRead = 0; + size_t rn = 0; + long totalOutFrames = 0; + + srcdata.data_in = inbuffer; + srcdata.data_out = outbuffer; +// srcdata.data_out = buffer; + + // Set some kind of limit on the number of attempts to completely fill the output buffer, + // in case something is really screwed up - we don't want to get stuck in a loop here. + int attempts = 10; + for(int attempt = 0; attempt < attempts; ++attempt) + { + rn = f.readDirect(inbuffer, inFrames); + //sfTotalRead += rn; + + // convert + //srcdata.data_in = inbuffer; + //srcdata.data_out = outbuffer; + //srcdata.data_out = poutbuf; + //srcdata.input_frames = inSize; + srcdata.input_frames = rn; + srcdata.output_frames = outFrames; + srcdata.end_of_input = ((long)rn != inFrames); + srcdata.src_ratio = srcratio; + + //#ifdef AUDIOCONVERT_DEBUG_PRC + //printf("AudioConverter::process attempt:%d inFrames:%ld outFrames:%ld rn:%d data in:%p out:%p", + // attempt, inFrames, outFrames, rn, srcdata.data_in, srcdata.data_out); + //#endif + + int srcerr = src_process(_src_state, &srcdata); + if(srcerr != 0) + { + printf("\nSRCAudioConverter::process SampleRate converter process failed: %s\n", src_strerror(srcerr)); + return _sfCurFrame += rn; + } + + totalOutFrames += srcdata.output_frames_gen; + + //#ifdef AUDIOCONVERT_DEBUG_PRC + //printf(" frames used in:%ld out:%ld totalOutFrames:%ld data in:%p out:%p\n", srcdata.input_frames_used, srcdata.output_frames_gen, totalOutFrames, srcdata.data_in, srcdata.data_out); + //#endif + + #ifdef AUDIOCONVERT_DEBUG + if(srcdata.output_frames_gen != outFrames) + printf("SRCAudioConverter::process %s output_frames_gen:%ld != outFrames:%ld inFrames:%ld srcdata.input_frames_used:%ld rn:%d\n", + f.name().latin1(), srcdata.output_frames_gen, outFrames, inFrames, srcdata.input_frames_used, rn); + #endif + + // If the number of frames read by the soundfile equals the input frames, go back. + // Otherwise we have reached the end of the file, so going back is useless since + // there shouldn't be any further calls. + if((long)rn == inFrames) + { + // Go back by the amount of unused frames. + sf_count_t seekn = inFrames - srcdata.input_frames_used; + if(seekn != 0) + { + #ifdef AUDIOCONVERT_DEBUG_PRC + printf("SRCAudioConverter::process Seek-back by:%d\n", seekn); + #endif + _sfCurFrame = f.seek(-seekn, SEEK_CUR); + } + else + _sfCurFrame += rn; + + if(totalOutFrames == n) + { + // We got our desired number of output frames. Stop attempting. + break; + } + else + { + // No point in continuing if on last attempt. + if(attempt == (attempts - 1)) + break; + + #ifdef AUDIOCONVERT_DEBUG + printf("SRCAudioConverter::process %s attempt:%d totalOutFrames:%ld != n:%d try again\n", f.name().latin1(), attempt, totalOutFrames, n); + #endif + + // SRC didn't give us the number of frames we requested. + // This can occasionally be radically different from the requested frames, or zero, + // even when ample excess input frames are supplied. + // Move the src output pointer to a new position. + srcdata.data_out += srcdata.output_frames_gen * channel; + // Set new number of maximum out frames. + outFrames -= srcdata.output_frames_gen; + // Calculate the new number of file input frames required. + inFrames = (long)ceil(((double)outFrames / srcratio)) + inComp; + // Keep trying. + continue; + } + } + else + { + _sfCurFrame += rn; + #ifdef AUDIOCONVERT_DEBUG + printf("SRCAudioConverter::process %s rn:%zd != inFrames:%ld output_frames_gen:%ld outFrames:%ld srcdata.input_frames_used:%ld\n", + f.name().latin1(), rn, inFrames, srcdata.output_frames_gen, outFrames, srcdata.input_frames_used); + #endif + + // We've reached the end of the file. Convert the number of frames read. + //rn = (double)rn * srcratio + 1; + //rn = (long)floor((double)rn * srcratio); + //if(rn > (size_t)outFrames) + // rn = outFrames; + // Stop attempting. + break; + } + } + + // If we still didn't get the desired number of output frames. + if(totalOutFrames != n) + { + #ifdef AUDIOCONVERT_DEBUG + printf("SRCAudioConverter::process %s totalOutFrames:%ld != n:%d\n", f.name().latin1(), totalOutFrames, n); + #endif + + // Let's zero the rest of it. + long b = totalOutFrames * channel; + long e = n * channel; + for(long i = b; i < e; ++i) + outbuffer[i] = 0.0f; + //buffer[i] = 0.0f; + } + + //float* poutbuf = &outbuffer[0]; + float* poutbuf = outbuffer; + if(fchan == channel) + { + if(overwrite) + //for (size_t i = 0; i < rn; ++i) + for (int i = 0; i < n; ++i) + { + for(int ch = 0; ch < channel; ++ch) + *(buffer[ch] + i) = *poutbuf++; + } + else + //for(size_t i = 0; i < rn; ++i) + for(int i = 0; i < n; ++i) + { + for(int ch = 0; ch < channel; ++ch) + *(buffer[ch] + i) += *poutbuf++; + } + } + else if((fchan == 2) && (channel == 1)) + { + // stereo to mono + if(overwrite) + //for(size_t i = 0; i < rn; ++i) + for(int i = 0; i < n; ++i) + *(buffer[0] + i) = poutbuf[i + i] + poutbuf[i + i + 1]; + else + //for(size_t i = 0; i < rn; ++i) + for(int i = 0; i < n; ++i) + *(buffer[0] + i) += poutbuf[i + i] + poutbuf[i + i + 1]; + } + else if((fchan == 1) && (channel == 2)) + { + // mono to stereo + if(overwrite) + //for(size_t i = 0; i < rn; ++i) + for(int i = 0; i < n; ++i) + { + float data = *poutbuf++; + *(buffer[0]+i) = data; + *(buffer[1]+i) = data; + } + else + //for(size_t i = 0; i < rn; ++i) + for(int i = 0; i < n; ++i) + { + float data = *poutbuf++; + *(buffer[0]+i) += data; + *(buffer[1]+i) += data; + } + } + else + { + #ifdef AUDIOCONVERT_DEBUG + printf("SRCAudioConverter::process Channel mismatch: source chans:%d -> dst chans:%d\n", fchan, channel); + #endif + } + + return _sfCurFrame; +} + +#ifdef RUBBERBAND_SUPPORT + +//--------------------------------------------------------- +// RubberBandAudioConverter +//--------------------------------------------------------- + +RubberBandAudioConverter::RubberBandAudioConverter(int channels, int options) : AudioConverter() +{ + #ifdef AUDIOCONVERT_DEBUG + printf("RubberBandAudioConverter::RubberBandAudioConverter this:%p channels:%d options:%x\n", this, channels, options); + #endif + + _options = options; + _rbs = 0; + _channels = channels; + + _rbs = new RubberBandStretcher(sampleRate, _channels, _options); // , initialTimeRatio = 1.0, initialPitchScale = 1.0 +} + +RubberBandAudioConverter::~RubberBandAudioConverter() +{ + #ifdef AUDIOCONVERT_DEBUG + printf("RubberBandAudioConverter::~RubberBandAudioConverter this:%p\n", this); + #endif + if(_rbs) + delete _rbs; +} + +void RubberBandAudioConverter::setChannels(int ch) +{ + #ifdef AUDIOCONVERT_DEBUG + printf("RubberBandAudioConverter::setChannels this:%p channels:%d\n", this, ch); + #endif + if(_rbs) + delete _rbs; + _rbs = 0; + + _channels = ch; + _rbs = new RubberBandStretcher(sampleRate, _channels, _options); // , initialTimeRatio = 1.0, initialPitchScale = 1.0 +} + +void RubberBandAudioConverter::reset() +{ + if(!_rbs) + return; + #ifdef AUDIOCONVERT_DEBUG + printf("RubberBandAudioConverter::reset this:%p\n", this); + #endif + _rbs->reset(); + return; +} + +///////////////////////////////// +// TODO: Not finished yet.. +//////////////////////////////// +//off_t RubberBandAudioConverter::process(SndFileR& f, off_t sfCurFrame, float** buffer, int channel, int n, bool overwrite) +off_t RubberBandAudioConverter::process(SndFileR& f, float** buffer, int channel, int n, bool overwrite) +{ + //return src_process(_src_state, sd); + + if(f.isNull()) + //return; + return _sfCurFrame; + + // Added by Tim. p3.3.17 + //#ifdef AUDIOCONVERT_DEBUG_PRC + //printf("AudioConverter::process %s audConv:%p sfCurFrame:%ld offset:%u channel:%d fchan:%d n:%d\n", + // f.name().latin1(), this, sfCurFrame, offset, channel, f.channels(), n); + //#endif + +// off_t frame = offset; // _spos is added before the call. + unsigned fsrate = f.samplerate(); + //bool resample = src_state && ((unsigned)sampleRate != fsrate); +// bool resample = isValid() && ((unsigned)sampleRate != fsrate); + + if((sampleRate == 0) || (fsrate == 0)) + { + #ifdef AUDIOCONVERT_DEBUG + printf("RubberBandAudioConverter::process Error: sampleRate or file samplerate is zero!\n"); + #endif + return _sfCurFrame; + } + +// SRC_DATA srcdata; + int fchan = f.channels(); + // Ratio is defined as output sample rate over input samplerate. + double srcratio = (double)sampleRate / (double)fsrate; + // Extra input compensation. + long inComp = 1; + + long outFrames = n; + //long outSize = outFrames * channel; + long outSize = outFrames * fchan; + + //long inSize = long(outSize * srcratio) + 1 // From MusE-2 file converter. + //long inSize = (long)floor(((double)outSize / srcratio)); // From simplesynth. + //long inFrames = (long)floor(((double)outFrames / srcratio)); // From simplesynth. + long inFrames = (long)ceil(((double)outFrames / srcratio)) + inComp; // From simplesynth. + //long inFrames = (long)floor(double(outFrames * sfinfo.samplerate) / double(sampleRate)); // From simplesynth. + + long inSize = inFrames * fchan; + //long inSize = inFrames * channel; + + // Start with buffers at expected sizes. We won't need anything larger than this, but add 4 for good luck. + float inbuffer[inSize]; // +4 +// float outbuffer[outSize]; + + //float* rbinbuffer[fchan]; + //float rbindata[inSize]; + //for (int i = 0; i < fchan; ++i) + // rbinbuffer[i] = rbindata + i * inFrames; + + float* rboutbuffer[fchan]; + float rboutdata[outSize]; + for (int i = 0; i < fchan; ++i) + rboutbuffer[i] = rboutdata + i * outFrames; + + //size_t sfTotalRead = 0; + size_t rn = 0; + long totalOutFrames = 0; + +// srcdata.data_in = inbuffer; + //srcdata.data_out = outbuffer; +// srcdata.data_out = buffer; + float** data_out = rboutbuffer; + + // For just sample rate conversion, apply same ratio to both time and pitch. + _rbs->setTimeRatio(srcratio); + _rbs->setPitchScale(srcratio); + + // Set some kind of limit on the number of attempts to completely fill the output buffer, + // in case something is really screwed up - we don't want to get stuck in a loop here. + int attempts = 10; + for(int attempt = 0; attempt < attempts; ++attempt) + { + size_t sreq = _rbs->getSamplesRequired(); + + size_t rbinSize = sreq * fchan; + float* rbinbuffer[fchan]; + float rbindata[rbinSize]; + for(int i = 0; i < fchan; ++i) + rbinbuffer[i] = rbindata + i * sreq; + +// rn = f.readDirect(inbuffer, inFrames); + rn = f.readDirect(inbuffer, sreq); + //sfTotalRead += rn; + + // Must de-interleave soundfile data to feed to rubberband. + for(size_t i = 0; i < rn; ++i) + { + for(int ch = 0; ch < fchan; ++ch) + *(rbinbuffer[ch] + i) = *inbuffer++; + } + + _rbs->process(rbinbuffer, rn, (long)rn != inFrames); + + // "This function returns -1 if all data has been fully processed and all output read, and the stretch process is now finished." + int savail = _rbs->available(); + + + // convert + //srcdata.data_in = inbuffer; + //srcdata.data_out = outbuffer; + //srcdata.data_out = poutbuf; + //srcdata.input_frames = inSize; + srcdata.input_frames = rn; + srcdata.output_frames = outFrames; + srcdata.end_of_input = ((long)rn != inFrames); + srcdata.src_ratio = srcratio; + + //#ifdef AUDIOCONVERT_DEBUG_PRC + //printf("AudioConverter::process attempt:%d inFrames:%ld outFrames:%ld rn:%d data in:%p out:%p", + // attempt, inFrames, outFrames, rn, srcdata.data_in, srcdata.data_out); + //#endif + + int srcerr = src_process(_src_state, &srcdata); + if(srcerr != 0) + { + printf("\RubberBandAudioConverter::process SampleRate converter process failed: %s\n", src_strerror(srcerr)); + return _sfCurFrame += rn; + } + + totalOutFrames += srcdata.output_frames_gen; + + //#ifdef AUDIOCONVERT_DEBUG_PRC + //printf(" frames used in:%ld out:%ld totalOutFrames:%ld data in:%p out:%p\n", srcdata.input_frames_used, srcdata.output_frames_gen, totalOutFrames, srcdata.data_in, srcdata.data_out); + //#endif + + #ifdef AUDIOCONVERT_DEBUG + if(srcdata.output_frames_gen != outFrames) + printf("RubberBandAudioConverter::process %s output_frames_gen:%ld != outFrames:%ld inFrames:%ld srcdata.input_frames_used:%ld rn:%d\n", + f.name().latin1(), srcdata.output_frames_gen, outFrames, inFrames, srcdata.input_frames_used, rn); + #endif + + // If the number of frames read by the soundfile equals the input frames, go back. + // Otherwise we have reached the end of the file, so going back is useless since + // there shouldn't be any further calls. + if((long)rn == inFrames) + { + // Go back by the amount of unused frames. + sf_count_t seekn = inFrames - srcdata.input_frames_used; + if(seekn != 0) + { + #ifdef AUDIOCONVERT_DEBUG_PRC + printf("RubberBandAudioConverter::process Seek-back by:%d\n", seekn); + #endif + _sfCurFrame = f.seek(-seekn, SEEK_CUR); + } + else + _sfCurFrame += rn; + + if(totalOutFrames == n) + { + // We got our desired number of output frames. Stop attempting. + break; + } + else + { + // No point in continuing if on last attempt. + if(attempt == (attempts - 1)) + break; + + #ifdef AUDIOCONVERT_DEBUG + printf("RubberBandAudioConverter::process %s attempt:%d totalOutFrames:%ld != n:%d try again\n", f.name().latin1(), attempt, totalOutFrames, n); + #endif + + // We didn't get the number of frames we requested. + // This can occasionally be radically different from the requested frames, or zero, + // even when ample excess input frames are supplied. + // Move the src output pointer to a new position. + srcdata.data_out += srcdata.output_frames_gen * channel; + // Set new number of maximum out frames. + outFrames -= srcdata.output_frames_gen; + // Calculate the new number of file input frames required. + inFrames = (long)ceil(((double)outFrames / srcratio)) + inComp; + // Keep trying. + continue; + } + } + else + { + _sfCurFrame += rn; + #ifdef AUDIOCONVERT_DEBUG + printf("RubberBandAudioConverter::process %s rn:%zd != inFrames:%ld output_frames_gen:%ld outFrames:%ld srcdata.input_frames_used:%ld\n", + f.name().latin1(), rn, inFrames, srcdata.output_frames_gen, outFrames, srcdata.input_frames_used); + #endif + + // We've reached the end of the file. Convert the number of frames read. + //rn = (double)rn * srcratio + 1; + //rn = (long)floor((double)rn * srcratio); + //if(rn > (size_t)outFrames) + // rn = outFrames; + // Stop attempting. + break; + } + } + + // If we still didn't get the desired number of output frames. + if(totalOutFrames != n) + { + #ifdef AUDIOCONVERT_DEBUG + printf("RubberBandAudioConverter::process %s totalOutFrames:%ld != n:%d\n", f.name().latin1(), totalOutFrames, n); + #endif + + // Let's zero the rest of it. + long b = totalOutFrames * channel; + long e = n * channel; + for(long i = b; i < e; ++i) + //outbuffer[i] = 0.0f; + buffer[i] = 0.0f; + } + + //float* poutbuf = &outbuffer[0]; + float* poutbuf = outbuffer; + if(fchan == channel) + { + if(overwrite) + //for (size_t i = 0; i < rn; ++i) + for (int i = 0; i < n; ++i) + { + for(int ch = 0; ch < channel; ++ch) + *(buffer[ch] + i) = *poutbuf++; + } + else + //for(size_t i = 0; i < rn; ++i) + for(int i = 0; i < n; ++i) + { + for(int ch = 0; ch < channel; ++ch) + *(buffer[ch] + i) += *poutbuf++; + } + } + else if((fchan == 2) && (channel == 1)) + { + // stereo to mono + if(overwrite) + //for(size_t i = 0; i < rn; ++i) + for(int i = 0; i < n; ++i) + *(buffer[0] + i) = poutbuf[i + i] + poutbuf[i + i + 1]; + else + //for(size_t i = 0; i < rn; ++i) + for(int i = 0; i < n; ++i) + *(buffer[0] + i) += poutbuf[i + i] + poutbuf[i + i + 1]; + } + else if((fchan == 1) && (channel == 2)) + { + // mono to stereo + if(overwrite) + //for(size_t i = 0; i < rn; ++i) + for(int i = 0; i < n; ++i) + { + float data = *poutbuf++; + *(buffer[0]+i) = data; + *(buffer[1]+i) = data; + } + else + //for(size_t i = 0; i < rn; ++i) + for(int i = 0; i < n; ++i) + { + float data = *poutbuf++; + *(buffer[0]+i) += data; + *(buffer[1]+i) += data; + } + } + else + { + #ifdef AUDIOCONVERT_DEBUG + printf("RubberBandAudioConverter::process Channel mismatch: source chans:%d -> dst chans:%d\n", fchan, channel); + #endif + } + + return _sfCurFrame; +} + +#endif // RUBBERBAND_SUPPORT |