Загрузка данных


Архитектура проекта 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)