diff --git a/docs/chord_format_spec.md b/docs/chord_format_spec.md new file mode 100644 index 0000000..29a1a44 --- /dev/null +++ b/docs/chord_format_spec.md @@ -0,0 +1,402 @@ +# Спецификация формата данных + +## Проект: генератор аккордовых последовательностей + +**Версия:** 1.0 +**Дата:** 2026-05-03 + +--- + +## 1. Архитектура формата + +Формат двухуровневый: + +- **Источник** — то, что ты пишешь руками. Близок к лид-шиту, человекочитаем, легко правится. +- **Токены** — то, что видит модель. Факторизованное представление с маленьким словарём. + +Между уровнями стоит парсер. Источник → токены — детерминированное преобразование. + +--- + +## 2. Исходный формат + +### 2.1 Структура файла + +Один файл — одна пьеса. Расширение `.chord`. Кодировка UTF-8. + +``` +# title: Sea Glass +# key: D_major +# time: 4/4 +# subdivision: 4 +# style: user +# tempo_bucket: medium + +[intro] +| D . . . | A/C# . . . | Bm7 . . . | A . . . | + +[verse] +| D . . . | F#m7 . . . | G . . . | A . . . | +| Bm7 . . . | F#m7 . . . | G . . . | Asus4 . A . | + +[chorus] +| Gmaj7 . . . | A . . . | F#m7 . . . | Bm7 . . . | +| Gmaj7 . . . | A . . . | D . . . | D . . . | +``` + +### 2.2 Шапка (метаданные) + +Любая строка, начинающаяся с `#`, — метаданные. Формат: `# key: value`. + +| Поле | Обязательно | Допустимые значения | Пример | +| -------------- | ----------- | ------------------------------------------------------------------------------------------- | ----------- | +| `title` | да | свободная строка | `Sea Glass` | +| `key` | да | `_major` или `_minor`, где `` — `C, C#, D, D#, E, F, F#, G, G#, A, A#, B` | `D_major` | +| `time` | да | `4/4`, `3/4`, `6/8`, `2/4`, `12/8` | `4/4` | +| `subdivision` | да | `4` (четвертные) или `8` (восьмые) | `4` | +| `style` | да | `user`, `jpop`, `classical`, `jazz`, `other` | `user` | +| `tempo_bucket` | нет | `slow`, `medium`, `fast`, `very_fast` | `medium` | + +`subdivision` определяет, сколько позиций в одном такте. В `4/4` при `subdivision: 4` — 4 позиции на такт; при `subdivision: 8` — 8 позиций. + +### 2.3 Структурные теги секций + +В квадратных скобках на отдельной строке. Действуют до следующего тега. + +| Тег | Назначение | +| ------------- | ---------- | +| `[intro]` | вступление | +| `[verse]` | куплет | +| `[prechorus]` | предприпев | +| `[chorus]` | припев | +| `[bridge]` | бридж | +| `[interlude]` | проигрыш | +| `[solo]` | соло | +| `[outro]` | концовка | + +### 2.4 Записи аккордов + +Внутри секции — последовательность тактов. Каждый такт обрамлён `|`. + +Внутри такта — `subdivision` позиций, разделённых пробелами. На каждой позиции либо аккордовый символ (новый аккорд начинается здесь), либо `.` (удержать предыдущий аккорд), либо `NC` (no chord — пауза/тишина в гармонии). + +``` +| D . . . | A/C# . . . | ← такт 1: D на 4 четверти; такт 2: A/C# на 4 четверти +| Em7 . D . | A . . . | ← такт 3: Em7 на 2 четверти, D на 2 четверти +| NC . . . | D . . . | ← такт 4: пауза; такт 5: D +``` + +Пробелов между токенами должно быть **строго один**, чтобы парсер по позициям различал доли. + +### 2.5 Комментарии + +Строки, начинающиеся с `//`, парсер игнорирует. Можно использовать для пометок. + +``` +// здесь модулируем в параллельный минор +[bridge] +| Bm . . . | F#m . . . | +``` + +--- + +## 3. Аккордовая нотация + +### 3.1 Корневой тон + +Один из 12 классов высоты, через диез: `C, C#, D, D#, E, F, F#, G, G#, A, A#, B`. + +Бемольная запись (`Db`, `Eb`, `Gb`, `Ab`, `Bb`) допускается на входе и парсер сам приведёт к диезной форме. Энгармоническое написание для модели не значимо. + +### 3.2 Базовые качества (18) + +| Символ | Название | Состав от корня | +| ------------------- | --------------------------- | --------------- | +| `maj` или ничего | мажорное трезвучие | 1, 3, 5 | +| `m` или `min` | минорное трезвучие | 1, b3, 5 | +| `dim` или `°` | уменьшённое трезвучие | 1, b3, b5 | +| `aug` или `+` | увеличенное трезвучие | 1, 3, #5 | +| `sus2` | sus2 | 1, 2, 5 | +| `sus4` | sus4 | 1, 4, 5 | +| `maj7` или `M7` | большой мажорный септаккорд | 1, 3, 5, 7 | +| `m7` | минорный септаккорд | 1, b3, 5, b7 | +| `7` | доминантовый септаккорд | 1, 3, 5, b7 | +| `m7b5` или `ø` | полууменьшённый | 1, b3, b5, b7 | +| `dim7` или `°7` | уменьшённый септ | 1, b3, b5, bb7 | +| `mM7` или `m(maj7)` | минорно-мажорный септ | 1, b3, 5, 7 | +| `7sus4` | доминанта на сус4 | 1, 4, 5, b7 | +| `aug7` или `7#5` | увеличенный септ | 1, 3, #5, b7 | +| `6` | мажорный с секстой | 1, 3, 5, 6 | +| `m6` | минорный с секстой | 1, b3, 5, 6 | +| `add9` | мажор с добавленной ноной | 1, 3, 5, 9 | +| `m(add9)` | минор с добавленной ноной | 1, b3, 5, 9 | + +Запись «без качества» (просто `C`) автоматически = `Cmaj`. + +### 3.3 Расширения (опционально) + +Один опциональный слот после качества. Поддерживаются: + +| Символ | Значение | +| --------------- | ------------------------------------------ | +| `9`, `b9`, `#9` | нона (натуральная, пониженная, повышенная) | +| `11`, `#11` | ундецима | +| `13`, `b13` | терцдецима | + +Примеры: + +- `Cmaj9` = `Cmaj7` + расширение `9` +- `C7b9` = `C7` + расширение `b9` +- `Fmaj7#11` = `Fmaj7` + расширение `#11` (лидийский) +- `Dm9` = `Dm7` + расширение `9` + +Условные сокращения, которые парсер расшифровывает: + +- `9` (например, `C9`) = `7` + расширение `9` (доминантовая нона) +- `maj9` = `maj7` + расширение `9` +- `m9` = `m7` + расширение `9` +- `13` = `7` + расширение `13` +- `m11` = `m7` + расширение `11` + +Если хочется указать сразу несколько расширений (например, альтерированный доминант `C7#9b13`) — модель использует только **первое** расширение в записи. Это сознательное упрощение, чтобы не раздувать комбинаторику. На практике для J-Pop и поп-музыки этого хватает; для джазовых случаев можно записать как ближайший эквивалент. + +### 3.4 Бас и слэш-аккорды + +Для инверсий и слэш-аккордов — стандартный формат `/`: + +``` +F/A ← F с басом A (первое обращение) +G/B ← G с басом B +F/G ← F с басом G (характерный «on-аккорд» из J-Pop) +Em7/G ← Em7 с басом G +``` + +Бас может быть как любой из 12 нот, так и любой ступенью аккорда. Парсер не проверяет, входит ли бас в состав аккорда — это ответственность транскрибера. + +Если слэш-нотация не указана, считается, что бас совпадает с корнем (BASS = root). + +### 3.5 Специальные значения + +| Запись | Значение | +| ------ | -------------------------------------------------------------------------------- | +| `.` | удержать предыдущий аккорд на этой позиции | +| `NC` | нет аккорда (пауза в гармонии) | +| `?` | unknown — для случаев, когда не уверен в транскрипции; парсер заменит на `` | + +--- + +## 4. Внутреннее токенизированное представление + +### 4.1 Словарь (≈100 токенов) + +**Служебные (4):** +``, ``, ``, `` + +**Метаданные (всегда в начале последовательности, после ``):** + +- `KEY__` — 24 токена (12 нот × major/minor) +- `TIME_/` — 5 токенов: `TIME_4/4`, `TIME_3/4`, `TIME_6/8`, `TIME_2/4`, `TIME_12/8` +- `STYLE_` — 5 токенов: `STYLE_user`, `STYLE_jpop`, `STYLE_classical`, `STYLE_jazz`, `STYLE_other` +- `TEMPO_` — 4 токена: `TEMPO_slow`, `TEMPO_medium`, `TEMPO_fast`, `TEMPO_very_fast` +- `SUB_` — 2 токена: `SUB_4`, `SUB_8` + +**Структурные:** + +- `SEC_` — 8 токенов: `SEC_intro`, `SEC_verse`, `SEC_prechorus`, `SEC_chorus`, `SEC_bridge`, `SEC_interlude`, `SEC_solo`, `SEC_outro` +- `BAR` — конец такта + +**Аккордовые (4 слота на каждый аккорд):** + +- `ROOT_` — 12 токенов +- `QUAL_` — 18 токенов (см. §3.2) +- `EXT_` — 8 токенов: `EXT_none`, `EXT_9`, `EXT_b9`, `EXT_#9`, `EXT_11`, `EXT_#11`, `EXT_13`, `EXT_b13` +- `BASS_` — 13 токенов: `BASS_root` плюс 12 нот + +**Временные/специальные:** + +- `HOLD` — позиция продолжает предыдущий аккорд +- `NC` — пауза в гармонии + +**Итого: ≈100 токенов.** + +### 4.2 Структура последовательности + +``` + +KEY_ TIME_ SUB_ STYLE_ [TEMPO_] +SEC_ +ROOT_ QUAL_ EXT_ BASS_ ← новый аккорд = ровно 4 токена +HOLD ← удержание = 1 токен +HOLD +HOLD +BAR +ROOT_ QUAL_ EXT_ BASS_ +HOLD +ROOT_ QUAL_ EXT_ BASS_ +HOLD +BAR +SEC_ +... + +``` + +### 4.3 Правила токенизации (источник → токены) + +1. Прочитать шапку → выпустить `` и токены метаданных. +2. Каждая `[section]` строка → `SEC_`. +3. Для каждой позиции внутри такта: + - Если аккорд: разобрать на (root, quality, extension, bass). Выпустить 4 токена в этом порядке. + - Если `.`: выпустить `HOLD`. + - Если `NC`: выпустить `NC`. + - Если `?`: выпустить ``. +4. После последней позиции такта → `BAR`. +5. В конце пьесы → ``. + +### 4.4 Инвариант длины + +При `subdivision: 4` каждый такт даёт **переменное** число токенов (от 5 до 17): один `BAR` + от 4 (один аккорд × 4 поля) до 16 (четыре аккорда × 4 поля), плюс `HOLD`-ы. В среднем для поп-музыки получится 6–10 токенов на такт. + +Типичная пьеса (~80 тактов) → **600–800 токенов**. Это комфортно укладывается в стандартное контекстное окно 1024–2048. + +--- + +## 5. Полный пример + +### 5.1 Источник + +``` +# title: Example Song +# key: C_major +# time: 4/4 +# subdivision: 4 +# style: user +# tempo_bucket: medium + +[verse] +| Cmaj7 . . . | Am7 . . . | Dm7 . G7 . | Cmaj7 . . . | + +[chorus] +| F . . . | F/G . G . | Em7 . Am7 . | Dm7 . G7sus4 G7 | +``` + +### 5.2 Токенизация + +``` + KEY_C_major TIME_4/4 SUB_4 STYLE_user TEMPO_medium + +SEC_verse + +ROOT_C QUAL_maj7 EXT_none BASS_root +HOLD HOLD HOLD +BAR + +ROOT_A QUAL_min7 EXT_none BASS_root +HOLD HOLD HOLD +BAR + +ROOT_D QUAL_min7 EXT_none BASS_root +HOLD +ROOT_G QUAL_7 EXT_none BASS_root +HOLD +BAR + +ROOT_C QUAL_maj7 EXT_none BASS_root +HOLD HOLD HOLD +BAR + +SEC_chorus + +ROOT_F QUAL_maj EXT_none BASS_root +HOLD HOLD HOLD +BAR + +ROOT_F QUAL_maj EXT_none BASS_G +HOLD +ROOT_G QUAL_maj EXT_none BASS_root +HOLD +BAR + +ROOT_E QUAL_min7 EXT_none BASS_root +HOLD +ROOT_A QUAL_min7 EXT_none BASS_root +HOLD +BAR + +ROOT_D QUAL_min7 EXT_none BASS_root +HOLD +ROOT_G QUAL_7sus4 EXT_none BASS_root +ROOT_G QUAL_7 EXT_none BASS_root +BAR + + +``` + +(В реальности — без переносов строк и пустых строк, всё идёт одним потоком; здесь форматирование только для читаемости.) + +--- + +## 6. Краевые случаи и соглашения + +### 6.1 Анакруза (затакт) + +Записывается как первый «обычный» такт, но с `NC` на пустых позициях: + +``` +| NC . . D | G . . . | +``` + +### 6.2 Смена тональности + +Если внутри пьесы происходит модуляция, можно ввести inline-тег `[modulate: F_major]`. На уровне токенов это выпустит `KEY_F_major` посреди последовательности. **Для первой версии** этим лучше не пользоваться — модель проще учить на тонально стабильных пьесах. Если в твоих работах часто бывают модуляции, расскажи отдельно — обсудим, как разрезать пьесу на тонально-однородные сегменты. + +### 6.3 Смена тактового размера + +Аналогично — inline `[time: 3/4]`. Тоже лучше избегать в первой версии. + +### 6.4 Полиаккорды + +Запись `D/C` (треугольник вверху, квадрат внизу) **не поддерживается** как полиаккорд, только как inverse/слэш. В подавляющем большинстве случаев в поп-музыке слэш-нотации достаточно. Истинные полиаккорды редки и для проекта не критичны. + +### 6.5 Аккорды вне 12-ступенной системы + +Не поддерживаются. Если в материале есть микротональные элементы — округлять до ближайшего темперированного аккорда или отмечать как `?`. + +### 6.6 Pickup notes / fills + +Гармонические заполнения и проходящие аккорды записываются обычным образом, на сетке. Если они короче subdivision (например, проходящий восьмой аккорд при subdivision: 4) — либо переключить subdivision на 8 для этой пьесы, либо округлить. + +### 6.7 Имена файлов + +Рекомендованный формат: `YYYY_NN_short-title.chord`, где `YYYY` — год создания пьесы, `NN` — её номер в этом году. Это упростит хронологическую сортировку датасета и поможет, если потом захочется анализировать эволюцию стиля во времени. + +### 6.8 Что НЕ кодируется + +Сознательно вне формата: + +- voicing (расположение голосов внутри аккорда сверх баса); +- ритмический паттерн внутри удержания (пунктир, синкопы внутри одного аккорда); +- динамика, артикуляция; +- тембр, аранжировка; +- мелодия (это отдельная задача). + +Это правильный уровень абстракции для гармонической задачи. Всё остальное — на ручную работу в DAW при использовании сгенерированной прогрессии. + +--- + +## 7. Чек-лист транскрипции + +При перекладывании пьесы из DAW в `.chord`-файл: + +1. Заполнить шапку: title, key, time, subdivision, style, tempo_bucket. +2. Прослушать пьесу целиком, разметить секции. +3. Для каждой секции — определить шаблонную единицу (4 такта? 8?), записать гармонию по позициям. +4. Прогнать парсер (когда он будет написан) и проверить, что нет `` токенов и предупреждений о неизвестных качествах. +5. Сравнить «на слух»: воспроизвести аккорды в DAW по транскрипции и убедиться, что слышимая гармония совпадает с оригиналом. + +Этот шаг 5 особенно важен — даже с абсолютным слухом легко пропустить инверсию или septима↔nona в плотной фактуре. + +--- + +## 8. История изменений + +- **v1.0** — первоначальная спецификация.