Improved the resample filter. It will now also handle the adjustment of the bit-depth.
This commit is contained in:
parent
1a238db3db
commit
a392864916
@ -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!)
|
||||||
|
@ -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))
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user