# Спецификация формата данных ## Проект: генератор аккордовых последовательностей **Версия:** 2.0 **Дата:** 2026-05-16 --- ## 1. Что описывает этот документ Формат хранения и кодирования гармонических периодов для обучения генеративной модели и для практического использования модели как творческого помощника. Один файл в этом формате описывает **один гармонический период** (4–16 тактов) — замкнутую гармоническую фразу. --- ## 2. Архитектура формата Формат двухуровневый: - **Исходный (`.chord`)** — то, что пишется руками. Близок к лид-шиту, человекочитаем, легко правится в любом текстовом редакторе. - **Токенизированный** — то, что подаётся в модель. Факторизованное представление с маленьким словарём (~75 токенов). Между уровнями стоит детерминированный парсер. --- ## 3. Исходный формат `.chord` ### 3.1 Пример ``` # title: Sea Glass - chorus # key: D_major # time: 4/4 # subdivision: 4 # style: user # function: chorus | Gmaj7 . . . | A . . . | F#m7 . . . | Bm7 . . . | | Gmaj7 . . . | A . . . | D . . . | D . . . | ``` ### 3.2 Структура файла Один файл — один период. Расширение `.chord`. Кодировка UTF-8. Состоит из двух частей: 1. **Шапка** — строки, начинающиеся с `#`, в любом порядке. 2. **Тело** — последовательность тактов, каждый обрамлён `|`. Пустые строки игнорируются. Комментарии (`// ...`) игнорируются парсером. ### 3.3 Поля шапки | Поле | Обязательно | Допустимые значения | Назначение | | ------------- | ----------- | -------------------------------------------------------------------------------- | -------------------------------------------- | | `title` | да | свободная строка | идентификация периода | | `key` | да | `_major` или `_minor` | для нормализации в C/Am перед обучением | | `time` | да | `4/4`, `3/4`, `6/8`, `2/4`, `12/8` | тактовый размер | | `subdivision` | да | `4` или `8` | сколько позиций в одном такте | | `style` | да | `user`, `jpop`, `classical`, `jazz`, `other` | стилевой тег периода | | `function` | нет | `verse`, `prechorus`, `chorus`, `bridge`, `intro`, `outro`, `interlude`, `other` | функциональная роль периода в исходной пьесе | **Допустимые ноты для `key`:** `C, C#, D, D#, E, F, F#, G, G#, A, A#, B`. Бемольные написания (`Db`, `Eb`, ...) принимаются и нормализуются к диезной форме. **`subdivision`** определяет, сколько позиций в одном такте: - При `subdivision: 4` в `4/4` — 4 позиции на такт (одна на четверть). - При `subdivision: 8` в `4/4` — 8 позиций на такт (одна на восьмую). - Для `3/4` — соответственно 3 или 6 позиций. - Для `6/8` — 6 позиций при `subdivision: 8`, рекомендуемое значение. ### 3.4 Тело файла Последовательность тактов. Такты записываются на одной строке через `|` или каждый на своей строке — парсер обрабатывает оба варианта одинаково. Внутри такта — ровно `subdivision` позиций (или соответствующее число для нестандартных размеров), разделённых **одним пробелом**. На каждой позиции — один токен. ### 3.5 Что может стоять на позиции | Запись | Значение | | ----------------- | ------------------------------------------------------------ | | Аккордовый символ | новый аккорд начинается здесь | | `.` | удержать предыдущий аккорд | | `NC` | no chord — пауза в гармонии | | `?` | unknown — для случаев неуверенности; парсер выпустит `` | Первая позиция первого такта не может быть `.` (нечего удерживать). ### 3.6 Комментарии Строки и хвосты строк, начинающиеся с `//`, игнорируются: ``` // здесь характерный приём с проходящим басом | F . . . | F/E . . . | Dm . . . | Dm/C . . . | ``` --- ## 4. Аккордовая нотация ### 4.1 Структура аккордового символа ``` (/)? ``` Примеры: - `C` → root=C, quality=maj (по умолчанию), без extension, bass=root - `Am7` → root=A, quality=min7, без extension, bass=root - `Fmaj9` → root=F, quality=maj7, extension=9, bass=root - `G7/B` → root=G, quality=7, без extension, bass=B - `Dm9/F` → root=D, quality=min7, extension=9, bass=F ### 4.2 Корневой тон Один из 12 классов: `C, C#, D, D#, E, F, F#, G, G#, A, A#, B`. Бемольная запись принимается. ### 4.3 Базовые качества (18) | Символ | Альтернативы | Состав от корня | | --------------- | ------------------------------ | --------------- | | `maj` или пусто | — | 1, 3, 5 | | `m`, `min` | `-` | 1, ♭3, 5 | | `dim` | `°` | 1, ♭3, ♭5 | | `aug` | `+` | 1, 3, ♯5 | | `sus2` | — | 1, 2, 5 | | `sus4` | `sus` | 1, 4, 5 | | `maj7` | `M7`, `Δ7`, `Δ` | 1, 3, 5, 7 | | `m7` | `min7`, `-7` | 1, ♭3, 5, ♭7 | | `7` | — | 1, 3, 5, ♭7 | | `m7b5` | `ø`, `ø7`, `m7♭5` | 1, ♭3, ♭5, ♭7 | | `dim7` | `°7` | 1, ♭3, ♭5, ♭♭7 | | `mM7` | `m(maj7)`, `minMaj7` | 1, ♭3, 5, 7 | | `7sus4` | `7sus` | 1, 4, 5, ♭7 | | `aug7` | `7#5`, `+7` | 1, 3, ♯5, ♭7 | | `6` | `maj6` | 1, 3, 5, 6 | | `m6` | `min6` | 1, ♭3, 5, 6 | | `add9` | `2` (в некоторых поп-нотациях) | 1, 3, 5, 9 | | `m(add9)` | `madd9`, `m(add2)` | 1, ♭3, 5, 9 | Если качество не указано (например, просто `C`), оно автоматически = `maj`. ### 4.4 Расширения (опционально) Один опциональный слот после качества: | Символ | Значение | | ------ | ---------------- | | `9` | нона натуральная | | `b9` | ♭9 | | `#9` | ♯9 | | `11` | ундецима | | `#11` | ♯11 (лидийская) | | `13` | терцдецима | | `b13` | ♭13 | **Условные сокращения, которые парсер расшифровывает автоматически:** | Запись | Расшифровка | | ---------- | --------------------------- | | `C9` | quality=7, extension=9 | | `Cmaj9` | quality=maj7, extension=9 | | `Cm9` | quality=m7, extension=9 | | `C13` | quality=7, extension=13 | | `Cmaj13` | quality=maj7, extension=13 | | `Cm11` | quality=m7, extension=11 | | `C7b9` | quality=7, extension=b9 | | `Cmaj7#11` | quality=maj7, extension=#11 | **Ограничение:** ровно один слот расширения на аккорд. Если в исходной пьесе встречается аккорд с несколькими альтерациями (например, `C7♯9♭13`), нужно выбрать одну наиболее характерную и записать её. Это сознательное упрощение для уменьшения комбинаторики словаря. ### 4.5 Инверсии и слэш-аккорды Стандартный формат `/`: ``` F/A ← F, бас A (первое обращение) G/B ← G, бас B (первое обращение) F/G ← F с басом G (характерный on-аккорд из J-Pop) Em7/G ← Em7, бас G D/F# ← D, бас F♯ ``` Бас может быть любой из 12 нот. Парсер не проверяет, входит ли бас в состав аккорда — это ответственность транскрибера. Если слэш не указан, считается `bass = root`. **Инверсии обязательны к точной записи.** Они несут значительную часть стилистической информации (особенно для J-Pop материала с характерной on-нотацией). ### 4.6 Полные примеры разбора | Запись | root | quality | extension | bass | | --------- | ---- | ------- | --------- | ---- | | `C` | C | maj | none | root | | `Am` | A | m | none | root | | `F#m7` | F# | m7 | none | root | | `Cmaj9` | C | maj7 | 9 | root | | `G7sus4` | G | 7sus4 | none | root | | `F/G` | F | maj | none | G | | `Bb7b9/D` | A# | 7 | b9 | D | | `Em7b5` | E | m7b5 | none | root | | `D#dim7` | D# | dim7 | none | root | --- ## 5. Токенизированное представление ### 5.1 Принцип нормализации тональности **Перед токенизацией каждый период транспонируется в каноническую тональность:** - мажорные периоды → C major, - минорные периоды → A minor. После транспозиции аккорды записываются абсолютными именами, но фактически отражают функциональные отношения относительно тоники. Тональность исходного периода в токенах **не присутствует**. На инференсе пользователь задаёт желаемую тональность, модель генерирует в C/Am, и результат транспонируется обратно постпроцессингом. ### 5.2 Полный словарь **Служебные (4):** ``, ``, ``, `` **Метаданные периода (выпускаются один раз в начале последовательности, после ``):** - `MODE_major`, `MODE_minor` — 2 токена (наследие тональности; нужны, потому что мажор и минор остаются разделёнными) - `TIME_4/4`, `TIME_3/4`, `TIME_6/8`, `TIME_2/4`, `TIME_12/8` — 5 токенов - `SUB_4`, `SUB_8` — 2 токена - `STYLE_user`, `STYLE_jpop`, `STYLE_classical`, `STYLE_jazz`, `STYLE_other` — 5 токенов - `FUNC_verse`, `FUNC_prechorus`, `FUNC_chorus`, `FUNC_bridge`, `FUNC_intro`, `FUNC_outro`, `FUNC_interlude`, `FUNC_other`, `FUNC_unspecified` — 9 токенов **Аккордовые слоты (новый аккорд = ровно 4 токена в порядке root, quality, extension, bass):** - `ROOT_C`, `ROOT_C#`, ..., `ROOT_B` — 12 токенов - `QUAL_maj`, `QUAL_m`, `QUAL_dim`, `QUAL_aug`, `QUAL_sus2`, `QUAL_sus4`, `QUAL_maj7`, `QUAL_m7`, `QUAL_7`, `QUAL_m7b5`, `QUAL_dim7`, `QUAL_mM7`, `QUAL_7sus4`, `QUAL_aug7`, `QUAL_6`, `QUAL_m6`, `QUAL_add9`, `QUAL_m_add9` — 18 токенов - `EXT_none`, `EXT_9`, `EXT_b9`, `EXT_#9`, `EXT_11`, `EXT_#11`, `EXT_13`, `EXT_b13` — 8 токенов - `BASS_root`, `BASS_C`, `BASS_C#`, ..., `BASS_B` — 13 токенов **Временные/структурные:** - `HOLD` — позиция продолжает предыдущий аккорд - `NC` — пауза в гармонии - `BAR` — конец такта **Итого:** 4 + 2 + 5 + 2 + 5 + 9 + 12 + 18 + 8 + 13 + 3 = **81 токен**. ### 5.3 Структура обучающей последовательности ``` MODE_ TIME_ SUB_ STYLE_ FUNC_ ROOT_ QUAL_ EXT_ BASS_ ← новый аккорд = 4 токена HOLD ← удержание = 1 токен HOLD HOLD BAR ROOT_ QUAL_ EXT_ BASS_ HOLD ROOT_ QUAL_ EXT_ BASS_ HOLD BAR ... ``` ### 5.4 Алгоритм токенизации (источник → токены) 1. Прочитать шапку. 2. Транспонировать все аккорды: если `key = X_major`, транспонировать так, чтобы X стало C; если `key = X_minor` — так, чтобы X стало A. 3. Выпустить ``. 4. Выпустить метатокены: `MODE_`, `TIME_`, `SUB_`, `STYLE_`, `FUNC_` (если `function` не задан — выпустить `FUNC_unspecified`). 5. Для каждого такта: - Для каждой позиции в такте: - Если новый аккорд: разобрать на (root, quality, extension, bass), выпустить 4 токена в этом порядке. - Если `.`: выпустить `HOLD`. - Если `NC`: выпустить `NC`. - Если `?`: выпустить ``. - После последней позиции — `BAR`. 6. Выпустить ``. ### 5.5 Алгоритм детокенизации (токены → MIDI) 1. Считать метатокены, восстановить параметры периода. 2. Группировать аккордовые токены по 4 (root, quality, extension, bass). 3. Развернуть в последовательность аккордов с длительностями, считая HOLD-ы как продолжение предыдущего. 4. Транспонировать обратно из C/Am в целевую тональность (задаваемую пользователем на инференсе). 5. Сгенерировать MIDI через `pretty_midi`: для каждого аккорда выложить ноты в один трек, бас — отдельной линией в нижней октаве. ### 5.6 Оценка длины последовательности Период 8 тактов в 4/4 с subdivision=4, в среднем 2 смены аккорда на такт: - Метатокены: 1 (BOS) + 5 = 6 токенов - На такт: 2 аккорда × 4 + 2 HOLD-а + 1 BAR = 11 токенов - 8 тактов: ~88 токенов - EOS: 1 - **Итого: ~95 токенов на типичный период.** Длинный период (16 тактов с частой сменой): редко превышает 250 токенов. Контекстное окно 512 токенов более чем достаточно. --- ## 6. Полный пример ### 6.1 Исходный `.chord` файл ``` # title: Example period # key: G_major # time: 4/4 # subdivision: 4 # style: user # function: chorus | Gmaj7 . . . | Bm7 . . . | Em7 . . . | C . . D . | | Cmaj7 . . . | G/B . . . | Am7 . D . | G . . . | ``` ### 6.2 Токенизация Шаг 1: транспонировать из G major в C major (вниз на 7 полутонов или вверх на 5): ``` | Cmaj7 . . . | Em7 . . . | Am7 . . . | F . . G . | | Fmaj7 . . . | C/E . . . | Dm7 . G . | C . . . | ``` Шаг 2: выпустить токены: ``` MODE_major TIME_4/4 SUB_4 STYLE_user FUNC_chorus ROOT_C QUAL_maj7 EXT_none BASS_root HOLD HOLD HOLD BAR ROOT_E QUAL_m7 EXT_none BASS_root HOLD HOLD HOLD BAR ROOT_A QUAL_m7 EXT_none BASS_root HOLD HOLD HOLD BAR ROOT_F QUAL_maj EXT_none BASS_root HOLD ROOT_G QUAL_maj EXT_none BASS_root HOLD BAR ROOT_F QUAL_maj7 EXT_none BASS_root HOLD HOLD HOLD BAR ROOT_C QUAL_maj EXT_none BASS_E HOLD HOLD HOLD BAR ROOT_D QUAL_m7 EXT_none BASS_root HOLD ROOT_G QUAL_maj EXT_none BASS_root HOLD BAR ROOT_C QUAL_maj EXT_none BASS_root HOLD HOLD HOLD BAR ``` (Переносы строк здесь для читаемости; в реальности — один поток.) --- ## 7. Краевые случаи ### 7.1 Анакруза (затакт) Записывается как первый такт с `NC` на пустых позициях: ``` | NC . . D | G . . . | ... ``` ### 7.2 Тонально нестабильные фрагменты Если внутри периода невозможно однозначно определить тональность (например, секвенция через несколько тоник) — записать его в наиболее подходящей тональности по контексту исходной пьесы. Внутренние отклонения и тонизации записываются обычными функциональными аккордами; это не модуляция. Истинная модуляция (смена тональности в середине периода) **в текущей версии формата не поддерживается**. Если в исходной пьесе период модулирует — разрезать его на два периода: до и после модуляции. ### 7.3 Смена тактового размера внутри периода Не поддерживается. Если есть — разрезать на два периода. ### 7.4 Полиаккорды Не поддерживаются. Записывать как слэш-аккорд или ближайший наиболее характерный single chord. ### 7.5 Микротональность Не поддерживается. Округлять до ближайшего темперированного аккорда. ### 7.6 Аккорды короче subdivision Если в пьесе систематически встречаются аккорды длительностью короче выбранного subdivision (например, восьмая нота при `subdivision: 4`) — переключить весь период на `subdivision: 8`. Не округлять и не выбрасывать аккорды. --- ## 8. Соглашения по именам файлов Рекомендованный формат: ``` YYYY_NNN__.chord ``` Где: - `YYYY` — год создания исходной пьесы - `NNN` — порядковый номер периода в датасете (000–999) - `` — короткое имя в kebab-case - `` — функциональная роль (опционально, для удобства поиска) Примеры: ``` 2024_001_sea-glass_chorus.chord 2024_002_sea-glass_verse.chord 2025_037_winter-light_bridge.chord ``` Это упростит хронологическую сортировку датасета и поиск по функции. --- ## 9. Что НЕ кодируется (сознательные пропуски) - **Voicing** (расположение голосов внутри аккорда выше баса). Бас передаётся, остальное — на ручную работу в DAW. - **Ритмический паттерн** внутри удержания аккорда (восьмые, синкопы, паттерны типа альбертиевых басов). - **Динамика, артикуляция, тембр, аранжировка.** - **Мелодия.** Это отдельная задача за пределами текущего проекта. - **Полная форма пьесы.** Юнит — период, не пьеса целиком. - **Метроритмическая микроразметка** (свинг, рубато, ramp'ы темпа). --- ## 10. Чек-лист транскрипции При перекладывании периода из DAW в `.chord` файл: 1. **Прослушать пьесу целиком**, определить границы периодов. Замкнутая фраза с возвратом к тонике или ясной полукаденцией — кандидат на период. 2. **Заполнить шапку:** title, key, time, subdivision, style, function. 3. **Проверить subdivision.** Если в выбранном периоде аккорды стабильно меняются не чаще четверти — `subdivision: 4`. Если есть систематические восьмые смены — `subdivision: 8`. 4. **Транскрибировать гармонию по позициям**, аккуратно фиксируя инверсии. 5. **Прогнать парсер**, проверить отсутствие `` и предупреждений. 6. **Прогнать sanity-check утилиту** (`.chord` → MIDI), воспроизвести в DAW параллельно с оригиналом, убедиться в совпадении. 7. **Сохранить файл** под именем по схеме из §8. --- ## 11. История изменений - **v2.0** (текущая) - Единицей датасета стал **гармонический период**, не пьеса целиком. - Введена **нормализация тональности** в C major / A minor. Поле `key` сохраняется в шапке для парсера, но в словаре модели нет — есть только `MODE_major` / `MODE_minor`. - Введён тег `function` (необязательный) как метаданные периода. - Удалены секционные теги (больше не нужны при периодной разбивке). - Удалён тег `tempo_bucket` (мало пользы при текущем объёме данных). - Словарь сокращён с ~100 до 81 токена. - **v1.0** — первоначальная спецификация, единицей была целая пьеса, тональность входила в словарь, использовались секционные теги внутри последовательности.