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_TYPE Alpha
#define VER_LAMEXP_PATCH 11
#define VER_LAMEXP_BUILD 825
#define VER_LAMEXP_BUILD 827
///////////////////////////////////////////////////////////////////////////////
// Tool versions (minimum expected versions!)

View File

@ -27,7 +27,12 @@
#include <QProcess>
#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"))
{
@ -36,7 +41,13 @@ ResampleFilter::ResampleFilter(int samplingRate)
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)
@ -53,9 +64,26 @@ bool ResampleFilter::apply(const QString &sourceFile, const QString &outputFile,
args << "-V3" << "-S";
args << "--guard" << "--temp" << ".";
args << QDir::toNativeSeparators(sourceFile);
if(m_bitDepth)
{
args << "-b" << QString::number(m_bitDepth);
}
args << QDir::toNativeSeparators(outputFile);
if(m_samplingRate)
{
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))
{

View File

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

View File

@ -45,6 +45,7 @@
#include <stdlib.h>
#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)
QMutex *ProcessThread::m_mutex_genFileName = NULL;
@ -158,6 +159,8 @@ void ProcessThread::processFile()
{
sourceFile = tempFile;
handleMessage("\n-------------------------------\n");
m_audioFile.setFormatContainerType(QString::fromLatin1("Wave"));
m_audioFile.setFormatAudioType(QString::fromLatin1("PCM"));
}
}
else
@ -167,9 +170,12 @@ void ProcessThread::processFile()
emit processStateFinished(m_jobId, outFileName, false);
return;
}
}
//------------------------------------
//Update audio properties after decode
if(bSuccess)
//------------------------------------
if(bSuccess && IS_WAVE(m_audioFile))
{
if(m_encoder->supportedSamplerates() || m_encoder->supportedBitdepths() || m_encoder->requiresDownmix())
{
@ -180,23 +186,16 @@ void ProcessThread::processFile()
{
handleMessage("\n-------------------------------\n");
//Do we need to take care of downsampling the input?
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?
//Do we need to take care if Stereo downmix?
if(m_encoder->requiresDownmix())
{
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)
{
int targetSampleRate = 0;
int targetBitDepth = 0;
/* Adjust sample rate */
if(m_encoder->supportedSamplerates() && m_audioFile.formatAudioSamplerate())
{
bool applyDownsampling = true;
@ -399,11 +404,12 @@ void ProcessThread::insertDownsampleFilter(void)
if(dynamic_cast<ResampleFilter*>(m_filters.at(i)))
{
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;
}
}
//Now add the downsampling filter, if needed
//Now determine the target sample rate, if required
if(applyDownsampling)
{
const unsigned int *supportedRates = m_encoder->supportedSamplerates();
@ -424,14 +430,41 @@ void ProcessThread::insertDownsampleFilter(void)
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)
@ -454,7 +487,7 @@ void ProcessThread::insertDownmixFilter(void)
unsigned int channels = m_audioFile.formatAudioChannels();
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);
void insertDownsampleFilter(void);
void insertDownmixFilter(void);
void insertBitdepthFilter(void);
const QUuid m_jobId;
AudioFileModel m_audioFile;