From 489829fb3743b23b82f962cb7cdec4e56288b5bc Mon Sep 17 00:00:00 2001 From: lordmulder Date: Mon, 16 May 2011 18:05:50 +0200 Subject: [PATCH] Refactored Cue Sheet splitter thread: Now we simply pass a pointer to the Cue Sheet model into the Cue Sheet splitter thread instead of having to copying all the information in the Cue Sheet import dialog. Also the Cue Sheet import process can now be aborted by the user. --- etc/Translation/Blank.ts | 4 + etc/Translation/LameXP_DE.ts | 4 + etc/Translation/LameXP_ES.ts | 4 + etc/Translation/LameXP_FR.ts | 4 + etc/Translation/LameXP_IT.ts | 4 + etc/Translation/LameXP_KR.ts | 4 + etc/Translation/LameXP_RU.ts | 4 + etc/Translation/LameXP_UK.ts | 4 + res/localization/LameXP_DE.qm | Bin 67885 -> 68101 bytes src/Config.h | 6 +- src/Dialog_CueImport.cpp | 51 ++++--------- src/Dialog_WorkingBanner.cpp | 5 ++ src/Dialog_WorkingBanner.h | 3 + src/Model_CueSheet.cpp | 44 +++++++++++ src/Model_CueSheet.h | 6 +- src/Thread_CueSplitter.cpp | 137 +++++++++++++++++++--------------- src/Thread_CueSplitter.h | 29 +++---- 17 files changed, 199 insertions(+), 114 deletions(-) diff --git a/etc/Translation/Blank.ts b/etc/Translation/Blank.ts index 072c5c44..348b45de 100644 --- a/etc/Translation/Blank.ts +++ b/etc/Translation/Blank.ts @@ -341,6 +341,10 @@ Splitting file(s), please wait... + + Process was aborted by the user after %1 track(s)! + + An unexpected error has occured while splitting the Cue Sheet! diff --git a/etc/Translation/LameXP_DE.ts b/etc/Translation/LameXP_DE.ts index ca2bd41e..0d4c0f36 100644 --- a/etc/Translation/LameXP_DE.ts +++ b/etc/Translation/LameXP_DE.ts @@ -353,6 +353,10 @@ Abort Abbrechen + + Process was aborted by the user after %1 track(s)! + Der Vorgang wurde vom Benutzter nach %1 Track(s) abgebrochen! + CueSheetImport diff --git a/etc/Translation/LameXP_ES.ts b/etc/Translation/LameXP_ES.ts index 4f1391eb..29ec05b2 100644 --- a/etc/Translation/LameXP_ES.ts +++ b/etc/Translation/LameXP_ES.ts @@ -353,6 +353,10 @@ Abort Cancelar + + Process was aborted by the user after %1 track(s)! + + CueSheetImport diff --git a/etc/Translation/LameXP_FR.ts b/etc/Translation/LameXP_FR.ts index 17fd4982..862369e9 100644 --- a/etc/Translation/LameXP_FR.ts +++ b/etc/Translation/LameXP_FR.ts @@ -357,6 +357,10 @@ Abort Abandonner + + Process was aborted by the user after %1 track(s)! + + CueSheetImport diff --git a/etc/Translation/LameXP_IT.ts b/etc/Translation/LameXP_IT.ts index dc61af37..e3af3cd2 100644 --- a/etc/Translation/LameXP_IT.ts +++ b/etc/Translation/LameXP_IT.ts @@ -353,6 +353,10 @@ Abort Ferma + + Process was aborted by the user after %1 track(s)! + + CueSheetImport diff --git a/etc/Translation/LameXP_KR.ts b/etc/Translation/LameXP_KR.ts index 862dce83..f3aed3d8 100644 --- a/etc/Translation/LameXP_KR.ts +++ b/etc/Translation/LameXP_KR.ts @@ -353,6 +353,10 @@ Abort 취소 + + Process was aborted by the user after %1 track(s)! + + CueSheetImport diff --git a/etc/Translation/LameXP_RU.ts b/etc/Translation/LameXP_RU.ts index 4dab993a..ba83fc99 100644 --- a/etc/Translation/LameXP_RU.ts +++ b/etc/Translation/LameXP_RU.ts @@ -353,6 +353,10 @@ Abort Отмена + + Process was aborted by the user after %1 track(s)! + + CueSheetImport diff --git a/etc/Translation/LameXP_UK.ts b/etc/Translation/LameXP_UK.ts index d1c1a46b..0c2e7949 100644 --- a/etc/Translation/LameXP_UK.ts +++ b/etc/Translation/LameXP_UK.ts @@ -353,6 +353,10 @@ Abort + + Process was aborted by the user after %1 track(s)! + + CueSheetImport diff --git a/res/localization/LameXP_DE.qm b/res/localization/LameXP_DE.qm index f613ec6ffd679c408574ff44db30f9ec9e2eba7a..edc4a39b6f22791e6cd859fae300d25f544df49b 100644 GIT binary patch delta 4169 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 aTjivg9~KZetJOTGxRl-va}@pBUicr9_YnC2 delta 4124 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 aXn_8hiAh-B!KTp>uUgqIM{f3RTkwCqRQ2}& diff --git a/src/Config.h b/src/Config.h index 3848047b..8611572e 100644 --- a/src/Config.h +++ b/src/Config.h @@ -28,9 +28,9 @@ #define VER_LAMEXP_MAJOR 4 #define VER_LAMEXP_MINOR_HI 0 #define VER_LAMEXP_MINOR_LO 2 -#define VER_LAMEXP_TYPE Alpha -#define VER_LAMEXP_PATCH 15 -#define VER_LAMEXP_BUILD 526 +#define VER_LAMEXP_TYPE Beta +#define VER_LAMEXP_PATCH 1 +#define VER_LAMEXP_BUILD 528 /////////////////////////////////////////////////////////////////////////////// // Tools versions diff --git a/src/Dialog_CueImport.cpp b/src/Dialog_CueImport.cpp index 45d33d92..4d6e5f5d 100644 --- a/src/Dialog_CueImport.cpp +++ b/src/Dialog_CueImport.cpp @@ -111,6 +111,11 @@ int CueImportDialog::exec(void) } m_outputDir = QString("%1/%2").arg(cueFileInfo.canonicalPath(), cueFileInfo.completeBaseName()); + for(int n = 2; QDir(m_outputDir).exists(); n++) + { + m_outputDir = QString("%1/%2 (%3)").arg(cueFileInfo.canonicalPath(), cueFileInfo.completeBaseName(), QString::number(n)); + } + setWindowTitle(QString("%1: %2").arg(windowTitle().split(":", QString::SkipEmptyParts).first().trimmed(), cueFileInfo.fileName())); int iResult = m_model->loadCueSheet(m_cueFileName, QApplication::instance()); @@ -259,7 +264,7 @@ bool CueImportDialog::analyzeFiles(QStringList &files) progress->show(tr("Analyzing file(s), please wait..."), analyzer); progress->close(); - if(analyzer->filesAccepted() < files.count()) + if(analyzer->filesAccepted() < static_cast(files.count())) { if(QMessageBox::warning(this, tr("Analysis Failed"), tr("Warning: The format of some of the input files could not be determined!"), tr("Continue Anyway"), tr("Abort")) == 1) { @@ -275,55 +280,29 @@ bool CueImportDialog::analyzeFiles(QStringList &files) void CueImportDialog::splitFiles(void) { - int nTracksSkipped = 0; + QString baseName = QFileInfo(m_cueFileName).completeBaseName().replace(".", " ").left(42).trimmed(); WorkingBanner *progress = new WorkingBanner(this); - CueSplitter *splitter = new CueSplitter(m_outputDir, QFileInfo(m_cueFileName).completeBaseName().replace(".", " ").left(42).trimmed(), m_fileInfo); - splitter->setAlbumInfo(m_model->getAlbumPerformer(), m_model->getAlbumTitle()); + CueSplitter *splitter = new CueSplitter(m_outputDir, baseName, m_model, m_fileInfo); connect(splitter, SIGNAL(fileSelected(QString)), progress, SLOT(setText(QString)), Qt::QueuedConnection); + connect(progress, SIGNAL(userAbort()), splitter, SLOT(abortProcess()), Qt::DirectConnection); connect(splitter, SIGNAL(fileSplit(AudioFileModel)), m_fileList, SLOT(addFile(AudioFileModel)), Qt::QueuedConnection); - int nFiles = m_model->getFileCount(); - for(int i = 0; i < nFiles; i++) - { - QString currentFileName = m_model->getFileName(i); - int nTracks = m_model->getTrackCount(i); - - for(int j = 0; j < nTracks; j++) - { - int trackNo = m_model->getTrackNo(i, j); - double startIndex = std::numeric_limits::quiet_NaN(); - double duration = std::numeric_limits::quiet_NaN(); - m_model->getTrackIndex(i, j, &startIndex, &duration); - - AudioFileModel metaInfo(QString().sprintf("cue://File%02d/Track%02d", i, j)); - metaInfo.setFileName(m_model->getTrackTitle(i, j)); - metaInfo.setFileArtist(m_model->getTrackPerformer(i, j)); - metaInfo.setFilePosition(trackNo); - - try - { - splitter->addTrack(trackNo, currentFileName, startIndex, duration, metaInfo); - } - catch(char *err) - { - qWarning("Failed to add track #%02d: %s", trackNo, err); - nTracksSkipped++; - } - } - } - progress->show(tr("Splitting file(s), please wait..."), splitter); progress->close(); - if(!splitter->getSuccess()) + if(splitter->getAborted()) + { + QMessageBox::warning(this, tr("Cue Sheet Error"), tr("Process was aborted by the user after %1 track(s)!").arg(QString::number(splitter->getTracksSuccess()))); + } + else if(!splitter->getSuccess()) { QMessageBox::warning(this, tr("Cue Sheet Error"), tr("An unexpected error has occured while splitting the Cue Sheet!")); } else { - QString text = QString("%1").arg(tr("Imported %1 track(s) from the Cue Sheet and skipped %2 track(s).").arg(QString::number(splitter->getTracksSuccess()), QString::number(splitter->getTracksSkipped() + nTracksSkipped))); + QString text = QString("%1").arg(tr("Imported %1 track(s) from the Cue Sheet and skipped %2 track(s).").arg(QString::number(splitter->getTracksSuccess()), QString::number(splitter->getTracksSkipped() /*+ nTracksSkipped*/))); QMessageBox::information(this, tr("Cue Sheet Completed"), text); } diff --git a/src/Dialog_WorkingBanner.cpp b/src/Dialog_WorkingBanner.cpp index 971cf35b..8340dfc4 100644 --- a/src/Dialog_WorkingBanner.cpp +++ b/src/Dialog_WorkingBanner.cpp @@ -139,6 +139,11 @@ void WorkingBanner::show(const QString &text, QEventLoop *loop) void WorkingBanner::keyPressEvent(QKeyEvent *event) { + if(event->key() == Qt::Key_Escape) + { + emit userAbort(); + } + event->ignore(); } diff --git a/src/Dialog_WorkingBanner.h b/src/Dialog_WorkingBanner.h index 7ccf7a15..8b6cee91 100644 --- a/src/Dialog_WorkingBanner.h +++ b/src/Dialog_WorkingBanner.h @@ -47,6 +47,9 @@ private: public slots: void setText(const QString &text); +signals: + void userAbort(void); + protected: void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); diff --git a/src/Model_CueSheet.cpp b/src/Model_CueSheet.cpp index 853acb96..1781d463 100644 --- a/src/Model_CueSheet.cpp +++ b/src/Model_CueSheet.cpp @@ -95,6 +95,8 @@ private: // Constructor & Destructor //////////////////////////////////////////////////////////// +QMutex CueSheetModel::m_mutex(QMutex::Recursive); + CueSheetModel::CueSheetModel() : m_fileIcon(":/icons/music.png"), @@ -127,6 +129,8 @@ CueSheetModel::~CueSheetModel(void) QModelIndex CueSheetModel::index(int row, int column, const QModelIndex &parent) const { + QMutexLocker lock(&m_mutex); + if(!parent.isValid()) { return (row < m_files.count()) ? createIndex(row, column, m_files.at(row)) : QModelIndex(); @@ -143,11 +147,14 @@ QModelIndex CueSheetModel::index(int row, int column, const QModelIndex &parent) int CueSheetModel::columnCount(const QModelIndex &parent) const { + QMutexLocker lock(&m_mutex); return 4; } int CueSheetModel::rowCount(const QModelIndex &parent) const { + QMutexLocker lock(&m_mutex); + if(!parent.isValid()) { return m_files.count(); @@ -164,6 +171,8 @@ int CueSheetModel::rowCount(const QModelIndex &parent) const QModelIndex CueSheetModel::parent(const QModelIndex &child) const { + QMutexLocker lock(&m_mutex); + if(child.isValid()) { CueSheetItem *childItem = static_cast(child.internalPointer()); @@ -178,6 +187,8 @@ QModelIndex CueSheetModel::parent(const QModelIndex &child) const QVariant CueSheetModel::headerData (int section, Qt::Orientation orientation, int role) const { + QMutexLocker lock(&m_mutex); + if(role == Qt::DisplayRole) { switch(section) @@ -207,6 +218,8 @@ QVariant CueSheetModel::headerData (int section, Qt::Orientation orientation, in QVariant CueSheetModel::data(const QModelIndex &index, int role) const { + QMutexLocker lock(&m_mutex); + if(role == Qt::DisplayRole) { CueSheetItem *item = reinterpret_cast(index.internalPointer()); @@ -331,6 +344,8 @@ QVariant CueSheetModel::data(const QModelIndex &index, int role) const void CueSheetModel::clearData(void) { + QMutexLocker lock(&m_mutex); + beginResetModel(); while(!m_files.isEmpty()) delete m_files.takeLast(); endResetModel(); @@ -342,11 +357,14 @@ void CueSheetModel::clearData(void) int CueSheetModel::getFileCount(void) { + QMutexLocker lock(&m_mutex); return m_files.count(); } QString CueSheetModel::getFileName(int fileIndex) { + QMutexLocker lock(&m_mutex); + if(fileIndex < 0 || fileIndex >= m_files.count()) { return QString(); @@ -357,6 +375,8 @@ QString CueSheetModel::getFileName(int fileIndex) int CueSheetModel::getTrackCount(int fileIndex) { + QMutexLocker lock(&m_mutex); + if(fileIndex < 0 || fileIndex >= m_files.count()) { return -1; @@ -367,6 +387,8 @@ int CueSheetModel::getTrackCount(int fileIndex) int CueSheetModel::getTrackNo(int fileIndex, int trackIndex) { + QMutexLocker lock(&m_mutex); + if(fileIndex >= 0 && fileIndex < m_files.count()) { CueSheetFile *currentFile = m_files.at(fileIndex); @@ -381,6 +403,8 @@ int CueSheetModel::getTrackNo(int fileIndex, int trackIndex) void CueSheetModel::getTrackIndex(int fileIndex, int trackIndex, double *startIndex, double *duration) { + QMutexLocker lock(&m_mutex); + *startIndex = std::numeric_limits::quiet_NaN(); *duration = std::numeric_limits::quiet_NaN(); @@ -398,6 +422,8 @@ void CueSheetModel::getTrackIndex(int fileIndex, int trackIndex, double *startIn QString CueSheetModel::getTrackPerformer(int fileIndex, int trackIndex) { + QMutexLocker lock(&m_mutex); + if(fileIndex >= 0 && fileIndex < m_files.count()) { CueSheetFile *currentFile = m_files.at(fileIndex); @@ -407,11 +433,14 @@ QString CueSheetModel::getTrackPerformer(int fileIndex, int trackIndex) return currentTrack->performer(); } } + return QString(); } QString CueSheetModel::getTrackTitle(int fileIndex, int trackIndex) { + QMutexLocker lock(&m_mutex); + if(fileIndex >= 0 && fileIndex < m_files.count()) { CueSheetFile *currentFile = m_files.at(fileIndex); @@ -421,15 +450,30 @@ QString CueSheetModel::getTrackTitle(int fileIndex, int trackIndex) return currentTrack->title(); } } + return QString(); } +QString CueSheetModel::getAlbumPerformer(void) +{ + QMutexLocker lock(&m_mutex); + return m_albumPerformer; +} + +QString CueSheetModel::getAlbumTitle(void) +{ + QMutexLocker lock(&m_mutex); + return m_albumTitle; +} + //////////////////////////////////////////////////////////// // Cue Sheet Parser //////////////////////////////////////////////////////////// int CueSheetModel::loadCueSheet(const QString &cueFileName, QCoreApplication *application) { + QMutexLocker lock(&m_mutex); + QFile cueFile(cueFileName); if(!cueFile.open(QIODevice::ReadOnly)) { diff --git a/src/Model_CueSheet.h b/src/Model_CueSheet.h index cf817e53..43ba8119 100644 --- a/src/Model_CueSheet.h +++ b/src/Model_CueSheet.h @@ -65,8 +65,8 @@ public: void getTrackIndex(int fileIndex, int trackIndex, double *startIndex, double *duration); QString getTrackPerformer(int fileIndex, int trackIndex); QString getTrackTitle(int fileIndex, int trackIndex); - QString getAlbumPerformer(void) { return m_albumPerformer; } - QString getAlbumTitle(void) { return m_albumTitle; } + QString getAlbumPerformer(void); + QString getAlbumTitle(void); //Cue Sheet functions int loadCueSheet(const QString &cueFile, QCoreApplication *application = NULL); @@ -76,6 +76,8 @@ private: double parseTimeIndex(const QString &index); QString indexToString(const double index) const; + static QMutex m_mutex; + QList m_files; QString m_albumTitle; QString m_albumPerformer; diff --git a/src/Thread_CueSplitter.cpp b/src/Thread_CueSplitter.cpp index e9746e0e..b36ba461 100644 --- a/src/Thread_CueSplitter.cpp +++ b/src/Thread_CueSplitter.cpp @@ -24,7 +24,7 @@ #include "Global.h" #include "LockedFile.h" #include "Model_AudioFile.h" -#include "PlaylistImporter.h" +#include "Model_CueSheet.h" #include "Registry_Decoder.h" #include "Decoder_Abstract.h" @@ -41,8 +41,9 @@ // Constructor //////////////////////////////////////////////////////////// -CueSplitter::CueSplitter(const QString &outputDir, const QString &baseName, const QList &inputFiles) +CueSplitter::CueSplitter(const QString &outputDir, const QString &baseName, CueSheetModel *model, const QList &inputFilesInfo) : + m_model(model), m_outputDir(outputDir), m_baseName(baseName), m_soxBin(lamexp_lookup_tool("sox.exe")) @@ -52,18 +53,16 @@ CueSplitter::CueSplitter(const QString &outputDir, const QString &baseName, cons qFatal("Invalid path to SoX binary. Tool not initialized properly."); } - m_albumPerformer.clear(); - m_albumTitle.clear(); m_decompressedFiles.clear(); m_tempFiles.clear(); qDebug("\n[CueSplitter::CueSplitter]"); - int nInputFiles = inputFiles.count(); + int nInputFiles = inputFilesInfo.count(); for(int i = 0; i < nInputFiles; i++) { - m_inputFiles.insert(inputFiles[i].filePath(), inputFiles[i]); - qDebug("%02d <%s>", i, inputFiles[i].filePath().toUtf8().constData()); + m_inputFilesInfo.insert(inputFilesInfo[i].filePath(), inputFilesInfo[i]); + qDebug("%02d <%s>", i, inputFilesInfo[i].filePath().toUtf8().constData()); } qDebug("All input files added."); @@ -85,6 +84,7 @@ CueSplitter::~CueSplitter(void) void CueSplitter::run() { m_bSuccess = false; + m_bAborted = false; m_abortFlag = false; m_nTracksSuccess = 0; m_nTracksSkipped = 0; @@ -97,13 +97,13 @@ void CueSplitter::run() return; } - QStringList inputFileList = m_inputFiles.keys(); + QStringList inputFileList = m_inputFilesInfo.keys(); int nInputFiles = inputFileList.count(); //Decompress all input files for(int i = 0; i < nInputFiles; i++) { - AudioFileModel &inputFileInfo = m_inputFiles[inputFileList.at(i)]; + AudioFileModel &inputFileInfo = m_inputFilesInfo[inputFileList.at(i)]; if(inputFileInfo.formatContainerType().compare("Wave", Qt::CaseInsensitive) || inputFileInfo.formatAudioType().compare("PCM", Qt::CaseInsensitive)) { AbstractDecoder *decoder = DecoderRegistry::lookup(inputFileInfo.formatContainerType(), inputFileInfo.formatContainerProfile(), inputFileInfo.formatAudioType(), inputFileInfo.formatAudioProfile(), inputFileInfo.formatAudioVersion()); @@ -135,50 +135,78 @@ void CueSplitter::run() { m_decompressedFiles.insert(inputFileList.at(i), inputFileList.at(i)); } + if(m_abortFlag) + { + m_bAborted = true; + qWarning("The user has requested to abort the process!"); + return; + } } - int nTracks = min(min(min(m_trackFile.count(), m_trackNo.count()), min(m_trackOffset.count(), m_trackLength.count())), m_trackMetaInfo.count()); + int nFiles = m_model->getFileCount(); + QString albumPerformer = m_model->getAlbumPerformer(); + QString albumTitle = m_model->getAlbumTitle(); //Now split all tracks - for(int i = 0; i < nTracks; i++) + for(int i = 0; i < nFiles; i++) { - QString outputFile = QString("%1/%2 - Track %3.wav").arg(m_outputDir, m_baseName, QString().sprintf("%02d", m_trackNo.at(i))); - for(int n = 2; QFileInfo(outputFile).exists(); n++) - { - outputFile = QString("%1/%2 - Track %3 (%4).wav").arg(m_outputDir, m_baseName, QString().sprintf("%02d", m_trackNo.at(i)), QString::number(n)); - } + int nTracks = m_model->getTrackCount(i); + QString trackFile = m_model->getFileName(i); + int maxProgress = 0; - emit fileSelected(QFileInfo(outputFile).fileName()); - splitFile(outputFile, m_trackNo.at(i), m_trackFile.at(i), m_trackOffset.at(i), m_trackLength.at(i), m_trackMetaInfo.at(i)); + for(int j = 0; j < nTracks; j++) + { + int trackNo = m_model->getTrackNo(i, j); + double trackOffset = std::numeric_limits::quiet_NaN(); + double trackLength = std::numeric_limits::quiet_NaN(); + m_model->getTrackIndex(i, j, &trackOffset, &trackLength); + + if((trackNo < 0) || _isnan(trackOffset) || _isnan(trackLength)) + { + qWarning("Failed to fetch information for track #%d of file #%d!", j, i); + continue; + } + + AudioFileModel trackMetaInfo(QString().sprintf("cue://File%02d/Track%02d", i, j)); + trackMetaInfo.setFileName(m_model->getTrackTitle(i, j)); + trackMetaInfo.setFileArtist(m_model->getTrackPerformer(i, j)); + trackMetaInfo.setFilePosition(trackNo); + + if(!albumTitle.isEmpty()) + { + trackMetaInfo.setFileAlbum(albumTitle); + } + if(!albumPerformer.isEmpty() && trackMetaInfo.fileArtist().isEmpty()) + { + trackMetaInfo.setFileArtist(albumPerformer); + } + if(_finite(trackLength)) + { + trackMetaInfo.setFileDuration(static_cast(abs(trackLength))); + } + + QString outputFile = QString("%1/%2 - Track %3.wav").arg(m_outputDir, m_baseName, QString().sprintf("%02d", trackNo)); + for(int n = 2; QFileInfo(outputFile).exists(); n++) + { + outputFile = QString("%1/%2 - Track %3 (%4).wav").arg(m_outputDir, m_baseName, QString().sprintf("%02d", trackNo), QString::number(n)); + } + + emit fileSelected(QFileInfo(outputFile).fileName()); + splitFile(outputFile, trackNo, trackFile, trackOffset, trackLength, trackMetaInfo, maxProgress); + + if(m_abortFlag) + { + m_bAborted = true; + qWarning("The user has requested to abort the process!"); + return; + } + } } qDebug("All files were split.\n"); m_bSuccess = true; } -void CueSplitter::addTrack(const int trackNo, const QString &file, const double offset, const double length, const AudioFileModel &metaInfo) -{ - - if(m_inputFiles.contains(file)) - { - m_trackFile << file; - m_trackNo << trackNo; - m_trackOffset << offset; - m_trackLength << length; - m_trackMetaInfo << metaInfo; - } - else - { - throw "The input file is unknown/missing!"; - } -} - -void CueSplitter::setAlbumInfo(const QString &performer, const QString &title) -{ - if(!performer.isEmpty()) m_albumPerformer = performer; - if(!title.isEmpty()) m_albumTitle = title; -} - //////////////////////////////////////////////////////////// // Slots //////////////////////////////////////////////////////////// @@ -192,7 +220,7 @@ void CueSplitter::handleUpdate(int progress) // Privtae Functions //////////////////////////////////////////////////////////// -void CueSplitter::splitFile(const QString &output, const int trackNo, const QString &file, const double offset, const double length, const AudioFileModel &metaInfo) +void CueSplitter::splitFile(const QString &output, const int trackNo, const QString &file, const double offset, const double length, const AudioFileModel &metaInfo, int &maxProgress) { qDebug("[Track %02d]", trackNo); qDebug("File: <%s>", file.toUtf8().constData()); @@ -212,23 +240,12 @@ void CueSplitter::splitFile(const QString &output, const int trackNo, const QStr QString decompressedInput = m_decompressedFiles[file]; qDebug("Input: <%s>", decompressedInput.toUtf8().constData()); + emit fileSelected(QString("%1 [%2%]").arg(baseName, QString::number(maxProgress))); + AudioFileModel outFileInfo(metaInfo); outFileInfo.setFilePath(output); outFileInfo.setFormatContainerType("Wave"); outFileInfo.setFormatAudioType("PCM"); - - if(length != std::numeric_limits::infinity()) - { - outFileInfo.setFileDuration(static_cast(abs(length))); - } - if(!m_albumTitle.isEmpty()) - { - outFileInfo.setFileAlbum(m_albumTitle); - } - if(!m_albumPerformer.isEmpty() && outFileInfo.fileArtist().isEmpty()) - { - outFileInfo.setFileArtist(m_albumPerformer); - } QStringList args; args << "-S" << "-V3"; @@ -237,12 +254,12 @@ void CueSplitter::splitFile(const QString &output, const int trackNo, const QStr args << QDir::toNativeSeparators(output); //Add trim parameters, if needed - if(offset != 0.0 || length != std::numeric_limits::infinity()) + if(_finite(offset) || _finite(length)) { args << "trim"; args << indexToString(offset); - if((length != std::numeric_limits::quiet_NaN()) && (length != std::numeric_limits::infinity())) + if(_finite(length)) { args << indexToString(length); } @@ -275,6 +292,7 @@ void CueSplitter::splitFile(const QString &output, const int trackNo, const QStr if(m_abortFlag) { process.kill(); + qWarning("Process was aborted on user request!"); break; } process.waitForReadyRead(); @@ -294,7 +312,8 @@ void CueSplitter::splitFile(const QString &output, const int trackNo, const QStr int progress = rxProgress.cap(1).toInt(&ok); if(ok) { - emit fileSelected(QString("%1 [%2%]").arg(baseName, QString::number(progress))); + maxProgress = max(maxProgress, progress); + emit fileSelected(QString("%1 [%2%]").arg(baseName, QString::number(maxProgress))); } } else if(rxChannels.lastIndexIn(text) >= 0) @@ -361,7 +380,7 @@ void CueSplitter::splitFile(const QString &output, const int trackNo, const QStr QString CueSplitter::indexToString(const double index) const { - if(index == std::numeric_limits::quiet_NaN() || index == std::numeric_limits::infinity() || index < 0.0) + if(!_finite(index) || (index < 0.0)) { return QString(); } diff --git a/src/Thread_CueSplitter.h b/src/Thread_CueSplitter.h index 5c06b490..a3717a0a 100644 --- a/src/Thread_CueSplitter.h +++ b/src/Thread_CueSplitter.h @@ -26,6 +26,7 @@ #include class AudioFileModel; +class CueSheetModel; class QFile; class QDir; class QFileInfo; @@ -39,14 +40,14 @@ class CueSplitter: public QThread Q_OBJECT public: - CueSplitter(const QString &outputDir, const QString &baseName, const QList &inputFiles); + CueSplitter(const QString &outputDir, const QString &baseName, CueSheetModel *model, const QList &inputFilesInfo); ~CueSplitter(void); + void run(); - bool getSuccess(void) { return !isRunning() && m_bSuccess; } unsigned int getTracksSuccess(void) { return m_nTracksSuccess; } unsigned int getTracksSkipped(void) { return m_nTracksSkipped; } - void addTrack(const int trackNo, const QString &file, const double offset, const double length, const AudioFileModel &metaInfo); - void setAlbumInfo(const QString &performer, const QString &title); + bool getSuccess(void) { return !isRunning() && m_bSuccess; } + bool getAborted(void) { return m_bAborted; } signals: void fileSelected(const QString &fileName); @@ -55,8 +56,11 @@ signals: private slots: void handleUpdate(int progress); +public slots: + void abortProcess(void) { m_abortFlag = true; } + private: - void splitFile(const QString &output, const int trackNo, const QString &file, const double offset, const double length, const AudioFileModel &metaInfo); + void splitFile(const QString &output, const int trackNo, const QString &file, const double offset, const double length, const AudioFileModel &metaInfo, int &maxProgress); QString indexToString(const double index) const; const QString m_soxBin; @@ -64,18 +68,15 @@ private: const QString m_baseName; unsigned int m_nTracksSuccess; unsigned int m_nTracksSkipped; + + bool m_bAborted; bool m_bSuccess; + volatile bool m_abortFlag; - QString m_albumTitle; - QString m_albumPerformer; - QString m_activeFile; - QMap m_inputFiles; + CueSheetModel *m_model; + QMap m_inputFilesInfo; QMap m_decompressedFiles; QStringList m_tempFiles; - QList m_trackFile; - QList m_trackNo; - QList m_trackOffset; - QList m_trackLength; - QList m_trackMetaInfo; + QString m_activeFile; };