1
0
forked from blue/mlc

Compare commits

..

1 Commits

Author SHA1 Message Date
ceab08a26d
Typo fixes, readme updates 2024-07-06 13:53:26 -03:00
13 changed files with 86 additions and 58 deletions

View File

@ -1,5 +1,8 @@
# Changelog # Changelog
## MLC 1.3.4 (UNRELEASED)
- Build fixes
## MLC 1.3.3 (October 13, 2023) ## MLC 1.3.3 (October 13, 2023)
- Regex to specify non-music files to copy - Regex to specify non-music files to copy
- Encoding settings (VBR/CBR, encoding quality, output quality) - Encoding settings (VBR/CBR, encoding quality, output quality)
@ -23,7 +26,7 @@
## MLC 1.1.0 (July 23, 2023) ## MLC 1.1.0 (July 23, 2023)
- New logging system - New logging system
- Artist, Album artist, Album and Title are now utf16 encoded, should fix broten titles - Artist, Album artist, Album and Title are now utf16 encoded, should fix broken titles
- BPM tag is now rounded, as it supposed to be by spec - BPM tag is now rounded, as it supposed to be by spec
- Lyrics is not set now for USLT tag for unsychronized lyrics is not supported in LAME - Lyrics is not set now for USLT tag for unsychronized lyrics is not supported in LAME
- Date bug fix, it was MMDD instead of standard DDMM - Date bug fix, it was MMDD instead of standard DDMM

View File

@ -1,8 +1,8 @@
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
project( project(
mlc mlc
VERSION 1.3.3 VERSION 1.3.4
DESCRIPTION "Media Library Compiler: rips your media library to a lossy compilation" DESCRIPTION "Media Library Compiler: converts your media library to a lossy compilation"
LANGUAGES CXX LANGUAGES CXX
) )
cmake_policy(SET CMP0076 NEW) cmake_policy(SET CMP0076 NEW)

View File

@ -1,6 +1,8 @@
# MLC - Music Library Compiler # MLC - Music Library Compiler
This is a program for compilation of your loseless music library to lossy formats [![AUR version](https://img.shields.io/aur/version/mlc?style=flat-square)](https://aur.archlinux.org/packages/mlc/)
This is a program to compile your local lossless music library to lossy formats
### Prerequisites ### Prerequisites
@ -11,7 +13,7 @@ This is a program for compilation of your loseless music library to lossy format
### Building ### Building
``` ```sh
$ git clone https://git.macaw.me/blue/mlc $ git clone https://git.macaw.me/blue/mlc
$ cd mlc $ cd mlc
$ mkdir build $ mkdir build
@ -22,12 +24,48 @@ $ cmake --build .
### Usage ### Usage
Just to compile lossless library to lossy you can use this command
assuming you are in the same directory you have just built `MLC`:
``` ```
./mlc path/to/loseless/library path/to/store/lossy/library ./mlc path/to/lossless/library path/to/store/lossy/library
``` ```
For now the program is very primitive, it only works to convert `.flac` files (it trusts the suffix) to `.mp3` VBR best possible quality slowest possible conversion algorithm. There are more ways to use `MLC`, please refer to help for more options:
MLC keeps file structure, copies all the non `.flac` files, tries to adapt some `.flac` (vorbis) tags to id3v1 and id3v2 of destination `.mp3` file. ```sh
$ ./mlc help
# or
$ ./mlc --help
#
# or
$ ./mlc -h
```
For now it's siglethread, no interrupt controll, not even sure converted files are valid, no exotic cases handled, no conversion options can be passed. May be will improve in the futer. `MLC` has a way to configure conversion process, it will generate global for you user config on the first launch.
It will be located in `~/.config/mlc.conf` and `MLC` will notify you when it's generated.
You can also make local configs for each directory you launch mlc from.
To output the default config run the following, assuming you are in the same directory you have just built `MLC`:
```sh
$ ./mlc config
```
To use non default config run the following, assuming you are in the same directory you have just built `MLC`:
```sh
$ ./mlc path/to/lossless/library path/to/store/lossy/library -c path/to/config/file
```
### About
For now the program is very primitive, it only works to convert `.flac` files (it trusts the suffix) to `.mp3`.
I'm planing to add more lossy formats first then, may be, more lossless.
`MLC` keeps file structure, copies all the non `.flac` files, tries to adapt some `.flac` (vorbis) tags to id3v1 and id3v2 of destination `.mp3` file.
You can set up output format and quality and which kind of files should it skip in the config.
By default `MLC` runs on as many threads as your system can provide to speed up conversion process.
You can set up correct amount of threads in the config.

View File

@ -9,11 +9,11 @@ if(TAGLIB_FOUND)
add_library(TAGLIB::TAGLIB SHARED IMPORTED) add_library(TAGLIB::TAGLIB SHARED IMPORTED)
set_target_properties(TAGLIB::TAGLIB PROPERTIES set_target_properties(TAGLIB::TAGLIB PROPERTIES
IMPORTED_LOCATION "${TAGLIB_LIBRARIES}" IMPORTED_LOCATION "${TAGLIB_LIBRARIES}"
INTERFACE_INCLUDE_DIRECTORIES "${FLAC_INCLUDE_DIR}/taglib" INTERFACE_INCLUDE_DIRECTORIES "${TAGLIB_INCLUDE_DIR}/taglib"
INTERFACE_LINK_LIBRARIES "${TAGLIB_LIBRARIES}" INTERFACE_LINK_LIBRARIES "${TAGLIB_LIBRARIES}"
) )
if (NOT TAGLIB_FIND_QUIETLY) if (NOT TAGLIB_FIND_QUIETLY)
message(STATUS "Found TAGLIB includes: ${FLAC_INCLUDE_DIR}/taglib") message(STATUS "Found TAGLIB includes: ${TAGLIB_INCLUDE_DIR}/taglib")
message(STATUS "Found TAGLIB library: ${TAGLIB_LIBRARIES}") message(STATUS "Found TAGLIB library: ${TAGLIB_LIBRARIES}")
endif () endif ()
else() else()

View File

@ -1,6 +1,6 @@
# Maintainer: Yury Gubich <blue@macaw.me> # Maintainer: Yury Gubich <blue@macaw.me>
pkgname=mlc pkgname=mlc
pkgver=1.3.3 pkgver=1.3.4
pkgrel=1 pkgrel=1
pkgdesc="Media Library Compiler: rips your media library to a lossy compilation" pkgdesc="Media Library Compiler: rips your media library to a lossy compilation"
arch=('i686' 'x86_64') arch=('i686' 'x86_64')

View File

@ -5,12 +5,12 @@
# #
# Use # sign for comments # Use # sign for comments
# #
# All printed comented out values are default values # All printed commented out values are default values
# #
# You should have one of this files as ~/.config/mlc.conf, # You should have one of this files as ~/.config/mlc.conf,
# if you have started mlc at least once. # if you have started mlc at least once.
# This is going to be used every time you launch mlc, # This is going to be used every time you launch mlc,
# so, edit it if you wish to change default behaviour. # so, edit it if you wish to change default behavior.
# #
# Alternatively, you can launch `mlc -c customConfig.conf` # Alternatively, you can launch `mlc -c customConfig.conf`
# if you wish to override ~/.config/mlc.conf file # if you wish to override ~/.config/mlc.conf file
@ -20,26 +20,26 @@
#level info #level info
# Output type # Output type
# Allowed values are: [mp3] (more comming soon) # Allowed values are: [mp3] (more coming soon)
#type mp3 #type mp3
# Source collection path # Source collection path
# This is a default path to your music collection source. # This is a default path to your music collection source.
# It's usefull to set it when you always encode the same collection # It's useful to set it when you always encode the same collection
# Leaving this empty (as it is by default) will make you always # Leaving this empty (as it is by default) will make you always
# specify source in the command line # specify source in the command line
#source #source
# Destingation path # Destination path
# This is a default path for your encoding destination # This is a default path for your encoding destination
# It's usefull to set it when you often encode your collection # It's useful to set it when you often encode your collection
# to the same output # to the same output
# Leaving this empty (as it is by default) will make you always # Leaving this empty (as it is by default) will make you always
# specify destination in the command line # specify destination in the command line
#destination #destination
# Parallel tasks # Parallel tasks
# Defines how many threads are going to be started in parralel # Defines how many threads are going to be started in parallel
# Allowed values are [0, 1, 2, 3 ...] etc # Allowed values are [0, 1, 2, 3 ...] etc
# If it's set to 0 - amount of threads is going to be # If it's set to 0 - amount of threads is going to be
# as high as your processor can effectively handle # as high as your processor can effectively handle
@ -62,9 +62,9 @@
# Output quality # Output quality
# Sets up output quality # Sets up output quality
# The higher quality the less information is lonst in compression # The higher quality the less information is lost in compression
# 0 is the highest possible quality for selected mode and type and results in the biggest file # 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 # 9 is the lowest quality but results in the smallest file
# Allowed values are [0, 1, 2, ... 9] # Allowed values are [0, 1, 2, ... 9]
# For the constant bitrate modes (CBR) the following table is valid # For the constant bitrate modes (CBR) the following table is valid
# Quality | MP3 | # Quality | MP3 |
@ -94,5 +94,5 @@
# Switches on or off variable bitrate # Switches on or off variable bitrate
# VBR files are usually smaller, but not supped to be worse # 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 # in terms of quality. VBR files might be a bit more tricky for the player
# Allowedvalues are: [true, false] # Allowed values are: [true, false]
#vbr true #vbr true

View File

@ -294,28 +294,16 @@ bool FLACtoMP3::scaleJPEG(const FLAC__StreamMetadata_Picture& picture) {
return true; return true;
} }
bool FLACtoMP3::decodeFrame(const int32_t * const buffer[], uint32_t size, const uint32_t bitsPerSample) { bool FLACtoMP3::decodeFrame(const int32_t * const buffer[], uint32_t size) {
if (!outputInitilized) { if (!outputInitilized) {
bool success = initializeOutput(); bool success = initializeOutput();
if (!success) if (!success)
return false; return false;
} }
if (bitsPerSample >= 16)
return decodeFrameImpl(buffer, size, 1 << (bitsPerSample - 16));
return false;
}
bool FLACtoMP3::decodeFrameImpl(const int32_t * const buffer[], uint32_t size, const uint32_t divisor)
{
for (size_t i = 0; i < size; ++i) { for (size_t i = 0; i < size; ++i) {
int32_t left = buffer[0][i]; pcm[pcmCounter++] = (int16_t)buffer[0][i];
int32_t right = buffer[1][i]; pcm[pcmCounter++] = (int16_t)buffer[1][i];
left /= divisor;
right /= divisor;
pcm[pcmCounter++] = (int16_t)left;
pcm[pcmCounter++] = (int16_t)right;
if (pcmCounter == pcmSize) if (pcmCounter == pcmSize)
return flush(); return flush();
@ -406,8 +394,8 @@ FLAC__StreamDecoderWriteStatus FLACtoMP3::write(
self->logger.fatal("ERROR: buffer [1] is NULL"); self->logger.fatal("ERROR: buffer [1] is NULL");
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
} }
bool result = self->decodeFrame(buffer, frame->header.blocksize, frame->header.bits_per_sample); bool result = self->decodeFrame(buffer, frame->header.blocksize);
if (result) if (result)
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;

View File

@ -29,8 +29,7 @@ private:
void processTags(const FLAC__StreamMetadata_VorbisComment& tags); void processTags(const FLAC__StreamMetadata_VorbisComment& tags);
void processInfo(const FLAC__StreamMetadata_StreamInfo& info); void processInfo(const FLAC__StreamMetadata_StreamInfo& info);
void processPicture(const FLAC__StreamMetadata_Picture& picture); void processPicture(const FLAC__StreamMetadata_Picture& picture);
bool decodeFrame(const int32_t * const buffer[], uint32_t size, const uint32_t bitsPerSample); bool decodeFrame(const int32_t * const buffer[], uint32_t size);
bool decodeFrameImpl(const int32_t * const buffer[], uint32_t size, const uint32_t divisor);
bool flush(); bool flush();
bool initializeOutput(); bool initializeOutput();
bool scaleJPEG(const FLAC__StreamMetadata_Picture& picture); bool scaleJPEG(const FLAC__StreamMetadata_Picture& picture);

View File

@ -20,23 +20,23 @@ Flags:
- sets action to help, and prints this page - sets action to help, and prints this page
Examples: Examples:
`mlc ~/Music comile/latest` `mlc ~/Music compile/latest`
- reads config file from `~/.config/mlc.conf` - reads config file from `~/.config/mlc.conf`
- if there was not - creates default that changes nothing - if there was not - creates default that changes nothing
- creates directory `conpile` in the CURRENT directory if it was not created before - creates directory `compile` in the CURRENT directory if it was not created before
- create `latest` directory in `compile` dirrectory if it was not created before - create `latest` directory in `compile` directory if it was not created before
- searches for music in `~/Music` directory - searches for music in `~/Music` directory
- converts all music to `comile/latest` directory - converts all music to `compile/latest` directory
- copies all other files found in `~/Music` to `comile/latest` - copies all other files found in `~/Music` to `compile/latest`
- any file name overlap will be overriden - any file name overlap will be overridden
`mlc config > myConfig.conf` `mlc config > myConfig.conf`
- prints default config to standard output - prints default config to standard output
- unix operator `>` redirects output to a file `myConfig.conf` - unix operator `>` redirects output to a file `myConfig.conf`
`mlc rip -c myConfig.conf` `mlc convert -c myConfig.conf`
- reads file `myConfig.conf` from current directory - reads file `myConfig.conf` from current directory
- if `myConfig.conf` has a valid `source` entry - uses it and uses `rip` as destination - if `myConfig.conf` has a valid `source` entry - uses it and uses `rip` as destination
- if `myConfig.conf` has a valid `destination` entry - uses it and uses `rip` as source - if `myConfig.conf` has a valid `destination` entry - uses it and uses `rip` as source
- if both present (don't do this way) - it depends on the order, who comes first - defines behaviour - if both present (don't do this way) - it depends on the order, who comes first - defines behavior
- the rest is the same from the first example apart from default config - the rest is the same from the first example apart from default config

View File

@ -4,7 +4,7 @@
#include <string_view> #include <string_view>
#include <algorithm> #include <algorithm>
constexpr std::array<std::string_view, static_cast<int>(Logger::Severity::_sevetirySize)> levels({ constexpr std::array<std::string_view, static_cast<int>(Logger::Severity::_severitySize)> levels({
"debug", "debug",
"info", "info",
"minor", "minor",
@ -46,8 +46,8 @@ void Logger::fatal(const std::string& comment, bool colored) const {
Logger::Severity Logger::stringToSeverity(const std::string& line) { Logger::Severity Logger::stringToSeverity(const std::string& line) {
unsigned char dist = std::distance(levels.begin(), std::find(levels.begin(), levels.end(), line)); unsigned char dist = std::distance(levels.begin(), std::find(levels.begin(), levels.end(), line));
if (dist < static_cast<unsigned char>(Severity::_sevetirySize)) if (dist < static_cast<unsigned char>(Severity::_severitySize))
return static_cast<Severity>(dist); return static_cast<Severity>(dist);
return Severity::_sevetirySize; return Severity::_severitySize;
} }

View File

@ -13,7 +13,7 @@ public:
warning, warning,
error, error,
fatal, fatal,
_sevetirySize _severitySize
}; };
using Message = std::pair<Severity, std::string>; using Message = std::pair<Severity, std::string>;

View File

@ -4,7 +4,7 @@
#include <string_view> #include <string_view>
#include <iostream> #include <iostream>
constexpr const std::array<std::string_view, static_cast<int>(Logger::Severity::_sevetirySize)> logSettings({ constexpr const std::array<std::string_view, static_cast<int>(Logger::Severity::_severitySize)> logSettings({
/*debug*/ "\e[90m", /*debug*/ "\e[90m",
/*info*/ "\e[32m", /*info*/ "\e[32m",
/*minor*/ "\e[34m", /*minor*/ "\e[34m",
@ -14,7 +14,7 @@ constexpr const std::array<std::string_view, static_cast<int>(Logger::Severity::
/*fatal*/ "\e[91m" /*fatal*/ "\e[91m"
}); });
constexpr const std::array<std::string_view, static_cast<int>(Logger::Severity::_sevetirySize)> logHeaders({ constexpr const std::array<std::string_view, static_cast<int>(Logger::Severity::_severitySize)> logHeaders({
/*debug*/ "DEBUG: ", /*debug*/ "DEBUG: ",
/*info*/ "INFO: ", /*info*/ "INFO: ",
/*minor*/ "MINOR: ", /*minor*/ "MINOR: ",

View File

@ -203,14 +203,14 @@ unsigned char Settings::getOutputQuality() const {
if (outputQuality.has_value()) if (outputQuality.has_value())
return outputQuality.value(); return outputQuality.value();
else else
return minQuality; //actually, it means max possible quality return minQuality; //it means max possible quality, min is for min enum value
} }
unsigned char Settings::getEncodingQuality() const { unsigned char Settings::getEncodingQuality() const {
if (encodingQuality.has_value()) if (encodingQuality.has_value())
return encodingQuality.value(); return encodingQuality.value();
else else
return minQuality; //actually, it means max possible quality return minQuality; //it means max possible quality, min is for min enum value
} }
bool Settings::getVBR() const { bool Settings::getVBR() const {
@ -269,7 +269,7 @@ void Settings::readConfigLine(const std::string& line) {
std::string lv; std::string lv;
if (!logLevel.has_value() && stream >> lv) { if (!logLevel.has_value() && stream >> lv) {
Logger::Severity level = Logger::stringToSeverity(lv); Logger::Severity level = Logger::stringToSeverity(lv);
if (level < Logger::Severity::_sevetirySize) if (level < Logger::Severity::_severitySize)
logLevel = level; logLevel = level;
} }
} break; } break;