diff --git a/README.md b/README.md index e21c2e1..8fefacc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ - # BSCWorks BSCWorks is a somewhat feature rich editor for the Burnt Sound Container format, version 14, that Company of Heroes uses and also provides several tools for handling related files. This editor is about a decade too late to be relevant, but was made to more easily edit sound related aspects of the game in the unreleased quality-of-life mod I develop in my spare time for use with a small group of friends/family that still play the original. I am sharing it here in the hopes that it could be useful the remnants of CoH modders or research purposes, such as a starting point for examining other versions of this format from other Relic Games (i.e. CoH 2, Dawn of War, Warhammer 40k, etc.), or if someone ever decides to make a source port of the original game (if we are lucky enough to ever get the source, instead of just a really random licensed iPad port >>) . @@ -15,7 +14,7 @@ BSCWorks is a somewhat feature rich editor for the Burnt Sound Container format, - Sound Container settings - Mostly complete editing of Sound Containers including sound container order insertion/removal of new/existing Sound Containers - Basic editing of *uninterpreted* Effect Container data - - Single and batch conversion of both SMF->WAV and WAV->SMF + - Single and batch conversion of both SMF->WAV/MP3 and WAV/MP3->SMF - Creation and updating of Speechmanager Caches that performs byte-level validity checking, avoids adding redundant entries and removes any existing duplicates from the cache ## Usage @@ -63,7 +62,7 @@ There are still considerable unknowns regarding the BSC format that unfortunatel - [ ] Add support for window resizing/fullscreen ## Source -This tool was written in C++ 17 along with Qt 5 and currently only targets Windows Vista and above; however, this tool can easily be ported to Linux with minimal changes, though to what end I am not sure since this is for a Windows game. The source includes an easy-to-use .pro file if you wish to build the application in Qt Creator and the available latest release was compiled in Qt Creator 4.12.0 using MSVC 2019 and a static compilation of Qt 5.14.0. Other than a C++ 17 capable compiler and Qt 5.14.x+ all files required to compile this software are included, with the exception of a standard make file. +This tool was written in C++ 17 along with Qt 5 and currently only targets Windows Vista and above; however, this tool can easily be ported to Linux with minimal changes, though to what end I am not sure since this is for a Windows game. The source includes an easy-to-use .pro file if you wish to build the application in Qt Creator and the available latest release was compiled in Qt Creator 4.12.0 using MSVC 2019 and a static compilation of Qt 5.15.0. Other than a C++ 17 capable compiler and Qt 5.15.x+ all files required to compile this software are included, with the exception of a standard make file. All functions/variables under the "Qx" (QExtended) namespace belong to a small, personal library I maintain to always have access to frequently used functionality in my projects. A pre-compiled static version of this library is provided with the source for this tool. If anyone truly needs it, I can provide the source for this library as well. diff --git a/src/main.cpp b/src/main.cpp index 8c53efd..185f401 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,7 @@ int main(int argc, char *argv[]) { + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication a(argc, argv); MainWindow w; w.show(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 29afabd..d8041d3 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -753,7 +753,7 @@ void MainWindow::cacheSubRoutine(bool existing) { QFile cacheFile(cachePath); - SMC cache = SMC(); + Smc cache = Smc(); if(existing) { @@ -761,7 +761,7 @@ void MainWindow::cacheSubRoutine(bool existing) Qx::IOOpReport openReport = Qx::readAllBytesFromFile(cacheData, cacheFile); if(openReport.wasSuccessful()) - cache = SMC(cacheData); + cache = Smc(cacheData); else { execIOReport(openReport); @@ -1162,19 +1162,20 @@ void MainWindow::all_on_menuAction_triggered() QFile smfFile(smfPath); QByteArray smfData; Qx::IOOpReport openReport = Qx::readAllBytesFromFile(smfData, smfFile); - SMF smfIn(smfData); + Smf smfIn(smfData); if(openReport.wasSuccessful()) { if(smfIn.isValid()) { - QString wavPath = QFileDialog::getSaveFileName(this, MENU_CONV_SMF_OUT_TITLE, QDir::currentPath(), MENU_WAV_FILE_FILTER); + QString outputPath = QFileDialog::getSaveFileName(this, smfIn.getType() == Smf::WAVE ? MENU_CONV_SMF_OUT_WAV_TITLE : MENU_BATCH_WAV_MP3_OUT_TITLE, + QDir::currentPath(), smfIn.getType() == Smf::WAVE ? MENU_WAV_FILE_FILTER : MENU_MP3_FILE_FILTER); - if(wavPath != "") + if(outputPath != "") { - QFile wavFile(wavPath); + QFile outPutFile(outputPath); - Qx::IOOpReport writeReport = Qx::writeBytesAsFile(wavFile, smfIn.toWAV().getFullData(), true); + Qx::IOOpReport writeReport = Qx::writeBytesAsFile(outPutFile, smfIn.getType() == Smf::WAVE ? smfIn.toWav().getFullData() : smfIn.toMp3().getFullData(), true); if(writeReport.wasSuccessful()) { QApplication::beep(); @@ -1183,7 +1184,7 @@ void MainWindow::all_on_menuAction_triggered() else { execIOReport(writeReport); - QMessageBox::critical(this, QApplication::applicationName(), MSG_CONV_SMF_FAIL.arg(QDir::toNativeSeparators(wavPath)), QMessageBox::Ok, QMessageBox::Ok); + QMessageBox::critical(this, QApplication::applicationName(), MSG_CONV_SMF_FAIL.arg(QDir::toNativeSeparators(outputPath)), QMessageBox::Ok, QMessageBox::Ok); } } } @@ -1196,40 +1197,45 @@ void MainWindow::all_on_menuAction_triggered() } else if(senderAction == ui->actionConvert_WAV_MP3_to_SMF) { - QString wavPath = QFileDialog::getOpenFileName(this, MENU_CONV_WAV_IN_TITLE, QDir::currentPath(), MENU_WAV_FILE_FILTER); + QString inputPath = QFileDialog::getOpenFileName(this, MENU_CONV_WAV_MP3_IN_TITLE, QDir::currentPath(), MENU_WAV_MP3_FILE_FILTER); - if(wavPath != "") + if(inputPath != "") { - QFile wavFile(wavPath); - QByteArray wavData; - Qx::IOOpReport wavRead = Qx::readAllBytesFromFile(wavData, wavFile); - WAV wavIn(wavData); + QFile inputFile(inputPath); + QByteArray inputData; + Qx::IOOpReport openReport = Qx::readAllBytesFromFile(inputData, inputFile); - if(wavRead.wasSuccessful()) + if(openReport.wasSuccessful()) { - if(wavIn.isValid()) + Smf::Type inputType = QFileInfo(inputFile).suffix() == Wav::FILE_EXT ? Smf::WAVE : Smf::MP3; + + Wav wavIn(inputData); + Mp3 mp3In(inputData); + + if(wavIn.isValid() || mp3In.isValid()) { - QString smfPath = QFileDialog::getSaveFileName(this, MENU_CONV_WAV_OUT_TITLE, QDir::currentPath(), MENU_SMF_FILE_FILTER); + QString smfPath = QFileDialog::getSaveFileName(this, MENU_CONV_WAV_MP3_OUT_TITLE, QDir::currentPath(), MENU_SMF_FILE_FILTER); if(smfPath != "") { QFile smfFile(smfPath); - Qx::IOOpReport writeReport = Qx::writeBytesAsFile(smfFile, SMF::fromStandard(wavIn).getFullData(), true); + Qx::IOOpReport writeReport = Qx::writeBytesAsFile(smfFile, wavIn.isValid() ? Smf::fromStandard(wavIn).getFullData() : Smf::fromStandard(mp3In).getFullData(), true); if(writeReport.wasSuccessful()) - QMessageBox::information(this, QApplication::applicationName(), MSG_CONV_WAV_SUCCESS, QMessageBox::Ok, QMessageBox::Ok); + QMessageBox::information(this, QApplication::applicationName(), MSG_CONV_WAV_MP3_SUCCESS, QMessageBox::Ok, QMessageBox::Ok); else { execIOReport(writeReport); - QMessageBox::critical(this, QApplication::applicationName(), MSG_CONV_WAV_FAIL.arg(QDir::toNativeSeparators(wavPath)), QMessageBox::Ok, QMessageBox::Ok); + QMessageBox::critical(this, QApplication::applicationName(), MSG_CONV_WAV_MP3_FAIL.arg(QDir::toNativeSeparators(inputPath)), QMessageBox::Ok, QMessageBox::Ok); } } } else - QMessageBox::critical(this, QApplication::applicationName(), MSG_CONV_WAV_INVALID.arg(QDir::toNativeSeparators(wavPath)), QMessageBox::Ok, QMessageBox::Ok); + QMessageBox::critical(this, QApplication::applicationName(), (inputType == Smf::WAVE ? MSG_CONV_WAV_INVALID : MSG_CONV_MP3_INVALID).arg(QDir::toNativeSeparators(inputPath)), + QMessageBox::Ok, QMessageBox::Ok); } else - execIOReport(wavRead); + execIOReport(openReport); } } else if(senderAction == ui->actionBatch_SMF_to_WAV_MP3) @@ -1242,13 +1248,13 @@ void MainWindow::all_on_menuAction_triggered() MSG_BATCH_SMF_SUB_PROMPT, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes; - QString wavFolderPath = QFileDialog::getExistingDirectory(this, MENU_BATCH_SMF_OUT_TITLE, QDir::currentPath()); + QString outputFolderPath = QFileDialog::getExistingDirectory(this, MENU_BATCH_SMF_OUT_TITLE, QDir::currentPath()); - if(wavFolderPath != "") + if(outputFolderPath != "") { QDir smfFolder(smfFolderPath); QStringList smfList; - Qx::IOOpReport dirRead = Qx::getDirFileList(smfList, smfFolder, {SMF::FILE_EXT}, + Qx::IOOpReport dirRead = Qx::getDirFileList(smfList, smfFolder, {Smf::FILE_EXT}, includeSubFolders ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags); if(dirRead.wasSuccessful()) @@ -1279,19 +1285,19 @@ void MainWindow::all_on_menuAction_triggered() QFile currentFile(smfList.value(i)); QByteArray smfData; Qx::IOOpReport smfRead = Qx::readAllBytesFromFile(smfData, currentFile); - SMF currentSMF(smfData); + Smf currentSMF(smfData); if(smfRead.wasSuccessful()) { if(currentSMF.isValid()) { - QString wavOutPath = smfList.value(i).remove(smfFolderPath).prepend(wavFolderPath); - wavOutPath = wavOutPath.left(wavOutPath.length() - 3).append(WAV::FILE_EXT); - QFile wavOut(wavOutPath); + QString outputPath = smfList.value(i).remove(smfFolderPath).prepend(outputFolderPath); + outputPath = outputPath.left(outputPath.length() - 3).append(currentSMF.getType() == Smf::WAVE ? Wav::FILE_EXT : Mp3::FILE_EXT); + QFile fileOut(outputPath); - if(wavOut.exists() && QFileInfo(wavOut).isFile() && showOverwritePrompt) + if(fileOut.exists() && QFileInfo(fileOut).isFile() && showOverwritePrompt) { - int overwriteChoice = QMessageBox::question(this, QApplication::applicationName(), MSG_BATCH_ALL_FILE_EXST.arg(QDir::toNativeSeparators(wavOutPath)), + int overwriteChoice = QMessageBox::question(this, QApplication::applicationName(), MSG_BATCH_ALL_FILE_EXST.arg(QDir::toNativeSeparators(outputPath)), QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll, QMessageBox::No); switch(overwriteChoice) @@ -1311,7 +1317,8 @@ void MainWindow::all_on_menuAction_triggered() } } - Qx::IOOpReport writeReport = Qx::writeBytesAsFile(wavOut, currentSMF.toWAV().getFullData(), overwriteExisting); + Qx::IOOpReport writeReport = Qx::writeBytesAsFile(fileOut, currentSMF.getType() == Smf::WAVE ? currentSMF.toWav().getFullData() : + currentSMF.toMp3().getFullData(), overwriteExisting); if(!writeReport.wasSuccessful()) { failedConvList.append(smfList.value(i)); @@ -1387,21 +1394,21 @@ void MainWindow::all_on_menuAction_triggered() } else if(senderAction == ui->actionBatch_WAV_MP3_to_SMF) { - QString wavFolderPath = QFileDialog::getExistingDirectory(this, MENU_BATCH_WAV_IN_TITLE, QDir::currentPath()); + QString inputFolderPath = QFileDialog::getExistingDirectory(this, MENU_BATCH_WAV_MP3_IN_TITLE, QDir::currentPath()); - if(wavFolderPath != "") + if(inputFolderPath != "") { bool includeSubFolders = QMessageBox::question(this, QApplication::applicationName(), - MSG_BATCH_WAV_SUB_PROMPT, + MSG_BATCH_WAV_MP3_SUB_PROMPT, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes; - QString smfFolderPath = QFileDialog::getExistingDirectory(this, MENU_BATCH_WAV_OUT_TITLE, QDir::currentPath()); + QString smfFolderPath = QFileDialog::getExistingDirectory(this, MENU_BATCH_WAV_MP3_OUT_TITLE, QDir::currentPath()); - if(wavFolderPath != "") + if(inputFolderPath != "") { - QDir wavFolder(wavFolderPath); - QStringList wavList; - Qx::IOOpReport dirRead = Qx::getDirFileList(wavList, wavFolder, {WAV::FILE_EXT}, + QDir inputFolder(inputFolderPath); + QStringList inputList; + Qx::IOOpReport dirRead = Qx::getDirFileList(inputList, inputFolder, {Wav::FILE_EXT, Mp3::FILE_EXT}, includeSubFolders ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags); if(dirRead.wasSuccessful()) @@ -1415,10 +1422,10 @@ void MainWindow::all_on_menuAction_triggered() int filesProcessed = 0; - QProgressDialog conversionProgress(MSG_BATCH_WAV_IN_PROGRESS, MSG_BATCH_ALL_ABORT, 0, wavList.length(), this); + QProgressDialog conversionProgress(MSG_BATCH_WAV_MP3_IN_PROGRESS, MSG_BATCH_ALL_ABORT, 0, inputList.length(), this); conversionProgress.setWindowModality(Qt::WindowModal); - for(int i = 0; i < wavList.length(); i++) + for(int i = 0; i < inputList.length(); i++) { conversionProgress.setValue(i); @@ -1429,17 +1436,19 @@ void MainWindow::all_on_menuAction_triggered() break; } - QFile currentFile(wavList.value(i)); - QByteArray wavData; - Qx::IOOpReport wavRead = Qx::readAllBytesFromFile(wavData, currentFile); - WAV currentWAV(wavData); + QFile currentFile(inputList.value(i)); + QByteArray inputData; + Qx::IOOpReport openReport = Qx::readAllBytesFromFile(inputData, currentFile); - if(wavRead.wasSuccessful()) - { - if(currentWAV.isValid()) + if(openReport.wasSuccessful()) + { + Wav currentWav(inputData); + Mp3 currentMp3(inputData); + + if(currentWav.isValid() || currentMp3.isValid()) { - QString smfOutPath = wavList.value(i).remove(wavFolderPath).prepend(smfFolderPath); - smfOutPath = smfOutPath.left(smfOutPath.length() - 3).append(SMF::FILE_EXT); + QString smfOutPath = inputList.value(i).remove(inputFolderPath).prepend(smfFolderPath); + smfOutPath = smfOutPath.left(smfOutPath.length() - 3).append(Smf::FILE_EXT); QFile smfOut(smfOutPath); @@ -1465,45 +1474,46 @@ void MainWindow::all_on_menuAction_triggered() } } - Qx::IOOpReport writeReport = Qx::writeBytesAsFile(smfOut, SMF::fromStandard(currentWAV).getFullData(), overwriteExisting); + Qx::IOOpReport writeReport = Qx::writeBytesAsFile(smfOut, currentWav.isValid() ? Smf::fromStandard(currentWav).getFullData() : + Smf::fromStandard(currentMp3).getFullData(), overwriteExisting); if(!writeReport.wasSuccessful()) { - failedConvList.append(wavList.value(i)); + failedConvList.append(inputList.value(i)); failedReasonList.append(writeReport.getOutcomeInfo()); } } else { - failedConvList.append(wavList.value(i)); - failedReasonList.append(MSG_BATCH_WAV_INV_FILES_CAT_BAD); + failedConvList.append(inputList.value(i)); + failedReasonList.append(MSG_BATCH_WAV_MP3_INV_FILES_CAT_BAD); } } else { - failedConvList.append(wavList.value(i)); - failedReasonList.append(wavRead.getOutcomeInfo()); + failedConvList.append(inputList.value(i)); + failedReasonList.append(openReport.getOutcomeInfo()); } } - conversionProgress.setValue(wavList.length()); // Finish progress dialog + conversionProgress.setValue(inputList.length()); // Finish progress dialog QMessageBox batchResult; batchResult.setIcon(QMessageBox::Information); batchResult.setStandardButtons(QMessageBox::Ok); batchResult.setDefaultButton(QMessageBox::Ok); - if(wavList.isEmpty()) + if(inputList.isEmpty()) { batchResult.setIcon(QMessageBox::Critical); - batchResult.setText(MSG_BATCH_WAV_NO_FILES.arg(QDir::toNativeSeparators(wavFolderPath))); + batchResult.setText(MSG_BATCH_WAV_MP3_NO_FILES.arg(QDir::toNativeSeparators(inputFolderPath))); } - else if(wavList.length() == failedConvList.length()) + else if(inputList.length() == failedConvList.length()) { batchResult.setIcon(QMessageBox::Critical); - batchResult.setText(MSG_BATCH_WAV_NO_VALID_FILES_TXT.arg(QDir::toNativeSeparators(wavFolderPath))); - batchResult.setInformativeText(MSG_BATCH_WAV_NO_VALID_FILES_INFO); + batchResult.setText(MSG_BATCH_WAV_MP3_NO_VALID_FILES_TXT.arg(QDir::toNativeSeparators(inputFolderPath))); + batchResult.setInformativeText(MSG_BATCH_WAV_MP3_NO_VALID_FILES_INFO); - QString details = MSG_BATCH_WAV_INV_FILES_DETAILS + "\n"; + QString details = MSG_BATCH_WAV_MP3_INV_FILES_DETAILS + "\n"; for(int i = 0; i < failedConvList.length(); i ++) details.append("\n- " + failedConvList.value(i) + " " + failedReasonList.value(i)); @@ -1514,15 +1524,15 @@ void MainWindow::all_on_menuAction_triggered() { batchResult.setIcon(QMessageBox::Warning); batchResult.setText(MSG_BATCH_ALL_ABORTED_TXT); - batchResult.setInformativeText(MSG_BATCH_ALL_ABORTED_INFO.arg(filesProcessed).arg(wavList.length())); + batchResult.setInformativeText(MSG_BATCH_ALL_ABORTED_INFO.arg(filesProcessed).arg(inputList.length())); } else if(!failedConvList.isEmpty()) { batchResult.setIcon(QMessageBox::Warning); - batchResult.setText(MSG_BATCH_WAV_SUCCESS_TXT); - batchResult.setInformativeText(MSG_BATCH_WAV_INV_FILES_INFO); + batchResult.setText(MSG_BATCH_WAV_MP3_SUCCESS_TXT); + batchResult.setInformativeText(MSG_BATCH_WAV_MP3_INV_FILES_INFO); - QString details = MSG_BATCH_WAV_INV_FILES_DETAILS + "\n"; + QString details = MSG_BATCH_WAV_MP3_INV_FILES_DETAILS + "\n"; for(int i = 0; i < failedConvList.length(); i ++) details.append("\n- " + failedConvList.value(i) + " " + failedReasonList.value(i)); @@ -1530,7 +1540,7 @@ void MainWindow::all_on_menuAction_triggered() batchResult.setDetailedText(details); } else - batchResult.setText(MSG_BATCH_WAV_SUCCESS_TXT); + batchResult.setText(MSG_BATCH_WAV_MP3_SUCCESS_TXT); QApplication::beep(); batchResult.exec(); diff --git a/src/mainwindow.h b/src/mainwindow.h index b325298..9790514 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -4,7 +4,6 @@ #include "bsc.h" #include "smc.h" #include "smf.h" -#include "wav.h" #include #include @@ -41,7 +40,7 @@ class MainWindow : public QMainWindow "BSC inoperable if performed incorrectly. Only edit this section if you know what you're doing."; static inline const QString MSG_EFF_CON_EDIT_WARN_INFO_TXT = "Effect Container count must be 1 or greater before any data can be changed."; - static inline const QString MENU_CACHE_FILE_FILTER = "Speechmanager Cache (*." + SMC::FILE_EXT + ")"; + static inline const QString MENU_CACHE_FILE_FILTER = "Speechmanager Cache (*." + Smc::FILE_EXT + ")"; static inline const QString MENU_CACHE_OPEN_TITLE = "Select Speechmanager Cache"; static inline const QString MENU_CACHE_FOLDER_TITLE = "Select folder to scan for BSC files"; static inline const QString MSG_CACHE_INVALID = """%1"" is not a valid Speechmanager Cache!"; @@ -64,20 +63,24 @@ class MainWindow : public QMainWindow static inline const QString MSG_CACHE_SCAN_ABORT = "Abort"; static inline const QString MSG_CACHE_SCAN_ABORTED = "Speechmanager cache update aborted by user."; - static inline const QString MENU_SMF_FILE_FILTER = "SMF Audio (*." + SMF::FILE_EXT + ")"; - static inline const QString MENU_WAV_FILE_FILTER = "WAVE Audio (*." + WAV::FILE_EXT + ")"; + static inline const QString MENU_SMF_FILE_FILTER = "SMF Audio (*." + Smf::FILE_EXT + ")"; + static inline const QString MENU_WAV_FILE_FILTER = "WAVE Audio (*." + Wav::FILE_EXT + ")"; + static inline const QString MENU_MP3_FILE_FILTER = "MP3 Audio (*." + Mp3::FILE_EXT + ")"; + static inline const QString MENU_WAV_MP3_FILE_FILTER = "WAVE/MP3 Audio (*." + Wav::FILE_EXT + ", *." + Mp3::FILE_EXT + ")"; static inline const QString MENU_CONV_SMF_IN_TITLE = "Select SMF to convert"; - static inline const QString MENU_CONV_SMF_OUT_TITLE = "Enter output WAV destination"; + static inline const QString MENU_CONV_SMF_OUT_WAV_TITLE = "Enter output WAV destination"; + static inline const QString MENU_CONV_SMF_OUT_MP3_TITLE = "Enter output MP3 destination"; static inline const QString MSG_CONV_SMF_INVALID = """%1"" is not a valid SMF file!"; static inline const QString MSG_CONV_SMF_SUCCESS = "Conversion completed successfully."; static inline const QString MSG_CONV_SMF_FAIL = "Error writting ""%1"""; - static inline const QString MENU_CONV_WAV_IN_TITLE = "Select WAV to convert"; - static inline const QString MENU_CONV_WAV_OUT_TITLE = "Enter output SMF destination"; + static inline const QString MENU_CONV_WAV_MP3_IN_TITLE = "Select WAV/MP3 to convert"; + static inline const QString MENU_CONV_WAV_MP3_OUT_TITLE = "Enter output SMF destination"; static inline const QString MSG_CONV_WAV_INVALID = """%1"" is not a valid WAVE file!"; - static inline const QString MSG_CONV_WAV_SUCCESS = "Conversion completed successfully."; - static inline const QString MSG_CONV_WAV_FAIL = "Error writting ""%1"""; + static inline const QString MSG_CONV_MP3_INVALID = """%1"" is not a valid MP3 file!"; + static inline const QString MSG_CONV_WAV_MP3_SUCCESS = "Conversion completed successfully."; + static inline const QString MSG_CONV_WAV_MP3_FAIL = "Error writting ""%1"""; static inline const QString MSG_BATCH_ALL_FILE_EXST = """%1"" already exists. Do you want to overwrite this file?"; static inline const QString MSG_BATCH_ALL_ABORT = "Abort Conversion"; @@ -94,19 +97,19 @@ class MainWindow : public QMainWindow static inline const QString MSG_BATCH_SMF_INV_FILES_INFO = "Some files were skipped due to read/write issues. See details below"; static inline const QString MSG_BATCH_SMF_INV_FILES_DETAILS = "The following files were skipped:"; static inline const QString MSG_BATCH_SMF_INV_FILES_CAT_BAD = "(Invalid data)"; - static inline const QString MSG_BATCH_SMF_IN_PROGRESS = "Converting SMF files to WAV..."; - - static inline const QString MENU_BATCH_WAV_IN_TITLE = "Select folder to scan for WAV files"; - static inline const QString MENU_BATCH_WAV_OUT_TITLE = "Select output folder"; - static inline const QString MSG_BATCH_WAV_SUB_PROMPT = "Include sub-directories?"; - static inline const QString MSG_BATCH_WAV_NO_FILES = "No WAV files found in %1"; - static inline const QString MSG_BATCH_WAV_NO_VALID_FILES_TXT = "No valid/convertable WAV files found in %1"; - static inline const QString MSG_BATCH_WAV_NO_VALID_FILES_INFO = "All present WAV files are corrupt, or experienced IO errors during conversion!"; - static inline const QString MSG_BATCH_WAV_SUCCESS_TXT = "Batch WAV conversion completed successfully."; - static inline const QString MSG_BATCH_WAV_INV_FILES_INFO = "Some files were skipped due to read/write issues. See details below"; - static inline const QString MSG_BATCH_WAV_INV_FILES_DETAILS = "The following files were skipped:"; - static inline const QString MSG_BATCH_WAV_INV_FILES_CAT_BAD = "(Invalid data)"; - static inline const QString MSG_BATCH_WAV_IN_PROGRESS = "Converting WAV files to SMF..."; + static inline const QString MSG_BATCH_SMF_IN_PROGRESS = "Converting SMF files to WAV/MP3..."; + + static inline const QString MENU_BATCH_WAV_MP3_IN_TITLE = "Select folder to scan for WAV/MP3 files"; + static inline const QString MENU_BATCH_WAV_MP3_OUT_TITLE = "Select output folder"; + static inline const QString MSG_BATCH_WAV_MP3_SUB_PROMPT = "Include sub-directories?"; + static inline const QString MSG_BATCH_WAV_MP3_NO_FILES = "No WAV/MP3 files found in %1"; + static inline const QString MSG_BATCH_WAV_MP3_NO_VALID_FILES_TXT = "No valid/convertable WAV/MP3 files found in %1"; + static inline const QString MSG_BATCH_WAV_MP3_NO_VALID_FILES_INFO = "All present WAV/MP3 files are corrupt, or experienced IO errors during conversion!"; + static inline const QString MSG_BATCH_WAV_MP3_SUCCESS_TXT = "Batch WAV/MP3 conversion completed successfully."; + static inline const QString MSG_BATCH_WAV_MP3_INV_FILES_INFO = "Some files were skipped due to read/write issues. See details below"; + static inline const QString MSG_BATCH_WAV_MP3_INV_FILES_DETAILS = "The following files were skipped:"; + static inline const QString MSG_BATCH_WAV_MP3_INV_FILES_CAT_BAD = "(Invalid data)"; + static inline const QString MSG_BATCH_WAV_MP3_IN_PROGRESS = "Converting WAV/MP3 files to SMF..."; static inline const QString MSG_ABOUT_TXT = "BSCWorks " + QString::fromStdString(VER_PRODUCTVERSION_STR) + " @oblivioncth"; static inline const QString MSG_ABOUT_INFO_TXT = "Distrubted under the GNU General Public License V3.0. See " + QString::fromStdString(VER_COMPANYDOMAIN_STR) + "/BSCWorks for more information."; diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 59899ee..b113228 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -1594,9 +1594,9 @@ - 208 + 29 380 - 542 + 901 51 diff --git a/src/mp3.cpp b/src/mp3.cpp index 7057858..910d39b 100644 --- a/src/mp3.cpp +++ b/src/mp3.cpp @@ -8,18 +8,20 @@ //-Constructor------------------------------------------------------------------------------------------------ //Public: -MP3::MP3(QByteArray rawMP3Data) : mFileDataF(rawMP3Data) +Mp3::Mp3() {} + +Mp3::Mp3(QByteArray rawMP3Data) : mFileDataF(rawMP3Data) { - if(!fileIsValidMP3()) + if(!fileIsValidMp3()) mFileDataF = QByteArray(); } //-Instance Functions------------------------------------------------------------------------------------------------ //Private: -bool MP3::fileIsValidMP3() +bool Mp3::fileIsValidMp3() { // Get header region - QByteArray header = mFileDataF.left(0x04); + QByteArray header = mFileDataF.left(0x03); QByteArray mp3OldSigRegion = header.left(L_MP3_OLD_SIG); QByteArray mp3NewSigRegion = header; @@ -29,5 +31,5 @@ bool MP3::fileIsValidMP3() } //Public: -bool MP3::isValid() { return !mFileDataF.isNull(); } -QByteArray MP3::getFullData() { return mFileDataF; } +bool Mp3::isValid() { return !mFileDataF.isNull(); } +QByteArray Mp3::getFullData() { return mFileDataF; } diff --git a/src/mp3.h b/src/mp3.h index f1cba88..2e29872 100644 --- a/src/mp3.h +++ b/src/mp3.h @@ -4,7 +4,7 @@ #include "qx.h" #include "qx-io.h" -class MP3 +class Mp3 { //-Class Variables----------------------------------------------------------------------------------------------- public: @@ -13,8 +13,8 @@ class MP3 static inline const QByteArray MP3_OLD_SIG_2 = Qx::ByteArray::RAWFromStringHex("FFF3"); static inline const QByteArray MP3_OLD_SIG_3 = Qx::ByteArray::RAWFromStringHex("FFF2"); static inline const QByteArray MP3_NEW_SIG = Qx::ByteArray::RAWFromStringHex("494433"); - static const int L_MP3_OLD_SIG = 0x03; - static const int L_MP3_NEW_SIG = 0x04; + static const int L_MP3_OLD_SIG = 0x02; + static const int L_MP3_NEW_SIG = 0x03; //-Instance Variables-------------------------------------------------------------------------------------------- private: @@ -22,11 +22,12 @@ class MP3 //-Constructor------------------------------------------------------------------------------------------------- public: - MP3(QByteArray rawMP3Data); + Mp3(); + Mp3(QByteArray rawMP3Data); //-Instance Functions--------------------------------------------------------------------------------------------------- private: - bool fileIsValidMP3(); + bool fileIsValidMp3(); public: bool isValid(); diff --git a/src/smc.cpp b/src/smc.cpp index 992b44c..5323abc 100644 --- a/src/smc.cpp +++ b/src/smc.cpp @@ -9,7 +9,7 @@ //-Constructor------------------------------------------------------------------------------------------------ //Public: -SMC::SMC(QByteArray rawData) +Smc::Smc(QByteArray rawData) : mFileDataF(rawData) { mValidFile = separateData(); @@ -17,18 +17,18 @@ SMC::SMC(QByteArray rawData) interpretData(); } -SMC::SMC() +Smc::Smc() { mValidFile = true; } //-Instance Functions------------------------------------------------------------------------------------------------ //Public: -QStringList& SMC::getInterpretedCacheListR() { return mCacheListI; } -QStringList SMC::getInterpretedCacheListV() { return mCacheListI; } -bool SMC::isValidCache() { return mValidFile; } +QStringList& Smc::getInterpretedCacheListR() { return mCacheListI; } +QStringList Smc::getInterpretedCacheListV() { return mCacheListI; } +bool Smc::isValidCache() { return mValidFile; } -void SMC::deinterpretData() +void Smc::deinterpretData() { mCacheListR.clear(); @@ -36,7 +36,7 @@ void SMC::deinterpretData() mCacheListR.append(Qx::ByteArray::RAWFromString(mCacheListI.value(i))); } -QByteArray SMC::rebuildRawFile() +QByteArray Smc::rebuildRawFile() { QByteArray rawFile; @@ -51,7 +51,7 @@ QByteArray SMC::rebuildRawFile() } //Private: -bool SMC::separateData() +bool Smc::separateData() { bool fileIsValid = true; mDataCursor = 0x00; // Start of data @@ -80,13 +80,13 @@ bool SMC::separateData() return true; } -void SMC::interpretData() +void Smc::interpretData() { for (int i = 0; i< mCacheListR.length(); i++) mCacheListI.append(Qx::String::fromByteArrayDirectly(mCacheListR.value(i))); } -bool SMC::rawEntryIsValid(QByteArray entry) +bool Smc::rawEntryIsValid(QByteArray entry) { for(int i = 0; i < entry.length(); i++) { diff --git a/src/smc.h b/src/smc.h index b85b3c3..c77030e 100644 --- a/src/smc.h +++ b/src/smc.h @@ -4,7 +4,7 @@ #include #include -class SMC +class Smc { //-Class Variables----------------------------------------------------------------------------------------------- public: @@ -34,8 +34,8 @@ class SMC //-Constructor------------------------------------------------------------------------------------------------- public: - SMC(QByteArray rawData); - SMC(); + Smc(QByteArray rawData); + Smc(); //-Class Functions------------------------------------------------------------------------------------------------------ public: diff --git a/src/smf.cpp b/src/smf.cpp index dadba53..c918f7d 100644 --- a/src/smf.cpp +++ b/src/smf.cpp @@ -9,19 +9,19 @@ //-Constructor------------------------------------------------------------------------------------------------ //Public: -SMF::SMF(QByteArray rawData) : mFileDataF(rawData) +Smf::Smf(QByteArray rawData) : mFileDataF(rawData) { if(!fileIsValidSMF()) mFileDataF = QByteArray(); } //-Class Functions--------------------------------------------------------------------------------------------------- -SMF SMF::fromStandard(WAV wavData) { return addSMFHeader(wavData.getFullData()); } -SMF SMF::fromStandard(MP3 mp3Data) { return addSMFHeader(mp3Data.getFullData()); } +Smf Smf::fromStandard(Wav wavData) { return addSMFHeader(wavData.getFullData()); } +Smf Smf::fromStandard(Mp3 mp3Data) { return addSMFHeader(mp3Data.getFullData()); } //-Instance Functions------------------------------------------------------------------------------------------------ //Private: -bool SMF::fileIsValidSMF() +bool Smf::fileIsValidSMF() { // Get header region QByteArray headers = mFileDataF.left(0x1B); @@ -34,14 +34,14 @@ bool SMF::fileIsValidSMF() if(smfSigRegion == SMF_SIG) { // WAV Check - if(toWAV().isValid()) + if(toWav().isValid()) { - mType = Wav; + mType = WAVE; return true; } - else if(toMP3().isValid()) // MP3 Check + else if(toMp3().isValid()) // MP3 Check { - mType = Mp3; + mType = MP3; return true; } } @@ -50,14 +50,15 @@ bool SMF::fileIsValidSMF() return false; } -QByteArray SMF::addSMFHeader(const QByteArray& fileData) +QByteArray Smf::addSMFHeader(const QByteArray& fileData) { - return Qx::ByteArray::RAWFromString(SMF::SMF_SIG) + QByteArray(SMF::SMF_CMN_FLAGS, 8) + fileData; + return Qx::ByteArray::RAWFromString(Smf::SMF_SIG) + QByteArray(Smf::SMF_CMN_FLAGS, 8) + fileData; } //Public: -bool SMF::isValid() { return !mFileDataF.isNull(); } -QByteArray SMF::getFullData() { return mFileDataF; } -WAV SMF::toWAV() { return WAV(mFileDataF.mid(L_SMF_SIG + L_SMF_CMN_FLAGS)); } // Uses unknown flag values that seem to be common to a huge majority of SMFs -MP3 SMF::toMP3() { return MP3(mFileDataF.mid(L_SMF_SIG + L_SMF_CMN_FLAGS)); } // Uses unknown flag values that seem to be common to a huge majority of SMFs +bool Smf::isValid() { return !mFileDataF.isNull(); } +Smf::Type Smf::getType() { return mType; } +QByteArray Smf::getFullData() { return mFileDataF; } +Wav Smf::toWav() { return Wav(mFileDataF.mid(L_SMF_SIG + L_SMF_CMN_FLAGS)); } // Uses unknown flag values that seem to be common to a huge majority of SMFs +Mp3 Smf::toMp3() { return Mp3(mFileDataF.mid(L_SMF_SIG + L_SMF_CMN_FLAGS)); } // Uses unknown flag values that seem to be common to a huge majority of SMFs diff --git a/src/smf.h b/src/smf.h index c4288f5..9260fbc 100644 --- a/src/smf.h +++ b/src/smf.h @@ -6,11 +6,11 @@ #include "mp3.h" #include "qx-io.h" -class SMF +class Smf { //-Class Enums--------------------------------------------------------------------------------------------------- public: - enum Type {Wav, Mp3}; + enum Type {WAVE, MP3}; //-Class Variables----------------------------------------------------------------------------------------------- public: @@ -33,15 +33,15 @@ class SMF //-Constructor------------------------------------------------------------------------------------------------- public: - SMF(QByteArray rawSMFData); + Smf(QByteArray rawSMFData); //-Class Functions------------------------------------------------------------------------------------------------------- private: static QByteArray addSMFHeader(const QByteArray& fileData); public: - static SMF fromStandard(WAV wavData); - static SMF fromStandard(MP3 mp3Data); + static Smf fromStandard(Wav wavData); + static Smf fromStandard(Mp3 mp3Data); //-Instance Functions--------------------------------------------------------------------------------------------------- private: @@ -49,9 +49,10 @@ class SMF public: bool isValid(); + Type getType(); QByteArray getFullData(); - WAV toWAV(); - MP3 toMP3(); + Wav toWav(); + Mp3 toMp3(); }; #endif // SMF_H diff --git a/src/version.h b/src/version.h index 9cc5869..5d64071 100644 --- a/src/version.h +++ b/src/version.h @@ -1,16 +1,16 @@ #ifndef VERSION_H #define VERSION_H -#define VER_FILEVERSION 0,1,6,0 -#define VER_FILEVERSION_STR "0.1.6.0" +#define VER_FILEVERSION 0,1,7,0 +#define VER_FILEVERSION_STR "0.1.7.0" -#define VER_PRODUCTVERSION 0,1,6,0 -#define VER_PRODUCTVERSION_STR "0.1.6.0" +#define VER_PRODUCTVERSION 0,1,7,0 +#define VER_PRODUCTVERSION_STR "0.1.7.0" #define VER_COMPANYNAME_STR "Obby Apps" #define VER_FILEDESCRIPTION_STR "BSCWorks (CoH:v14)" #define VER_INTERNALNAME_STR "CoH: BSC Editor" -#define VER_LEGALCOPYRIGHT_STR "Copyright © 2020 Obby Apps" +#define VER_LEGALCOPYRIGHT_STR "Copyright © 2021 Obby Apps" #define VER_LEGALTRADEMARKS1_STR "All Rights Reserved" #define VER_LEGALTRADEMARKS2_STR "GNU GPL V3" #define VER_ORIGINALFILENAME_STR "BSCWorks.exe" diff --git a/src/wav.cpp b/src/wav.cpp index 8741277..a2ec4ad 100644 --- a/src/wav.cpp +++ b/src/wav.cpp @@ -8,15 +8,17 @@ //-Constructor------------------------------------------------------------------------------------------------ //Public: -WAV::WAV(QByteArray rawWAVData) : mFileDataF(rawWAVData) +Wav::Wav() {} + +Wav::Wav(QByteArray rawWAVData) : mFileDataF(rawWAVData) { - if(!fileIsValidWAV()) + if(!fileIsValidWav()) mFileDataF = QByteArray(); } //-Instance Functions------------------------------------------------------------------------------------------------ //Private: -bool WAV::fileIsValidWAV() +bool Wav::fileIsValidWav() { // Get header region QByteArray headers = mFileDataF.left(0x0F); @@ -32,6 +34,6 @@ bool WAV::fileIsValidWAV() } //Public: -bool WAV::isValid() { return !mFileDataF.isNull(); } -QByteArray WAV::getFullData() { return mFileDataF; } +bool Wav::isValid() { return !mFileDataF.isNull(); } +QByteArray Wav::getFullData() { return mFileDataF; } diff --git a/src/wav.h b/src/wav.h index bc7b0c2..8425018 100644 --- a/src/wav.h +++ b/src/wav.h @@ -4,7 +4,7 @@ #include #include "qx-io.h" -class WAV +class Wav { //-Class Variables----------------------------------------------------------------------------------------------- public: @@ -22,11 +22,12 @@ class WAV //-Constructor------------------------------------------------------------------------------------------------- public: - WAV(QByteArray rawWAVData); + Wav(); + Wav(QByteArray rawWAVData); //-Instance Functions--------------------------------------------------------------------------------------------------- private: - bool fileIsValidWAV(); + bool fileIsValidWav(); public: bool isValid();