From 5c3a4a592e3be9dabe234cceccc9a3e2580e2363 Mon Sep 17 00:00:00 2001 From: blue Date: Fri, 13 Oct 2023 16:10:08 -0300 Subject: [PATCH] encoding settings --- CHANGELOG.md | 3 ++- src/default.conf | 45 +++++++++++++++++++++++++++++++++++++++ src/flactomp3.cpp | 34 ++++++++++++++++++++++++----- src/flactomp3.h | 2 ++ src/settings.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++-- src/settings.h | 6 ++++++ src/taskmanager.cpp | 22 +++++++++---------- src/taskmanager.h | 6 +++--- 8 files changed, 148 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d7b62e..baa5c37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # Changelog -## MLC 1.3.3 (UNRELEASED) +## MLC 1.3.3 (October 13, 2023) - Regex to specify non-music files to copy +- Encoding settings (VBR/CBR, encoding quality, output quality) ## MLC 1.3.2 (October 10, 2023) - A release purely for CI diff --git a/src/default.conf b/src/default.conf index 7add1f7..68f329a 100644 --- a/src/default.conf +++ b/src/default.conf @@ -51,3 +51,48 @@ # Allowed value are: [all, none] or regex without any additional syntax, # for example: filesToCopy cover\.jpe?g #filesToCopy all + +# Encoding quality +# Sets up encoding quality (NOT OUTPUT QUALITY) +# The higher quality the slower the encoding process +# 0 is the highest quality and slowest process +# 9 is the lowest quality and the fastest process fastest +# Allowed values are: [0, 1, 2, ... 9] +#encodingQuality 0 + +# Output quality +# Sets up output quality +# The higher quality the less information is lonst in compression +# 0 is the highest possible quality for selected mode and type and results in the biggest file +# 9 is the lowest quality but results in the smalest file +# Allowed values are [0, 1, 2, ... 9] +# For the constant bitrate modes (CBR) the following table is valid +# Quality | MP3 | +# --------+-----+-- +# 0 | 320 | +# --------+-----+-- +# 1 | 288 | +# --------+-----+-- +# 2 | 256 | +# --------+-----+-- +# 3 | 224 | +# --------+-----+-- +# 4 | 192 | +# --------+-----+-- +# 5 | 160 | +# --------+-----+-- +# 6 | 128 | +# --------+-----+-- +# 7 | 96 | +# --------+-----+-- +# 8 | 64 | +# --------+-----+-- +# 9 | 32 | +#outputQuality 0 + +# Variable bitrate +# Switches on or off variable bitrate +# VBR files are usually smaller, but not supped to be worse +# in terms of quality. VBR files might be a bit more tricky for the player +# Allowedvalues are: [true, false] +#vbr true diff --git a/src/flactomp3.cpp b/src/flactomp3.cpp index 5b01c1c..2f7d67c 100644 --- a/src/flactomp3.cpp +++ b/src/flactomp3.cpp @@ -12,6 +12,18 @@ constexpr std::string_view jpeg ("image/jpeg"); const std::map textIdentificationReplacements({ {"PUBLISHER", "TPUB"} }); +constexpr std::array bitrates({ + 320, + 288, + 256, + 224, + 192, + 160, + 128, + 96, + 64, + 32 +}); FLACtoMP3::FLACtoMP3(Logger::Severity severity, uint8_t size) : logger(severity), @@ -46,7 +58,7 @@ bool FLACtoMP3::run() { if (pcmCounter > 0) flush(); - int nwrite = lame_encode_flush(encoder, outputBuffer, pcmSize * 2); + int nwrite = lame_encode_flush(encoder, outputBuffer, outputBufferSize); fwrite((char*)outputBuffer, nwrite, 1, output); @@ -98,9 +110,21 @@ void FLACtoMP3::setOutputFile(const std::string& path) { outPath = path; - lame_set_VBR(encoder, vbr_default); - lame_set_VBR_quality(encoder, 0); - lame_set_quality(encoder, 0); +} + +void FLACtoMP3::setParameters(unsigned char encodingQuality, unsigned char outputQuality, bool vbr) { + if (vbr) { + logger.info("Encoding to VBR with quality " + std::to_string(outputQuality)); + lame_set_VBR(encoder, vbr_default); + lame_set_VBR_quality(encoder, outputQuality); + } else { + int bitrate = bitrates[outputQuality]; + logger.info("Encoding to CBR " + std::to_string(bitrate)); + lame_set_VBR(encoder, vbr_off); + lame_set_brate(encoder, bitrate); + } + + lame_set_quality(encoder, encodingQuality); } bool FLACtoMP3::initializeOutput() { @@ -306,7 +330,7 @@ bool FLACtoMP3::flush() { nwrite = lame_encode_buffer_interleaved( encoder, pcm, - pcmCounter, + pcmCounter / 2, outputBuffer, outputBufferSize ); diff --git a/src/flactomp3.h b/src/flactomp3.h index 6ebefc6..fba27db 100644 --- a/src/flactomp3.h +++ b/src/flactomp3.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "logger/accumulator.h" @@ -19,6 +20,7 @@ public: void setInputFile(const std::string& path); void setOutputFile(const std::string& path); + void setParameters(unsigned char encodingQuality, unsigned char outputQuality, bool vbr); bool run(); std::list getHistory() const; diff --git a/src/settings.cpp b/src/settings.cpp index 889aef4..0dabf3b 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -17,6 +17,9 @@ enum class Option { destination, parallel, filesToCopy, + encodingQuality, + outputQuality, + vbr, _optionsSize }; @@ -38,13 +41,19 @@ constexpr std::array(Option::_optionsSize)> o "source", "destination", "parallel", - "filesToCopy" + "filesToCopy", + "encodingQuality", + "outputQuality", + "vbr" }); constexpr std::array types({ "mp3" }); +constexpr unsigned int maxQuality = 9; +constexpr unsigned int minQuality = 0; + bool is_space(char ch){ return std::isspace(static_cast(ch)); } @@ -77,7 +86,10 @@ Settings::Settings(int argc, char ** argv): logLevel(std::nullopt), configPath(std::nullopt), threads(std::nullopt), - nonMusic(std::nullopt) + nonMusic(std::nullopt), + encodingQuality(std::nullopt), + outputQuality(std::nullopt), + vbr(std::nullopt) { for (int i = 1; i < argc; ++i) arguments.push_back(argv[i]); @@ -187,6 +199,27 @@ unsigned int Settings::getThreads() const { return 0; } +unsigned char Settings::getOutputQuality() const { + if (outputQuality.has_value()) + return outputQuality.value(); + else + return minQuality; //actually, it means max possible quality +} + +unsigned char Settings::getEncodingQuality() const { + if (encodingQuality.has_value()) + return encodingQuality.value(); + else + return minQuality; //actually, it means max possible quality +} + +bool Settings::getVBR() const { + if (vbr.has_value()) + return vbr.value(); + else + return true; +} + void Settings::strip(std::string& line) { line.erase(line.begin(), std::find_if(line.begin(), line.end(), std::not_fn(is_space))); line.erase(std::find_if(line.rbegin(), line.rend(), std::not_fn(is_space)).base(), line.end()); @@ -280,6 +313,21 @@ void Settings::readConfigLine(const std::string& line) { nonMusic = regex; } } break; + case Option::outputQuality: { + unsigned int value; + if (!outputQuality.has_value() && stream >> value) + outputQuality = std::clamp(value, minQuality, maxQuality); + } break; + case Option::encodingQuality: { + unsigned int value; + if (!encodingQuality.has_value() && stream >> value) + encodingQuality = std::clamp(value, minQuality, maxQuality); + } break; + case Option::vbr: { + bool value; + if (!vbr.has_value() && stream >> std::boolalpha >> value) + vbr = value; + } break; default: break; } diff --git a/src/settings.h b/src/settings.h index 7c33935..d13b7f8 100644 --- a/src/settings.h +++ b/src/settings.h @@ -40,6 +40,9 @@ public: Action getAction() const; unsigned int getThreads() const; bool matchNonMusic(const std::string& fileName) const; + unsigned char getEncodingQuality() const; + unsigned char getOutputQuality() const; + bool getVBR() const; bool readConfigFile(); void readConfigLine(const std::string& line); @@ -66,4 +69,7 @@ private: std::optional configPath; std::optional threads; std::optional nonMusic; + std::optional encodingQuality; + std::optional outputQuality; + std::optional vbr; }; diff --git a/src/taskmanager.cpp b/src/taskmanager.cpp index 5569040..81cd97f 100644 --- a/src/taskmanager.cpp +++ b/src/taskmanager.cpp @@ -119,14 +119,15 @@ unsigned int TaskManager::getCompleteTasks() const { return completeTasks; } -TaskManager::JobResult TaskManager::execute(const Job& job) { +TaskManager::JobResult TaskManager::execute(Job& job) { switch (job.type) { case Job::copy: - return copyJob(job, settings->getLogLevel()); + return copyJob(job, settings); case Job::convert: switch (settings->getType()) { case Settings::mp3: - return mp3Job(job, settings->getLogLevel()); + job.destination.replace_extension("mp3"); + return mp3Job(job, settings); default: break; } @@ -162,19 +163,18 @@ void TaskManager::printResilt(const TaskManager::Job& job, const TaskManager::Jo ); } -TaskManager::JobResult TaskManager::mp3Job( - const TaskManager::Job& job, - Logger::Severity logLevel) -{ - FLACtoMP3 convertor(logLevel); +TaskManager::JobResult TaskManager::mp3Job(const TaskManager::Job& job, const std::shared_ptr& settings) { + FLACtoMP3 convertor(settings->getLogLevel()); convertor.setInputFile(job.source); - convertor.setOutputFile(job.destination.string() + ".mp3"); + convertor.setOutputFile(job.destination); + convertor.setParameters(settings->getEncodingQuality(), settings->getOutputQuality(), settings->getVBR()); bool result = convertor.run(); + return {result, convertor.getHistory()}; } -TaskManager::JobResult TaskManager::copyJob(const TaskManager::Job& job, Logger::Severity logLevel) { - (void)(logLevel); +TaskManager::JobResult TaskManager::copyJob(const TaskManager::Job& job, const std::shared_ptr& settings) { + (void)(settings); bool success = std::filesystem::copy_file( job.source, job.destination, diff --git a/src/taskmanager.h b/src/taskmanager.h index 25f8ddb..022c016 100644 --- a/src/taskmanager.h +++ b/src/taskmanager.h @@ -35,10 +35,10 @@ public: private: void loop(); - JobResult execute(const Job& job); + JobResult execute(Job& job); void printResilt(const Job& job, const JobResult& result); - static JobResult mp3Job(const Job& job, Logger::Severity logLevel); - static JobResult copyJob(const Job& job, Logger::Severity logLevel); + static JobResult mp3Job(const Job& job, const std::shared_ptr& settings); + static JobResult copyJob(const Job& job, const std::shared_ptr& settings); private: std::shared_ptr settings;