diff --git a/LameXP.vcproj b/LameXP.vcproj
index 73bd0112..62029661 100644
--- a/LameXP.vcproj
+++ b/LameXP.vcproj
@@ -290,6 +290,22 @@
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
+
+
+
+
+
+
+
+
@@ -374,6 +390,10 @@
RelativePath=".\src\Model_Settings.cpp"
>
+
+
@@ -394,6 +414,10 @@
RelativePath=".\src\Thread_Process.cpp"
>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -617,7 +679,7 @@
@@ -627,7 +689,7 @@
@@ -637,7 +699,7 @@
@@ -904,6 +966,10 @@
RelativePath=".\src\Model_Settings.h"
>
+
+
@@ -1082,12 +1148,50 @@
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1164,6 +1268,10 @@
RelativePath=".\tmp\MOC_Thread_Process.cpp"
>
+
+
@@ -1477,7 +1585,7 @@
@@ -1487,7 +1595,7 @@
@@ -1497,7 +1605,7 @@
diff --git a/src/Config.h b/src/Config.h
index 0c55f6dd..9d5bd259 100644
--- a/src/Config.h
+++ b/src/Config.h
@@ -25,7 +25,7 @@
#define VER_LAMEXP_MAJOR 4
#define VER_LAMEXP_MINOR_HI 0
#define VER_LAMEXP_MINOR_LO 0
-#define VER_LAMEXP_BUILD 105
+#define VER_LAMEXP_BUILD 110
#define VER_LAMEXP_SUFFIX TechPreview
/*
diff --git a/src/Decoder_Abstract.cpp b/src/Decoder_Abstract.cpp
new file mode 100644
index 00000000..685d2e6f
--- /dev/null
+++ b/src/Decoder_Abstract.cpp
@@ -0,0 +1,39 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2010 LoRd_MuldeR
+//
+// 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 "Decoder_Abstract.h"
+
+AbstractDecoder::AbstractDecoder(void)
+{
+}
+
+AbstractDecoder::~AbstractDecoder(void)
+{
+}
+
+/*
+ * Default implementation
+ */
+
+bool AbstractDecoder::isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion)
+{
+ return false;
+}
diff --git a/src/Decoder_Abstract.h b/src/Decoder_Abstract.h
new file mode 100644
index 00000000..581114b5
--- /dev/null
+++ b/src/Decoder_Abstract.h
@@ -0,0 +1,37 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2010 LoRd_MuldeR
+//
+// 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 "Tool_Abstract.h"
+
+class AbstractDecoder : public AbstractTool
+{
+ Q_OBJECT
+
+public:
+ AbstractDecoder(void);
+ ~AbstractDecoder(void);
+
+ //Internal decoder API
+ virtual bool decode(const QString &sourceFile, const QString &outputFile, volatile bool *abortFlag) = 0;
+ static bool isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion);
+};
diff --git a/src/Decoder_MP3.cpp b/src/Decoder_MP3.cpp
new file mode 100644
index 00000000..72451855
--- /dev/null
+++ b/src/Decoder_MP3.cpp
@@ -0,0 +1,142 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2010 LoRd_MuldeR
+//
+// 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 "Decoder_MP3.h"
+
+#include "Global.h"
+
+#include
+#include
+#include
+
+MP3Decoder::MP3Decoder(void)
+:
+ m_binary(lamexp_lookup_tool("mpg123.exe"))
+{
+ if(m_binary.isEmpty())
+ {
+ throw "Error initializing MPG123 decoder. Tool 'oggdec.exe' is not registred!";
+ }
+}
+
+MP3Decoder::~MP3Decoder(void)
+{
+}
+
+bool MP3Decoder::decode(const QString &sourceFile, const QString &outputFile, volatile bool *abortFlag)
+{
+ QProcess process;
+ QStringList args;
+
+ args << "-v" << "-w" << QDir::toNativeSeparators(outputFile);
+ args << QDir::toNativeSeparators(sourceFile);
+
+ if(!startProcess(process, m_binary, args))
+ {
+ return false;
+ }
+
+ bool bTimeout = false;
+ bool bAborted = false;
+
+ QRegExp regExp("\\s+Time:\\s+(\\d+):(\\d+)\\.(\\d+)\\s+\\[(\\d+):(\\d+)\\.(\\d+)\\],");
+
+ 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("mpg123 process timed out <-- killing!");
+ bTimeout = true;
+ break;
+ }
+ while(process.bytesAvailable() > 0)
+ {
+ QByteArray line = process.readLine();
+ QString text = QString::fromUtf8(line.constData()).simplified();
+ if(regExp.lastIndexIn(text) >= 0)
+ {
+ int values[6];
+ for(int i = 0; i < 6; i++)
+ {
+ bool ok = false;
+ int temp = regExp.cap(i+1).toInt(&ok);
+ values[i] = (ok ? temp : 0);
+ }
+ int timeDone = (60 * values[0]) + values[1];
+ int timeLeft = (60 * values[3]) + values[4];
+ if(timeDone > 0 || timeLeft > 0)
+ {
+ statusUpdated(static_cast((static_cast(timeDone) / static_cast(timeDone + timeLeft)) * 100.0));
+ }
+ }
+ else 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)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool MP3Decoder::isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion)
+{
+ if(containerType.compare("MPEG Audio", Qt::CaseInsensitive) == 0 || containerType.compare("Wave", Qt::CaseInsensitive) == 0)
+ {
+ if(formatType.compare("MPEG Audio", Qt::CaseInsensitive) == 0)
+ {
+ if(formatProfile.compare("Layer 3", Qt::CaseInsensitive) == 0 || formatProfile.compare("Layer 2", Qt::CaseInsensitive) == 0)
+ {
+ if(formatVersion.compare("Version 1", Qt::CaseInsensitive) == 0 || formatVersion.compare("Version 2", Qt::CaseInsensitive) == 0)
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
diff --git a/src/Decoder_MP3.h b/src/Decoder_MP3.h
new file mode 100644
index 00000000..6ebb7637
--- /dev/null
+++ b/src/Decoder_MP3.h
@@ -0,0 +1,37 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2010 LoRd_MuldeR
+//
+// 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 "Decoder_Abstract.h"
+
+class MP3Decoder : public AbstractDecoder
+{
+public:
+ MP3Decoder(void);
+ ~MP3Decoder(void);
+
+ virtual bool decode(const QString &sourceFile, const QString &outputFile, volatile bool *abortFlag);
+ static bool isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion);
+
+private:
+ const QString m_binary;
+};
diff --git a/src/Decoder_Vorbis.cpp b/src/Decoder_Vorbis.cpp
new file mode 100644
index 00000000..9e94808d
--- /dev/null
+++ b/src/Decoder_Vorbis.cpp
@@ -0,0 +1,126 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2010 LoRd_MuldeR
+//
+// 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 "Decoder_Vorbis.h"
+
+#include "Global.h"
+
+#include
+#include
+#include
+
+VorbisDecoder::VorbisDecoder(void)
+:
+ m_binary(lamexp_lookup_tool("oggdec.exe"))
+{
+ if(m_binary.isEmpty())
+ {
+ throw "Error initializing Vorbis decoder. Tool 'oggdec.exe' is not registred!";
+ }
+}
+
+VorbisDecoder::~VorbisDecoder(void)
+{
+}
+
+bool VorbisDecoder::decode(const QString &sourceFile, const QString &outputFile, volatile bool *abortFlag)
+{
+ QProcess process;
+ QStringList args;
+
+ args << "-w" << pathToShort(QDir::toNativeSeparators(outputFile));
+ args << pathToShort(QDir::toNativeSeparators(sourceFile));
+
+ if(!startProcess(process, m_binary, args))
+ {
+ return false;
+ }
+
+ bool bTimeout = false;
+ bool bAborted = false;
+
+ QRegExp regExp(" (\\d+)% decoded.");
+
+ 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("OggDec process timed out <-- killing!");
+ bTimeout = true;
+ break;
+ }
+ while(process.bytesAvailable() > 0)
+ {
+ QByteArray line = process.readLine();
+ QString text = QString::fromUtf8(line.constData()).simplified();
+ if(regExp.lastIndexIn(text) >= 0)
+ {
+ bool ok = false;
+ int progress = regExp.cap(1).toInt(&ok);
+ if(ok) emit statusUpdated(progress);
+ }
+ else 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;
+}
+
+bool VorbisDecoder::isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion)
+{
+ if(containerType.compare("OGG", Qt::CaseInsensitive) == 0)
+ {
+ if(formatType.compare("Vorbis", Qt::CaseInsensitive) == 0)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
diff --git a/src/Decoder_Vorbis.h b/src/Decoder_Vorbis.h
new file mode 100644
index 00000000..c856450e
--- /dev/null
+++ b/src/Decoder_Vorbis.h
@@ -0,0 +1,37 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2010 LoRd_MuldeR
+//
+// 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 "Decoder_Abstract.h"
+
+class VorbisDecoder : public AbstractDecoder
+{
+public:
+ VorbisDecoder(void);
+ ~VorbisDecoder(void);
+
+ virtual bool decode(const QString &sourceFile, const QString &outputFile, volatile bool *abortFlag);
+ static bool isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion);
+
+private:
+ const QString m_binary;
+};
diff --git a/src/Dialog_MainWindow.cpp b/src/Dialog_MainWindow.cpp
index a4cfc1e2..b229e7be 100644
--- a/src/Dialog_MainWindow.cpp
+++ b/src/Dialog_MainWindow.cpp
@@ -34,7 +34,6 @@
#include "Model_Settings.h"
#include "Model_FileList.h"
#include "Model_FileSystem.h"
-#include "Encoder_MP3.h"
//Qt includes
#include
diff --git a/src/Encoder_Abstract.cpp b/src/Encoder_Abstract.cpp
index 103a1ba3..e8aabd8c 100644
--- a/src/Encoder_Abstract.cpp
+++ b/src/Encoder_Abstract.cpp
@@ -21,57 +21,10 @@
#include "Encoder_Abstract.h"
-#include
-#include
-#include
-#include
-#include
#include
-#define max(a,b) (((a) > (b)) ? (a) : (b))
-#define min(a,b) (((a) < (b)) ? (a) : (b))
-
-QMutex *AbstractEncoder::m_mutex_startProcess = NULL;
-HANDLE AbstractEncoder::m_handle_jobObject = NULL;
-
AbstractEncoder::AbstractEncoder(void)
{
- typedef HANDLE (WINAPI *CreateJobObjectFun)(__in_opt LPSECURITY_ATTRIBUTES lpJobAttributes, __in_opt LPCSTR lpName);
- typedef BOOL (WINAPI *SetInformationJobObjectFun)(__in HANDLE hJob, __in JOBOBJECTINFOCLASS JobObjectInformationClass, __in_bcount(cbJobObjectInformationLength) LPVOID lpJobObjectInformation, __in DWORD cbJobObjectInformationLength);
-
- static CreateJobObjectFun CreateJobObjectPtr = NULL;
- static SetInformationJobObjectFun SetInformationJobObjectPtr = NULL;
-
- if(!m_mutex_startProcess)
- {
- m_mutex_startProcess = new QMutex();
- }
-
- if(!m_handle_jobObject)
- {
- if(!CreateJobObjectPtr || !SetInformationJobObjectPtr)
- {
- QLibrary Kernel32Lib("kernel32.dll");
- CreateJobObjectPtr = (CreateJobObjectFun) Kernel32Lib.resolve("CreateJobObjectA");
- SetInformationJobObjectPtr = (SetInformationJobObjectFun) Kernel32Lib.resolve("SetInformationJobObject");
- }
- if(CreateJobObjectPtr && SetInformationJobObjectPtr)
- {
- m_handle_jobObject = CreateJobObjectPtr(NULL, NULL);
- if(m_handle_jobObject == INVALID_HANDLE_VALUE)
- {
- m_handle_jobObject = NULL;
- }
- if(m_handle_jobObject)
- {
- JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobExtendedLimitInfo;
- memset(&jobExtendedLimitInfo, 0, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
- jobExtendedLimitInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
- SetInformationJobObjectPtr(m_handle_jobObject, JobObjectExtendedLimitInformation, &jobExtendedLimitInfo, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
- }
- }
- }
-
m_configBitrate = 0;
m_configRCMode = 0;
}
@@ -86,57 +39,3 @@ AbstractEncoder::~AbstractEncoder(void)
void AbstractEncoder::setBitrate(int bitrate) { m_configBitrate = max(0, bitrate); }
void AbstractEncoder::setRCMode(int mode) { m_configRCMode = max(0, mode); }
-
-/*
- * Auxiliary functions
- */
-
-bool AbstractEncoder::startProcess(QProcess &process, const QString &program, const QStringList &args)
-{
- typedef BOOL (WINAPI *AssignProcessToJobObjectFun)(__in HANDLE hJob, __in HANDLE hProcess);
- static AssignProcessToJobObjectFun AssignProcessToJobObjectPtr = NULL;
-
- QMutexLocker lock(m_mutex_startProcess);
-
- emit messageLogged(commandline2string(program, args) + "\n");
-
- if(!AssignProcessToJobObjectPtr)
- {
- QLibrary Kernel32Lib("kernel32.dll");
- AssignProcessToJobObjectPtr = (AssignProcessToJobObjectFun) Kernel32Lib.resolve("AssignProcessToJobObject");
- }
-
- process.setProcessChannelMode(QProcess::MergedChannels);
- process.setReadChannel(QProcess::StandardOutput);
- process.start(program, args);
-
- if(process.waitForStarted())
- {
-
- if(AssignProcessToJobObjectPtr)
- {
- AssignProcessToJobObjectPtr(m_handle_jobObject, process.pid()->hProcess);
- }
- if(!SetPriorityClass(process.pid()->hProcess, BELOW_NORMAL_PRIORITY_CLASS))
- {
- SetPriorityClass(process.pid()->hProcess, IDLE_PRIORITY_CLASS);
- }
- lock.unlock();
- emit statusUpdated(0);
- return true;
- }
-
- return false;
-}
-
-QString AbstractEncoder::commandline2string(const QString &program, const QStringList &arguments)
-{
- QString commandline = (program.contains(' ') ? QString("\"%1\"").arg(program) : program);
-
- for(int i = 0; i < arguments.count(); i++)
- {
- commandline += (arguments.at(i).contains(' ') ? QString(" \"%1\"").arg(arguments.at(i)) : QString(" %1").arg(arguments.at(i)));
- }
-
- return commandline;
-}
diff --git a/src/Encoder_Abstract.h b/src/Encoder_Abstract.h
index ec9fcfe9..98e72882 100644
--- a/src/Encoder_Abstract.h
+++ b/src/Encoder_Abstract.h
@@ -21,15 +21,14 @@
#pragma once
+#include "Tool_Abstract.h"
#include "Model_AudioFile.h"
-#include
-
class QProcess;
class QStringList;
class QMutex;
-class AbstractEncoder : public QObject
+class AbstractEncoder : public AbstractTool
{
Q_OBJECT
@@ -38,7 +37,7 @@ public:
~AbstractEncoder(void);
//Internal encoder API
- virtual bool encode(const AudioFileModel &sourceFile, const QString &outputFile, volatile bool *abortFlag) = 0;
+ virtual bool encode(const QString &sourceFile, const AudioFileModel &metaInfo, const QString &outputFile, volatile bool *abortFlag) = 0;
virtual bool isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion) = 0;
virtual QString extension(void) = 0;
@@ -46,19 +45,7 @@ public:
void setBitrate(int bitrate);
void setRCMode(int mode);
- //Auxiliary functions
- bool startProcess(QProcess &process, const QString &program, const QStringList &args);
- static QString commandline2string(const QString &program, const QStringList &arguments);
-
-signals:
- void statusUpdated(int progress);
- void messageLogged(const QString &line);
-
protected:
int m_configBitrate;
int m_configRCMode;
-
-private:
- static QMutex *m_mutex_startProcess;
- static void *m_handle_jobObject;
};
diff --git a/src/Encoder_MP3.cpp b/src/Encoder_MP3.cpp
index e00cd395..2b983d51 100644
--- a/src/Encoder_MP3.cpp
+++ b/src/Encoder_MP3.cpp
@@ -27,11 +27,11 @@
#include
#include
-#define max(a,b) (((a) > (b)) ? (a) : (b))
-#define min(a,b) (((a) < (b)) ? (a) : (b))
#define IS_UNICODE(STR) (qstricmp(STR.toUtf8().constData(), QString::fromLocal8Bit(STR.toLocal8Bit()).toUtf8().constData()))
-MP3Encoder::MP3Encoder(void) : m_binary(lamexp_lookup_tool("lame.exe"))
+MP3Encoder::MP3Encoder(void)
+:
+ m_binary(lamexp_lookup_tool("lame.exe"))
{
if(m_binary.isEmpty())
{
@@ -43,10 +43,9 @@ MP3Encoder::~MP3Encoder(void)
{
}
-bool MP3Encoder::encode(const AudioFileModel &sourceFile, const QString &outputFile, volatile bool *abortFlag)
+bool MP3Encoder::encode(const QString &sourceFile, const AudioFileModel &metaInfo, const QString &outputFile, volatile bool *abortFlag)
{
QProcess process;
- const QString baseName = QFileInfo(outputFile).fileName();
QStringList args;
args << "--nohist";
@@ -69,17 +68,17 @@ bool MP3Encoder::encode(const AudioFileModel &sourceFile, const QString &outputF
break;
}
- if(!sourceFile.fileName().isEmpty()) args << (IS_UNICODE(sourceFile.fileName()) ? "--uTitle" : "--lTitle") << sourceFile.fileName();
- if(!sourceFile.fileArtist().isEmpty()) args << (IS_UNICODE(sourceFile.fileArtist()) ? "--uArtist" : "--lArtist") << sourceFile.fileArtist();
- if(!sourceFile.fileAlbum().isEmpty()) args << (IS_UNICODE(sourceFile.fileAlbum()) ? "--uAlbum" : "--lAlbum") << sourceFile.fileAlbum();
- if(!sourceFile.fileGenre().isEmpty()) args << (IS_UNICODE(sourceFile.fileGenre()) ? "--uGenre" : "--lGenre") << sourceFile.fileGenre();
- if(!sourceFile.fileComment().isEmpty()) args << (IS_UNICODE(sourceFile.fileComment()) ? "--uComment" : "--lComment") << sourceFile.fileComment();
- if(sourceFile.fileYear()) args << "--ty" << QString::number(sourceFile.fileYear());
- if(sourceFile.filePosition()) args << "--tn" << QString::number(sourceFile.filePosition());
+ if(!metaInfo.fileName().isEmpty()) args << (IS_UNICODE(metaInfo.fileName()) ? "--uTitle" : "--lTitle") << metaInfo.fileName();
+ if(!metaInfo.fileArtist().isEmpty()) args << (IS_UNICODE(metaInfo.fileArtist()) ? "--uArtist" : "--lArtist") << metaInfo.fileArtist();
+ if(!metaInfo.fileAlbum().isEmpty()) args << (IS_UNICODE(metaInfo.fileAlbum()) ? "--uAlbum" : "--lAlbum") << metaInfo.fileAlbum();
+ if(!metaInfo.fileGenre().isEmpty()) args << (IS_UNICODE(metaInfo.fileGenre()) ? "--uGenre" : "--lGenre") << metaInfo.fileGenre();
+ if(!metaInfo.fileComment().isEmpty()) args << (IS_UNICODE(metaInfo.fileComment()) ? "--uComment" : "--lComment") << metaInfo.fileComment();
+ if(metaInfo.fileYear()) args << "--ty" << QString::number(metaInfo.fileYear());
+ if(metaInfo.filePosition()) args << "--tn" << QString::number(metaInfo.filePosition());
//args << "--tv" << QString().sprintf("Encoder=LameXP v%d.%02d.%04d [%s]", lamexp_version_major(), lamexp_version_minor(), lamexp_version_build(), lamexp_version_release());
- args << QDir::toNativeSeparators(sourceFile.filePath());
+ args << QDir::toNativeSeparators(sourceFile);
args << QDir::toNativeSeparators(outputFile);
if(!startProcess(process, m_binary, args))
diff --git a/src/Encoder_MP3.h b/src/Encoder_MP3.h
index bed3a6e8..860cc8ad 100644
--- a/src/Encoder_MP3.h
+++ b/src/Encoder_MP3.h
@@ -33,7 +33,7 @@ public:
MP3Encoder(void);
~MP3Encoder(void);
- virtual bool encode(const AudioFileModel &sourceFile, const QString &outputFile, volatile bool *abortFlag);
+ virtual bool encode(const QString &sourceFile, const AudioFileModel &metaInfo, const QString &outputFile, volatile bool *abortFlag);
virtual bool isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion);
virtual QString extension(void);
diff --git a/src/Encoder_Vorbis.cpp b/src/Encoder_Vorbis.cpp
index 525d7db0..befd54c3 100644
--- a/src/Encoder_Vorbis.cpp
+++ b/src/Encoder_Vorbis.cpp
@@ -47,7 +47,7 @@ VorbisEncoder::~VorbisEncoder(void)
{
}
-bool VorbisEncoder::encode(const AudioFileModel &sourceFile, const QString &outputFile, volatile bool *abortFlag)
+bool VorbisEncoder::encode(const QString &sourceFile, const AudioFileModel &metaInfo, const QString &outputFile, volatile bool *abortFlag)
{
QProcess process;
QStringList args;
@@ -68,18 +68,18 @@ bool VorbisEncoder::encode(const AudioFileModel &sourceFile, const QString &outp
break;
}
- if(!sourceFile.fileName().isEmpty()) args << "-t" << sourceFile.fileName();
- if(!sourceFile.fileArtist().isEmpty()) args << "-a" << sourceFile.fileArtist();
- if(!sourceFile.fileAlbum().isEmpty()) args << "-l" << sourceFile.fileAlbum();
- if(!sourceFile.fileGenre().isEmpty()) args << "-G" << sourceFile.fileGenre();
- if(!sourceFile.fileComment().isEmpty()) args << "-c" << QString("comment=%1").arg(sourceFile.fileComment());
- if(sourceFile.fileYear()) args << "-d" << QString::number(sourceFile.fileYear());
- if(sourceFile.filePosition()) args << "-N" << QString::number(sourceFile.filePosition());
+ if(!metaInfo.fileName().isEmpty()) args << "-t" << metaInfo.fileName();
+ if(!metaInfo.fileArtist().isEmpty()) args << "-a" << metaInfo.fileArtist();
+ if(!metaInfo.fileAlbum().isEmpty()) args << "-l" << metaInfo.fileAlbum();
+ if(!metaInfo.fileGenre().isEmpty()) args << "-G" << metaInfo.fileGenre();
+ if(!metaInfo.fileComment().isEmpty()) args << "-c" << QString("comment=%1").arg(metaInfo.fileComment());
+ if(metaInfo.fileYear()) args << "-d" << QString::number(metaInfo.fileYear());
+ if(metaInfo.filePosition()) args << "-N" << QString::number(metaInfo.filePosition());
//args << "--tv" << QString().sprintf("Encoder=LameXP v%d.%02d.%04d [%s]", lamexp_version_major(), lamexp_version_minor(), lamexp_version_build(), lamexp_version_release());
args << "-o" << QDir::toNativeSeparators(outputFile);
- args << QDir::toNativeSeparators(sourceFile.filePath());
+ args << QDir::toNativeSeparators(sourceFile);
if(!startProcess(process, binary, args))
{
diff --git a/src/Encoder_Vorbis.h b/src/Encoder_Vorbis.h
index 00bac598..aa8fa679 100644
--- a/src/Encoder_Vorbis.h
+++ b/src/Encoder_Vorbis.h
@@ -33,7 +33,7 @@ public:
VorbisEncoder(void);
~VorbisEncoder(void);
- virtual bool encode(const AudioFileModel &sourceFile, const QString &outputFile, volatile bool *abortFlag);
+ virtual bool encode(const QString &sourceFile, const AudioFileModel &metaInfo, const QString &outputFile, volatile bool *abortFlag);
virtual bool isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion);
virtual QString extension(void);
diff --git a/src/Registry_Decoder.cpp b/src/Registry_Decoder.cpp
new file mode 100644
index 00000000..59cfe90b
--- /dev/null
+++ b/src/Registry_Decoder.cpp
@@ -0,0 +1,38 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2010 LoRd_MuldeR
+//
+// 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 "Registry_Decoder.h"
+
+#include "Decoder_Abstract.h"
+#include "Decoder_MP3.h"
+#include "Decoder_Vorbis.h"
+
+#include
+
+#define PROBE_DECODER(DEC) if(DEC::isFormatSupported(containerType, containerProfile, formatType, formatProfile, formatVersion)) { return new DEC(); }
+
+AbstractDecoder *DecoderRegistry::lookup(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion)
+{
+ PROBE_DECODER(MP3Decoder);
+ PROBE_DECODER(VorbisDecoder);
+ return NULL;
+}
+
diff --git a/src/Registry_Decoder.h b/src/Registry_Decoder.h
new file mode 100644
index 00000000..d7572e4f
--- /dev/null
+++ b/src/Registry_Decoder.h
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2010 LoRd_MuldeR
+//
+// 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
+
+class QString;
+class AbstractDecoder;
+
+class DecoderRegistry
+{
+public:
+ static AbstractDecoder *lookup(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion);
+};
diff --git a/src/Thread_Process.cpp b/src/Thread_Process.cpp
index 958fdce1..5b72e7db 100644
--- a/src/Thread_Process.cpp
+++ b/src/Thread_Process.cpp
@@ -25,7 +25,8 @@
#include "Model_AudioFile.h"
#include "Model_Progress.h"
#include "Encoder_Abstract.h"
-
+#include "Decoder_Abstract.h"
+#include "Registry_Decoder.h"
#include "Model_Settings.h"
#include
@@ -58,10 +59,17 @@ ProcessThread::ProcessThread(const AudioFileModel &audioFile, const QString &out
connect(m_encoder, SIGNAL(statusUpdated(int)), this, SLOT(handleUpdate(int)), Qt::DirectConnection);
connect(m_encoder, SIGNAL(messageLogged(QString)), this, SLOT(handleMessage(QString)), Qt::DirectConnection);
+
+ m_currentStep = UnknownStep;
}
ProcessThread::~ProcessThread(void)
{
+ while(!m_tempFiles.isEmpty())
+ {
+ QFile::remove(m_tempFiles.takeFirst());
+ }
+
LAMEXP_DELETE(m_encoder);
}
@@ -84,10 +92,12 @@ void ProcessThread::run()
void ProcessThread::processFile()
{
m_aborted = false;
+ bool bSuccess = true;
qDebug("Process thread %s has started.", m_jobId.toString().toLatin1().constData());
emit processStateInitialized(m_jobId, QFileInfo(m_audioFile.filePath()).fileName(), "Starting...", ProgressModel::JobRunning);
+ //Generate output file name
QString outFileName = generateOutFileName();
if(outFileName.isEmpty())
{
@@ -96,22 +106,53 @@ void ProcessThread::processFile()
return;
}
+ QString sourceFile = m_audioFile.filePath();
+
+ //Decode source file
if(!m_encoder->isFormatSupported(m_audioFile.formatContainerType(), m_audioFile.formatContainerProfile(), m_audioFile.formatAudioType(), m_audioFile.formatAudioProfile(), m_audioFile.formatAudioVersion()))
{
- handleMessage(QString("The format of this file is NOT supported:\n%1\n\nContainer Format:\t%2\nAudio Format:\t%3").arg(m_audioFile.filePath(), m_audioFile.formatContainerInfo(), m_audioFile.formatAudioCompressInfo()));
- emit processStateChanged(m_jobId, "Unsupported!", ProgressModel::JobFailed);
- emit processStateFinished(m_jobId, outFileName, false);
- return;
+ m_currentStep = DecodingStep;
+ AbstractDecoder *decoder = DecoderRegistry::lookup(m_audioFile.formatContainerType(), m_audioFile.formatContainerProfile(), m_audioFile.formatAudioType(), m_audioFile.formatAudioProfile(), m_audioFile.formatAudioVersion());
+
+ if(decoder)
+ {
+ QString tempFile = generateTempFileName();
+
+ connect(decoder, SIGNAL(statusUpdated(int)), this, SLOT(handleUpdate(int)), Qt::DirectConnection);
+ connect(decoder, SIGNAL(messageLogged(QString)), this, SLOT(handleMessage(QString)), Qt::DirectConnection);
+
+ bSuccess = decoder->decode(sourceFile, tempFile, &m_aborted);
+
+ if(bSuccess)
+ {
+ sourceFile = tempFile;
+ handleMessage("\n-------------------------------\n");
+ }
+ }
+ else
+ {
+ handleMessage(QString("The format of this file is NOT supported:\n%1\n\nContainer Format:\t%2\nAudio Format:\t%3").arg(m_audioFile.filePath(), m_audioFile.formatContainerInfo(), m_audioFile.formatAudioCompressInfo()));
+ emit processStateChanged(m_jobId, "Unsupported!", ProgressModel::JobFailed);
+ emit processStateFinished(m_jobId, outFileName, false);
+ return;
+ }
}
- bool bSuccess = m_encoder->encode(m_audioFile, outFileName, &m_aborted);
+ //Encode audio file
+ if(bSuccess)
+ {
+ m_currentStep = EncodingStep;
+ bSuccess = m_encoder->encode(sourceFile, m_audioFile, outFileName, &m_aborted);
+ }
+ //Make sure output file exists
if(bSuccess)
{
QFileInfo fileInfo(outFileName);
bSuccess = fileInfo.exists() && fileInfo.isFile() && (fileInfo.size() > 0);
}
+ //Report result
emit processStateChanged(m_jobId, (bSuccess ? "Done." : (m_aborted ? "Aborted!" : "Failed!")), (bSuccess ? ProgressModel::JobComplete : ProgressModel::JobFailed));
emit processStateFinished(m_jobId, outFileName, bSuccess);
@@ -124,7 +165,15 @@ void ProcessThread::processFile()
void ProcessThread::handleUpdate(int progress)
{
- emit processStateChanged(m_jobId, QString("Encoding (%1%)").arg(QString::number(progress)), ProgressModel::JobRunning);
+ switch(m_currentStep)
+ {
+ case EncodingStep:
+ emit processStateChanged(m_jobId, QString("Encoding (%1%)").arg(QString::number(progress)), ProgressModel::JobRunning);
+ break;
+ case DecodingStep:
+ emit processStateChanged(m_jobId, QString("Decoding (%1%)").arg(QString::number(progress)), ProgressModel::JobRunning);
+ break;
+ }
}
void ProcessThread::handleMessage(const QString &line)
@@ -200,6 +249,26 @@ QString ProcessThread::generateOutFileName(void)
return outFileName;
}
+QString ProcessThread::generateTempFileName(void)
+{
+ QMutexLocker lock(m_mutex_genFileName);
+ QString tempFileName = QString("%1/%2.wav").arg(QDir::tempPath(), QUuid::createUuid().toString());
+
+ while(QFileInfo(tempFileName).exists())
+ {
+ tempFileName = QString("%1/%2.wav").arg(QDir::tempPath(), QUuid::createUuid().toString());
+ }
+
+ QFile file(tempFileName);
+ if(file.open(QFile::ReadWrite))
+ {
+ file.close();
+ }
+
+ m_tempFiles << tempFileName;
+ return tempFileName;
+}
+
////////////////////////////////////////////////////////////
// EVENTS
////////////////////////////////////////////////////////////
diff --git a/src/Thread_Process.h b/src/Thread_Process.h
index 6945cab1..7e7eb2fa 100644
--- a/src/Thread_Process.h
+++ b/src/Thread_Process.h
@@ -23,6 +23,7 @@
#include
#include
+#include
#include "Model_AudioFile.h"
#include "Encoder_Abstract.h"
@@ -53,14 +54,25 @@ signals:
void processMessageLogged(const QUuid &jobId, const QString &line);
private:
+ enum ProcessStep
+ {
+ DecodingStep = 0,
+ FilteringStep = 1,
+ EncodingStep = 2,
+ UnknownStep = 3
+ };
+
void processFile();
QString generateOutFileName(void);
+ QString generateTempFileName(void);
const QUuid m_jobId;
AudioFileModel m_audioFile;
AbstractEncoder *m_encoder;
const QString m_outputDirectory;
volatile bool m_aborted;
+ ProcessStep m_currentStep;
+ QStringList m_tempFiles;
static QMutex *m_mutex_genFileName;
};
diff --git a/src/Tool_Abstract.cpp b/src/Tool_Abstract.cpp
new file mode 100644
index 00000000..2b599c31
--- /dev/null
+++ b/src/Tool_Abstract.cpp
@@ -0,0 +1,167 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2010 LoRd_MuldeR
+//
+// 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 "Tool_Abstract.h"
+
+#include
+#include
+#include
+#include
+#include
+
+/*
+ * Win32 API definitions
+ */
+typedef HANDLE (WINAPI *CreateJobObjectFun)(__in_opt LPSECURITY_ATTRIBUTES lpJobAttributes, __in_opt LPCSTR lpName);
+typedef BOOL (WINAPI *SetInformationJobObjectFun)(__in HANDLE hJob, __in JOBOBJECTINFOCLASS JobObjectInformationClass, __in_bcount(cbJobObjectInformationLength) LPVOID lpJobObjectInformation, __in DWORD cbJobObjectInformationLength);
+typedef BOOL (WINAPI *AssignProcessToJobObjectFun)(__in HANDLE hJob, __in HANDLE hProcess);
+
+/*
+ * Static vars
+ */
+QMutex *AbstractTool::m_mutex_startProcess = NULL;
+HANDLE AbstractTool::m_handle_jobObject = NULL;
+
+/*
+ * Constructor
+ */
+AbstractTool::AbstractTool(void)
+{
+ static CreateJobObjectFun CreateJobObjectPtr = NULL;
+ static SetInformationJobObjectFun SetInformationJobObjectPtr = NULL;
+
+ if(!m_mutex_startProcess)
+ {
+ m_mutex_startProcess = new QMutex();
+ }
+
+ if(!m_handle_jobObject)
+ {
+ if(!CreateJobObjectPtr || !SetInformationJobObjectPtr)
+ {
+ QLibrary Kernel32Lib("kernel32.dll");
+ CreateJobObjectPtr = (CreateJobObjectFun) Kernel32Lib.resolve("CreateJobObjectA");
+ SetInformationJobObjectPtr = (SetInformationJobObjectFun) Kernel32Lib.resolve("SetInformationJobObject");
+ }
+ if(CreateJobObjectPtr && SetInformationJobObjectPtr)
+ {
+ m_handle_jobObject = CreateJobObjectPtr(NULL, NULL);
+ if(m_handle_jobObject == INVALID_HANDLE_VALUE)
+ {
+ m_handle_jobObject = NULL;
+ }
+ if(m_handle_jobObject)
+ {
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobExtendedLimitInfo;
+ memset(&jobExtendedLimitInfo, 0, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
+ jobExtendedLimitInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
+ SetInformationJobObjectPtr(m_handle_jobObject, JobObjectExtendedLimitInformation, &jobExtendedLimitInfo, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
+ }
+ }
+ }
+}
+
+/*
+ * Destructor
+ */
+AbstractTool::~AbstractTool(void)
+{
+}
+
+/*
+ * Initialize and launch process object
+ */
+bool AbstractTool::startProcess(QProcess &process, const QString &program, const QStringList &args)
+{
+ static AssignProcessToJobObjectFun AssignProcessToJobObjectPtr = NULL;
+
+ QMutexLocker lock(m_mutex_startProcess);
+
+ emit messageLogged(commandline2string(program, args) + "\n");
+
+ if(!AssignProcessToJobObjectPtr)
+ {
+ QLibrary Kernel32Lib("kernel32.dll");
+ AssignProcessToJobObjectPtr = (AssignProcessToJobObjectFun) Kernel32Lib.resolve("AssignProcessToJobObject");
+ }
+
+ process.setProcessChannelMode(QProcess::MergedChannels);
+ process.setReadChannel(QProcess::StandardOutput);
+ process.start(program, args);
+
+ if(process.waitForStarted())
+ {
+
+ if(AssignProcessToJobObjectPtr)
+ {
+ AssignProcessToJobObjectPtr(m_handle_jobObject, process.pid()->hProcess);
+ }
+ if(!SetPriorityClass(process.pid()->hProcess, BELOW_NORMAL_PRIORITY_CLASS))
+ {
+ SetPriorityClass(process.pid()->hProcess, IDLE_PRIORITY_CLASS);
+ }
+ lock.unlock();
+ emit statusUpdated(0);
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Convert program arguments to single string
+ */
+QString AbstractTool::commandline2string(const QString &program, const QStringList &arguments)
+{
+ QString commandline = (program.contains(' ') ? QString("\"%1\"").arg(program) : program);
+
+ for(int i = 0; i < arguments.count(); i++)
+ {
+ commandline += (arguments.at(i).contains(' ') ? QString(" \"%1\"").arg(arguments.at(i)) : QString(" %1").arg(arguments.at(i)));
+ }
+
+ return commandline;
+}
+
+/*
+ * Convert long path to short path
+ */
+QString AbstractTool::pathToShort(const QString &longPath)
+{
+ QString shortPath;
+ DWORD buffSize = GetShortPathNameW(reinterpret_cast(longPath.utf16()), NULL, NULL);
+
+ if(buffSize > 0)
+ {
+ wchar_t *buffer = new wchar_t[buffSize];
+ DWORD result = GetShortPathNameW(reinterpret_cast(longPath.utf16()), buffer, buffSize);
+
+ if(result > 0 && result < buffSize)
+ {
+ shortPath = QString::fromUtf16(reinterpret_cast(buffer));
+ }
+
+ delete[] buffer;
+ }
+
+ return (shortPath.isEmpty() ? longPath : shortPath);
+}
+
diff --git a/src/Tool_Abstract.h b/src/Tool_Abstract.h
new file mode 100644
index 00000000..902d592f
--- /dev/null
+++ b/src/Tool_Abstract.h
@@ -0,0 +1,48 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2010 LoRd_MuldeR
+//
+// 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
+
+class QMutex;
+class QProcess;
+
+class AbstractTool : public QObject
+{
+ Q_OBJECT
+
+public:
+ AbstractTool(void);
+ ~AbstractTool(void);
+
+ bool startProcess(QProcess &process, const QString &program, const QStringList &args);
+ static QString commandline2string(const QString &program, const QStringList &arguments);
+ static QString AbstractTool::pathToShort(const QString &longPath);
+
+signals:
+ void statusUpdated(int progress);
+ void messageLogged(const QString &line);
+
+private:
+ static QMutex *m_mutex_startProcess;
+ static void *m_handle_jobObject;
+};