Привет, Хабр! Меня зовут Артур Валиев. Я продолжаю делать свой VST3-плагин Mix Teacher AI.
В прошлый раз я рассказывал про идею плагина: поставить его на дорожку, посмотреть уровни, пики, RMS, примерный LUFS, частотные зоны и получить простую подсказку человеческим языком.
Но довольно быстро стало понятно, что анализировать только одну дорожку мало.
Потому что в сведении часто проблема не в одной дорожке.
Кик сам по себе нормальный.
Бас сам по себе нормальный.
Вокал сам по себе нормальный.
Барабаны вроде тоже нормальные.
А вместе всё почему-то не звучит.
И вот тут начинается самая интересная часть: конфликты между дорожками.
Зачем понадобился Mix Hub
Когда я делал первую версию Mix Teacher AI, логика была простая:
поставил плагин на вокал — получил анализ вокала;
поставил на бас — получил анализ баса;
поставил на drum bus — получил анализ барабанов.
Это удобно, но только до определённого момента.
Например, плагин может сказать:
Бас активен в 40-150 Hz.
И отдельно на кике:
Кик активен в 40-150 Hz.
Но главная проблема не в том, что оба источника имеют низ. Это нормально. Кик и бас почти всегда живут рядом.
Проблема начинается тогда, когда они одновременно занимают одно и то же место и мешают друг другу.
Особенно в DnB, EDM, trap, hip-hop и вообще в музыке, где низ — это не просто фон, а основа грува.
Поэтому я начал делать Mix Hub.
Идея такая:
-
на отдельные дорожки ставится Mix Teacher AI в режиме
Track; -
на мастер ставится ещё один экземпляр в режиме
Mix Hub; -
дорожечные экземпляры публикуют свои данные;
-
Mix Hub собирает общую картину и пытается понять, кто с кем конфликтует.
Это всё ещё прототип. Но уже стало намного интереснее, потому что плагин начал смотреть не только на одну дорожку, а на отношения между ними.
Почему просто “частоты совпали” недостаточно
Сначала я сделал простую проверку: если две дорожки активны в одном диапазоне и уровни близкие, значит есть конфликт.
Примерно так:
if (kickLow > -55.0f && bassLow > -55.0f && std::abs(kickLow - bassLow) < 5.0f){ // Kick и Bass могут конфликтовать}
Работает? Иногда да.
Но в реальном миксе этого мало.
Например, у баса может быть стабильный саб, а кик может ударять коротко. По среднему спектру они оба есть в 40-150 Hz. Но это ещё не значит, что они реально мешают.
И наоборот: уровни могут быть не очень близкими, но если каждый удар кика совпадает с пиком баса, низ начинает мазаться.
Поэтому я добавил второй слой анализа: временное совпадение низа.
Low-end timing
Для каждой дорожки теперь считается lowEndCurve.
Это такая кривая активности низа по времени. Не полный спектр, а упрощённый индикатор: насколько активно ведёт себя зона ниже примерно 150 Hz в каждом временном окне.
Внутри это выглядит примерно так:
std::array<float, dynamicsBins> lowEndCurve {};
А при анализе истории аудио я дополнительно считаю низ через простой low-pass:
float lowState = 0.0f;const auto lowPassAlpha = std::exp(-twoPi * 155.0 / sampleRate);for (int i = samplesPerBin - 1; i >= 0; --i){ const auto value = analysisHistory[index]; lowState = lowPassAlpha * lowState + (1.0f - lowPassAlpha) * value; lowSumSquares += lowState * lowState;}const auto lowRms = std::sqrt(lowSumSquares / samplesPerBin);const auto lowDb = linearToDb(lowRms);snapshot.lowEndCurve[bin] = normaliseDb(lowDb, -78.0f, -20.0f);
Это не полноценный хирургический анализ саба. Но для MVP этого достаточно, чтобы понять: низ в этом временном окне активен или нет.
Как Mix Hub сравнивает кик и бас
Когда Mix Hub видит дорожку Kick или Drums Bus и дорожку Bass, он сравнивает их lowEndCurve.
Смысл простой:
-
где активен кик;
-
где активен бас;
-
где они активны одновременно;
-
насколько сильное совпадение;
-
насколько это может быть проблемой.
Упрощённо:
for (int i = 0; i < dynamicsBins; ++i){ const auto kickValue = kick.lowEndCurve[i]; const auto bassValue = bass.lowEndCurve[i]; const auto kickActive = kickValue >= kickThreshold; const auto bassActive = bassValue >= bassThreshold; if (kickActive || bassActive) ++activeBins; if (kickActive && bassActive) { ++overlapBins; curve[i] = std::sqrt(kickValue * bassValue); }}
Потом считается отношение:
simultaneousRatio = overlapBins / activeBins;
И общий риск:
risk = simultaneousRatio * 0.48f + weightedOverlap * 0.34f + audibility * 0.18f;
Если риск небольшой — это просто потенциальное пересечение.
Если риск выше — плагин уже пишет:
Низ Kick/Bass совпадает по времени.
И предлагает не сразу резать EQ, а сначала проверить в контексте:
Для DnB/808 проверь groove в контексте. Если низ мажется, начни с короткого sidechain или dynamic EQ 1-3 dB ниже 120 Hz, а не с большого static EQ cut.
Мне важно, чтобы плагин не говорил “делай вот так”. Он должен говорить:
похоже, тут есть риск; вот где смотреть; вот безопасный первый шаг.
Карта конфликтов
В UI я добавил карту частотных конфликтов.
Сначала она показывала только явные пересечения. Но это оказалось слишком строго. В реальном миксе полезно видеть и потенциальные пересечения.
Поэтому сейчас логика мягче:
-
есть явные конфликты;
-
есть потенциальные пересечения;
-
Kick/Bass проверяется отдельно;
-
линии сортируются по важности;
-
отображаются до 7 связей.
Если конфликтов нет, теперь текст звучит аккуратнее:
Потенциальных пересечений пока не видно.
А не “всё идеально”.
Потому что анализатор не должен врать. Если он не увидел проблему, это не значит, что проблемы нет. Это значит только то, что в текущем окне анализа он её не поймал.
LOW TIME
Самая полезная новая визуальная штука — полоса LOW TIME.
Она показывает моменты, где низ кика и баса совпадает.
Визуально это маленький timeline внутри карты конфликтов. Чем ярче сегмент, тем сильнее совпадение.
В коде это просто отрисовка массива:
for (int i = 0; i < dynamicsBins; ++i){ const auto value = hub.lowEndTiming.curve[i]; if (value <= 0.01f) continue; const auto h = area.getHeight() * value; g.fillRoundedRectangle( Rectangle<float>(x, bottom - h, cellW, h), 2.0f );}
Но с точки зрения пользователя это уже не просто “кик и бас где-то конфликтуют”.
Можно увидеть:
-
конфликт постоянный;
-
конфликт только на ударах;
-
конфликт появляется в хвосте баса;
-
конфликт происходит короткими всплесками.
Для DnB это особенно полезно, потому что там кик, саб, reese bass и драм-партия могут жить очень плотно.
JSON для Mix Hub
Я продолжаю делать JSON-экспорт, потому что в будущем хочу отправлять отчёт в AI/Ollama.
Теперь Mix Hub отдаёт не только общий список проблем, но и данные по low-end timing:
{ "analysis_mode": "mix_hub", "track_count": 3, "frequency_conflicts": [ { "track_a_type": "kick", "track_b_type": "bass", "band": "40-80 Hz foundation", "strength": 0.73, "severity": "problem" } ], "low_end_timing": { "available": true, "track_a_type": "kick", "track_b_type": "bass", "simultaneous_ratio": 0.46, "weighted_overlap": 0.52, "risk": 0.61, "severity": "warning", "curve": [0.0, 0.2, 0.7, 0.4] }}
Такой JSON потом можно отдать нейросети и попросить объяснить:
-
что происходит;
-
почему кик и бас мешают друг другу;
-
что попробовать;
-
какие действия безопасные;
-
чего лучше не делать.
Важный момент про audio thread
Я стараюсь держать audio callback лёгким.
В нём нельзя делать тяжёлые вещи:
-
FFT;
-
JSON;
-
UI;
-
HTTP;
-
аллокации;
-
долгие вычисления;
-
блокировки.
Поэтому архитектура такая:
-
Audio thread собирает минимальные данные.
-
Samples уходят в FIFO/history.
-
Анализ работает по накопленной истории.
-
UI показывает готовый snapshot.
Упрощённо:
void processBlock(AudioBuffer<float>& buffer, MidiBuffer& midi){ midi.clear(); applyGoodizer(buffer); // peak, RMS, clipping // mono samples -> FIFO}
А дальше уже вне audio callback:
updateDynamics(snapshot);updateHistoryLevels(snapshot);updateSpectrum(snapshot);updateValidity(snapshot);updateTrackDetection(snapshot);updateDrumProfile(snapshot);snapshot.issues = buildTeacherIssues(snapshot);
Для Mix Hub добавился ещё один слой:
auto peerSnapshot = processor->getLatestAnalysisSnapshot();hub.tracks.push_back(makeHubTrackSummary(peerSnapshot));
То есть master-инстанс собирает данные от других экземпляров.
Что стало понятнее после тестов
Когда я начал тестировать на кике и басе, сразу вылезла проблема: плагин мог писать “явных частотных пересечений нет”, хотя на слух низ явно мешался.
Почему?
Потому что первая версия искала слишком очевидный конфликт.
Она хотела, чтобы:
-
оба источника были достаточно громкими;
-
оба были в одной зоне;
-
уровни были почти одинаковыми.
Но в музыке так бывает не всегда.
Иногда бас тише, но его хвост совпадает с киком.
Иногда кик короткий, но в момент удара он ломает саб.
Иногда конфликт не постоянный, а ритмический.
Иногда проблема слышна только в контексте, а не по среднему спектру.
Поэтому я сделал анализ мягче и добавил “potential overlaps”.
Теперь плагин не ждёт идеального математического совпадения. Он показывает и возможные места, куда стоит посмотреть.
Про GOODIZER
Отдельно в плагине осталась экспериментальная ручка GOODIZER.
Это уже не анализатор, а творческий эффект.
На 0% звук не меняется.
Если начать крутить, включается обработка: drive, saturation, presence и soft-clip.
Я сделал её в стиле “одна большая ручка, чтобы стало веселее”. Интерфейс реагирует цветом и анимацией: чем больше значение, тем агрессивнее выглядит ручка.
Да, это немного несерьёзно.
Но музыка вообще не всегда должна быть только про серьёзные таблицы. Иногда хочется, чтобы инструмент был чуть живее.
Маленькое секретное окно
Ещё я добавил мелочь в интерфейс: если нажать на заголовок MIX TEACHER AI, появляется маленькое окно.
Там написано спасибо за тестирование, автор, короткое описание. Есть кнопка “Спасибо”. При нажатии запускается анимация рукопожатия.
Зачем?
Да просто потому что захотелось. Иногда в проекте должны быть маленькие человеческие штуки. Особенно если это не корпоративный продукт, а живой open-source прототип.
Что сейчас умеет проект
На текущий момент в Mix Teacher AI есть:
-
VST3 для Windows;
-
режим
Track; -
режим
Mix Hub; -
выбор типа источника;
-
русский и английский язык;
-
waveform;
-
spectrum;
-
peak/RMS;
-
approximate LUFS short-term;
-
crest factor;
-
headroom;
-
clipping count;
-
анализ частотных зон;
-
анализ динамики;
-
transient detection;
-
sibilance detection;
-
drum-oriented зоны;
-
mono compatibility warning;
-
JSON export;
-
GOODIZER;
-
карта частотных конфликтов;
-
low-end timing для Kick/Bass;
-
визуальная полоса LOW TIME;
-
удержание Mix Hub-картины, чтобы она не дёргалась слишком быстро.
Что пока ограничено
Важно честно сказать: это всё ещё прототип.
Ограничения есть:
-
LUFS пока approximate;
-
true peak ещё не полноценный oversampled true peak meter;
-
Mix Hub работает между экземплярами внутри одного процесса DAW;
-
плагин не знает настоящие имена дорожек из Studio One;
-
эвристики могут ошибаться;
-
AI/Ollama ещё не встроен напрямую;
-
reference track пока нет;
-
полноценного анализа всего проекта DAW нет.
И это нормально.
Я не пытаюсь сделать “идеальный автоматический звукорежиссёр”. Я пытаюсь сделать помощника, который подсказывает, куда смотреть.
Установка
Скачать можно здесь:
https://github.com/vaalimusic/mix-teacher-ai/releases
Установка:
-
Скачать архив.
-
Содержимое архива положить в:
C:\Program Files\Common Files\VST3
-
Сделать rescan VST3-плагинов в DAW.
-
Поставить Mix Teacher AI как insert-effect.
Для Mix Hub:
-
на кик поставить экземпляр в режиме
Track, типKick; -
на бас поставить экземпляр в режиме
Track, типBass; -
на мастер поставить экземпляр в режиме
Mix Hub; -
запустить playback.
После этого Mix Hub должен увидеть дорожки и показать возможные пересечения.
Что дальше
Ближайшие идеи:
-
улучшить LUFS;
-
сделать более точный true peak;
-
добавить жанровые режимы: DnB, Rap, Pop, Rock, EDM;
-
улучшить sibilance detection;
-
улучшить transient detection;
-
добавить имена дорожек вручную;
-
сделать heatmap частотных конфликтов;
-
добавить сравнение vocal/instrumental;
-
добавить before/after snapshots;
-
сделать reference track;
-
подключить Ollama;
-
сделать нормальный AI-ответ внутри плагина.
Особенно хочется развить Mix Hub.
Потому что анализ одной дорожки — это полезно. Но настоящая боль сведения часто живёт между дорожками.
Кик против баса.
Вокал против синтов.
Хэты против сибилянтов.
Гитары против вокала.
Низ против мастера.
И если плагин сможет хотя бы подсветить эти места, уже будет полезно.
Заключение
Я продолжаю делать Mix Teacher AI как инструмент для себя.
Не как “замену звукорежиссёра”.
Не как “магический AI-мастеринг”.
Не как “нажми кнопку и получи хит”.
А как помощника, который говорит:
похоже, здесь есть проблема;
вот почему она может мешать;
вот безопасный первый шаг;
дальше слушай сам в контексте.
Мне нравится эта философия.
Потому что сведение — это не набор рецептов. Это постоянное “послушал -> понял -> попробовал -> сравнил”.
Если плагин помогает быстрее дойти до этого понимания, значит я двигаюсь в правильную сторону.
В целом, огромное спасибо всем кто пишет и просит о функционале, я действительно чувствую обратную связь, это потрясающе. Я совместил мечту и желание сделать что-то полезное, это невероятно круто. Буду рад обратной связи от музыкантов, продюсеров и звукорежиссёров. Особенно интересно, где подсказки ошибаются, какие сценарии сведения стоит добавить и какие конфликты между дорожками реально хочется видеть в Mix Hub. Я обновил релиз на гитхабе.
Знаете, когда ты растешь как специалист, хабр позволяет рассказать свою историю. В Целом это чудо, Спасибо что прочитали!
ссылка на оригинал статьи https://habr.com/ru/articles/1055648/