diff --git a/gui/LogViewDialog.ui b/gui/LogViewDialog.ui
index ea0e5139..4a9eb201 100644
--- a/gui/LogViewDialog.ui
+++ b/gui/LogViewDialog.ui
@@ -10,13 +10,13 @@
0
0
640
- 512
+ 384
640
- 512
+ 384
@@ -26,154 +26,338 @@
:/icons/application_xp_terminal.png:/icons/application_xp_terminal.png
-
- -
-
-
-
-
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ 0
+
+
-
+
+
+
+ 0
+ 64
+
+
+
+
+ 16777215
+ 64
+
+
-
-
-
- 170
- 255
- 0
-
-
-
- 0
- 31
- 0
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
-
-
-
- 170
- 255
- 0
-
-
-
- 0
- 31
- 0
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
-
-
-
- 120
- 120
- 120
-
-
-
- 240
- 240
- 240
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
-
-
- Lucida Console
-
+
+ true
-
- C:\DOS
+
+ QFrame::NoFrame
+
+
+
+ 3
+
+
-
+
+
-
+
+
+
+ 56
+ 56
+
+
+
+
+ 56
+ 56
+
+
+
+
+
+
+ :/images/HeaderIcon_LogFile.png
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 15
+ 20
+
+
+
+
+ -
+
+
+ <b>Log File</b><br>The log file shows detailed information about the selected job.
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 2
+
+
+
+
+ 16777215
+ 2
+
+
+
+ QFrame::HLine
+
+
+ QFrame::Sunken
+
+
+
+ -
+
+
+ 10
+
+
+ 6
+
+
-
+
+
+
+
+
+
+
+ 170
+ 255
+ 0
+
+
+
+
+
+
+ 0
+ 31
+ 0
+
+
+
+
+
+
+
+
+ 170
+ 255
+ 0
+
+
+
+
+
+
+ 0
+ 31
+ 0
+
+
+
+
+
+
+
+
+ 120
+ 120
+ 120
+
+
+
+
+
+
+ 240
+ 240
+ 240
+
+
+
+
+
+
+
+
+ Lucida Console
+
+
+
+ C:\DOS
C:\DOS\RUN
RUN\DOS\RUN
-
-
- Qt::NoTextInteraction
-
-
-
- -
-
-
-
- 90
- 0
-
-
-
- Discard
-
-
-
- :/icons/cross.png:/icons/cross.png
-
-
-
- -
-
-
-
- 130
- 0
-
-
-
- Save to File...
-
-
-
- :/icons/disk.png:/icons/disk.png
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
- 130
- 0
-
-
-
- Copy to Clipboard
-
-
-
- :/icons/paste_plain.png:/icons/paste_plain.png
-
-
+
+
+ Qt::NoTextInteraction
+
+
+
+ -
+
+
+
+ 90
+ 0
+
+
+
+ Discard
+
+
+
+ :/icons/cross.png:/icons/cross.png
+
+
+
+ -
+
+
+
+ 130
+ 0
+
+
+
+ Save to File...
+
+
+
+ :/icons/disk.png:/icons/disk.png
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 130
+ 0
+
+
+
+ Copy to Clipboard
+
+
+
+ :/icons/paste_plain.png:/icons/paste_plain.png
+
+
+
+
@@ -181,6 +365,8 @@ RUN\DOS\RUN
+
+
diff --git a/res/Images.qrc b/res/Images.qrc
index 9fe1e8cc..6249dadd 100644
--- a/res/Images.qrc
+++ b/res/Images.qrc
@@ -3,6 +3,7 @@
images/Busy.gif
images/HeaderIcon_MetaInfo.png
+ images/HeaderIcon_LogFile.png
images/Label.png
images/Loading.gif
images/Logo.png
diff --git a/res/images/HeaderIcon_LogFile.png b/res/images/HeaderIcon_LogFile.png
new file mode 100644
index 00000000..67e09859
Binary files /dev/null and b/res/images/HeaderIcon_LogFile.png differ
diff --git a/src/Config.h b/src/Config.h
index d3bb937e..813275ad 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 70
+#define VER_LAMEXP_BUILD 74
#define VER_LAMEXP_SUFFIX TechPreview
/*
diff --git a/src/Dialog_LogView.cpp b/src/Dialog_LogView.cpp
index 1deab260..d5c73d31 100644
--- a/src/Dialog_LogView.cpp
+++ b/src/Dialog_LogView.cpp
@@ -23,6 +23,7 @@
#include
#include
+#include
LogViewDialog::LogViewDialog(QWidget *parent)
:
@@ -64,6 +65,7 @@ void LogViewDialog::copyButtonClicked(void)
mime->setData("text/plain", textEdit->toPlainText().toUtf8().constData());
QApplication::clipboard()->setMimeData(mime);
m_clipboardUsed = true;
+ MessageBeep(MB_ICONINFORMATION);
}
void LogViewDialog::saveButtonClicked(void)
diff --git a/src/Dialog_MainWindow.cpp b/src/Dialog_MainWindow.cpp
index 6d8f8fa9..8547aa8e 100644
--- a/src/Dialog_MainWindow.cpp
+++ b/src/Dialog_MainWindow.cpp
@@ -132,6 +132,7 @@ MainWindow::MainWindow(FileListModel *fileListModel, AudioFileModel *metaInfo, S
m_fileSystemModel = new QFileSystemModel();
m_fileSystemModel->setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
m_fileSystemModel->setRootPath(m_fileSystemModel->rootPath());
+ m_fileSystemModel->installEventFilter(this);
outputFolderView->setModel(m_fileSystemModel);
outputFolderView->header()->setStretchLastSection(true);
outputFolderView->header()->hideSection(1);
@@ -393,6 +394,17 @@ void MainWindow::resizeEvent(QResizeEvent *event)
m_dropNoteLabel->setGeometry(0, 0, sourceFileView->width(), sourceFileView->height());
}
+bool MainWindow::eventFilter(QObject *obj, QEvent *event)
+{
+ if(obj == m_fileSystemModel)
+ {
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ QTimer::singleShot(0, this, SLOT(restoreCursor()));
+ }
+
+ return false;
+}
+
////////////////////////////////////////////////////////////
// Slots
////////////////////////////////////////////////////////////
@@ -1111,3 +1123,11 @@ void MainWindow::saveToSourceFolderChanged(void)
{
m_settings->outputToSourceDir(saveToSourceFolderCheckBox->isChecked());
}
+
+/*
+ * Restore the override cursor
+ */
+void MainWindow::restoreCursor(void)
+{
+ QApplication::restoreOverrideCursor();
+}
diff --git a/src/Dialog_MainWindow.h b/src/Dialog_MainWindow.h
index a01c06a2..87153907 100644
--- a/src/Dialog_MainWindow.h
+++ b/src/Dialog_MainWindow.h
@@ -80,6 +80,7 @@ private slots:
void metaTagsEnabledChanged(void);
void playlistEnabledChanged(void);
void saveToSourceFolderChanged(void);
+ void restoreCursor(void);
protected:
void showEvent(QShowEvent *event);
@@ -87,6 +88,7 @@ protected:
void dropEvent(QDropEvent *event);
void closeEvent(QCloseEvent *event);
void resizeEvent(QResizeEvent *event);
+ bool eventFilter(QObject *obj, QEvent *event);
private:
void addFiles(const QStringList &files);
diff --git a/src/Dialog_Processing.cpp b/src/Dialog_Processing.cpp
index de7952fe..4a6058a1 100644
--- a/src/Dialog_Processing.cpp
+++ b/src/Dialog_Processing.cpp
@@ -41,6 +41,7 @@
#include
#include
#include
+#include
#include
@@ -90,6 +91,13 @@ ProcessingDialog::ProcessingDialog(FileListModel *fileListModel, AudioFileModel
connect(m_progressModel, SIGNAL(modelReset()), this, SLOT(progressModelChanged()));
connect(view_log, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(logViewDoubleClicked(QModelIndex)));
+ //Create context menu
+ m_contextMenu = new QMenu();
+ QAction *contextMenuAction = m_contextMenu->addAction(QIcon(":/icons/zoom.png"), "Show details for selected job");
+ view_log->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(view_log, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuTriggered(QPoint)));
+ connect(contextMenuAction, SIGNAL(triggered(bool)), this, SLOT(contextMenuActionTriggered()));
+
//Enque jobs
if(fileListModel)
{
@@ -117,6 +125,7 @@ ProcessingDialog::~ProcessingDialog(void)
if(m_progressIndicator) m_progressIndicator->stop();
LAMEXP_DELETE(m_progressIndicator);
LAMEXP_DELETE(m_progressModel);
+ LAMEXP_DELETE(m_contextMenu);
while(!m_threadList.isEmpty())
{
@@ -194,8 +203,12 @@ void ProcessingDialog::initEncoding(void)
button_AbortProcess->setEnabled(true);
progressBar->setRange(0, m_pendingJobs.count());
- startNextJob(); //TODO: Start as many jobs in parallel as processors available
- startNextJob();
+ lamexp_cpu_t cpuFeatures = lamexp_detect_cpu_features();
+
+ for(int i = 0; i < min(max(cpuFeatures.count, 1), 4); i++)
+ {
+ startNextJob();
+ }
}
void ProcessingDialog::abortEncoding(void)
@@ -292,9 +305,25 @@ void ProcessingDialog::logViewDoubleClicked(const QModelIndex &index)
{
const QStringList &logFile = m_progressModel->getLogFile(index);
LogViewDialog *logView = new LogViewDialog(this);
+ logView->setWindowTitle(QString("LameXP - %1").arg(m_progressModel->data(index, Qt::DisplayRole).toString()));
logView->exec(logFile);
LAMEXP_DELETE(logView);
}
+ else
+ {
+ MessageBeep(MB_ICONWARNING);
+ }
+}
+
+void ProcessingDialog::contextMenuTriggered(const QPoint &pos)
+{
+ m_contextMenu->popup(view_log->mapToGlobal(pos));
+}
+
+void ProcessingDialog::contextMenuActionTriggered(void)
+{
+ QModelIndex index = view_log->indexAt(view_log->mapFromGlobal(m_contextMenu->pos()));
+ logViewDoubleClicked(index.isValid() ? index : view_log->currentIndex());
}
////////////////////////////////////////////////////////////
diff --git a/src/Dialog_Processing.h b/src/Dialog_Processing.h
index 5fe602bd..69626cff 100644
--- a/src/Dialog_Processing.h
+++ b/src/Dialog_Processing.h
@@ -26,6 +26,7 @@
#include
class QMovie;
+class QMenu;
class ProgressModel;
class ProcessThread;
class FileListModel;
@@ -47,6 +48,8 @@ private slots:
void processFinished(const QUuid &jobId, const QString &outFileName, bool success);
void progressModelChanged(void);
void logViewDoubleClicked(const QModelIndex &index);
+ void contextMenuTriggered(const QPoint &pos);
+ void contextMenuActionTriggered(void);
protected:
void showEvent(QShowEvent *event);
@@ -66,6 +69,7 @@ private:
QMovie *m_progressIndicator;
ProgressModel *m_progressModel;
QStringList m_playList;
+ QMenu *m_contextMenu;
unsigned int m_runningThreads;
unsigned int m_currentFile;
unsigned int m_succeededFiles;
diff --git a/src/Encoder_Abstract.cpp b/src/Encoder_Abstract.cpp
index fdd44c6e..de965e24 100644
--- a/src/Encoder_Abstract.cpp
+++ b/src/Encoder_Abstract.cpp
@@ -22,12 +22,36 @@
#include "Encoder_Abstract.h"
#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)
{
+ if(!m_mutex_startProcess)
+ {
+ m_mutex_startProcess = new QMutex();
+ }
+
+ if(!m_handle_jobObject)
+ {
+ m_handle_jobObject = CreateJobObject(NULL, 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;
+ SetInformationJobObject(m_handle_jobObject, JobObjectExtendedLimitInformation, &jobExtendedLimitInfo, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
+ }
+ }
+
m_configBitrate = 0;
m_configRCMode = 0;
}
@@ -36,10 +60,40 @@ AbstractEncoder::~AbstractEncoder(void)
{
}
-//Setters
+/*
+ * Setters
+ */
+
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)
+{
+ QMutexLocker lock(m_mutex_startProcess);
+
+ emit messageLogged(commandline2string(program, args) + "\n");
+
+ process.setProcessChannelMode(QProcess::MergedChannels);
+ process.setReadChannel(QProcess::StandardOutput);
+ process.start(program, args);
+
+ if(process.waitForStarted())
+ {
+
+ AssignProcessToJobObject(m_handle_jobObject, process.pid()->hProcess);
+ SetPriorityClass(process.pid()->hProcess, BELOW_NORMAL_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);
diff --git a/src/Encoder_Abstract.h b/src/Encoder_Abstract.h
index dc8b2f2d..ff0507a8 100644
--- a/src/Encoder_Abstract.h
+++ b/src/Encoder_Abstract.h
@@ -25,6 +25,10 @@
#include
+class QProcess;
+class QStringList;
+class QMutex;
+
class AbstractEncoder : public QObject
{
Q_OBJECT
@@ -39,10 +43,18 @@ public:
void setBitrate(int bitrate);
void setRCMode(int mode);
+ 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 31181afb..f56131c4 100644
--- a/src/Encoder_MP3.cpp
+++ b/src/Encoder_MP3.cpp
@@ -45,14 +45,10 @@ MP3Encoder::~MP3Encoder(void)
bool MP3Encoder::encode(const AudioFileModel &sourceFile, const QString &outputFile, volatile bool *abortFlag)
{
- const QString baseName = QFileInfo(outputFile).fileName();
- emit statusUpdated(0);
-
QProcess process;
- process.setProcessChannelMode(QProcess::MergedChannels);
- process.setReadChannel(QProcess::StandardOutput);
-
+ const QString baseName = QFileInfo(outputFile).fileName();
QStringList args;
+
args << "--nohist";
args << "-h";
@@ -86,11 +82,7 @@ bool MP3Encoder::encode(const AudioFileModel &sourceFile, const QString &outputF
args << QDir::toNativeSeparators(sourceFile.filePath());
args << QDir::toNativeSeparators(outputFile);
- emit messageLogged(commandline2string(m_binary, args));
- emit messageLogged(QString());
-
- process.start(m_binary, args);
- if(!process.waitForStarted())
+ if(!startProcess(process, m_binary, args))
{
return false;
}
@@ -106,6 +98,7 @@ bool MP3Encoder::encode(const AudioFileModel &sourceFile, const QString &outputF
{
process.kill();
bAborted = true;
+ emit messageLogged("ABORTED BY USER !!!");
break;
}
process.waitForReadyRead();
@@ -128,7 +121,7 @@ bool MP3Encoder::encode(const AudioFileModel &sourceFile, const QString &outputF
}
else if(!text.isEmpty())
{
- emit messageLogged(text); //qDebug("%s", text.toUtf8().constData());
+ emit messageLogged(text);
}
}
}
@@ -139,6 +132,8 @@ bool MP3Encoder::encode(const AudioFileModel &sourceFile, const QString &outputF
process.kill();
process.waitForFinished(-1);
}
+
+ emit messageLogged(QString().sprintf("\n--> Exited with code: 0x%08x", process.exitCode()));
if(bTimeout || bAborted || process.exitStatus() != QProcess::NormalExit)
{
diff --git a/src/Encoder_MP3.h b/src/Encoder_MP3.h
index 677a4cf5..7c99cce6 100644
--- a/src/Encoder_MP3.h
+++ b/src/Encoder_MP3.h
@@ -36,10 +36,6 @@ public:
virtual bool encode(const AudioFileModel &sourceFile, const QString &outputFile, volatile bool *abortFlag);
virtual QString extension(void);
-signals:
- void statusUpdated(int progress);
- void messageLogged(const QString &line);
-
private:
const QString m_binary;
};
diff --git a/src/Main.cpp b/src/Main.cpp
index c381d8f0..7c933f0a 100644
--- a/src/Main.cpp
+++ b/src/Main.cpp
@@ -50,24 +50,6 @@ int lamexp_main(int argc, char* argv[])
//Init console
lamexp_init_console(argc, argv);
-
- //LPWSTR *szArglist;
- //int nArgs;
- //szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
- //
- //if(nArgs >= 2)
- //{
- // static HANDLE hConsole = NULL;
- // hConsole = CreateFile(L"CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
- // if(!SetConsoleCP(CP_UTF8))
- // {
- // wprintf(L"Failed to set CP !!!\n");
- // }
- // char buffer[4096];
- // WideCharToMultiByte(CP_UTF8, 0, szArglist[1], -1, buffer, 4096, NULL, NULL);
- // wprintf(L"%S\n", buffer);
- // WriteConsoleA(hConsole, buffer, strlen(buffer), NULL, NULL);
- //}
//Print version info
qDebug("LameXP - Audio Encoder Front-End");
@@ -87,7 +69,7 @@ int lamexp_main(int argc, char* argv[])
qDebug("CPU brand string : %s", cpuFeatures.brand);
qDebug(" CPU signature : Family: %d, Model: %d, Stepping: %d", cpuFeatures.family, cpuFeatures.model, cpuFeatures.stepping);
qDebug("CPU capabilities : MMX: %s, SSE: %s, SSE2: %s, SSE3: %s, SSSE3: %s, x64: %s", LAMEXP_BOOL(cpuFeatures.mmx), LAMEXP_BOOL(cpuFeatures.sse), LAMEXP_BOOL(cpuFeatures.sse2), LAMEXP_BOOL(cpuFeatures.sse3), LAMEXP_BOOL(cpuFeatures.ssse3), LAMEXP_BOOL(cpuFeatures.x64));
- qDebug("CPU no. of cores : %d\n", cpuFeatures.count);
+ qDebug(" Number of CPU's : %d\n", cpuFeatures.count);
//Initialize Qt
lamexp_init_qt(argc, argv);