#!/usr/bin/env bash # Детерминированно генерирует тестовую библиотеку (docs/testing.md#тестовая-музыка) в tests/fixtures/music/out. # Реальная музыка в репозиторий не кладётся: звук — синусы и шум разного темпа, теги — вымышленные. # Требуется ffmpeg. Запуск: tests/fixtures/music/generate.sh [out_dir] set -euo pipefail OUT="${1:-$(dirname "$0")/out}" rm -rf "$OUT" mkdir -p "$OUT" # Метроном с заданным BPM: короткие щелчки на синусе — даёт стабильный темп для проверки анализа. tone() { # tone [ffmpeg metadata args...] local file="$1" freq="$2" bpm="$3" secs="$4"; shift 4 mkdir -p "$(dirname "$file")" ffmpeg -nostdin -loglevel error -y \ -f lavfi -i "sine=frequency=${freq}:duration=${secs}:sample_rate=44100" \ -f lavfi -i "sine=frequency=1800:duration=${secs}:sample_rate=44100" \ -filter_complex "[1]volume='if(lt(mod(t,60/${bpm}),0.03),1,0)':eval=frame[clk];[0][clk]amix=inputs=2:normalize=0[a]" \ -map "[a]" -ac 2 "$@" -map_metadata -1 -fflags +bitexact -flags:a +bitexact "$file" } meta() { # meta artist album year track title [genre] local args=(-metadata "artist=$1" -metadata "album_artist=$1" -metadata "album=$2" -metadata "date=$3" -metadata "track=$4" -metadata "title=$5") [ -n "${6:-}" ] && args+=(-metadata "genre=$6") printf '%s\n' "${args[@]}" } with_meta() { # with_meta <genre|""> [encoder args...] local file="$1" freq="$2" bpm="$3" secs="$4"; shift 4 mapfile -t m < <(meta "$1" "$2" "$3" "$4" "$5" "$6") shift 6 tone "$file" "$freq" "$bpm" "$secs" "${m[@]}" "$@" } # 1. Структура «Исполнитель/Год - Альбом/NN - Название» — полные теги, разные форматы. with_meta "$OUT/Тестовый Ансамбль/2019 - Первый альбом/01 - Утро.flac" 440 90 8 "Тестовый Ансамбль" "Первый альбом" 2019 1 "Утро" "Rock" with_meta "$OUT/Тестовый Ансамбль/2019 - Первый альбом/02 - День.flac" 494 128 8 "Тестовый Ансамбль" "Первый альбом" 2019 2 "День" "Rock" with_meta "$OUT/Тестовый Ансамбль/2019 - Первый альбом/03 - Вечер.flac" 523 170 8 "Тестовый Ансамбль" "Первый альбом" 2019 3 "Вечер" "Rock" with_meta "$OUT/Test Collective/2021 - Second Album/01 - Signal.mp3" 330 120 6 "Test Collective" "Second Album" 2021 1 "Signal" "Electronic" -b:a 192k with_meta "$OUT/Test Collective/2021 - Second Album/02 - Noise.opus" 349 140 6 "Test Collective" "Second Album" 2021 2 "Noise" "Electronic" -b:a 96k with_meta "$OUT/Test Collective/2021 - Second Album/03 - Drift.m4a" 392 100 6 "Test Collective" "Second Album" 2021 3 "Drift" "Electronic" -c:a aac -b:a 160k # 2. Многодисковый альбом: «1-01 - …». with_meta "$OUT/Тестовый Ансамбль/2020 - Двойной/1-01 - Сторона А.mp3" 587 110 5 "Тестовый Ансамбль" "Двойной" 2020 1 "Сторона А" "" -b:a 128k with_meta "$OUT/Тестовый Ансамбль/2020 - Двойной/2-01 - Сторона Б.mp3" 622 115 5 "Тестовый Ансамбль" "Двойной" 2020 1 "Сторона Б" "" -b:a 128k # 3. Без тегов — данные только из пути (проверка регэкспов). tone "$OUT/Безымянный/2018 - Только путь/01 - Без тегов.flac" 660 95 5 tone "$OUT/Безымянный/2018 - Только путь/02 - Тоже без тегов.mp3" 698 105 5 -b:a 128k # 4. Другая структура: «Жанр/Исполнитель/Альбом (Год)/NN. Название». with_meta "$OUT/Jazz/Quiet Trio/Night Set (2015)/01. Blue.flac" 262 75 6 "Quiet Trio" "Night Set" 2015 1 "Blue" "Jazz" # 5. Сборник: «Compilations/Альбом/NN - Исполнитель - Название». with_meta "$OUT/Compilations/Best Of Tests/01 - Test Collective - Signal (Edit).mp3" 330 120 4 "Test Collective" "Best Of Tests" 2022 1 "Signal (Edit)" "" -b:a 192k # 6. Дубли: та же запись в другом формате и точная копия файла (проверка дедупликации). with_meta "$OUT/_dupes/День (mp3).mp3" 494 128 8 "Тестовый Ансамбль" "Первый альбом" 2019 2 "День" "Rock" -b:a 192k mkdir -p "$OUT/_dupes/copy" cp "$OUT/Тестовый Ансамбль/2019 - Первый альбом/01 - Утро.flac" "$OUT/_dupes/copy/01 - Утро.flac" # 7. Мусор, который сканер должен пропустить или пометить ошибкой. printf 'not audio' > "$OUT/Безымянный/2018 - Только путь/broken.mp3" printf 'cover' > "$OUT/Тестовый Ансамбль/2019 - Первый альбом/notes.txt" echo "generated $(find "$OUT" -type f | wc -l) files in $OUT"