1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-16 16:10:06 +02:00

Go back to simpler architecture for Resample class, now that libsoxr is proven for variable rate resampling.

This commit is contained in:
v.audacity 2013-08-04 01:58:54 +00:00
parent 51e0391b7d
commit 030d2450a8
10 changed files with 111 additions and 498 deletions

View File

@ -127,13 +127,13 @@ void AboutDialog::CreateCreditsList()
AddCredit(wxT("LAME"), roleLibrary); AddCredit(wxT("LAME"), roleLibrary);
AddCredit(wxT("libmad"), roleLibrary); AddCredit(wxT("libmad"), roleLibrary);
#if USE_LIBRESAMPLE #if USE_LIBRESAMPLE
AddCredit(wxT("libresample"), roleLibrary); AddCredit(wxT("libresample, by Dominic Mazzoni and Julius Smith"), roleLibrary);
#endif #endif
#if USE_LIBSAMPLERATE #if USE_LIBSAMPLERATE
AddCredit(wxT("libsamplerate, by Erik de Castro Lopo"), roleLibrary); AddCredit(wxT("libsamplerate, by Erik de Castro Lopo"), roleLibrary);
#endif #endif
#if USE_LIBSOXR #if USE_LIBSOXR
AddCredit(wxT("libsoxr"), roleLibrary); AddCredit(wxT("libsoxr, by Rob Sykes"), roleLibrary);
#endif #endif
AddCredit(wxT("libsndfile"), roleLibrary); AddCredit(wxT("libsndfile"), roleLibrary);
AddCredit(wxT("Nyquist"), roleLibrary); AddCredit(wxT("Nyquist"), roleLibrary);

View File

@ -1322,18 +1322,18 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
} }
mCaptureBuffers = new RingBuffer* [mCaptureTracks.GetCount()]; mCaptureBuffers = new RingBuffer* [mCaptureTracks.GetCount()];
mResample = new ConstRateResample* [mCaptureTracks.GetCount()]; mResample = new Resample* [mCaptureTracks.GetCount()];
mFactor = sampleRate / mRate; mFactor = sampleRate / mRate;
// Set everything to zero in case we have to delete these due to a memory exception. // Set everything to zero in case we have to delete these due to a memory exception.
memset(mCaptureBuffers, 0, sizeof(RingBuffer*)*mCaptureTracks.GetCount()); memset(mCaptureBuffers, 0, sizeof(RingBuffer*)*mCaptureTracks.GetCount());
memset(mResample, 0, sizeof(ConstRateResample*)*mCaptureTracks.GetCount()); memset(mResample, 0, sizeof(Resample*)*mCaptureTracks.GetCount());
for( unsigned int i = 0; i < mCaptureTracks.GetCount(); i++ ) for( unsigned int i = 0; i < mCaptureTracks.GetCount(); i++ )
{ {
mCaptureBuffers[i] = new RingBuffer( mCaptureTracks[i]->GetSampleFormat(), mCaptureBuffers[i] = new RingBuffer( mCaptureTracks[i]->GetSampleFormat(),
captureBufferSize ); captureBufferSize );
mResample[i] = new ConstRateResample(true, mFactor); mResample[i] = new Resample(true, mFactor, mFactor); // constant rate resampling
} }
} }
} }

View File

@ -38,7 +38,7 @@
class AudioIO; class AudioIO;
class RingBuffer; class RingBuffer;
class Mixer; class Mixer;
class ConstRateResample; class Resample;
class TimeTrack; class TimeTrack;
class AudioThread; class AudioThread;
class Meter; class Meter;
@ -474,7 +474,7 @@ private:
#ifdef EXPERIMENTAL_MIDI_OUT #ifdef EXPERIMENTAL_MIDI_OUT
AudioThread *mMidiThread; AudioThread *mMidiThread;
#endif #endif
ConstRateResample **mResample; Resample **mResample;
RingBuffer **mCaptureBuffers; RingBuffer **mCaptureBuffers;
WaveTrackArray mCaptureTracks; WaveTrackArray mCaptureTracks;
RingBuffer **mPlaybackBuffers; RingBuffer **mPlaybackBuffers;

View File

@ -286,11 +286,12 @@ Mixer::Mixer(int numInputTracks, WaveTrack **inputTracks,
for(i=0; i<mNumInputTracks; i++) { for(i=0; i<mNumInputTracks; i++) {
double factor = (mRate / mInputTrack[i]->GetRate()); double factor = (mRate / mInputTrack[i]->GetRate());
if (timeTrack) { if (timeTrack) {
mResample[i] = new VarRateResample(highQuality, // variable rate resampling
factor / timeTrack->GetRangeUpper(), mResample[i] = new Resample(highQuality,
factor / timeTrack->GetRangeLower()); factor / timeTrack->GetRangeUpper(),
factor / timeTrack->GetRangeLower());
} else { } else {
mResample[i] = new ConstRateResample(highQuality, factor); mResample[i] = new Resample(highQuality, factor, factor); // constant rate resampling
} }
mSampleQueue[i] = new float[mQueueMaxLen]; mSampleQueue[i] = new float[mQueueMaxLen];
mQueueStart[i] = 0; mQueueStart[i] = 0;

View File

@ -32,281 +32,11 @@
#include "Resample.h" #include "Resample.h"
//v Currently unused.
//void Resample::SetFastMethod(int index)
//{
// gPrefs->Write(GetFastMethodKey(), (long)index);
// gPrefs->Flush();
//}
//
//void Resample::SetBestMethod(int index)
//{
// gPrefs->Write(GetBestMethodKey(), (long)index);
// gPrefs->Flush();
//}
// constant-rate resamplers
#if USE_LIBRESAMPLE #if USE_LIBRESAMPLE
#include "libresample.h" #include "libresample.h"
ConstRateResample::ConstRateResample(const bool useBestMethod, const double dFactor) Resample::Resample(const bool useBestMethod, const double dMinFactor, const double dMaxFactor)
: Resample()
{
this->SetMethod(useBestMethod);
mHandle = resample_open(mMethod, dFactor, dFactor);
if(mHandle == NULL) {
fprintf(stderr, "libresample doesn't support factor %f.\n", dFactor);
// FIX-ME: Audacity will hang after this if branch.
return;
}
}
ConstRateResample::~ConstRateResample()
{
resample_close(mHandle);
mHandle = NULL;
}
//v Currently unused.
//wxString ConstRateResample::GetResamplingLibraryName()
//{
// return _("Libresample by Dominic Mazzoni and Julius Smith");
//}
int ConstRateResample::GetNumMethods() { return 2; }
wxString ConstRateResample::GetMethodName(int index)
{
if (index == 1)
return _("High-quality Sinc Interpolation");
return _("Fast Sinc Interpolation");
}
const wxString ConstRateResample::GetFastMethodKey()
{
return wxT("/Quality/LibresampleSampleRateConverter");
}
const wxString ConstRateResample::GetBestMethodKey()
{
return wxT("/Quality/LibresampleHQSampleRateConverter");
}
int ConstRateResample::GetFastMethodDefault() { return 0; }
int ConstRateResample::GetBestMethodDefault() { return 1; }
int ConstRateResample::Process(double factor,
float *inBuffer,
int inBufferLen,
bool lastFlag,
int *inBufferUsed,
float *outBuffer,
int outBufferLen)
{
return resample_process(mHandle, factor, inBuffer, inBufferLen,
(int)lastFlag, inBufferUsed, outBuffer, outBufferLen);
}
#elif USE_LIBSAMPLERATE
#include <samplerate.h>
ConstRateResample::ConstRateResample(const bool useBestMethod, const double dFactor)
: Resample()
{
this->SetMethod(useBestMethod);
if (!src_is_valid_ratio(dFactor))
{
fprintf(stderr, "libsamplerate supports only resampling factors between 1/SRC_MAX_RATIO and SRC_MAX_RATIO.\n");
// FIX-ME: Audacity will hang after this if branch.
mHandle = NULL;
return;
}
int err;
SRC_STATE *state = src_new(mMethod, 1, &err);
mHandle = (void *)state;
mShouldReset = false;
mSamplesLeft = 0;
}
ConstRateResample::~ConstRateResample()
{
src_delete((SRC_STATE *)mHandle);
mHandle = NULL;
}
//v Currently unused.
//wxString ConstRateResample::GetResamplingLibraryName()
//{
// return _("Libsamplerate by Erik de Castro Lopo");
//}
int ConstRateResample::GetNumMethods()
{
int i = 0;
while(src_get_name(i))
i++;
return i;
}
wxString ConstRateResample::GetMethodName(int index)
{
return wxString(wxString::FromAscii(src_get_name(index)));
}
const wxString ConstRateResample::GetFastMethodKey()
{
return wxT("/Quality/SampleRateConverter");
}
const wxString ConstRateResample::GetBestMethodKey()
{
return wxT("/Quality/HQSampleRateConverter");
}
int ConstRateResample::GetFastMethodDefault()
{
return SRC_SINC_FASTEST;
}
int ConstRateResample::GetBestMethodDefault()
{
return SRC_SINC_BEST_QUALITY;
}
int ConstRateResample::Process(double factor,
float *inBuffer,
int inBufferLen,
bool lastFlag,
int *inBufferUsed,
float *outBuffer,
int outBufferLen)
{
src_set_ratio((SRC_STATE *)mHandle, factor);
if(mShouldReset) {
if(inBufferLen > mSamplesLeft) {
mShouldReset = false;
src_reset((SRC_STATE *)mHandle);
} else {
mSamplesLeft -= inBufferLen;
}
}
SRC_DATA data;
data.data_in = inBuffer;
data.data_out = outBuffer;
data.input_frames = inBufferLen;
data.output_frames = outBufferLen;
data.input_frames_used = 0;
data.output_frames_gen = 0;
data.end_of_input = (int)lastFlag;
data.src_ratio = factor;
int err = src_process((SRC_STATE *)mHandle, &data);
if (err) {
wxFprintf(stderr, _("Libsamplerate error: %d\n"), err);
return 0;
}
if(lastFlag) {
mShouldReset = true;
mSamplesLeft = inBufferLen - (int)data.input_frames_used;
}
*inBufferUsed = (int)data.input_frames_used;
return (int)data.output_frames_gen;
}
#elif USE_LIBSOXR
#include <soxr.h>
ConstRateResample::ConstRateResample(const bool useBestMethod, const double dFactor)
: Resample()
{
this->SetMethod(useBestMethod);
soxr_quality_spec_t q_spec = soxr_quality_spec("\0\1\4\6"[mMethod], 0);
mHandle = (void *)soxr_create(1, dFactor, 1, 0, 0, &q_spec, 0);
}
ConstRateResample::~ConstRateResample()
{
soxr_delete((soxr_t)mHandle);
mHandle = NULL;
}
//v Currently unused.
//wxString ConstRateResample::GetResamplingLibraryName()
//{
// return _("Libsoxr by Rob Sykes");
//}
int ConstRateResample::GetNumMethods() { return 4; }
wxString ConstRateResample::GetMethodName(int index)
{
static char const * const soxr_method_names[] = {
"Low Quality (Fastest)", "Medium Quality", "High Quality", "Best Quality (Slowest)"
};
return wxString(wxString::FromAscii(soxr_method_names[index]));
}
const wxString ConstRateResample::GetFastMethodKey()
{
return wxT("/Quality/LibsoxrSampleRateConverter");
}
const wxString ConstRateResample::GetBestMethodKey()
{
return wxT("/Quality/LibsoxrHQSampleRateConverter");
}
int ConstRateResample::GetFastMethodDefault() {return 1;}
int ConstRateResample::GetBestMethodDefault() {return 3;}
int ConstRateResample::Process(double factor,
float *inBuffer,
int inBufferLen,
bool lastFlag,
int *inBufferUsed,
float *outBuffer,
int outBufferLen)
{
size_t idone , odone;
soxr_process((soxr_t)mHandle,
inBuffer , (size_t)(lastFlag? ~inBufferLen : inBufferLen), &idone,
outBuffer, (size_t) outBufferLen, &odone);
*inBufferUsed = (int)idone;
return (int)odone;
}
#else // no const-rate resampler
ConstRateResample::ConstRateResample(const bool useBestMethod, const double dFactor)
: Resample()
{
}
ConstRateResample::~ConstRateResample()
{
}
#endif
// variable-rate resamplers
#if USE_LIBRESAMPLE
#include "libresample.h"
VarRateResample::VarRateResample(const bool useBestMethod, const double dMinFactor, const double dMaxFactor)
: Resample()
{ {
this->SetMethod(useBestMethod); this->SetMethod(useBestMethod);
mHandle = resample_open(mMethod, dMinFactor, dMaxFactor); mHandle = resample_open(mMethod, dMinFactor, dMaxFactor);
@ -317,21 +47,15 @@
} }
} }
VarRateResample::~VarRateResample() Resample::~Resample()
{ {
resample_close(mHandle); resample_close(mHandle);
mHandle = NULL; mHandle = NULL;
} }
//v Currently unused. int Resample::GetNumMethods() { return 2; }
//wxString VarRateResample::GetResamplingLibraryName()
//{
// return _("Libresample by Dominic Mazzoni and Julius Smith");
//}
int VarRateResample::GetNumMethods() { return 2; } wxString Resample::GetMethodName(int index)
wxString VarRateResample::GetMethodName(int index)
{ {
if (index == 1) if (index == 1)
return _("High-quality Sinc Interpolation"); return _("High-quality Sinc Interpolation");
@ -339,20 +63,20 @@
return _("Fast Sinc Interpolation"); return _("Fast Sinc Interpolation");
} }
const wxString VarRateResample::GetFastMethodKey() const wxString Resample::GetFastMethodKey()
{ {
return wxT("/Quality/LibresampleSampleRateConverter"); return wxT("/Quality/LibresampleSampleRateConverter");
} }
const wxString VarRateResample::GetBestMethodKey() const wxString Resample::GetBestMethodKey()
{ {
return wxT("/Quality/LibresampleHQSampleRateConverter"); return wxT("/Quality/LibresampleHQSampleRateConverter");
} }
int VarRateResample::GetFastMethodDefault() { return 0; } int Resample::GetFastMethodDefault() { return 0; }
int VarRateResample::GetBestMethodDefault() { return 1; } int Resample::GetBestMethodDefault() { return 1; }
int VarRateResample::Process(double factor, int Resample::Process(double factor,
float *inBuffer, float *inBuffer,
int inBufferLen, int inBufferLen,
bool lastFlag, bool lastFlag,
@ -368,8 +92,7 @@
#include <samplerate.h> #include <samplerate.h>
VarRateResample::VarRateResample(const bool useBestMethod, const double dMinFactor, const double dMaxFactor) Resample::Resample(const bool useBestMethod, const double dMinFactor, const double dMaxFactor)
: Resample()
{ {
this->SetMethod(useBestMethod); this->SetMethod(useBestMethod);
if (!src_is_valid_ratio (dMinFactor) || !src_is_valid_ratio (dMaxFactor)) { if (!src_is_valid_ratio (dMinFactor) || !src_is_valid_ratio (dMaxFactor)) {
@ -386,19 +109,13 @@
mSamplesLeft = 0; mSamplesLeft = 0;
} }
VarRateResample::~VarRateResample() Resample::~Resample()
{ {
src_delete((SRC_STATE *)mHandle); src_delete((SRC_STATE *)mHandle);
mHandle = NULL; mHandle = NULL;
} }
//v Currently unused. int Resample::GetNumMethods()
//wxString Resample::GetResamplingLibraryName()
//{
// return _("Libsamplerate by Erik de Castro Lopo");
//}
int VarRateResample::GetNumMethods()
{ {
int i = 0; int i = 0;
@ -408,32 +125,32 @@
return i; return i;
} }
wxString VarRateResample::GetMethodName(int index) wxString Resample::GetMethodName(int index)
{ {
return wxString(wxString::FromAscii(src_get_name(index))); return wxString(wxString::FromAscii(src_get_name(index)));
} }
const wxString VarRateResample::GetFastMethodKey() const wxString Resample::GetFastMethodKey()
{ {
return wxT("/Quality/SampleRateConverter"); return wxT("/Quality/SampleRateConverter");
} }
const wxString VarRateResample::GetBestMethodKey() const wxString Resample::GetBestMethodKey()
{ {
return wxT("/Quality/HQSampleRateConverter"); return wxT("/Quality/HQSampleRateConverter");
} }
int VarRateResample::GetFastMethodDefault() int Resample::GetFastMethodDefault()
{ {
return SRC_SINC_FASTEST; return SRC_SINC_FASTEST;
} }
int VarRateResample::GetBestMethodDefault() int Resample::GetBestMethodDefault()
{ {
return SRC_SINC_BEST_QUALITY; return SRC_SINC_BEST_QUALITY;
} }
int VarRateResample::Process(double factor, int Resample::Process(double factor,
float *inBuffer, float *inBuffer,
int inBufferLen, int inBufferLen,
bool lastFlag, bool lastFlag,
@ -443,8 +160,6 @@
{ {
src_set_ratio((SRC_STATE *)mHandle, factor); src_set_ratio((SRC_STATE *)mHandle, factor);
SRC_DATA data;
if(mShouldReset) { if(mShouldReset) {
if(inBufferLen > mSamplesLeft) { if(inBufferLen > mSamplesLeft) {
mShouldReset = false; mShouldReset = false;
@ -454,6 +169,7 @@
} }
} }
SRC_DATA data;
data.data_in = inBuffer; data.data_in = inBuffer;
data.data_out = outBuffer; data.data_out = outBuffer;
data.input_frames = inBufferLen; data.input_frames = inBufferLen;
@ -479,29 +195,35 @@
} }
#elif USE_LIBSOXR #elif USE_LIBSOXR
// Note that as we currently do not distinguish USE_* flags for var-rate vs const-rate,
// we need to have USE_LIBSOXR last in the var-rate #if/#elif implementations, because
// it's always #defined in standard configuration, for use as the sole const-rate resampler.
#include <soxr.h> #include <soxr.h>
VarRateResample::VarRateResample(const bool useBestMethod, const double dMinFactor, const double dMaxFactor) Resample::Resample(const bool useBestMethod, const double dMinFactor, const double dMaxFactor)
: Resample()
{ {
this->SetMethod(useBestMethod); this->SetMethod(useBestMethod);
soxr_quality_spec_t q_spec = soxr_quality_spec(SOXR_HQ, SOXR_VR); soxr_quality_spec_t q_spec;
if (dMinFactor == dMaxFactor)
{
mbWantConstRateResampling = true; // constant rate resampling
q_spec = soxr_quality_spec("\0\1\4\6"[mMethod], 0);
}
else
{
mbWantConstRateResampling = false; // variable rate resampling
q_spec = soxr_quality_spec(SOXR_HQ, SOXR_VR);
}
mHandle = (void *)soxr_create(1, dMinFactor, 1, 0, 0, &q_spec, 0); mHandle = (void *)soxr_create(1, dMinFactor, 1, 0, 0, &q_spec, 0);
} }
VarRateResample::~VarRateResample() Resample::~Resample()
{ {
soxr_delete((soxr_t)mHandle); soxr_delete((soxr_t)mHandle);
mHandle = NULL; mHandle = NULL;
} }
int VarRateResample::GetNumMethods() { return 4; } int Resample::GetNumMethods() { return 4; }
wxString VarRateResample::GetMethodName(int index) wxString Resample::GetMethodName(int index)
{ {
static char const * const soxr_method_names[] = { static char const * const soxr_method_names[] = {
"Low Quality (Fastest)", "Medium Quality", "High Quality", "Best Quality (Slowest)" "Low Quality (Fastest)", "Medium Quality", "High Quality", "Best Quality (Slowest)"
@ -510,20 +232,20 @@
return wxString(wxString::FromAscii(soxr_method_names[index])); return wxString(wxString::FromAscii(soxr_method_names[index]));
} }
const wxString VarRateResample::GetFastMethodKey() const wxString Resample::GetFastMethodKey()
{ {
return wxT("/Quality/LibsoxrSampleRateConverter"); return wxT("/Quality/LibsoxrSampleRateConverter");
} }
const wxString VarRateResample::GetBestMethodKey() const wxString Resample::GetBestMethodKey()
{ {
return wxT("/Quality/LibsoxrHQSampleRateConverter"); return wxT("/Quality/LibsoxrHQSampleRateConverter");
} }
int VarRateResample::GetFastMethodDefault() {return 1;} int Resample::GetFastMethodDefault() {return 1;}
int VarRateResample::GetBestMethodDefault() {return 3;} int Resample::GetBestMethodDefault() {return 3;}
int VarRateResample::Process(double factor, int Resample::Process(double factor,
float *inBuffer, float *inBuffer,
int inBufferLen, int inBufferLen,
bool lastFlag, bool lastFlag,
@ -531,24 +253,23 @@
float *outBuffer, float *outBuffer,
int outBufferLen) int outBufferLen)
{ {
soxr_set_io_ratio((soxr_t)mHandle, 1/factor, 0); size_t idone, odone;
if (mbWantConstRateResampling)
{
soxr_process((soxr_t)mHandle,
inBuffer , (size_t)(lastFlag? ~inBufferLen : inBufferLen), &idone,
outBuffer, (size_t) outBufferLen, &odone);
}
else
{
soxr_set_io_ratio((soxr_t)mHandle, 1/factor, 0);
size_t idone , odone; inBufferLen = lastFlag? ~inBufferLen : inBufferLen;
inBufferLen = lastFlag? ~inBufferLen : inBufferLen; soxr_process((soxr_t)mHandle,
soxr_process((soxr_t)mHandle, inBuffer , (size_t)inBufferLen , &idone,
inBuffer , (size_t)inBufferLen , &idone, outBuffer, (size_t)outBufferLen, &odone);
outBuffer, (size_t)outBufferLen, &odone); }
*inBufferUsed = (int)idone; *inBufferUsed = (int)idone;
return (int)odone; return (int)odone;
} }
#else // no var-rate resampler
VarRateResample::VarRateResample(const bool useBestMethod, const double dMinFactor, const double dMaxFactor)
: Resample()
{
}
VarRateResample::~VarRateResample()
{
}
#endif #endif

View File

@ -23,33 +23,26 @@
class Resample class Resample
{ {
public: public:
/// The first parameter lets you select either the best method or
/// the fast method.
//v (The particular method used was previously set by
/// SetFastMethod or SetBestMethod.)
Resample()
{
mMethod = 0;
mHandle = NULL;
};
virtual ~Resample() {};
/// Returns the name of the library used for resampling
/// (long format, may include author name and version number).
//v Currently unused.
// virtual wxString GetResamplingLibraryName() { return _("Resampling disabled."); };
/// Resamplers may have more than one method, offering a /// Resamplers may have more than one method, offering a
/// tradeoff between speed and quality. /// tradeoff between speed and quality.
/// Audacity identifies two methods out of all of the choices: /// Audacity identifies two methods out of all of the choices:
/// a Fast method intended for real-time audio I/O, and a Best /// a Fast method intended for real-time audio I/O, and a Best
/// method intended for mixing and exporting. /// method intended for mixing and exporting.
//v (These were previously saved //
// in the preferences when you call Set[Best,Fast]Method. /// The first parameter lets you select either the best method or
// Now done with TieChoice() in QualityPrefs. /// the fast method.
// Implemented in descendant classes, for class-specificity.) // dMinFactor and dMaxFactor specify the range of factors for variable-rate resampling.
//static void SetFastMethod(int index); // For constant-rate, pass the same value for both.
//static void SetBestMethod(int index); Resample(const bool useBestMethod, const double dMinFactor, const double dMaxFactor);
virtual ~Resample();
static int GetNumMethods();
static wxString GetMethodName(int index);
static const wxString GetFastMethodKey();
static const wxString GetBestMethodKey();
static int GetFastMethodDefault();
static int GetBestMethodDefault();
/** @brief Main processing function. Resamples from the input buffer to the /** @brief Main processing function. Resamples from the input buffer to the
* output buffer. * output buffer.
@ -73,25 +66,21 @@ class Resample
@param outBufferLen How big outBuffer is. @param outBufferLen How big outBuffer is.
@return Number of output samples created by this call @return Number of output samples created by this call
*/ */
virtual int Process(double WXUNUSED(factor), virtual int Process(double factor,
float *inBuffer, float *inBuffer,
int inBufferLen, int inBufferLen,
bool WXUNUSED(lastFlag), bool lastFlag,
int * WXUNUSED(inBufferUsed), int *inBufferUsed,
float *outBuffer, float *outBuffer,
int outBufferLen) int outBufferLen);
protected:
void SetMethod(const bool useBestMethod)
{ {
// Base class method just copies data with no change. if (useBestMethod)
int i; mMethod = gPrefs->Read(GetBestMethodKey(), GetBestMethodDefault());
int len = inBufferLen; else
mMethod = gPrefs->Read(GetFastMethodKey(), GetFastMethodDefault());
if (len > outBufferLen)
len = outBufferLen;
for(i=0; i<len; i++)
outBuffer[i] = inBuffer[i];
return len;
}; };
protected: protected:
@ -100,96 +89,9 @@ class Resample
#if USE_LIBSAMPLERATE #if USE_LIBSAMPLERATE
bool mShouldReset; // whether the resampler should be reset because lastFlag has been set previously bool mShouldReset; // whether the resampler should be reset because lastFlag has been set previously
int mSamplesLeft; // number of samples left before a reset is needed int mSamplesLeft; // number of samples left before a reset is needed
#elif USE_LIBSOXR
bool mbWantConstRateResampling;
#endif #endif
}; };
class ConstRateResample : public Resample
{
public:
ConstRateResample(const bool useBestMethod, const double dFactor);
virtual ~ConstRateResample();
// Override base class methods only if we actually have a sample rate conversion library.
#if USE_LIBRESAMPLE || USE_LIBSAMPLERATE || USE_LIBSOXR
static int GetNumMethods();
static wxString GetMethodName(int index);
static const wxString GetFastMethodKey();
static const wxString GetBestMethodKey();
static int GetFastMethodDefault();
static int GetBestMethodDefault();
virtual int Process(double factor,
float *inBuffer,
int inBufferLen,
bool lastFlag,
int *inBufferUsed,
float *outBuffer,
int outBufferLen);
#else
static int GetNumMethods() { return 1; };
static wxString GetMethodName(int WXUNUSED(index)) { return _("Resampling disabled."); };
static const wxString GetFastMethodKey() { return wxT("/Quality/DisabledConverter"); };
static const wxString GetBestMethodKey() { return wxT("/Quality/DisabledConverter"); };
static int GetFastMethodDefault() { return 0; };
static int GetBestMethodDefault() { return 0; };
#endif
protected:
void SetMethod(const bool useBestMethod)
{
if (useBestMethod)
mMethod = gPrefs->Read(GetBestMethodKey(), GetBestMethodDefault());
else
mMethod = gPrefs->Read(GetFastMethodKey(), GetFastMethodDefault());
};
};
class VarRateResample : public Resample
{
public:
// dMinFactor and dMaxFactor specify the range of factors for variable-rate resampling.
VarRateResample(const bool useBestMethod, const double dMinFactor, const double dMaxFactor);
virtual ~VarRateResample();
// Override base class methods only if we actually have a sample rate conversion library.
#if USE_LIBRESAMPLE || USE_LIBSAMPLERATE || USE_LIBSOXR
//vvv Note that we're not actually calling any of these Get* methods
// for var-rate, as the decision was to not allow QualityPrefs for it.
// However the methods already existed for libresample and libsamplerate,
// so they're now implemented for all, in case we decide to provide prefs.
static int GetNumMethods();
static wxString GetMethodName(int index);
static const wxString GetFastMethodKey();
static const wxString GetBestMethodKey();
static int GetFastMethodDefault();
static int GetBestMethodDefault();
virtual int Process(double factor,
float *inBuffer,
int inBufferLen,
bool lastFlag,
int *inBufferUsed,
float *outBuffer,
int outBufferLen);
#else
static int GetNumMethods() { return 1; };
static wxString GetMethodName(int WXUNUSED(index)) { return _("Resampling disabled."); };
static const wxString GetFastMethodKey() { return wxT("/Quality/DisabledConverter"); };
static const wxString GetBestMethodKey() { return wxT("/Quality/DisabledConverter"); };
static int GetFastMethodDefault() { return 0; };
static int GetBestMethodDefault() { return 0; };
#endif
protected:
void SetMethod(const bool useBestMethod)
{
if (useBestMethod)
mMethod = gPrefs->Read(GetBestMethodKey(), GetBestMethodDefault());
else
mMethod = gPrefs->Read(GetFastMethodKey(), GetFastMethodDefault());
};
};
#endif // __AUDACITY_RESAMPLE_H__ #endif // __AUDACITY_RESAMPLE_H__

View File

@ -1526,7 +1526,7 @@ bool WaveClip::Resample(int rate, ProgressDialog *progress)
return true; // Nothing to do return true; // Nothing to do
double factor = (double)rate / (double)mRate; double factor = (double)rate / (double)mRate;
ConstRateResample* resample = new ConstRateResample(true, factor); ::Resample* resample = new ::Resample(true, factor, factor); // constant rate resampling
int bufsize = 65536; int bufsize = 65536;
float* inBuffer = new float[bufsize]; float* inBuffer = new float[bufsize];

View File

@ -214,7 +214,7 @@ bool EffectChangeSpeed::ProcessOne(WaveTrack * track,
float * outBuffer = new float[outBufferSize]; float * outBuffer = new float[outBufferSize];
// Set up the resampling stuff for this track. // Set up the resampling stuff for this track.
ConstRateResample resample(true, mFactor); Resample resample(true, mFactor, mFactor); // constant rate resampling
//Go through the track one buffer at a time. samplePos counts which //Go through the track one buffer at a time. samplePos counts which
//sample the current buffer starts at. //sample the current buffer starts at.
@ -437,7 +437,7 @@ bool ChangeSpeedDialog::TransferDataFromWindow()
// handler implementations for ChangeSpeedDialog // handler implementations for ChangeSpeedDialog
void ChangeSpeedDialog::OnText_PercentChange(wxCommandEvent & event) void ChangeSpeedDialog::OnText_PercentChange(wxCommandEvent & WXUNUSED(event))
{ {
if (mbLoopDetect) if (mbLoopDetect)
return; return;
@ -457,7 +457,7 @@ void ChangeSpeedDialog::OnText_PercentChange(wxCommandEvent & event)
} }
} }
void ChangeSpeedDialog::OnSlider_PercentChange(wxCommandEvent & event) void ChangeSpeedDialog::OnSlider_PercentChange(wxCommandEvent & WXUNUSED(event))
{ {
if (mbLoopDetect) if (mbLoopDetect)
return; return;
@ -475,7 +475,7 @@ void ChangeSpeedDialog::OnSlider_PercentChange(wxCommandEvent & event)
} }
} }
void ChangeSpeedDialog::OnChoice_FromVinyl(wxCommandEvent & event) void ChangeSpeedDialog::OnChoice_FromVinyl(wxCommandEvent & WXUNUSED(event))
{ {
if (mbLoopDetect) if (mbLoopDetect)
return; return;
@ -489,7 +489,7 @@ void ChangeSpeedDialog::OnChoice_FromVinyl(wxCommandEvent & event)
} }
} }
void ChangeSpeedDialog::OnChoice_ToVinyl(wxCommandEvent & event) void ChangeSpeedDialog::OnChoice_ToVinyl(wxCommandEvent & WXUNUSED(event))
{ {
if (mbLoopDetect) if (mbLoopDetect)
return; return;

View File

@ -107,17 +107,9 @@ void QualityPrefs::GetNamesAndLabels()
mSampleFormatNames.Add(wxT("32-bit float")); mSampleFormatLabels.Add(floatSample); mSampleFormatNames.Add(wxT("32-bit float")); mSampleFormatLabels.Add(floatSample);
//------------- Converter Names //------------- Converter Names
// We used to set and get best/fast method via Resample.cpp. int numConverters = Resample::GetNumMethods();
// Need to ensure that preferences strings in Resample.cpp match.
// Note that these methods used to be public and static, but are now protected and pure virtual.
//
//vvv Note that we're now using libsoxr for constant-rate resampling
// and either libresample, libsamplerate, or libsoxr for variable-rate,
// and currently not allowing prefs method choice for variable-rate,
// per discussion on -devel.
int numConverters = ConstRateResample::GetNumMethods();
for (int i = 0; i < numConverters; i++) { for (int i = 0; i < numConverters; i++) {
mConverterNames.Add(ConstRateResample::GetMethodName(i)); mConverterNames.Add(Resample::GetMethodName(i));
mConverterLabels.Add(i); mConverterLabels.Add(i);
} }
} }
@ -173,8 +165,8 @@ void QualityPrefs::PopulateOrExchange(ShuttleGui & S)
S.SetStretchyCol(2); S.SetStretchyCol(2);
S.TieChoice(_("Sample Rate Con&verter:"), S.TieChoice(_("Sample Rate Con&verter:"),
ConstRateResample::GetFastMethodKey(), Resample::GetFastMethodKey(),
ConstRateResample::GetFastMethodDefault(), Resample::GetFastMethodDefault(),
mConverterNames, mConverterNames,
mConverterLabels), mConverterLabels),
S.SetSizeHints(mConverterNames); S.SetSizeHints(mConverterNames);
@ -195,8 +187,8 @@ void QualityPrefs::PopulateOrExchange(ShuttleGui & S)
S.StartMultiColumn(2); S.StartMultiColumn(2);
{ {
S.TieChoice(_("Sample Rate Conver&ter:"), S.TieChoice(_("Sample Rate Conver&ter:"),
ConstRateResample::GetBestMethodKey(), Resample::GetBestMethodKey(),
ConstRateResample::GetBestMethodDefault(), Resample::GetBestMethodDefault(),
mConverterNames, mConverterNames,
mConverterLabels), mConverterLabels),
S.SetSizeHints(mConverterNames); S.SetSizeHints(mConverterNames);
@ -215,7 +207,7 @@ void QualityPrefs::PopulateOrExchange(ShuttleGui & S)
/// Enables or disables the Edit box depending on /// Enables or disables the Edit box depending on
/// whether we selected 'Other...' or not. /// whether we selected 'Other...' or not.
void QualityPrefs::OnSampleRateChoice(wxCommandEvent & e) void QualityPrefs::OnSampleRateChoice(wxCommandEvent & WXUNUSED(e))
{ {
int sel = mSampleRates->GetSelection(); int sel = mSampleRates->GetSelection();
mOtherSampleRate->Enable(sel == (int)mSampleRates->GetCount() - 1); mOtherSampleRate->Enable(sel == (int)mSampleRates->GetCount() - 1);

View File

@ -22,16 +22,13 @@
// #define USE_LIBLRDF 1 // #define USE_LIBLRDF 1
#define USE_LIBMAD 1 #define USE_LIBMAD 1
// Resamplers. // Resamplers:
// Only one of each type of resampler (constant or variable rate) should be defined. // Exactly one resampler should be defined.
// libsoxr is used for constant-rate and var-rate resampling. // Should build only one of libsoxr, libresample, or libsamplerate for resampling,
// libsoxr currently our only const-rate resampler, so should always be #defined.
#define USE_LIBSOXR 1
// Should build only one of libsoxr, libresample, or libsamplerate for variable-rate resampling,
// but if more than one are defined, priority is libresample over libsamplerate over libsoxr. // but if more than one are defined, priority is libresample over libsamplerate over libsoxr.
// We cannot release builds with libsamplerate, due to licensing. // We cannot release builds with libsamplerate, due to licensing.
// Standard configuration is to have only USE_LIBSOXR #defined. // Standard configuration is to have only USE_LIBSOXR #defined.
#define USE_LIBSOXR 1
#undef USE_LIBRESAMPLE #undef USE_LIBRESAMPLE
#undef USE_LIBSAMPLERATE #undef USE_LIBSAMPLERATE