diff --git a/doc/Changelog.html b/doc/Changelog.html
index aa29f669..cfdfa33a 100644
--- a/doc/Changelog.html
+++ b/doc/Changelog.html
@@ -19,7 +19,7 @@ a:visited { color: #0000EE; }
Changes between v4.01 and v4.02:
- Upgraded build environment to Microsoft Visual Studio 2010
- Dropping support for Windows 2000 and for Windows XP RTM/SP1, Windows XP needs SP2 or SP3 now!
-
- Added Cue Sheet import wizard, only uncompressed Wave/PCM files are suppported at the moment
+
- Added Cue Sheet import wizard, which allows splitting and importing tracks from Cue Sheet images
- Added ATSC A/52 (AC-3) encoding support, based on Aften encoder v0.0.8+ (Git Master)
- Added one new translation: Korean
- Added a method to use custom tools instead of the "built-in" ones (see FAQ doc for details)
diff --git a/etc/Translation/Blank.ts b/etc/Translation/Blank.ts
index a7699e6c..072c5c44 100644
--- a/etc/Translation/Blank.ts
+++ b/etc/Translation/Blank.ts
@@ -321,6 +321,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/etc/Translation/LameXP_DE.ts b/etc/Translation/LameXP_DE.ts
index 4b9854b2..ca2bd41e 100644
--- a/etc/Translation/LameXP_DE.ts
+++ b/etc/Translation/LameXP_DE.ts
@@ -331,12 +331,28 @@
- %1 Datei(ein) wurden aus dem Cuesheet importiert und %2 Datei(en) übersprungen.
+ %1 Datei(ein) wurden aus dem Cuesheet importiert, %2 Datei(en) übersprungen.
Cuesheet Abgeschlossen
+
+
+ Analyse fehlgeschlagen
+
+
+
+ Achtung: Das Dateiformat einiger Dateien konnte nicht festgestellt werden!
+
+
+
+ Trotzdem fortfahren
+
+
+
+ Abbrechen
+
CueSheetImport
diff --git a/etc/Translation/LameXP_ES.ts b/etc/Translation/LameXP_ES.ts
index 5dc0e994..4f1391eb 100644
--- a/etc/Translation/LameXP_ES.ts
+++ b/etc/Translation/LameXP_ES.ts
@@ -337,6 +337,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancelar
+
CueSheetImport
diff --git a/etc/Translation/LameXP_FR.ts b/etc/Translation/LameXP_FR.ts
index 0f358b9a..17fd4982 100644
--- a/etc/Translation/LameXP_FR.ts
+++ b/etc/Translation/LameXP_FR.ts
@@ -341,6 +341,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Abandonner
+
CueSheetImport
diff --git a/etc/Translation/LameXP_IT.ts b/etc/Translation/LameXP_IT.ts
index f18d3ea9..dc61af37 100644
--- a/etc/Translation/LameXP_IT.ts
+++ b/etc/Translation/LameXP_IT.ts
@@ -337,6 +337,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ferma
+
CueSheetImport
diff --git a/etc/Translation/LameXP_KR.ts b/etc/Translation/LameXP_KR.ts
index 23a3386e..862dce83 100644
--- a/etc/Translation/LameXP_KR.ts
+++ b/etc/Translation/LameXP_KR.ts
@@ -337,6 +337,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 취소
+
CueSheetImport
diff --git a/etc/Translation/LameXP_RU.ts b/etc/Translation/LameXP_RU.ts
index 237f27cd..4dab993a 100644
--- a/etc/Translation/LameXP_RU.ts
+++ b/etc/Translation/LameXP_RU.ts
@@ -337,6 +337,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Отмена
+
CueSheetImport
diff --git a/etc/Translation/LameXP_UK.ts b/etc/Translation/LameXP_UK.ts
index 5d08ef25..d1c1a46b 100644
--- a/etc/Translation/LameXP_UK.ts
+++ b/etc/Translation/LameXP_UK.ts
@@ -337,6 +337,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
CueSheetImport
diff --git a/gui/CueSheetImport.ui b/gui/CueSheetImport.ui
index 9e9f4c3f..2e281b9b 100644
--- a/gui/CueSheetImport.ui
+++ b/gui/CueSheetImport.ui
@@ -186,6 +186,15 @@
QAbstractItemView::SelectRows
+
+ true
+
+
+ true
+
+
+ false
+
-
@@ -616,6 +625,7 @@
+
diff --git a/res/localization/LameXP_DE.qm b/res/localization/LameXP_DE.qm
index a9fd4631..f613ec6f 100644
Binary files a/res/localization/LameXP_DE.qm and b/res/localization/LameXP_DE.qm differ
diff --git a/res/localization/LameXP_ES.qm b/res/localization/LameXP_ES.qm
index d37c7224..9b09741a 100644
Binary files a/res/localization/LameXP_ES.qm and b/res/localization/LameXP_ES.qm differ
diff --git a/res/localization/LameXP_FR.qm b/res/localization/LameXP_FR.qm
index b902e77e..065c7051 100644
Binary files a/res/localization/LameXP_FR.qm and b/res/localization/LameXP_FR.qm differ
diff --git a/res/localization/LameXP_IT.qm b/res/localization/LameXP_IT.qm
index 6d156327..41f3a41f 100644
Binary files a/res/localization/LameXP_IT.qm and b/res/localization/LameXP_IT.qm differ
diff --git a/res/localization/LameXP_KR.qm b/res/localization/LameXP_KR.qm
index a5202191..290bafb4 100644
Binary files a/res/localization/LameXP_KR.qm and b/res/localization/LameXP_KR.qm differ
diff --git a/res/localization/LameXP_RU.qm b/res/localization/LameXP_RU.qm
index 5dfd160a..eeeba8d0 100644
Binary files a/res/localization/LameXP_RU.qm and b/res/localization/LameXP_RU.qm differ
diff --git a/src/Dialog_CueImport.cpp b/src/Dialog_CueImport.cpp
index d58f80f7..45d33d92 100644
--- a/src/Dialog_CueImport.cpp
+++ b/src/Dialog_CueImport.cpp
@@ -230,11 +230,13 @@ void CueImportDialog::importCueSheet(void)
files << temp;
}
- //Analyze all source files
- analyzeFiles(files);
+ //Analyze all source files first
+ if(analyzeFiles(files))
+ {
+ //Now split files according to Cue Sheet
+ splitFiles();
+ }
- //Now split files according to Cue Sheet
- splitFiles();
//Release locks
while(!m_locks.isEmpty())
@@ -243,9 +245,10 @@ void CueImportDialog::importCueSheet(void)
}
}
-void CueImportDialog::analyzeFiles(QStringList &files)
+bool CueImportDialog::analyzeFiles(QStringList &files)
{
m_fileInfo.clear();
+ bool bSuccess = true;
WorkingBanner *progress = new WorkingBanner(this);
FileAnalyzer *analyzer = new FileAnalyzer(files);
@@ -255,7 +258,19 @@ void CueImportDialog::analyzeFiles(QStringList &files)
progress->show(tr("Analyzing file(s), please wait..."), analyzer);
progress->close();
+
+ if(analyzer->filesAccepted() < 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)
+ {
+ bSuccess = false;
+ }
+ }
+
LAMEXP_DELETE(progress);
+ LAMEXP_DELETE(analyzer);
+
+ return bSuccess;
}
void CueImportDialog::splitFiles(void)
@@ -308,7 +323,7 @@ void CueImportDialog::splitFiles(void)
}
else
{
- QString text = 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_CueImport.h b/src/Dialog_CueImport.h
index 523306ab..025934c2 100644
--- a/src/Dialog_CueImport.h
+++ b/src/Dialog_CueImport.h
@@ -51,8 +51,8 @@ private slots:
private:
void importCueSheet(void);
- void analyzeFiles(QStringList &files);
- void CueImportDialog::splitFiles(void);
+ bool analyzeFiles(QStringList &files);
+ void splitFiles(void);
CueSheetModel *m_model;
FileListModel *m_fileList;
diff --git a/src/Model_CueSheet.cpp b/src/Model_CueSheet.cpp
index b05c23fc..853acb96 100644
--- a/src/Model_CueSheet.cpp
+++ b/src/Model_CueSheet.cpp
@@ -129,13 +129,13 @@ QModelIndex CueSheetModel::index(int row, int column, const QModelIndex &parent)
{
if(!parent.isValid())
{
- return createIndex(row, column, m_files.at(row));
+ return (row < m_files.count()) ? createIndex(row, column, m_files.at(row)) : QModelIndex();
}
CueSheetItem *parentItem = static_cast(parent.internalPointer());
if(CueSheetFile *filePtr = dynamic_cast(parentItem))
{
- return createIndex(row, column, filePtr->track(row));
+ return (row < filePtr->trackCount()) ? createIndex(row, column, filePtr->track(row)) : QModelIndex();
}
return QModelIndex();
diff --git a/src/Thread_CueSplitter.cpp b/src/Thread_CueSplitter.cpp
index 692cb803..e9746e0e 100644
--- a/src/Thread_CueSplitter.cpp
+++ b/src/Thread_CueSplitter.cpp
@@ -25,6 +25,8 @@
#include "LockedFile.h"
#include "Model_AudioFile.h"
#include "PlaylistImporter.h"
+#include "Registry_Decoder.h"
+#include "Decoder_Abstract.h"
#include
#include
@@ -52,6 +54,8 @@ CueSplitter::CueSplitter(const QString &outputDir, const QString &baseName, cons
m_albumPerformer.clear();
m_albumTitle.clear();
+ m_decompressedFiles.clear();
+ m_tempFiles.clear();
qDebug("\n[CueSplitter::CueSplitter]");
@@ -59,13 +63,21 @@ CueSplitter::CueSplitter(const QString &outputDir, const QString &baseName, cons
for(int i = 0; i < nInputFiles; i++)
{
m_inputFiles.insert(inputFiles[i].filePath(), inputFiles[i]);
- qDebug("%02d <%s>", i, inputFiles[i].filePath());
+ qDebug("%02d <%s>", i, inputFiles[i].filePath().toUtf8().constData());
}
qDebug("All input files added.");
m_bSuccess = false;
}
+CueSplitter::~CueSplitter(void)
+{
+ while(!m_tempFiles.isEmpty())
+ {
+ lamexp_remove_file(m_tempFiles.takeFirst());
+ }
+}
+
////////////////////////////////////////////////////////////
// Thread Main
////////////////////////////////////////////////////////////
@@ -73,18 +85,61 @@ CueSplitter::CueSplitter(const QString &outputDir, const QString &baseName, cons
void CueSplitter::run()
{
m_bSuccess = false;
+ m_abortFlag = false;
m_nTracksSuccess = 0;
m_nTracksSkipped = 0;
- m_abortFlag = false;
-
- int nTracks = min(min(min(m_trackFile.count(), m_trackNo.count()), min(m_trackOffset.count(), m_trackLength.count())), m_trackMetaInfo.count());
+ m_decompressedFiles.clear();
+ m_activeFile.clear();
if(!QDir(m_outputDir).exists())
{
qWarning("Output directory \"%s\" does not exist!", m_outputDir.toUtf8().constData());
return;
}
+
+ QStringList inputFileList = m_inputFiles.keys();
+ int nInputFiles = inputFileList.count();
+
+ //Decompress all input files
+ for(int i = 0; i < nInputFiles; i++)
+ {
+ AudioFileModel &inputFileInfo = m_inputFiles[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());
+ if(decoder)
+ {
+ m_activeFile = QFileInfo(inputFileList.at(i)).fileName().left(54).trimmed();
+ emit fileSelected(m_activeFile);
+ QString tempFile = QString("%1/~%2.wav").arg(m_outputDir, lamexp_rand_str());
+ connect(decoder, SIGNAL(statusUpdated(int)), this, SLOT(handleUpdate(int)), Qt::DirectConnection);
+ if(decoder->decode(inputFileList.at(i), tempFile, &m_abortFlag))
+ {
+ m_decompressedFiles.insert(inputFileList.at(i), tempFile);
+ m_tempFiles.append(tempFile);
+ }
+ else
+ {
+ qWarning("Failed to decompress file: <%s>", inputFileList.at(i).toLatin1().constData());
+ lamexp_remove_file(tempFile);
+ }
+ m_activeFile.clear();
+ LAMEXP_DELETE(decoder);
+ }
+ else
+ {
+ qWarning("Unsupported input file: <%s>", inputFileList.at(i).toLatin1().constData());
+ }
+ }
+ else
+ {
+ m_decompressedFiles.insert(inputFileList.at(i), inputFileList.at(i));
+ }
+ }
+ int nTracks = min(min(min(m_trackFile.count(), m_trackNo.count()), min(m_trackOffset.count(), m_trackLength.count())), m_trackMetaInfo.count());
+
+ //Now split all tracks
for(int i = 0; i < nTracks; i++)
{
QString outputFile = QString("%1/%2 - Track %3.wav").arg(m_outputDir, m_baseName, QString().sprintf("%02d", m_trackNo.at(i)));
@@ -114,7 +169,7 @@ void CueSplitter::addTrack(const int trackNo, const QString &file, const double
}
else
{
- throw "Unknown input file!";
+ throw "The input file is unknown/missing!";
}
}
@@ -124,40 +179,43 @@ void CueSplitter::setAlbumInfo(const QString &performer, const QString &title)
if(!title.isEmpty()) m_albumTitle = title;
}
+////////////////////////////////////////////////////////////
+// Slots
+////////////////////////////////////////////////////////////
+
+void CueSplitter::handleUpdate(int progress)
+{
+ emit fileSelected(QString("%1 [%2%]").arg(m_activeFile, QString::number(progress)));
+}
+
////////////////////////////////////////////////////////////
// Privtae Functions
////////////////////////////////////////////////////////////
void CueSplitter::splitFile(const QString &output, const int trackNo, const QString &file, const double offset, const double length, const AudioFileModel &metaInfo)
{
- qDebug("\n[Track %02d]", trackNo);
+ qDebug("[Track %02d]", trackNo);
qDebug("File: <%s>", file.toUtf8().constData());
qDebug("Offset: %f", offset);
qDebug("Length: %f", length);
qDebug("Artist: <%s>", metaInfo.fileArtist().toUtf8().constData());
qDebug("Title: <%s>", metaInfo.fileName().toUtf8().constData());
+
+ if(!m_decompressedFiles.contains(file))
+ {
+ qWarning("Unknown or unsupported input file, skipping!");
+ m_nTracksSkipped++;
+ return;
+ }
QString baseName = QFileInfo(output).fileName();
-
- if(!m_inputFiles.contains(file))
- {
- qWarning("Unknown input file, skipping!");
- m_nTracksSkipped++;
- return;
- }
-
- AudioFileModel &inputFileInfo = m_inputFiles[file];
- if(inputFileInfo.formatContainerType().compare("Wave", Qt::CaseInsensitive) || inputFileInfo.formatAudioType().compare("PCM", Qt::CaseInsensitive))
- {
- qWarning("Sorry, only Wave/PCM files are supported at this time!");
- m_nTracksSkipped++;
- return;
- }
-
+ QString decompressedInput = m_decompressedFiles[file];
+ qDebug("Input: <%s>", decompressedInput.toUtf8().constData());
+
AudioFileModel outFileInfo(metaInfo);
outFileInfo.setFilePath(output);
- outFileInfo.setFormatContainerType(inputFileInfo.formatContainerType());
- outFileInfo.setFormatAudioType(inputFileInfo.formatAudioType());
+ outFileInfo.setFormatContainerType("Wave");
+ outFileInfo.setFormatAudioType("PCM");
if(length != std::numeric_limits::infinity())
{
@@ -175,9 +233,10 @@ void CueSplitter::splitFile(const QString &output, const int trackNo, const QStr
QStringList args;
args << "-S" << "-V3";
args << "--guard" << "--temp" << ".";
- args << QDir::toNativeSeparators(file);
+ args << QDir::toNativeSeparators(decompressedInput);
args << QDir::toNativeSeparators(output);
+ //Add trim parameters, if needed
if(offset != 0.0 || length != std::numeric_limits::infinity())
{
args << "trim";
@@ -268,7 +327,9 @@ void CueSplitter::splitFile(const QString &output, const int trackNo, const QStr
if(length == std::numeric_limits::infinity())
{
qDebug("Duration updated from SoX info!");
- outFileInfo.setFileDuration(max(0, intputLen - static_cast(floor(offset + 0.5))));
+ int duration = intputLen - static_cast(floor(offset + 0.5));
+ if(duration < 0) qWarning("Track is out of bounds: Track offset exceeds input file duration!");
+ outFileInfo.setFileDuration(max(0, duration));
}
else
{
diff --git a/src/Thread_CueSplitter.h b/src/Thread_CueSplitter.h
index 0baa6a22..5c06b490 100644
--- a/src/Thread_CueSplitter.h
+++ b/src/Thread_CueSplitter.h
@@ -40,6 +40,7 @@ class CueSplitter: public QThread
public:
CueSplitter(const QString &outputDir, const QString &baseName, const QList &inputFiles);
+ ~CueSplitter(void);
void run();
bool getSuccess(void) { return !isRunning() && m_bSuccess; }
unsigned int getTracksSuccess(void) { return m_nTracksSuccess; }
@@ -51,6 +52,9 @@ signals:
void fileSelected(const QString &fileName);
void fileSplit(const AudioFileModel &file);
+private slots:
+ void handleUpdate(int progress);
+
private:
void splitFile(const QString &output, const int trackNo, const QString &file, const double offset, const double length, const AudioFileModel &metaInfo);
QString indexToString(const double index) const;
@@ -65,7 +69,10 @@ private:
QString m_albumTitle;
QString m_albumPerformer;
+ QString m_activeFile;
QMap m_inputFiles;
+ QMap m_decompressedFiles;
+ QStringList m_tempFiles;
QList m_trackFile;
QList m_trackNo;
QList m_trackOffset;