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"
|
RelativePath=".\src\Filter_Downmix.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\src\Filter_Normalize.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\src\Genres.cpp"
|
RelativePath=".\src\Genres.cpp"
|
||||||
>
|
>
|
||||||
@ -1122,6 +1126,10 @@
|
|||||||
RelativePath=".\src\Filter_Downmix.h"
|
RelativePath=".\src\Filter_Downmix.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\src\Filter_Normalize.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\src\Genres.h"
|
RelativePath=".\src\Genres.h"
|
||||||
>
|
>
|
||||||
|
@ -985,7 +985,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>602</width>
|
<width>604</width>
|
||||||
<height>520</height>
|
<height>520</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@ -1688,10 +1688,10 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<double>-12.000000000000000</double>
|
<double>-32.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<double>0.000000000000000</double>
|
<double>-0.500000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
<property name="singleStep">
|
<property name="singleStep">
|
||||||
<double>0.500000000000000</double>
|
<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"/>
|
<include location="../res/Icons.qrc"/>
|
||||||
|
<include location="../res/Icons.qrc"/>
|
||||||
|
<include location="../res/Icons.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
<connections>
|
<connections>
|
||||||
<connection>
|
<connection>
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "Encoder_AAC.h"
|
#include "Encoder_AAC.h"
|
||||||
#include "Encoder_FLAC.h"
|
#include "Encoder_FLAC.h"
|
||||||
#include "Encoder_Wave.h"
|
#include "Encoder_Wave.h"
|
||||||
|
#include "Filter_Normalize.h"
|
||||||
#include "WinSevenTaskbar.h"
|
#include "WinSevenTaskbar.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@ -496,6 +497,11 @@ void ProcessingDialog::startNextJob(void)
|
|||||||
m_settings->prependRelativeSourcePath()
|
m_settings->prependRelativeSourcePath()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if(m_settings->normalizationFilterEnabled())
|
||||||
|
{
|
||||||
|
thread->addFilter(new NormalizeFilter(m_settings->normalizationFilterMaxVolume()));
|
||||||
|
}
|
||||||
|
|
||||||
m_threadList.append(thread);
|
m_threadList.append(thread);
|
||||||
m_allJobs.append(thread->getId());
|
m_allJobs.append(thread->getId());
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ bool DownmixFilter::apply(const QString &sourceFile, const QString &outputFile,
|
|||||||
process.setWorkingDirectory(lamexp_temp_folder());
|
process.setWorkingDirectory(lamexp_temp_folder());
|
||||||
|
|
||||||
args << "-V3";
|
args << "-V3";
|
||||||
args << "--norm" << "--temp" << ".";
|
args << "--guard" << "--temp" << ".";
|
||||||
args << QDir::toNativeSeparators(sourceFile);
|
args << QDir::toNativeSeparators(sourceFile);
|
||||||
args << "-c2";
|
args << "-c2";
|
||||||
args << QDir::toNativeSeparators(outputFile);
|
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},
|
{"d837bf6ee4dab557d8b02d46c75a24e58980fffa", "gpgv.gpg", UINT_MAX},
|
||||||
{"143fc001a2f6c56fe1b9e6f8a2eb2b53b9e1e504", "lame.exe", 39910},
|
{"143fc001a2f6c56fe1b9e6f8a2eb2b53b9e1e504", "lame.exe", 39910},
|
||||||
{"a4e929cfaa42fa2e61a3d0c6434c77a06d45aef3", "mac.exe", 406},
|
{"a4e929cfaa42fa2e61a3d0c6434c77a06d45aef3", "mac.exe", 406},
|
||||||
{"61d584ffaf428e9afb0ed9bd32706a954af492b0", "mediainfo_i386.exe", 739},
|
{"ec235c6404caa31e7975e9bbf9ba59599258ae1d", "mediainfo_i386.exe", 741},
|
||||||
{"81fb728cbc6057906fa1b637738e6aefe5dccf54", "mediainfo_x64.exe", 739},
|
{"72d7efdcafc2dee3b534f27ab6e01916d02ba470", "mediainfo_x64.exe", 741},
|
||||||
{"55c293a80475f7aeccf449ac9487a4626e5139cb", "mpcdec.exe", UINT_MAX},
|
{"55c293a80475f7aeccf449ac9487a4626e5139cb", "mpcdec.exe", UINT_MAX},
|
||||||
{"8bbf4a3fffe2ff143eb5ba2cf82ca16d676e865d", "mpg123.exe", UINT_MAX},
|
{"6b6913a54cac08b22d5b468aaed83550fc9ae5b4", "mpg123.exe", 1131},
|
||||||
{"8dd7138714c3bcb39f5a3213413addba13d06f1e", "oggdec.exe", UINT_MAX},
|
{"8dd7138714c3bcb39f5a3213413addba13d06f1e", "oggdec.exe", UINT_MAX},
|
||||||
{"ecd15abe103184aca96e406f5f1c82c6fb2e665d", "oggenc2_i386.exe", 287},
|
{"ecd15abe103184aca96e406f5f1c82c6fb2e665d", "oggenc2_i386.exe", 287},
|
||||||
{"ffe0fbd73352396dc3752ac9d484dbfc754a226d", "oggenc2_sse2.exe", 287},
|
{"ffe0fbd73352396dc3752ac9d484dbfc754a226d", "oggenc2_sse2.exe", 287},
|
||||||
|
@ -73,6 +73,11 @@ ProcessThread::~ProcessThread(void)
|
|||||||
lamexp_remove_file(m_tempFiles.takeFirst());
|
lamexp_remove_file(m_tempFiles.takeFirst());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while(!m_filters.isEmpty())
|
||||||
|
{
|
||||||
|
delete m_filters.takeFirst();
|
||||||
|
}
|
||||||
|
|
||||||
LAMEXP_DELETE(m_encoder);
|
LAMEXP_DELETE(m_encoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,18 +114,16 @@ void ProcessThread::processFile()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<AbstractFilter*> filters;
|
|
||||||
|
|
||||||
//Do we need Stereo downmix?
|
//Do we need Stereo downmix?
|
||||||
if(m_audioFile.formatAudioChannels() > 2 && m_encoder->requiresDownmix())
|
if(m_audioFile.formatAudioChannels() > 2 && m_encoder->requiresDownmix())
|
||||||
{
|
{
|
||||||
filters.prepend(new DownmixFilter());
|
m_filters.prepend(new DownmixFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString sourceFile = m_audioFile.filePath();
|
QString sourceFile = m_audioFile.filePath();
|
||||||
|
|
||||||
//Decode source file
|
//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;
|
m_currentStep = DecodingStep;
|
||||||
AbstractDecoder *decoder = DecoderRegistry::lookup(m_audioFile.formatContainerType(), m_audioFile.formatContainerProfile(), m_audioFile.formatAudioType(), m_audioFile.formatAudioProfile(), m_audioFile.formatAudioVersion());
|
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
|
//Apply all filters
|
||||||
while(!filters.isEmpty())
|
while(!m_filters.isEmpty())
|
||||||
{
|
{
|
||||||
QString tempFile = generateTempFileName();
|
QString tempFile = generateTempFileName();
|
||||||
AbstractFilter *poFilter = filters.takeFirst();
|
AbstractFilter *poFilter = m_filters.takeFirst();
|
||||||
|
|
||||||
if(bSuccess)
|
if(bSuccess)
|
||||||
{
|
{
|
||||||
@ -317,6 +320,11 @@ QString ProcessThread::generateTempFileName(void)
|
|||||||
return tempFileName;
|
return tempFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProcessThread::addFilter(AbstractFilter *filter)
|
||||||
|
{
|
||||||
|
m_filters.append(filter);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// EVENTS
|
// EVENTS
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "Encoder_Abstract.h"
|
#include "Encoder_Abstract.h"
|
||||||
|
|
||||||
class QMutex;
|
class QMutex;
|
||||||
|
class AbstractFilter;
|
||||||
|
|
||||||
class ProcessThread: public QThread
|
class ProcessThread: public QThread
|
||||||
{
|
{
|
||||||
@ -42,6 +43,7 @@ public:
|
|||||||
|
|
||||||
void abort() { m_aborted = true; }
|
void abort() { m_aborted = true; }
|
||||||
QUuid getId() { return m_jobId; }
|
QUuid getId() { return m_jobId; }
|
||||||
|
void addFilter(AbstractFilter *filter);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleUpdate(int progress);
|
void handleUpdate(int progress);
|
||||||
@ -74,6 +76,7 @@ private:
|
|||||||
ProcessStep m_currentStep;
|
ProcessStep m_currentStep;
|
||||||
QStringList m_tempFiles;
|
QStringList m_tempFiles;
|
||||||
const bool m_prependRelativeSourcePath;
|
const bool m_prependRelativeSourcePath;
|
||||||
|
QList<AbstractFilter*> m_filters;
|
||||||
|
|
||||||
static QMutex *m_mutex_genFileName;
|
static QMutex *m_mutex_genFileName;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user