Added a normalization filter, based on SoX.
This commit is contained in:
parent
ab1b25d7a0
commit
58ded8c2e4
@ -410,6 +410,10 @@
|
||||
RelativePath=".\src\Filter_Downmix.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\Filter_Normalize.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\Genres.cpp"
|
||||
>
|
||||
@ -1122,6 +1126,10 @@
|
||||
RelativePath=".\src\Filter_Downmix.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\Filter_Normalize.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\Genres.h"
|
||||
>
|
||||
|
@ -985,7 +985,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>602</width>
|
||||
<width>604</width>
|
||||
<height>520</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -1688,10 +1688,10 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-12.000000000000000</double>
|
||||
<double>-32.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.000000000000000</double>
|
||||
<double>-0.500000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.500000000000000</double>
|
||||
@ -2298,6 +2298,8 @@
|
||||
<include location="../res/Icons.qrc"/>
|
||||
<include location="../res/Icons.qrc"/>
|
||||
<include location="../res/Icons.qrc"/>
|
||||
<include location="../res/Icons.qrc"/>
|
||||
<include location="../res/Icons.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "Encoder_AAC.h"
|
||||
#include "Encoder_FLAC.h"
|
||||
#include "Encoder_Wave.h"
|
||||
#include "Filter_Normalize.h"
|
||||
#include "WinSevenTaskbar.h"
|
||||
|
||||
#include <QApplication>
|
||||
@ -495,7 +496,12 @@ void ProcessingDialog::startNextJob(void)
|
||||
encoder,
|
||||
m_settings->prependRelativeSourcePath()
|
||||
);
|
||||
|
||||
|
||||
if(m_settings->normalizationFilterEnabled())
|
||||
{
|
||||
thread->addFilter(new NormalizeFilter(m_settings->normalizationFilterMaxVolume()));
|
||||
}
|
||||
|
||||
m_threadList.append(thread);
|
||||
m_allJobs.append(thread->getId());
|
||||
|
||||
|
@ -49,7 +49,7 @@ bool DownmixFilter::apply(const QString &sourceFile, const QString &outputFile,
|
||||
process.setWorkingDirectory(lamexp_temp_folder());
|
||||
|
||||
args << "-V3";
|
||||
args << "--norm" << "--temp" << ".";
|
||||
args << "--guard" << "--temp" << ".";
|
||||
args << QDir::toNativeSeparators(sourceFile);
|
||||
args << "-c2";
|
||||
args << QDir::toNativeSeparators(outputFile);
|
||||
|
112
src/Filter_Normalize.cpp
Normal file
112
src/Filter_Normalize.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// LameXP - Audio Encoder Front-End
|
||||
// Copyright (C) 2004-2011 LoRd_MuldeR <MuldeR2@GMX.de>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
// http://www.gnu.org/licenses/gpl-2.0.txt
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Filter_Normalize.h"
|
||||
|
||||
#include "Global.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QProcess>
|
||||
#include <QRegExp>
|
||||
|
||||
NormalizeFilter::NormalizeFilter(int peakVolume)
|
||||
:
|
||||
m_binary(lamexp_lookup_tool("sox.exe"))
|
||||
{
|
||||
if(m_binary.isEmpty())
|
||||
{
|
||||
throw "Error initializing SoX filter. Tool 'sox.exe' is not registred!";
|
||||
}
|
||||
|
||||
m_peakVolume = min(-50, max(-3200, peakVolume));
|
||||
}
|
||||
|
||||
NormalizeFilter::~NormalizeFilter(void)
|
||||
{
|
||||
}
|
||||
|
||||
bool NormalizeFilter::apply(const QString &sourceFile, const QString &outputFile, volatile bool *abortFlag)
|
||||
{
|
||||
QProcess process;
|
||||
QStringList args;
|
||||
|
||||
process.setWorkingDirectory(lamexp_temp_folder());
|
||||
|
||||
args << "-V3";
|
||||
args << "--temp" << ".";
|
||||
args << QDir::toNativeSeparators(sourceFile);
|
||||
args << QDir::toNativeSeparators(outputFile);
|
||||
args << "gain";
|
||||
args << "-n" << QString().sprintf("%.2f", static_cast<double>(m_peakVolume) / 100.0);
|
||||
|
||||
if(!startProcess(process, m_binary, args))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bTimeout = false;
|
||||
bool bAborted = false;
|
||||
|
||||
while(process.state() != QProcess::NotRunning)
|
||||
{
|
||||
if(*abortFlag)
|
||||
{
|
||||
process.kill();
|
||||
bAborted = true;
|
||||
emit messageLogged("\nABORTED BY USER !!!");
|
||||
break;
|
||||
}
|
||||
process.waitForReadyRead();
|
||||
if(!process.bytesAvailable() && process.state() == QProcess::Running)
|
||||
{
|
||||
process.kill();
|
||||
qWarning("SoX process timed out <-- killing!");
|
||||
bTimeout = true;
|
||||
break;
|
||||
}
|
||||
while(process.bytesAvailable() > 0)
|
||||
{
|
||||
QByteArray line = process.readLine();
|
||||
QString text = QString::fromUtf8(line.constData()).simplified();
|
||||
if(!text.isEmpty())
|
||||
{
|
||||
emit messageLogged(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process.waitForFinished();
|
||||
if(process.state() != QProcess::NotRunning)
|
||||
{
|
||||
process.kill();
|
||||
process.waitForFinished(-1);
|
||||
}
|
||||
|
||||
emit statusUpdated(100);
|
||||
emit messageLogged(QString().sprintf("\nExited with code: 0x%04X", process.exitCode()));
|
||||
|
||||
if(bTimeout || bAborted || process.exitStatus() != QProcess::NormalExit || QFileInfo(outputFile).size() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
37
src/Filter_Normalize.h
Normal file
37
src/Filter_Normalize.h
Normal file
@ -0,0 +1,37 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// LameXP - Audio Encoder Front-End
|
||||
// Copyright (C) 2004-2011 LoRd_MuldeR <MuldeR2@GMX.de>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
// http://www.gnu.org/licenses/gpl-2.0.txt
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Filter_Abstract.h"
|
||||
|
||||
class NormalizeFilter : public AbstractFilter
|
||||
{
|
||||
public:
|
||||
NormalizeFilter(int peakVolume = -50);
|
||||
~NormalizeFilter(void);
|
||||
|
||||
virtual bool apply(const QString &sourceFile, const QString &outputFile, volatile bool *abortFlag);
|
||||
|
||||
private:
|
||||
const QString m_binary;
|
||||
int m_peakVolume;
|
||||
};
|
@ -55,10 +55,10 @@ g_lamexp_tools[] =
|
||||
{"d837bf6ee4dab557d8b02d46c75a24e58980fffa", "gpgv.gpg", UINT_MAX},
|
||||
{"143fc001a2f6c56fe1b9e6f8a2eb2b53b9e1e504", "lame.exe", 39910},
|
||||
{"a4e929cfaa42fa2e61a3d0c6434c77a06d45aef3", "mac.exe", 406},
|
||||
{"61d584ffaf428e9afb0ed9bd32706a954af492b0", "mediainfo_i386.exe", 739},
|
||||
{"81fb728cbc6057906fa1b637738e6aefe5dccf54", "mediainfo_x64.exe", 739},
|
||||
{"ec235c6404caa31e7975e9bbf9ba59599258ae1d", "mediainfo_i386.exe", 741},
|
||||
{"72d7efdcafc2dee3b534f27ab6e01916d02ba470", "mediainfo_x64.exe", 741},
|
||||
{"55c293a80475f7aeccf449ac9487a4626e5139cb", "mpcdec.exe", UINT_MAX},
|
||||
{"8bbf4a3fffe2ff143eb5ba2cf82ca16d676e865d", "mpg123.exe", UINT_MAX},
|
||||
{"6b6913a54cac08b22d5b468aaed83550fc9ae5b4", "mpg123.exe", 1131},
|
||||
{"8dd7138714c3bcb39f5a3213413addba13d06f1e", "oggdec.exe", UINT_MAX},
|
||||
{"ecd15abe103184aca96e406f5f1c82c6fb2e665d", "oggenc2_i386.exe", 287},
|
||||
{"ffe0fbd73352396dc3752ac9d484dbfc754a226d", "oggenc2_sse2.exe", 287},
|
||||
|
@ -73,6 +73,11 @@ ProcessThread::~ProcessThread(void)
|
||||
lamexp_remove_file(m_tempFiles.takeFirst());
|
||||
}
|
||||
|
||||
while(!m_filters.isEmpty())
|
||||
{
|
||||
delete m_filters.takeFirst();
|
||||
}
|
||||
|
||||
LAMEXP_DELETE(m_encoder);
|
||||
}
|
||||
|
||||
@ -108,19 +113,17 @@ void ProcessThread::processFile()
|
||||
emit processStateFinished(m_jobId, outFileName, false);
|
||||
return;
|
||||
}
|
||||
|
||||
QList<AbstractFilter*> filters;
|
||||
|
||||
//Do we need Stereo downmix?
|
||||
if(m_audioFile.formatAudioChannels() > 2 && m_encoder->requiresDownmix())
|
||||
{
|
||||
filters.prepend(new DownmixFilter());
|
||||
m_filters.prepend(new DownmixFilter());
|
||||
}
|
||||
|
||||
QString sourceFile = m_audioFile.filePath();
|
||||
|
||||
//Decode source file
|
||||
if(!filters.isEmpty() || !m_encoder->isFormatSupported(m_audioFile.formatContainerType(), m_audioFile.formatContainerProfile(), m_audioFile.formatAudioType(), m_audioFile.formatAudioProfile(), m_audioFile.formatAudioVersion()))
|
||||
if(!m_filters.isEmpty() || !m_encoder->isFormatSupported(m_audioFile.formatContainerType(), m_audioFile.formatContainerProfile(), m_audioFile.formatAudioType(), m_audioFile.formatAudioProfile(), m_audioFile.formatAudioVersion()))
|
||||
{
|
||||
m_currentStep = DecodingStep;
|
||||
AbstractDecoder *decoder = DecoderRegistry::lookup(m_audioFile.formatContainerType(), m_audioFile.formatContainerProfile(), m_audioFile.formatAudioType(), m_audioFile.formatAudioProfile(), m_audioFile.formatAudioVersion());
|
||||
@ -150,10 +153,10 @@ void ProcessThread::processFile()
|
||||
}
|
||||
|
||||
//Apply all filters
|
||||
while(!filters.isEmpty())
|
||||
while(!m_filters.isEmpty())
|
||||
{
|
||||
QString tempFile = generateTempFileName();
|
||||
AbstractFilter *poFilter = filters.takeFirst();
|
||||
AbstractFilter *poFilter = m_filters.takeFirst();
|
||||
|
||||
if(bSuccess)
|
||||
{
|
||||
@ -317,6 +320,11 @@ QString ProcessThread::generateTempFileName(void)
|
||||
return tempFileName;
|
||||
}
|
||||
|
||||
void ProcessThread::addFilter(AbstractFilter *filter)
|
||||
{
|
||||
m_filters.append(filter);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// EVENTS
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "Encoder_Abstract.h"
|
||||
|
||||
class QMutex;
|
||||
class AbstractFilter;
|
||||
|
||||
class ProcessThread: public QThread
|
||||
{
|
||||
@ -42,6 +43,7 @@ public:
|
||||
|
||||
void abort() { m_aborted = true; }
|
||||
QUuid getId() { return m_jobId; }
|
||||
void addFilter(AbstractFilter *filter);
|
||||
|
||||
private slots:
|
||||
void handleUpdate(int progress);
|
||||
@ -74,6 +76,7 @@ private:
|
||||
ProcessStep m_currentStep;
|
||||
QStringList m_tempFiles;
|
||||
const bool m_prependRelativeSourcePath;
|
||||
QList<AbstractFilter*> m_filters;
|
||||
|
||||
static QMutex *m_mutex_genFileName;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user