encoding settings
This commit is contained in:
parent
03e7f29d84
commit
5c3a4a592e
@ -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
|
||||
|
@ -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
|
||||
|
@ -12,6 +12,18 @@ constexpr std::string_view jpeg ("image/jpeg");
|
||||
const std::map<std::string, std::string> textIdentificationReplacements({
|
||||
{"PUBLISHER", "TPUB"}
|
||||
});
|
||||
constexpr std::array<int, 10> 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
|
||||
);
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <map>
|
||||
#include <array>
|
||||
#include <stdio.h>
|
||||
|
||||
#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<Logger::Message> getHistory() const;
|
||||
|
@ -17,6 +17,9 @@ enum class Option {
|
||||
destination,
|
||||
parallel,
|
||||
filesToCopy,
|
||||
encodingQuality,
|
||||
outputQuality,
|
||||
vbr,
|
||||
_optionsSize
|
||||
};
|
||||
|
||||
@ -38,13 +41,19 @@ constexpr std::array<std::string_view, static_cast<int>(Option::_optionsSize)> o
|
||||
"source",
|
||||
"destination",
|
||||
"parallel",
|
||||
"filesToCopy"
|
||||
"filesToCopy",
|
||||
"encodingQuality",
|
||||
"outputQuality",
|
||||
"vbr"
|
||||
});
|
||||
|
||||
constexpr std::array<std::string_view, Settings::_typesSize> types({
|
||||
"mp3"
|
||||
});
|
||||
|
||||
constexpr unsigned int maxQuality = 9;
|
||||
constexpr unsigned int minQuality = 0;
|
||||
|
||||
bool is_space(char ch){
|
||||
return std::isspace(static_cast<unsigned char>(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;
|
||||
}
|
||||
|
@ -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<std::string> configPath;
|
||||
std::optional<unsigned int> threads;
|
||||
std::optional<std::regex> nonMusic;
|
||||
std::optional<unsigned char> encodingQuality;
|
||||
std::optional<unsigned char> outputQuality;
|
||||
std::optional<bool> vbr;
|
||||
};
|
||||
|
@ -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>& 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>& settings) {
|
||||
(void)(settings);
|
||||
bool success = std::filesystem::copy_file(
|
||||
job.source,
|
||||
job.destination,
|
||||
|
@ -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>& settings);
|
||||
static JobResult copyJob(const Job& job, const std::shared_ptr<Settings>& settings);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Settings> settings;
|
||||
|
Loading…
Reference in New Issue
Block a user