Files
hamori/docs/chord_format_spec.md
T
H1K0 967257a555 docs: add chord format specification
Authoritative .chord file format spec covering header fields, body
syntax, chord symbol grammar, tokenization rules, and key normalization.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 10:40:39 +03:00

403 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Спецификация формата данных
## Проект: генератор аккордовых последовательностей
**Версия:** 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` | да | `<note>_major` или `<note>_minor`, где `<note>``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 Бас и слэш-аккорды
Для инверсий и слэш-аккордов — стандартный формат `<chord>/<bass>`:
```
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 — для случаев, когда не уверен в транскрипции; парсер заменит на `<UNK>` |
---
## 4. Внутреннее токенизированное представление
### 4.1 Словарь (≈100 токенов)
**Служебные (4):**
`<BOS>`, `<EOS>`, `<PAD>`, `<UNK>`
**Метаданные (всегда в начале последовательности, после `<BOS>`):**
- `KEY_<note>_<mode>` — 24 токена (12 нот × major/minor)
- `TIME_<n>/<m>` — 5 токенов: `TIME_4/4`, `TIME_3/4`, `TIME_6/8`, `TIME_2/4`, `TIME_12/8`
- `STYLE_<x>` — 5 токенов: `STYLE_user`, `STYLE_jpop`, `STYLE_classical`, `STYLE_jazz`, `STYLE_other`
- `TEMPO_<x>` — 4 токена: `TEMPO_slow`, `TEMPO_medium`, `TEMPO_fast`, `TEMPO_very_fast`
- `SUB_<n>` — 2 токена: `SUB_4`, `SUB_8`
**Структурные:**
- `SEC_<x>` — 8 токенов: `SEC_intro`, `SEC_verse`, `SEC_prechorus`, `SEC_chorus`, `SEC_bridge`, `SEC_interlude`, `SEC_solo`, `SEC_outro`
- `BAR` — конец такта
**Аккордовые (4 слота на каждый аккорд):**
- `ROOT_<note>` — 12 токенов
- `QUAL_<x>` — 18 токенов (см. §3.2)
- `EXT_<x>` — 8 токенов: `EXT_none`, `EXT_9`, `EXT_b9`, `EXT_#9`, `EXT_11`, `EXT_#11`, `EXT_13`, `EXT_b13`
- `BASS_<x>` — 13 токенов: `BASS_root` плюс 12 нот
**Временные/специальные:**
- `HOLD` — позиция продолжает предыдущий аккорд
- `NC` — пауза в гармонии
**Итого: ≈100 токенов.**
### 4.2 Структура последовательности
```
<BOS>
KEY_<x> TIME_<x> SUB_<x> STYLE_<x> [TEMPO_<x>]
SEC_<x>
ROOT_<x> QUAL_<x> EXT_<x> BASS_<x> ← новый аккорд = ровно 4 токена
HOLD ← удержание = 1 токен
HOLD
HOLD
BAR
ROOT_<x> QUAL_<x> EXT_<x> BASS_<x>
HOLD
ROOT_<x> QUAL_<x> EXT_<x> BASS_<x>
HOLD
BAR
SEC_<x>
...
<EOS>
```
### 4.3 Правила токенизации (источник → токены)
1. Прочитать шапку → выпустить `<BOS>` и токены метаданных.
2. Каждая `[section]` строка → `SEC_<x>`.
3. Для каждой позиции внутри такта:
- Если аккорд: разобрать на (root, quality, extension, bass). Выпустить 4 токена в этом порядке.
- Если `.`: выпустить `HOLD`.
- Если `NC`: выпустить `NC`.
- Если `?`: выпустить `<UNK>`.
4. После последней позиции такта → `BAR`.
5. В конце пьесы → `<EOS>`.
### 4.4 Инвариант длины
При `subdivision: 4` каждый такт даёт **переменное** число токенов (от 5 до 17): один `BAR` + от 4 (один аккорд × 4 поля) до 16 (четыре аккорда × 4 поля), плюс `HOLD`-ы. В среднем для поп-музыки получится 6–10 токенов на такт.
Типичная пьеса (~80 тактов) → **600800 токенов**. Это комфортно укладывается в стандартное контекстное окно 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 Токенизация
```
<BOS> 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
<EOS>
```
(В реальности — без переносов строк и пустых строк, всё идёт одним потоком; здесь форматирование только для читаемости.)
---
## 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. Прогнать парсер (когда он будет написан) и проверить, что нет `<UNK>` токенов и предупреждений о неизвестных качествах.
5. Сравнить «на слух»: воспроизвести аккорды в DAW по транскрипции и убедиться, что слышимая гармония совпадает с оригиналом.
Этот шаг 5 особенно важен — даже с абсолютным слухом легко пропустить инверсию или septима↔nona в плотной фактуре.
---
## 8. История изменений
- **v1.0** — первоначальная спецификация.