Загрузка данных
Архитектура проекта Audio Visualizer
Общая схема
Проект — веб-приложение для генерации видео-визуализаций аудиофайлов. Пользователь загружает аудио через браузер, настраивает слои визуализации, нажимает «Render» — сервер покадрово рендерит видео и отдаёт результат.
Бэкенд (Python / Flask)
Точка входа: web/app.py — Flask-сервер на порту 5001.
Маршруты:
GET / — отдаёт index.html
GET /api/layers — возвращает метаданные всех слоёв (параметры, типы, дефолты, описания). Парсит configs/default.yaml через get_layers_metadata()
GET /api/samples — список сэмплов из web/samples/
GET /sample/<filename> — отдаёт сэмпл-файл
POST /upload — принимает аудио (файл / reuse_audio_job_id / sample_file) + JSON с конфигом pipeline. Запускает рендер в отдельном потоке
GET /status/<job_id> — поллинг прогресса рендера (JSON с progress, status, message)
POST /cancel/<job_id> — отмена рендера
GET /preview/<job_id> / GET /download/<job_id> — отдача готового видео
GET /audio/<job_id> — отдача загруженного аудио (для restore из истории)
Процесс рендера (process_video()):
AudioProcessor загружает аудио через librosa, анализирует (BPM, биты, RMS, FFT)
VisualizerFactory.create('pipeline', ...) создаёт PipelineRenderer
PipelineRenderer через LayerRegistry создаёт цепочку слоёв по order из конфига
render_with_progress() покадрово вызывает visualizer.render_frame(time) — каждый слой рисует поверх предыдущего
Видео пишется через FFMPEG_VideoWriter, затем ffmpeg мержит с аудио
Конфигурация: ConfigLoader загружает configs/default.yaml как базу, мержит с пользовательскими параметрами через deep update.
Система слоёв: BaseLayer — абстрактный класс. Каждый слой реализует _render_direct(time, frame). Базовый класс обеспечивает:
Блендинг (normal / add / multiply / screen / overwrite) в _apply_blend()
Цветовой градиент primary→secondary в get_color_gradient()
Opacity
9 слоёв (зарегистрированы в LayerRegistry):
Слой Файл Что делает
background background_layer.py Фон: gradient / solid / animated (не зависит от звука)
waveform waveform_layer.py Волна по амплитуде: mirror / filled / simple / energy
spectrum spectrum_layer.py FFT-спектр: bars / circular / wave
particles particles_layer.py Частицы, реагируют на RMS и частоты
energy_rings energy_rings_layer.py Концентрические кольца, пульсируют по частотным зонам
circular_waveform circular_waveform_layer.py Круговая волна: mirror / filled / bars / energy
circular_spectrum circular_spectrum_layer.py Круговой FFT-спектр: bars / wave
circular_particles circular_particles_layer.py Частицы по орбитам вокруг центра
effects effects_layer.py Постобработка: glow / vignette / grain / chromatic aberration
Фронтенд (Vanilla JS + CSS)
HTML: web/templates/index.html — одностраничное приложение с тремя зонами: основная панель, сайдбар истории, оверлеи (прогресс, превью).
JS-модули:
app.js — главный оркестратор. Управляет:
Загрузкой файла / выбором сэмпла
Запуском рендера (POST /upload с FormData)
Поллингом прогресса (GET /status/<id> каждые 500мс)
Превью / скачиванием результата
Восстановлением из истории (reuse audio)
pipeline.js — управление pipeline UI:
Рендерит список слоёв (drag & drop для порядка)
Рендерит панель параметров выбранного слоя (автогенерация по метаданным с /api/layers)
Типы контролов: color picker, enum select, multi-enum chips, boolean toggle, number input, text
Сортировка параметров: цвета → enum → boolean → числа
Floating tooltip для описаний параметров (через JS, не CSS ::after)
player.js — кастомный аудиоплеер с trim (обрезка start/end)
history.js — история рендеров в localStorage
CSS: Модульная структура в web/static/css/:
base.css — переменные, reset, контролы
layout.css — сетка, upload area, sidebar
pipeline.css — слои, параметры, tooltip
player.css — аудиоплеер, trim
overlay.css — прогресс, превью
Поток данных (полный цикл)
[Браузер] [Сервер]
│ │
├─ GET /api/layers ──────────────────► парсит default.yaml
│◄─ JSON {layers, default_order} ─────┤
│ │
├─ GET /api/samples ─────────────────► сканирует web/samples/
│◄─ JSON [{filename, name}] ──────────┤
│ │
│ [Пользователь настраивает pipeline] │
│ │
├─ POST /upload ─────────────────────► сохраняет аудио
│ FormData: audio + pipeline_config │ создаёт config
│◄─ {job_id} ─────────────────────────┤ запускает Thread
│ │
├─ GET /status/{id} (polling) ───────► AudioProcessor.load_audio()
│◄─ {progress, status, message} ──────┤ PipelineRenderer(layers)
│ ... каждые 500мс ... │ покадровый render_frame()
│ │ ffmpeg merge audio
│◄─ {status: 'completed'} ────────────┤
│ │
├─ GET /preview/{id} ────────────────► send_file(output.mp4)
└─ GET /download/{id} ───────────────► send_file(output.mp4)