I prefer local control of media data, the rent-to-listen approach of various streaming services is certainly convenient, but pay-forever, you get what we think you should models don’t appeal to me. Over the decades, I’ve converted various eras of my physical media to digital formats using different standards that were in vogue at the time and with different emphasis on various metadata tags yielding a rather heterogeneous collection with some annoying incompatibilities that sometimes show up, for example using the Music plugin with NextCloud streaming via Subsonic to Sublime Music or Ultrasonic on Android. I spent some time poking around to find a set of tools that satisfied my preferences for organization and structure and filled in a missing gap or two; this is what I’m doing these days and what with.
The steps outlined here are tuned to my particular use case:
- Linux-based process.
- I prefer mp3 to aac or flac because the format is widely compatible. mp3 is pretty clearly inferior to aac for coding efficiency (aac produces better sound with less bits) and aac has some cool features that mp3 doesn’t but for my use compatibility wins.
- My ears ain’t what they used to be. I’m not sure I could ever reliably have heard the difference between 320 CBR and 190 VBR, but I definitely can’t now and less data is less data.
- I like metadata and the flexibility in organization it provides, and like it standardized.
So to scratch that itch, I use the following steps:
- Convert FLAC/high-data rate mp3s to VBR (about 190 kbps) with ffmpeg
- Fix MP3 meta info wierdsies with MP3 Diags
- NEW! Verify the audio with sox
- Add Replay Gain tags with loudness-scanner
- Add BPM tags with bpm-tag from bpm-tools
- Use Puddletag to:
- Clean any stray tags
- Assign Genre, Artist, Year, Album, Disk Number, Track, Title, & Cover
- Apply a standard replace function to clean text of weird characters
- Refile and re-name in a most-os-friendly way
- Clean up any stray data in the file system.
Links to the tools at the bottom.
Convert FLAC to MP3 with FFMPEG
The standard tool for media processing is ffmpeg. This works for me:
find . -depth -type f -name "*.flac" -exec ffmpeg -i {} -q:a 2 -c:v copy -map_metadata 0 -id3v2_version 3 -write_id3v1 1 {}.mp3 \; A summary: find unix find command to return each found file one-by-one . search from the current directory down -depth start at the bottom and work up -type f find only files (not directories) -name "*.flac" files that end with .flac -exec ffmpeg pass each found file to ffmpeg -i {} ffmpeg takes the found file name as input -q:a 2 VBR MP3 170-210 kbps -c:v copy copy the video stream (usually the cover image) -map_metadata 0 copy the metadata from input to global metadata of output -id3v2_version 3 write ID3v2.3 tag format (more compatible than ID3v2.4) -write_id3v1 1 also write old style ID3v1 tags (maybe useless) {}.mp3 \; write output file (which yields "/original/filename.flac.mp3")
For album encodes with a .cue or in other formats where the above would yield one giant file, Flacon is your friend. I would use two steps: single flac -> exploded flac, then the ffmpeg encoder myself just for comfort with the encoding parameters.
Convert high data rate CBR MP3 to VBR
Converting high data rate CBR files requires a bit more code to detect that a given file is high data rate and CBR, for which I wrote a small bash script that leverages mediainfo to extract tags from the source file and validate.
#!/bin/bash # first make sure at least some parameter was passed, if not echo some instructions if [ $# -eq 0 ]; then echo "pass a file name or try: # find . -type f -name "*.mp3" -exec recomp.sh {} \;" exit 1 fi # assign input 1 to “file” to make it a little easier to follow file=$1 # get the media type, the bitrate, and the encoding mode and assign to variables type=$(mediainfo --Inform='General;%Format/String%' "$file") brate=$(mediainfo --Inform='General;%OverallBitRate/String%' "$file" |& grep -Eo [0-9]+) mode=$(mediainfo --Inform='Audio;%BitRate_Mode/String%' "$file") # first check: is the file an mpeg audio file, if not quit if [[ "$type" != "MPEG Audio" ]]; then echo $file skipped, not valid audio exit 0 fi # second check: if the file is already VBR, move on. if [[ "$mode" = "Variable" ]]; then echo $file skipped, already variable exit 0 fi # third check: the output will be 170-210, no reason to expand low bit rate files if [[ "$brate" -gt 221 ]] then ffmpeg -hide_banner -loglevel error -i "$file" -q:a 2 -c:v copy -map_metadata 0 -id3v2_version 3 -write_id3v1 1 "${file}.mp3" rm "${file}" mv "${file}.mp3" "${file}" echo $file recompressed to variable fi exit
I named this script “~/projects/recomp/recomp.sh” and call it with
find . -depth -type f -name "*.mp3" -exec ~/projects/recomp/recomp.sh {} \;
which will scan down through all sub-directories and find files with .mp3 extensions, and if suitable, re-compress them to VBR as above. Yes, this is double lossy and not very audiophile, definitely prioritizing smaller files over acoustic fidelity which I cannot really hear anyway.
Fix bad data with MP3 Diags
MP3 Diags is a GUI tool for cleaning up bad tags. It is pretty solid and hasn’t mangled any of my files yet. It has two basic functions: passively highlight missing useful tags (replaygain, cover image, etc) and actively fix messed up tags which is a file-changing operation so make backups if needed. I generally just click the tools buttons “1”–”4″ and it seems to do the right thing. Thanks Ciobi!
Install was easy on Ubuntu:
sudo apt install mp3diags
UPDATE Jan 2024
Binaries aren’t being built for Linux any more. If you’re going to build, the slightly non-standard dependencies include:
sudo apt install libqt5svg5 zlib1g-dev libzstd-dev libboost-dev libboost-program-options-dev git clone https://github.com/mciobanu/mp3diags.git cd mp3diags cmake -S . -B build/release -DCMAKE_BUILD_TYPE=Release cmake --build build/release -j $(getconf _NPROCESSORS_ONLN) cd build/release sudo make install
Check MP3 content validity with sox
Sox actually reads the audio stream block by block, which is a slow way to check files, but if there’s some bit flip or other corruption in the data stream, the other validation options won’t see it, but sox will and probably barf. An easy way to check is to have sox read all the mp3 files and output any encountered errors like so:
find . -depth -type f -name "*.mp3" -exec sox {} -n -V2 \; -n # null output - just do the math on the input, don't write anything -V2 # verbose 2: Errors and warnings, including clipping
Errors might look like:
sox FAIL formats: can't open input file `./11-Precious_Memories.mp3': Invalid argument
Bummer, probably a borked file.
sox
is slow and single threaded, so running multiple instances down different directory trees may speed results.
I wrote a shell script to gather stats and flag outliers, here.
Add ReplayGain Tags
To bulk add (or update) ReplayGain tags, I find loudness-scanner very easy. I just use the droplet version and drop folders on it. The defaults do the right thing, computing track and album gain by folder. The droplet pops up a confirmation dialog which can be lost on a busy desktop, remember it. Click to apply the tags then wait for it to finish before closing that tag list window or it will seg fault. The only indication is in the command prompt window used to launch it, which shows “….” as it progresses and when the dots stop, you can close the tags window.
I built it from source – these steps did the needful for me:
git clone https://github.com/jiixyj/loudness-scanner cd loudness-scanner git submodule init git submodule update mkdir build cd build cmake .. make sudo make install
Then launch the droplet with
~/projects/loudness-scanner/build/loudness-drop-gtk
Add Beats Per Minute Tags
Beats per minute calcs are mostly useful for DJ types, but I use them to easily sort music for different moods or for exercise. The calculation seems a bit arbitrary for things like speech or classical, but for those genres where BPM is relevant, bpm-tools seems to yield results that make sense.
Install with
sudo apt-get install libsox-fmt-mp3 bpm-tag
Then write tags with (the -f
option overwrites existing tags).
find . -name "*.mp3" -exec bpm-tag -f {} \;
Puddletag
Back in my Windows days, I really liked MP3Tag. I was really happy to find puddletag, an mp3tag inspired linux variant. It’s great, does everything it should. I wish I had something like this for image metadata editing: the spreadsheet format is very easy to parse. One problem I had was the deunicode tool wasn’t decoding for me, so I wrote my own wee function to extend the functions.py
by calling the unidecode function. only puddlestuff/functions.py
needs to be patched to add this useful decode feature. UTF8 characters are well supported in tags, but not in all file structures and since the goal is compatibility, mapping them to fairly intelligible ASCII characters is useful.
This works with the 2.1.1 version.
Below is a patch file to show the very few changes needed.
--- functions.py.bak 2022-04-14 13:58:47.937873000 +0300 +++ functions.py 2022-04-14 16:49:23.705786696 +0300 @@ -43,6 +43,7 @@ from mutagen.mp3 import HeaderNotFoundError from collections import defaultdict from functools import partial +from unidecode import unidecode import pyparsing @@ -769,6 +770,10 @@ cleaned_fn = unicodedata.normalize('NFKD', t_fn).encode('ASCII', 'ignore') return ''.join(chr(c) for c in cleaned_fn if chr(c) in VALID_FILENAME_CHARS) +# hack by David Gessel +def deunicode(text): + dutext = unidecode(text) + return (dutext) def remove_dupes(m_text, matchcase=False): """Remove duplicate values, "Remove Dupes: $0, Match Case $1" @@ -1126,7 +1131,8 @@ 'update_from_tag': update_from_tag, "validate": validate, 'to_ascii': to_ascii, - 'to_num': to_num + 'to_num': to_num, + 'deunicode': deunicode } no_fields = [filenametotag, load_images, move, remove_except
I use the “standard” action to clean up file names with a few changes:
- In “title” and “album” I replace ‘ – ‘ with ‘–‘
- in all, I RegExp replace ‘(\s)’ with ‘ ‘ – all blank space with a regular space.
- I replace all %13 characters with a space
- I RegExp ‘(\s)+’ with ‘ ‘ – all blank runs with a single space
- Trim all to remove leading and ending spaces.
My tag->filename function looks like this craziness which reduces the risk of filename misbehavior on most platforms:
~/$validate(%genre%,_,/\*?;”|: +<>=[])/$validate($deunicode(%artist%),_,/\*?;”|: +<>=[])/%year%--$left($validate($deunicode(%album%),_,/\*?;”|: +<>=[]),136)$if(%discnumber%, --D$num(%discnumber%,2),"")/$left($num(%track%,2)--$validate($deunicode(%title%),_,/\*?;”|: +<>=[]),132)
Puddletag is probably in your repository. To mod the code, I first installed from source per the puddletag instructions, but had to also add unidecode to my system with
pip install unidecode
Last File System Cleanups
The above steps should yield a clean file structure without leading or trailing spaces, indeed without any spaces at all, but in case it doesn’t the rename function can help. I installed it with
sudo apt install rename
This is useful to, for example, normalize errant spelling of mp3 – for example Mp3 or MP3 or, I suppose, mP3.
find . -depth -exec rename 's/\.mp3$/.mp3/i' {} + aside from parameters explained previously 's/A/B/' substitute B for each instance of A \. escaped "." because "." has special meaning $ match end of string - so .mp3files won't match, but files.mp3 does i case insensitive match (.mp3 .MP3 .mP3 .Mp3 all match)
The following commands clean up errant spaces before after and repeated:
find . -depth -exec rename 's/^ *//' {} + find . -depth -exec rename 's/ *$//' {} + find . -depth -exec rename 's/\s+/_/g' {} +
If moving files around results in empty directories (or empty files, which shouldn’t happen) then they can be cleaned with
find . -depth -type d -empty -print -delete find . -depth -type f -empty -print -delete
Players
If workflow preferences are highly personal, player prefs seem even more so. Mine are as follows:
For Local Playback on a PC: Quod Libet
I like to sort by genre, artist, year, and album and Quod Libet makes that as easy as in foobar2000 did back in the olde days when Windows was still an acceptable desktop OS. Those days are long, long over and while I am still fond of the foobar2000 approach, Quod Libet doesn’t need Wine.
Alas, one shortcoming still is that Quod Libet does not support subsonic or ampache. That’s too bad because I really like the UI/UX.
For Subsonic Streaming on a PC: Sublime Music
Not the text editor, the music app. It is pretty good, more pretty than Quod Libet and in a way that doesn’t entirely appeal to me, but it seems to work fairly well with NextCloud and is the best solution I’ve found so far. It tends to flow quite a few errors and I see an odd bug where album tile selection jumps around, but it seems to work and a local program linking back to a server is generally more performant than in browser, but that’s also an option (see below) or run foobar2000 in Wine, perhaps even as an (ugh!) snap.
In Browser: NextCloud Music
Nextcloud’s Music app is one of those that imposes a sorting model that doesn’t work for me – not at all foobar2000ish – and so I don’t really use it much, but there are times, working on site for example, that a browser window is easiest. I find I often have to rebuild the music database after changes. Foam or Ample might be more satisfying choices functionally and aesthetically and can connect to the backend provided by Music.
Mobile: Ultrasonic
Ultrasonic works pretty well for me and seems to connect fairly reliably to my NextCloud server even in low bandwidth situations (though, obviously, not fast enough to actually listen to anything, but it doesn’t barf.) Power Ampache might be another choice still currently developed (but I haven’t tried it myself). Subsonic also worked with NextCloud, but I like Ultrasonic better and it is still actively developed.
If you’re on iOS instead of Android (congratulations on the envy your overpriced corporate icon inspires in the less fortunate) you almost certainly stick exclusively with your tribal allegiance and have no need for media outside of iTunes/Apple TV approved content.
[…] sound processing,” and a useful tool for checking audio files that belongs in anyone’s audio processing workflow. I thought it might be useful for detecting improperly encoded audio files or those files that have […]