2026-06-29 10:42:56 +02:00
2026-06-28 13:50:48 +02:00
2026-06-28 18:55:40 +02:00
2026-06-08 15:51:44 +02:00
2026-06-28 13:51:28 +02:00
2026-06-28 18:55:40 +02:00

audio-library-manager

audio-library-manager maintains a music library in two forms:

  1. a source FLAC tree, optionally normalised so FLAC files do not exceed a configured sample rate; and
  2. a mirrored Opus tree, where FLAC files are converted to .opus and non-FLAC sidecar files are copied unchanged.

The current entry point is audio-manager.rkt, exported as the function audio-manager from main.rkt.

The implementation is intentionally simple. It is a command-line batch process: scan files, compare with the saved state, run a small ordered set of processing steps, write the state, send a report. It does not use places, channels, threads or a worker protocol.

Requirements

Racket packages:

  • racket-audio
  • simple-ini
  • simple-log
  • net-lib

Native libraries are provided or loaded by racket-audio. For the current audio path this normally means FLAC, Opus/Opusenc, TagLib and SoXR. FFmpeg is not part of the intended FLAC-to-Opus path; it is only relevant for racket-audio features that need FFmpeg-based decoding.

Usage

From a Racket REPL or a small wrapper script:

#lang racket/base

(require audio-library-manager)

(audio-manager "/mnt/music" "/mnt/music-opus")

The first argument is the source music tree. The second argument is the target Opus mirror tree.

The optional log level defaults to debug:

(audio-manager "/mnt/music" "/mnt/music-opus" #:log-level 'info)

Files created in the source tree

The manager stores its administration files in the source directory:

  • .audio-manager.ini — configuration, read with simple-ini.
  • .audio-manager.db — serialized state hash, keyed by normalized relative paths.
  • .audio-manager.log — log file.

State keys are normalized relative paths from the source tree. Absolute mount points are not stored, and path separators are normalized to /. This makes the state less dependent on the local mount point used on a particular machine.

Configuration

The manager expects a configuration file at:

<source-tree>/.audio-manager.ini

Example:

[flac]
max-khz=48000

[opus]
kbps=224

[mail]
from=Audio Manager <audio@example.org>
to=Hans <hans@example.org>
server=smtp.example.org
port=25
user=
passwd=

The mail section is currently required. If the mail configuration is missing or incomplete, the manager fails at startup with a configuration error. This is intentional: a batch run should not silently skip reporting.

Processing model

The manager uses a file walker with an ordered processing pipeline. Each step receives:

base-path path info

and returns the same three values, with info possibly enriched. The info hash contains the relative path, type, extension, state and any metadata discovered by earlier steps.

The important file states are:

  • new — the relative path was not present in the saved state.
  • changed — the path existed before, but type, size or modification time changed.
  • unchanged — the path exists and its basic filesystem state is unchanged.
  • deleted — the path existed in the saved state but no longer exists in the source tree.

For unchanged entries, the previous enriched info hash is reused. For changed entries, the previous info hash is reused but marked as changed and updated with the current type, size and modification time. Stages must therefore treat changed as the signal to re-inspect content-dependent data.

The pipeline is grouped conceptually as:

  1. enrichment: normalize/identify known extensions, sniff audio files, detect FLAC-with-ID3, and read FLAC sample rate/bit depth when needed;
  2. conversion/actions: downsample FLAC files above the configured rate, embed a sidecar cover image when a FLAC has no embedded picture, convert FLAC to Opus, and copy non-FLAC sidecar files;
  3. cleanup/logging: remove target files for deleted source entries and log progress.

FLAC handling

FLAC files are detected by extension and confirmed by racket-audio sniffing. A file with extension .flac but an ID3 prefix is reported as a FLAC-with-ID3 case. Such files are not treated as ordinary sidecar files.

For valid FLAC files:

  • sample rate and bit depth are read through the FLAC decoder;
  • files with a sample rate greater than [flac] max-khz are converted in place through racket-audio/audio-encoder;
  • conversion is synchronous and direct;
  • if the file has no embedded picture, cover.jpg, cover.jpeg, folder.jpg, folder.jpeg, cover.png or folder.png in the same directory is embedded as a front-cover picture.

Temporary FLAC files produced by interrupted conversions should be ignored by the scanner. The implementation uses manager-specific temporary names for this purpose.

Opus mirror handling

For every processable FLAC source file, the manager writes a corresponding Opus file under the target tree:

source: album/track.flac
target: album/track.opus

The default bitrate is 224 kbps and can be changed with [opus] kbps.

Non-FLAC files are copied unchanged to the target tree when they are new, changed, or missing from the target. Hidden files are ignored. Typical copied sidecar files include cover images, PDFs, cue sheets and logs.

When a source entry is deleted, the corresponding target entry is removed. For a deleted FLAC source, the target extension is changed from .flac to .opus. Renames are deliberately represented as deleted plus new; no rename detection is attempted.

Logging and report

The manager logs to:

<source-tree>/.audio-manager.log

The report contains sections for:

  • FLAC files with ID3 tags;
  • FLAC conversions and cover updates;
  • Opus conversions;
  • file counters for processed, new, changed, unchanged and deleted files;
  • failed conversions and failed copies.

At the end of a successful scan the serialized state is written to .audio-manager.db and the report is sent by mail.

API

(audio-manager music-path opus-path #:log-level [log-level 'debug])

Runs the complete batch process. music-path is the source tree and opus-path is the target Opus mirror tree. The function returns 'done after a completed run.

Design notes

The package intentionally keeps responsibilities separated:

  • audio-manager.rkt orchestrates the batch run and owns the pipeline;
  • private/file-walker.rkt scans the filesystem and maintains the state model;
  • private/flac-handling.rkt contains FLAC inspection and FLAC downsampling;
  • private/opus-handling.rkt contains FLAC-to-Opus conversion;
  • private/mail.rkt sends reports;
  • private/log.rkt defines the logger;
  • private/util.rkt contains small path/date/cover helpers.

The manager does not implement an audio pipeline itself. Audio decoding, encoding, metadata and resampling are delegated to racket-audio.

S
Description
If you have a directory with, e.g. /music with a library containing flac music tracks, this will resample the files to at most 48.000Hz (get rid of the 96Khz/192Khz files that one will never hear the difference to 48Khz). Also there's a flac -> opus conversion path (to e.g. /music-opus) to make a portable library. It will keep the information about the files in /music/.music-info.db.
Readme MIT 108 KiB
Languages
Racket 98.8%
Shell 1.1%
Makefile 0.1%