Improved the resample filter. It will now also handle the adjustment of the bit-depth.

This commit is contained in:
LoRd_MuldeR 2011-12-22 18:36:41 +01:00
parent 1a238db3db
commit a392864916
5 changed files with 118 additions and 57 deletions

View File

@ -30,7 +30,7 @@
#define VER_LAMEXP_MINOR_LO 4 #define VER_LAMEXP_MINOR_LO 4
#define VER_LAMEXP_TYPE Alpha #define VER_LAMEXP_TYPE Alpha
#define VER_LAMEXP_PATCH 11 #define VER_LAMEXP_PATCH 11
#define VER_LAMEXP_BUILD 825 #define VER_LAMEXP_BUILD 827
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Tool versions (minimum expected versions!) // Tool versions (minimum expected versions!)

View File

@ -27,7 +27,12 @@
#include <QProcess> #include <QProcess>
#include <QRegExp> #include <QRegExp>
ResampleFilter::ResampleFilter(int samplingRate) static __inline int multipleOf(int value, int base)
{
return qRound(static_cast<double>(value) / static_cast<double>(base)) * base;
}
ResampleFilter::ResampleFilter(int samplingRate, int bitDepth)
: :
m_binary(lamexp_lookup_tool("sox.exe")) m_binary(lamexp_lookup_tool("sox.exe"))
{ {
@ -36,7 +41,13 @@ ResampleFilter::ResampleFilter(int samplingRate)
throw "Error initializing SoX filter. Tool 'sox.exe' is not registred!"; throw "Error initializing SoX filter. Tool 'sox.exe' is not registred!";
} }
m_samplingRate = qMin(192000, qMax(8000, samplingRate)); m_samplingRate = (samplingRate > 0) ? qBound(8000, samplingRate, 192000) : 0;
m_bitDepth = (bitDepth > 0) ? qBound(8, multipleOf(bitDepth, 8), 32) : 0;
if((m_samplingRate == 0) && (m_bitDepth == 0))
{
qWarning("ResampleFilter: Nothing to do, filter will be NOP!");
}
} }
ResampleFilter::~ResampleFilter(void) ResampleFilter::~ResampleFilter(void)
@ -53,9 +64,26 @@ bool ResampleFilter::apply(const QString &sourceFile, const QString &outputFile,
args << "-V3" << "-S"; args << "-V3" << "-S";
args << "--guard" << "--temp" << "."; args << "--guard" << "--temp" << ".";
args << QDir::toNativeSeparators(sourceFile); args << QDir::toNativeSeparators(sourceFile);
if(m_bitDepth)
{
args << "-b" << QString::number(m_bitDepth);
}
args << QDir::toNativeSeparators(outputFile); args << QDir::toNativeSeparators(outputFile);
if(m_samplingRate)
{
args << "rate"; args << "rate";
args << "-h" << QString::number(m_samplingRate); args << ((m_bitDepth > 16) ? "-v" : "-h"); //if resampling at/to > 16 bit depth (i.e. most commonly 24-bit), use VHQ (-v), otherwise, use HQ (-h)
args << ((m_samplingRate > 40000) ? "-L" : "-I"); //if resampling to < 40k, use intermediate phase (-I), otherwise use linear phase (-L)
args << QString::number(m_samplingRate);
}
if((m_bitDepth || m_samplingRate) && (m_bitDepth <= 16))
{
args << "dither" << "-s"; //if you're mastering to 16-bit, you also need to add 'dither' (and in most cases noise-shaping) after the rate
}
if(!startProcess(process, m_binary, args)) if(!startProcess(process, m_binary, args))
{ {

View File

@ -26,7 +26,7 @@
class ResampleFilter : public AbstractFilter class ResampleFilter : public AbstractFilter
{ {
public: public:
ResampleFilter(int samplingRate = 44100); ResampleFilter(int samplingRate = 0, int bitDepth = 0);
~ResampleFilter(void); ~ResampleFilter(void);
virtual bool apply(const QString &sourceFile, const QString &outputFile, volatile bool *abortFlag); virtual bool apply(const QString &sourceFile, const QString &outputFile, volatile bool *abortFlag);
@ -34,4 +34,5 @@ public:
private: private:
const QString m_binary; const QString m_binary;
int m_samplingRate; int m_samplingRate;
int m_bitDepth;
}; };

View File

@ -45,6 +45,7 @@
#include <stdlib.h> #include <stdlib.h>
#define DIFF(X,Y) ((X > Y) ? (X-Y) : (Y-X)) #define DIFF(X,Y) ((X > Y) ? (X-Y) : (Y-X))
#define IS_WAVE(X) ((X.formatContainerType().compare("Wave", Qt::CaseInsensitive) == 0) && (X.formatAudioType().compare("PCM", Qt::CaseInsensitive) == 0))
#define STRDEF(STR,DEF) ((!STR.isEmpty()) ? STR : DEF) #define STRDEF(STR,DEF) ((!STR.isEmpty()) ? STR : DEF)
QMutex *ProcessThread::m_mutex_genFileName = NULL; QMutex *ProcessThread::m_mutex_genFileName = NULL;
@ -158,6 +159,8 @@ void ProcessThread::processFile()
{ {
sourceFile = tempFile; sourceFile = tempFile;
handleMessage("\n-------------------------------\n"); handleMessage("\n-------------------------------\n");
m_audioFile.setFormatContainerType(QString::fromLatin1("Wave"));
m_audioFile.setFormatAudioType(QString::fromLatin1("PCM"));
} }
} }
else else
@ -167,9 +170,12 @@ void ProcessThread::processFile()
emit processStateFinished(m_jobId, outFileName, false); emit processStateFinished(m_jobId, outFileName, false);
return; return;
} }
}
//------------------------------------
//Update audio properties after decode //Update audio properties after decode
if(bSuccess) //------------------------------------
if(bSuccess && IS_WAVE(m_audioFile))
{ {
if(m_encoder->supportedSamplerates() || m_encoder->supportedBitdepths() || m_encoder->requiresDownmix()) if(m_encoder->supportedSamplerates() || m_encoder->supportedBitdepths() || m_encoder->requiresDownmix())
{ {
@ -180,23 +186,16 @@ void ProcessThread::processFile()
{ {
handleMessage("\n-------------------------------\n"); handleMessage("\n-------------------------------\n");
//Do we need to take care of downsampling the input? //Do we need to take care if Stereo downmix?
if(m_encoder->supportedSamplerates())
{
insertDownsampleFilter();
}
//Do we need to change the bits per sample of the input?
if(m_encoder->supportedBitdepths())
{
insertBitdepthFilter();
}
//Do we need Stereo downmix?
if(m_encoder->requiresDownmix()) if(m_encoder->requiresDownmix())
{ {
insertDownmixFilter(); insertDownmixFilter();
} }
//Do we need to take care of downsampling the input?
if(m_encoder->supportedSamplerates() || m_encoder->supportedBitdepths())
{
insertDownsampleFilter();
} }
} }
} }
@ -390,6 +389,12 @@ QString ProcessThread::generateTempFileName(void)
} }
void ProcessThread::insertDownsampleFilter(void) void ProcessThread::insertDownsampleFilter(void)
{
int targetSampleRate = 0;
int targetBitDepth = 0;
/* Adjust sample rate */
if(m_encoder->supportedSamplerates() && m_audioFile.formatAudioSamplerate())
{ {
bool applyDownsampling = true; bool applyDownsampling = true;
@ -399,11 +404,12 @@ void ProcessThread::insertDownsampleFilter(void)
if(dynamic_cast<ResampleFilter*>(m_filters.at(i))) if(dynamic_cast<ResampleFilter*>(m_filters.at(i)))
{ {
qWarning("Encoder requires downsampling, but user has already set resamling filter!"); qWarning("Encoder requires downsampling, but user has already set resamling filter!");
handleMessage("WARNING: Encoder may need resampling, but already using resample filter. Encoding *may* fail!\n");
applyDownsampling = false; applyDownsampling = false;
} }
} }
//Now add the downsampling filter, if needed //Now determine the target sample rate, if required
if(applyDownsampling) if(applyDownsampling)
{ {
const unsigned int *supportedRates = m_encoder->supportedSamplerates(); const unsigned int *supportedRates = m_encoder->supportedSamplerates();
@ -424,14 +430,41 @@ void ProcessThread::insertDownsampleFilter(void)
if(bestRate != inputRate) if(bestRate != inputRate)
{ {
m_filters.prepend(new ResampleFilter((bestRate != UINT_MAX) ? bestRate : supportedRates[0])); targetSampleRate = (bestRate != UINT_MAX) ? bestRate : supportedRates[0];
} }
} }
} }
void ProcessThread::insertBitdepthFilter(void) /* Adjust bit depth (word size) */
if(m_encoder->supportedBitdepths() && m_audioFile.formatAudioBitdepth())
{ {
qFatal("ProcessThread::insertBitdepthFilter not implemented yet!"); const unsigned int *supportedBPS = m_encoder->supportedBitdepths();
const unsigned int inputBPS = m_audioFile.formatAudioBitdepth();
unsigned int currentDiff = UINT_MAX, minimumDiff = UINT_MAX, bestBPS = UINT_MAX;
//Find the most suitable supported bit depth
for(int i = 0; supportedBPS[i]; i++)
{
currentDiff = DIFF(inputBPS, supportedBPS[i]);
if(currentDiff < minimumDiff)
{
bestBPS = supportedBPS[i];
minimumDiff = currentDiff;
if(!(minimumDiff > 0)) break;
}
}
if(bestBPS != inputBPS)
{
targetBitDepth = (bestBPS != UINT_MAX) ? bestBPS : supportedBPS[0];
}
}
/* Insert the filter */
if(targetSampleRate || targetBitDepth)
{
m_filters.append(new ResampleFilter(targetSampleRate, targetBitDepth));
}
} }
void ProcessThread::insertDownmixFilter(void) void ProcessThread::insertDownmixFilter(void)
@ -454,7 +487,7 @@ void ProcessThread::insertDownmixFilter(void)
unsigned int channels = m_audioFile.formatAudioChannels(); unsigned int channels = m_audioFile.formatAudioChannels();
if((channels == 0) || (channels > 2)) if((channels == 0) || (channels > 2))
{ {
m_filters.prepend(new DownmixFilter()); m_filters.append(new DownmixFilter());
} }
} }
} }

View File

@ -72,7 +72,6 @@ private:
QString generateTempFileName(void); QString generateTempFileName(void);
void insertDownsampleFilter(void); void insertDownsampleFilter(void);
void insertDownmixFilter(void); void insertDownmixFilter(void);
void insertBitdepthFilter(void);
const QUuid m_jobId; const QUuid m_jobId;
AudioFileModel m_audioFile; AudioFileModel m_audioFile;