#define VER_LAMEXP_MAJOR 4
#define VER_LAMEXP_MINOR_HI 0
#define VER_LAMEXP_MINOR_LO 0
-#define VER_LAMEXP_BUILD 54
+#define VER_LAMEXP_BUILD 57
#define VER_LAMEXP_SUFFIX TechPreview
/*
#include <Windows.h>
//Helper macros
-#define ABORT_IF_BUSY \
-if(m_banner->isVisible() || m_delayedFileTimer->isActive()) \
-{ \
- MessageBeep(MB_ICONEXCLAMATION); \
- return; \
-}
+#define ABORT_IF_BUSY if(m_banner->isVisible() || m_delayedFileTimer->isActive()) { MessageBeep(MB_ICONEXCLAMATION); return; }
+#define SET_TEXT_COLOR(WIDGET,COLOR) { QPalette _palette = WIDGET->palette(); _palette.setColor(QPalette::WindowText, COLOR); WIDGET->setPalette(_palette); }
+#define SET_FONT_BOLD(WIDGET,BOLD) { QFont _font = WIDGET->font(); _font.setBold(BOLD); WIDGET->setFont(_font); }
#define LINK(URL) QString("<a href=\"%1\">%2</a>").arg(URL).arg(URL)
+
//Helper class
class Index: public QObjectUserData
{
m_fileListModel(fileListModel),
m_metaData(metaInfo),
m_settings(settingsModel),
- m_accepted(false)
+ m_accepted(false),
+ m_firstTimeShown(true)
{
//Init the dialog, from the .ui file
setupUi(this);
m_dropNoteLabel = new QLabel(sourceFileView);
m_dropNoteLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
m_dropNoteLabel->setText("» You can drop in audio files here! «");
+ SET_FONT_BOLD(m_dropNoteLabel, true);
+ SET_TEXT_COLOR(m_dropNoteLabel, Qt::darkGray);
connect(buttonAddFiles, SIGNAL(clicked()), this, SLOT(addFilesButtonClicked()));
connect(buttonRemoveFile, SIGNAL(clicked()), this, SLOT(removeFileButtonClicked()));
connect(buttonClearFiles, SIGNAL(clicked()), this, SLOT(clearFilesButtonClicked()));
metaDataView->verticalHeader()->hide();
metaDataView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
while(writeMetaDataCheckBox->isChecked() != m_settings->writeMetaTags()) writeMetaDataCheckBox->click();
+ while(generatePlaylistCheckBox->isChecked() != m_settings->createPlaylist()) generatePlaylistCheckBox->click();
connect(buttonEditMeta, SIGNAL(clicked()), this, SLOT(editMetaButtonClicked()));
connect(buttonClearMeta, SIGNAL(clicked()), this, SLOT(clearMetaButtonClicked()));
connect(writeMetaDataCheckBox, SIGNAL(clicked()), this, SLOT(metaTagsEnabledChanged()));
-
+ connect(generatePlaylistCheckBox, SIGNAL(clicked()), this, SLOT(playlistEnabledChanged()));
+
//Setup "Compression" tab
m_encoderButtonGroup = new QButtonGroup(this);
m_encoderButtonGroup->addButton(radioButtonEncoderMP3, SettingsModel::MP3Encoder);
m_accepted = false;
m_dropNoteLabel->setGeometry(0, 0, sourceFileView->width(), sourceFileView->height());
modelReset();
- QTimer::singleShot(0, this, SLOT(windowShown()));
+ tabWidget->setCurrentIndex(0);
+
+ if(m_firstTimeShown)
+ {
+ m_firstTimeShown = false;
+ QTimer::singleShot(0, this, SLOT(windowShown()));
+ }
}
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
m_settings->writeMetaTags(writeMetaDataCheckBox->isChecked());
}
+
+/*
+ * Playlist enabled changed
+ */
+void MainWindow::playlistEnabledChanged(void)
+{
+ m_settings->createPlaylist(generatePlaylistCheckBox->isChecked());
+}
void rowsChanged(const QModelIndex &parent, int start, int end);
void modelReset(void);
void metaTagsEnabledChanged(void);
+ void playlistEnabledChanged(void);
protected:
void showEvent(QShowEvent *event);
void addFiles(const QStringList &files);
bool m_accepted;
+ bool m_firstTimeShown;
FileListModel *m_fileListModel;
QFileSystemModel *m_fileSystemModel;
QActionGroup *m_tabActionGroup;
#include <QCloseEvent>
#include <QDesktopServices>
#include <QUrl>
+#include <QUuid>
+#include <QFileInfo>
+
#include <Windows.h>
////////////////////////////////////////////////////////////
m_runningThreads = 0;
m_currentFile = 0;
m_userAborted = false;
+ m_playList.clear();
label_progress->setText("Encoding files, please wait...");
m_progressIndicator->start();
qDebug("Running jobs: %u", m_runningThreads);
+ if(!m_userAborted && m_settings->createPlaylist() && !m_settings->outputDir().isEmpty())
+ {
+ label_progress->setText("Creatig the play list, please wait...");
+ QApplication::processEvents();
+ writePlayList();
+ }
+
label_progress->setText(m_userAborted ? "Process was aborted by the user!" : "Alle files completed successfully.");
m_progressIndicator->stop();
progressBar->setValue(100);
}
+void ProcessingDialog::processFinished(const QUuid &jobId, const QString &outFileName, bool success)
+{
+ if(success)
+ {
+ m_playList.append(outFileName);
+ }
+}
+
////////////////////////////////////////////////////////////
// Private Functions
////////////////////////////////////////////////////////////
connect(thread, SIGNAL(finished()), this, SLOT(doneEncoding()), Qt::QueuedConnection);
connect(thread, SIGNAL(processStateInitialized(QUuid,QString,QString,int)), m_progressModel, SLOT(addJob(QUuid,QString,QString,int)), Qt::QueuedConnection);
connect(thread, SIGNAL(processStateChanged(QUuid,QString,int)), m_progressModel, SLOT(updateJob(QUuid,QString,int)), Qt::QueuedConnection);
+ connect(thread, SIGNAL(processStateFinished(QUuid,QString,bool)), this, SLOT(processFinished(QUuid,QString,bool)), Qt::QueuedConnection);
m_runningThreads++;
thread->start();
}
+void ProcessingDialog::writePlayList(void)
+{
+ QString playListName = (m_metaInfo->fileAlbum().isEmpty() ? "Playlist" : m_metaInfo->fileAlbum());
+
+ const static char *invalidChars = "\\/:*?\"<>|";
+ for(int i = 0; invalidChars[i]; i++)
+ {
+ playListName.replace(invalidChars[i], ' ');
+ playListName = playListName.simplified();
+ }
+
+ QString playListFile = QString("%1/%2.m3u").arg(m_settings->outputDir(), playListName);
+
+ int counter = 1;
+ while(QFileInfo(playListFile).exists())
+ {
+ playListFile = QString("%1/%2 (%3).m3u").arg(m_settings->outputDir(), playListName, QString::number(++counter));
+ }
+
+ QFile playList(playListFile);
+ if(playList.open(QIODevice::WriteOnly))
+ {
+ playList.write("#EXTM3U\r\n");
+ for(int i = 0; i < m_playList.count(); i++)
+ {
+ playList.write(QFileInfo(m_playList.at(i)).fileName().toUtf8().constData());
+ playList.write("\r\n");
+ }
+ playList.close();
+ }
+}
+
AudioFileModel ProcessingDialog::updateMetaInfo(const AudioFileModel &audioFile)
{
if(!m_settings->writeMetaTags())
#include "../tmp/UIC_ProcessingDialog.h"
+#include <QUuid>
+
class QMovie;
class ProgressModel;
class ProcessThread;
void initEncoding(void);
void doneEncoding(void);
void abortEncoding(void);
+ void processFinished(const QUuid &jobId, const QString &outFileName, bool success);
protected:
void showEvent(QShowEvent *event);
void setCloseButtonEnabled(bool enabled);
void startNextJob(void);
AudioFileModel updateMetaInfo(const AudioFileModel &audioFile);
-
+ void writePlayList(void);
QList<AudioFileModel> m_pendingJobs;
SettingsModel *m_settings;
QList<ProcessThread*> m_threadList;
QMovie *m_progressIndicator;
ProgressModel *m_progressModel;
+ QStringList m_playList;
unsigned int m_runningThreads;
unsigned int m_currentFile;
bool m_userAborted;
//Print version info
qDebug("LameXP - Audio Encoder Front-End");
- qDebug("Version %d.%02d %s, Build %d [%s], MSVC compiler v%02d.%02d", lamexp_version_major(), lamexp_version_minor(), lamexp_version_release(), lamexp_version_build(), lamexp_version_date().toString(Qt::ISODate).toLatin1().constData(), _MSC_VER / 100, _MSC_VER % 100);
+ qDebug("Version %d.%02d %s, Build %d [%s], compiled with %s", lamexp_version_major(), lamexp_version_minor(), lamexp_version_release(), lamexp_version_build(), lamexp_version_date().toString(Qt::ISODate).toLatin1().constData(), lamexp_version_compiler());
qDebug("Copyright (C) 2004-%04d LoRd_MuldeR <MuldeR2@GMX.de>\n", max(lamexp_version_date().year(),QDate::currentDate().year()));
//print license info
//Detect CPU capabilities
lamexp_cpu_t cpuFeatures = lamexp_detect_cpu_features();
- 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("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);
//Initialize Qt
lamexp_init_qt(argc, argv);
SplashScreen::showSplash(poInitializationThread);
LAMEXP_DELETE(poInitializationThread);
- //Show main window
+ //Create main window
+ MainWindow *poMainWindow = new MainWindow(fileListModel, metaInfo, settingsModel);
+
+ //Main application loop
while(bAccepted)
{
- MainWindow *poMainWindow = new MainWindow(fileListModel, metaInfo, settingsModel);
+ //Show main window
poMainWindow->show();
iResult = QApplication::instance()->exec();
bAccepted = poMainWindow->isAccepted();
- LAMEXP_DELETE(poMainWindow);
//Show processing dialog
if(bAccepted && fileListModel->rowCount() > 0)
}
//Free models
+ LAMEXP_DELETE(poMainWindow);
LAMEXP_DELETE(fileListModel);
LAMEXP_DELETE(metaInfo);
LAMEXP_DELETE(settingsModel);
static const char *g_settingsId_compressionBitrate = "Compression/Bitrate";
static const char *g_settingsId_outputDir = "OutputDirectory";
static const char *g_settingsId_writeMetaTags = "WriteMetaTags";
+static const char *g_settingsId_createPlaylist = "AutoCreatePlaylist";
#define MAKE_GETTER1(OPT,DEF) int SettingsModel::OPT(void) { return m_settings->value(g_settingsId_##OPT, DEF).toInt(); }
#define MAKE_SETTER1(OPT) void SettingsModel::OPT(int value) { m_settings->setValue(g_settingsId_##OPT, value); }
MAKE_GETTER1(compressionRCMode, 0)
MAKE_SETTER1(compressionRCMode)
-MAKE_GETTER1(compressionBitrate, 0)
+MAKE_GETTER1(compressionBitrate, 7)
MAKE_SETTER1(compressionBitrate)
MAKE_GETTER2(outputDir, QString())
MAKE_GETTER3(writeMetaTags, true)
MAKE_SETTER3(writeMetaTags)
+
+MAKE_GETTER3(createPlaylist, true)
+MAKE_SETTER3(createPlaylist)
MAKE_GETTER_DEC1(compressionBitrate);
MAKE_GETTER_DEC2(outputDir);
MAKE_GETTER_DEC3(writeMetaTags);
+ MAKE_GETTER_DEC3(createPlaylist);
//Setters
MAKE_SETTER_DEC1(licenseAccepted);
MAKE_SETTER_DEC1(compressionEncoder);
MAKE_SETTER_DEC2(outputDir);
MAKE_SETTER_DEC3(writeMetaTags);
+ MAKE_SETTER_DEC3(createPlaylist);
void validate(void);
#include <QUuid>
#include <QFileInfo>
#include <QDir>
+#include <QMutex>
+#include <QMutexLocker>
#include <limits.h>
#include <time.h>
+QMutex *ProcessThread::m_mutex_genFileName = NULL;
+
////////////////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////////////////
m_jobId(QUuid::createUuid()),
m_aborted(false)
{
+ if(m_mutex_genFileName)
+ {
+ m_mutex_genFileName = new QMutex;
+ }
+
connect(m_encoder, SIGNAL(statusUpdated(int)), this, SLOT(handleUpdate(int)), Qt::DirectConnection);
}
if(bSuccess)
{
- bSuccess = QFileInfo(outFileName).exists();
+ QFileInfo fileInfo(outFileName);
+ bSuccess = fileInfo.exists() && fileInfo.isFile() && (fileInfo.size() > 0);
}
emit processStateChanged(m_jobId, (bSuccess ? "Done." : (m_aborted ? "Aborted!" : "Failed!")), (bSuccess ? ProgressModel::JobComplete : ProgressModel::JobFailed));
+ emit processStateFinished(m_jobId, outFileName, bSuccess);
+
qDebug("Process thread is done.");
}
QString ProcessThread::generateOutFileName(void)
{
+ QMutexLocker lock(m_mutex_genFileName);
+
int n = 1;
QString baseName = QFileInfo(m_audioFile.filePath()).completeBaseName();
outFileName = QString("%1/%2 (%3).%4").arg(targetDir, baseName, QString::number(++n), m_encoder->extension());
}
+ QFile placeholder(outFileName);
+ if(placeholder.open(QIODevice::WriteOnly))
+ {
+ placeholder.close();
+ }
+
return outFileName;
}
// EVENTS
////////////////////////////////////////////////////////////
-/*NONE*/
\ No newline at end of file
+/*NONE*/
#include "Model_AudioFile.h"
#include "Encoder_Abstract.h"
+class QMutex;
+
class ProcessThread: public QThread
{
Q_OBJECT
signals:
void processStateInitialized(const QUuid &jobId, const QString &jobName, const QString &jobInitialStatus, int jobInitialState);
void processStateChanged(const QUuid &jobId, const QString &newStatus, int newState);
+ void processStateFinished(const QUuid &jobId, const QString &outFileName, bool success);
private:
QString generateOutFileName(void);
AbstractEncoder *m_encoder;
const QString m_outputDirectory;
volatile bool m_aborted;
+
+ static QMutex *m_mutex_genFileName;
};