🔔 School Bell Cutter
Автоматично намиране и рязане на най-добрия момент от песен за училищен звънец
School Bell Cutter е десктоп приложение с графичен интерфейс, което анализира аудио файлове и автоматично открива най-подходящия момент за рязане — така че звънецът да звучи отчетливо, на удар и без изрязани думи или слаби пасажи. Поддържа множество алгоритми за анализ, аудио обработка в реално време и директен предварителен преглед преди запис.
📋 Съдържание
- Защо съществува това?
- Как работи
- Алгоритми за анализ
- Изисквания
- Инсталация
- Употреба
- Аудио настройки
- Структура на проекта
- Известни ограничения
- Технически детайли
- Лиценз
🎯 Защо съществува това?
Ръчното рязане на музика за звънци е досаден и итеративен процес. Трябва да:
- Отвориш аудио редактор
- Слушаш откъс по откъс
- Намериш момент, където песента „влиза" убедително
- Режеш, добавяш fade-in/fade-out, нормализираш
- Повтаряш, докато резултатът звучи добре
Това отнема 10-30 минути за един звънец. School Bell Cutter го прави за под 30 секунди — автоматично, с научно базирани алгоритми за анализ на аудио.
⚙️ Как работи
Приложението следва следния pipeline:
Входен файл
│
▼
[Librosa зарежда аудиото като float32 array]
│
▼
[Избран алгоритъм изчислява "score" за всяка позиция]
│
▼
[top_candidates() намира топ 5 позиции без припокриване]
│
▼
[Потребителят преглежда, коригира и избира]
│
▼
[FFmpeg реже, обработва и записва изходния файл]
Стъпка 1 — Зареждане
При избор на файл librosa.load() го конвертира до mono float32 с оригиналната честота на дискретизация. Данните се пазят в RAM за бърз достъп по-късно. Зареждането е в отделен thread — интерфейсът не замръзва.
Стъпка 2 — Анализ
Избраният алгоритъм обхожда аудиото в рамките на зададения времеви прозорец (От → До) и изчислява скор за всяка потенциална начална позиция на клипа. Работи с hop size от 512 семпъла (~11.6 ms резолюция при 44100 Hz).
Стъпка 3 — Топ кандидати
top_candidates() прилага non-maximum suppression: след намиране на най-добрия пик, блокира зона с ширина clip_dur / 2 около него, преди да търси следващия. Така 5-те кандидата са реално различни позиции, а не клъстер около един пик.
Стъпка 4 — Рязане с FFmpeg
Рязането се извършва директно с FFmpeg чрез subprocess, без междинен файл от pydub. Командата изглежда така:
ffmpeg -y -ss <start> -i <input> -t <duration> -af <filters> -ar 44100 -ac 2 <output>Флагът -ss е поставен преди -i — това е „fast seek" режимът на FFmpeg, значително по-бърз при дълги файлове.
🧠 Алгоритми за анализ
🚀 Fusion (препоръчително)
Комбинира резултатите от всички останали методи чрез тегловно гласуване:
Fusion = Smart Bell × 0.4 + Onset × 0.3 + Percussive × 0.2 + Chorus × 0.1
Всеки метод е нормализиран до [0, 1] преди комбинирането. Fusion е най-устойчив при разнообразни жанрове.
🔔 Smart Bell
Специално проектиран за звуци с ясна атака (като звънец, удар на барабан или пиано). Комбинира:
- Onset strength (0.7 тегло) — открива моменти с рязко нарастване на енергията
- RMS energy (0.3 тегло) — предпочита части с висока средна сила
При конволюцията използва намаляващо ядро (linspace(1.0, 0.2)), за да даде по-голяма тежест на началото на потенциалния клип спрямо края му.
🥁 Beat
Открива темпото чрез librosa.beat.beat_track() и ограничава кандидатите само до позиции, съвпадащи с удари. Ако в зададения прозорец няма удари, автоматично се превключва на Energy метода. Работи добре за поп, рок и танцова музика с ясен ритъм.
⚡ Energy
Изчислява RMS (Root Mean Square) енергия и търси позицията с най-висока средна енергия за целия период на клипа (конволюция с правоъгълно ядро). Прост и бърз, подходящ за тежка музика.
🎵 Chorus
Използва self-similarity matrix базирана на хрома характеристики (chroma_cqt). Части с висок структурен повтор (припеви, теми) получават по-висок скор. Подходящ, когато искаш познатата, повтаряща се част от песента.
🎯 Onset
Чист onset strength без допълнителна обработка — открива моменти с максимална концентрация на нови звукови събития. По-прецизен от Energy за жанрове с много промени.
🥁 Percussive
Прилага Harmonic-Percussive Source Separation (HPSS) чрез librosa.effects.hpss() и изчислява RMS само върху ударния компонент. Идеален за хип-хоп, електронна музика или всяко парче с доминиращи барабани.
📦 Изисквания
Python
Python 3.8 или по-нов
Python пакети
| Пакет | Версия | Защо |
|---|---|---|
customtkinter |
≥ 5.2 | Модерен GUI framework |
librosa |
≥ 0.9 | Аудио анализ и DSP |
pydub |
≥ 0.25 | AudioSegment конфигурация |
numpy |
≥ 1.21 | Числени операции |
scipy |
≥ 1.7 | Сигнална обработка |
pygame |
≥ 2.0 | Предварителен преглед на аудио |
Забележка за pygame: Версии под 2.0 нямат
pygame.mixer.music.unload(). Приложението го открива автоматично сhasattr()и работи коректно и без него, но може да има проблеми с освобождаването на временния preview файл.
Забележка за librosa: От версия 0.10
librosa.beat.beat_track()връща(ndarray, ndarray)вместо(float, ndarray). Кодът е съвместим и с двете версии.
FFmpeg
FFmpeg е задължителен за рязане и аудио обработка. Не се разпространява с приложението.
Windows: Свали от ffmpeg.org и постави ffmpeg.exe в същата папка като main.py.
Linux/macOS:
# Ubuntu/Debian
sudo apt install ffmpeg
# macOS (Homebrew)
brew install ffmpegПриложението търси FFmpeg в следния ред:
- Папката на
main.py - Папката на стартирания процес
- Системния
PATH
🛠️ Инсталация
1. Клонирай репозиторито
git clone https://github.com/<твоето-потребителско-име>/school-bell-cutter.git
cd school-bell-cutter2. Създай виртуална среда (препоръчително)
python -m venv venv
# Windows
venv\Scripts\activate
# Linux/macOS
source venv/bin/activate3. Инсталирай зависимостите
pip install customtkinter librosa pydub numpy scipy pygame4. Добави FFmpeg
Windows: Постави ffmpeg.exe (и опционално ffprobe.exe) в папката на проекта.
Linux/macOS: FFmpeg от apt/brew се открива автоматично в PATH.
5. Стартирай
python main.pyПри успешно стартиране заглавната лента показва ✅ ffmpeg: ffmpeg.exe.
При неуспех — ❌ ffmpeg НЕ е намерен! и ще се появи диалог с инструкции.
🖥️ Употреба
Основен workflow
1. Избери входен файл → 2. Задай прозорец → 3. Анализирай
↓ ↓
4. Прегледай кандидатите → 5. (По желание) Коригирай времето
↓
6. Изрежи и запази
Подробно описание
Входен файл
Поддържани формати: .mp3, .wav, .flac, .ogg, .m4a, .aac — всичко, което FFmpeg може да декодира.
При избор на файл се стартира фоново зареждане, което показва:
- Пълна дължина в
MM:SS.ssформат - Честота на дискретизация в Hz
- Името на файла
Времеви прозорец
- От — начало на търсенето в секунди (0 = от самото начало)
- До — край на търсенето в секунди (остави
(края)за цялата песен)
Полезно когато знаеш приблизително къде е хубавата част на песента — стеснявайки прозореца ускоряваш анализа и намаляваш шума от нерелевантни участъци.
Дължина на клипа
Слайдерът контролира дължината на изходния клип от 5 до 120 секунди. Стандартните училищни звънци са 20-45 секунди.
Метод на анализ
Виж раздел [Алгоритми за анализ](#-алгоритми-за анализ). Бутонът ℹ️ отваря описание директно в приложението.
Топ кандидати
След анализа се появяват до 5 кандидата, наредени по скор. За всеки можеш да:
- ▶ Пусни — чуеш откъса с всички текущи аудио настройки (fade, EQ, нормализация)
- ⏹ Спри — спреш възпроизвеждането
- +/- бутони — коригираш начало и край с ±0.5 секунди
- Ръчно въведеш точно време в полетата (формат
MM:SS.ss, напр.01:23.50) - 🔄 — нулираш до оригиналната позиция от алгоритъма
- ✔ Избери — маркираш като активен кандидат за рязане
Динамично поле показва реалната дължина след корекциите.
Изходен файл
Ако не е зададен изричен път, файлът се записва до оригинала с наставка _bell:
/music/my_song.mp3 → /music/my_song_bell.mp3
Поддържани изходни формати: .mp3, .wav, .ogg, .flac.
🎚️ Аудио настройки
Нормализация
Контролира финалната сила на звука. Два режима:
LUFS (препоръчително) — Loudness Units Full Scale. Стандарт използван от стрийминг платформи. Прилага ffmpeg loudnorm филтъра.
- Target по подразбиране: -14 LUFS
- Диапазон: -23 до -6 LUFS
- По-ниска стойност = по-тих; по-висока = по-силен
Peak — нормализира до максимална амплитуда. По-просто, но без контрол над perceived loudness.
⚠️ Техническа бележка: FFmpeg
loudnormв единичен проход е приблизителен. За максимална точност е нужен двупроходен анализ (анализ → нормализация). За училищни звънци единичният проход е достатъчен.
Еквалайзер
| Параметър | Честота | Диапазон | Ефект |
|---|---|---|---|
| Bass | 100 Hz, октава | -10 до +10 dB | Повече/по-малко дъно |
| Treble | 8000 Hz, октава | -10 до +10 dB | По-ясни/по-меки висини |
| Volume | — | -12 до +12 dB | Обща сила след EQ |
Еквалайзерът използва FFmpeg equalizer филтър (biquad peaking EQ).
Fade In / Fade Out
Стандартни линейни fade ефекти чрез ffmpeg afade. Диапазон 0-5 секунди.
- Fade-in стартира от началото на клипа
- Fade-out завършва точно в края на клипа
Битрейт (само MP3/AAC/OGG)
| Стойност | Препоръка |
|---|---|
| 128k | Минимално приемливо качество |
| 192k | Добро качество, малък файл (по подразбиране) |
| 256k | Високо качество |
| 320k | Максимално MP3 качество |
📁 Структура на проекта
school-bell-cutter/
│
├── main.py # Целият код — GUI + аудио логика
├── ffmpeg.exe # (Windows) Постави тук ★
├── ffprobe.exe # (Windows, опционално) По-точен анализ
│
├── song_cache/ # Автоматично създадена при preview
│ └── preview.wav # Временен файл за предварителен преглед
│
└── README.md
Папката
song_cache/се създава автоматично при първото preview. Може да я изтриеш по всяко време — ще се пресъздаде. Препоръчително е да я добавиш в.gitignore.
.gitignore препоръка
# Cache
song_cache/
# Виртуална среда
venv/
.venv/
# FFmpeg бинарни файлове (не ги commit-вай)
ffmpeg.exe
ffprobe.exe
# Python
__pycache__/
*.pyc
*.pyo⚠️ Известни ограничения
Loudnorm единичен проход
FFmpeg loudnorm в единичен проход дава приблизителен резултат. При критично важна нормализация (напр. за излъчване) използвай двупроходна команда ръчно или се откажи от нормализацията в приложението и я направи отделно.
Preview файл и Windows file locking
На Windows OS заключва файлове докато се ползват. Ако спреш preview и веднага пуснеш нов, FFmpeg може да даде грешка Access denied при презаписването на preview.wav. Вградено решение: _stop_preview() + 0.2s пауза преди всяко ново preview. При персистиращи проблеми изчакай секунда преди пускане.
Librosa зарежда целия файл в RAM
За много дълги файлове (>1 час) зареждането може да отнеме 30+ секунди и да изисква 1-3 GB RAM. Нямаш нужда от streaming анализ за звънци — те обикновено идват от песни с нормална дължина.
Loudnorm и WAV изход
loudnorm работи правилно и за WAV изход, но резултатът може да се различава леко от MP3 поради различното вътрешно квантизиране.
🔧 Технически детайли
Thread архитектура
Приложението използва три типа threads:
| Thread | Задача | Защита |
|---|---|---|
| Main (Tkinter) | GUI events | — |
_load_meta |
Librosa зареждане | threading.Lock за _y, _sr, _total_dur |
_run_analysis |
Алгоритмичен анализ | Локално копие на аудио данните под lock |
_preview / worker |
FFmpeg + pygame | Daemon thread |
_do_cut / worker |
FFmpeg рязане | Daemon thread |
Всички UI обновявания от фонови threads минават през self.after(0, callback) — стандартният Tkinter-safe начин.
FFmpeg интеграция
Рязането не използва pydub за самото рязане — само за конфигурация на пътищата. Причините:
- pydub зарежда целия сегмент в RAM преди запис
- FFmpeg директно поддържа
loudnormиafadeкато native филтри - По-малко зависимости в критичния path
Командата за рязане е конструирана в build_af_filter() и изпълнена с subprocess.run() с capture_output=True за прихващане на грешки.
Hop size и времева резолюция
Всички librosa операции използват hop_length=512. При 44100 Hz:
Времева резолюция = 512 / 44100 ≈ 11.6 ms
Това е достатъчно за практически цели — разликата от 11ms не се чува.
📄 Лиценз
MIT License — виж LICENSE файла.
🙏 Благодарности
- librosa — аудио анализ
- CustomTkinter — модерен GUI
- FFmpeg — аудио обработка и кодиране
- pygame — аудио playback
Направен с 🔔 за всички, които режат звънци ръчно и страдат.