# Open Lyric Alignment Standard MIDI File binding 0.1

## 1. Scope

OLA-SMF 0.1 carries one complete OLA JSON document in Standard MIDI File (SMF)
Sequencer-Specific meta events (`FF 7F`) and carries one primary lane as a
separately generated standard Lyric meta-event (`FF 05`) stream.

The embedded JSON is lossless. The `FF 05` stream is the compatibility and
corruption fallback. An OLA-aware writer keeps them synchronized and never
requires an OLA-unaware player to parse private data before showing lyrics.

## 2. OLA model requirements

An OLA-SMF document has:

- a `documentId` that is an RFC 4122 UUID string;
- `revision` from 0 through 4,294,967,295;
- one target with `kind: "smf"`, `timeUnit: "tick"`, and the file's positive
  `ticksPerQuarterNote` for PPQ files;
- exactly one `isPrimary` lane with an alignment set for that target; and
- `noteTopologySha256`, `tempoMapSha256`, and `lyricProjectionSha256` in that
  target's `binding`.

Core OLA permits other document IDs and the full non-negative signed 64-bit
revision range. The narrower requirements apply only because the 0.1 SMF chunk
header uses an RFC 4122 UUID and unsigned 32-bit revision.

SMPTE-time-division SMF may use tick positions but has no
`ticksPerQuarterNote`. Until a typed SMPTE descriptor is standardized in a
later binding revision, such a file can carry OLA JSON and a compatibility
projection but MUST NOT claim full OLA-SMF 0.1 binding conformance.

## 3. OLA community namespace

The data portion of every canonical OLA-SMF 0.1 `FF 7F` event begins with the
three bytes `00 4C 41`, followed by the 88-byte OLA chunk header. `00` is the
MIDI three-byte manufacturer-ID extension marker; `4C 41` is ASCII `LA`, making
the complete value a memorable `0LA` wire-format rebus.

`00 4C 41` occupies the SMF manufacturer-ID slot but is deliberately
unregistered. It has not been assigned or endorsed by the MIDI Association.
Its use is an openly documented community extension and therefore carries a
future namespace-collision risk. A writer, file, or implementation MUST NOT
represent it as an assigned manufacturer ID.

The three namespace bytes are outside the 88-byte header and every header
offset below. Conforming OLA-SMF 0.1 writers MUST use `00 4C 41`. Readers MUST
recognize that value only when `OLA1` follows immediately and the complete
envelope validates. Requiring both values makes accidental interpretation of
unrelated sequencer-specific data extremely unlikely.

Readers MAY accept `OLA1` documents under another syntactically valid one- or
three-byte manufacturer namespace for private or vendor-specific use, but such
files are not canonical OLA-SMF 0.1 output. `7D` remains limited to private
development; IDs `7E` and `7F` are universal IDs and are not OLA namespaces.

## 4. Exact 88-byte chunk header

All unsigned integers are big-endian. Offsets are relative to the first byte
after the three-byte OLA community namespace.

| Offset | Size | Field | OLA-SMF 0.1 value or meaning |
|---:|---:|---|---|
| 0 | 4 | magic | ASCII `OLA1` (`4F 4C 41 31`) |
| 4 | 1 | wire major | `00` |
| 5 | 1 | wire minor | `01` |
| 6 | 1 | message type | `01`, document chunk |
| 7 | 1 | codec | `00`, raw UTF-8 JSON |
| 8 | 2 | flags | `0000`; all bits reserved |
| 10 | 2 | header length | `0058` (88) |
| 12 | 16 | document UUID | RFC 4122 bytes in network order |
| 28 | 4 | revision | OLA revision, unsigned |
| 32 | 4 | chunk index | Zero-based index |
| 36 | 4 | chunk count | Total chunks, at least one |
| 40 | 8 | encoded total length | Concatenated chunk-data bytes |
| 48 | 8 | decoded total length | Decoded JSON byte length |
| 56 | 32 | decoded SHA-256 | SHA-256 of exact decoded JSON bytes |
| 88 | variable | chunk data | Slice of the encoded payload |

The header UUID MUST equal the RFC 4122 byte representation of JSON
`documentId`. The header revision MUST equal the numeric value of the canonical
decimal-string JSON `revision`.

For codec `00`, encoded bytes are decoded bytes. The two lengths MUST be equal,
and concatenating chunk data by ascending `chunk index` MUST produce the exact
strict UTF-8 JSON bytes whose SHA-256 appears in the header.

No compression is defined in 0.1. Flags MUST be zero. A writer MUST NOT assign
a private meaning to a reserved codec, message type, or flag bit.

## 5. Chunking and assembly

All chunks of one document have identical manufacturer ID, wire version,
message type, codec, flags, header length, document UUID, revision, lengths,
and decoded hash. Only `chunk index` and chunk data differ.

A conforming writer:

- emits every index from zero through `chunk count - 1` exactly once;
- uses no more than 4,096 chunk-data bytes per event;
- places chunks at absolute tick zero;
- writes chunks in ascending index order, though readers cannot rely on
  same-tick order; and
- removes obsolete OLA chunks under its own manufacturer ID and `OLA1` magic
  when replacing the document.

A reader groups chunks by manufacturer ID, UUID, revision, and decoded hash,
then orders by index. A missing or duplicate index, inconsistent header, length
mismatch, invalid UTF-8, duplicate JSON property, JSON or semantic-validation
failure, or hash mismatch invalidates the complete chunk set, not the SMF.
Every chunk in one complete set MUST reside in the same track. The track carrying
that set is the candidate's projection track for binding verification; an
ambiguity tie-break never compares a candidate to an unrelated `FF 05` track.

Readers support at least 1,024 chunks of 4,096 bytes, matching the 4 MiB OLA
JSON limit. They fail safely to `FF 05` rather than allocate without bound.

A conforming file has one current complete document. If several valid revisions
of the same UUID remain, the greatest revision is current. Multiple different
UUIDs or equally current payloads are ambiguous unless exactly one matches the
SMF binding hashes. Readers MUST NOT merge documents silently.

## 6. Track and SMF type

For Type 1, a writer SHOULD append a dedicated track named
`Open Lyric Alignment` instead of inserting a track before musical tracks. OLA
chunks and the primary `FF 05` projection reside there. Appending preserves the
structural track indexes in note links.

For Type 0, OLA data resides in the sole track. A writer MUST NOT convert an
existing Type 0 file to Type 1 solely to carry OLA. New authoring files SHOULD
use Type 1 when compatibility permits.

A writer preserves foreign `FF 7F` events byte-for-byte. It may remove or
replace only OLA events under the manufacturer ID it is authorized to write and
with exact `OLA1` magic.

Because a conforming file has one current OLA document, a writer refuses to add
or reconcile its namespace when OLA magic is already present under another
manufacturer ID. It does not delete or take over that foreign namespace.

## 7. SMF note-link interpretation

An alignment set's `noteLinks` are redundant SMF note-onset locators:

| Field | SMF meaning |
|---|---|
| `trackIndex` | Zero-based track index. |
| `trackFingerprint` | Optional normalized fingerprint for that musical track. |
| `noteOnEventIndex` | Optional zero-based raw event index of the positive-velocity Note On. |
| `attackOrdinal` | Zero-based ordinal among positive-velocity Note On attacks in that track. |
| `tick` | Absolute tick. |
| `channel` | Channel 0 through 15. |
| `pitch` | Note number 0 through 127. |
| `occurrence` | Zero-based occurrence at the same track, tick, channel, and pitch. |
| `durationTicks` | Optional paired duration. |
| `context` | Optional nearby attacks as signed delta tick, channel, and pitch. |

Resolution proceeds conservatively:

1. Use `noteOnEventIndex` only if the event still matches tick, channel, pitch,
   occurrence, and attack ordinal.
2. Find an exact unique structural match for track, attack ordinal, tick,
   channel, pitch, and occurrence.
3. A product may offer a documented fuzzy candidate using duration, track
   fingerprint, and context.
4. If no unique safe match exists, retain the placement's `resolvedRange` and
   require review for a hard anchor.

A consumer MUST NOT silently choose another chord member or same-pitch overlap
for a hard anchor.

## 8. Binding hashes

The SMF target stores the following lowercase SHA-256 values in its binding:

```json
{
  "binding": {
    "noteTopologySha256": "...64 lowercase hex digits...",
    "tempoMapSha256": "...64 lowercase hex digits...",
    "lyricProjectionSha256": "...64 lowercase hex digits..."
  }
}
```

All hashes use exact UTF-8 bytes of canonical line records. Every record,
including the final one, ends in LF (`0A`). Decimal fields have no sign or
leading zero except zero. The vertical bar is ASCII `7C`.

### 8.1 Note topology

The first record is `OLA-NOTE-TOPOLOGY-0.1`. The next record is:

```text
division|ppq|<ticksPerQuarterNote>
```

For every positive-velocity Note On in track and event order, emit:

```text
n|<trackIndex>|<attackOrdinal>|<absoluteTick>|<channel>|<pitch>|<matchedEndTick-or-->
```

Pair note ends FIFO within each track by channel and pitch. A zero-velocity Note
On is a note end. Velocity, program changes, controllers, lyrics, tempos, and
unrelated meta events are excluded.

The optional track fingerprint is deliberately independent of the physical
track index and file time division so it remains useful when a track is moved.
Its first record is `OLA-TRACK-ATTACKS-0.1`. For each positive-velocity Note On
in event order, emit:

```text
a|<within-track-event-index>|<absoluteTick>|<channel>|<pitch>
```

`within-track-event-index` counts every timed event in that track, not just
note attacks. This fingerprint is recovery evidence; the redundant structural
fields on a note link remain authoritative and an ambiguous recovery is never
accepted silently.

### 8.2 Tempo map

The first record is `OLA-TEMPO-MAP-0.1`, followed by the division record. Gather
all `FF 51` events, sort by absolute tick, track index, and within-track event
order, and let the last event at a tick define that tick. If tick zero has no
event, insert the SMF default 500,000 microseconds per quarter note. Emit:

```text
t|<absoluteTick>|<microsecondsPerQuarter>
```

### 8.3 Lyric projection

The first record is `OLA-LYRIC-PROJECTION-0.1`. For every `FF 05` event in the
OLA projection track, in event order, emit:

```text
l|<eventOrdinal>|<absoluteTick>|<lowercaseHexOfUtf8EventText>
```

`eventOrdinal` counts only `FF 05`. OLA-SMF projection text is encoded as
well-formed UTF-8; strict RP-017 text is therefore its byte-identical ASCII
subset. The digest is over the canonical UTF-8 encoding of the decoded event
text. An implementation writing the SMF MUST use that same UTF-8 encoding.
Ill-formed UTF-8 is an external edit and cannot match this binding.

## 9. External-edit states

The chunk payload hash is checked before target binding hashes.

| OLA payload | Notes | Tempo | Projection | Required behavior |
|---|---|---|---|---|
| Valid | Match | Match | Match | Use OLA as authority. |
| Valid | Match | Match | Changed | Treat as external lyric edit; preserve both and reconcile before overwriting. |
| Valid | Changed | Match or changed | Match | Mark note links stale, rebind conservatively, and retain resolved ranges. |
| Valid | Match | Changed | Match | Tick placements remain usable; recompute real-time views and mappings. |
| Valid | Changed | Any | Changed | Treat as broadly edited; do not silently prefer OLA or projection. |
| Valid | Hash absent | Any | Any | Treat the relevant binding as unverified, not matched. |
| Missing, corrupt, unsupported, or ambiguous | Any | Any | Available | Ignore OLA authority and use `FF 05`. |
| Missing, corrupt, unsupported, or ambiguous | Any | Any | Missing | Report no usable lyrics. |

After explicit reconciliation, a save regenerates JSON binding hashes, OLA
chunks, and the `FF 05` projection atomically.

## 10. Compatibility projection

Every OLA-SMF document emits its sole primary lane as `FF 05`. The
[RP-017 portable profile](rp017-portable-v0.1.md) defines strict output. When
strict projection is impossible, a writer emits a documented coarse projection
and preserves exact Unicode and structure in OLA JSON.

## 11. Version handling

Wire version and JSON model version are independent. A reader rejects an
unsupported wire major or minor. OLA-SMF 0.1 uses wire version `00 01` and the
exact 88-byte header above; a later specification may define how a future
reader negotiates extended headers.

Unknown message types, codecs, or nonzero reserved flags are unsupported in
0.1. Readers ignore that chunk set and use fallback instead of guessing.

## 12. No experimental-manifest compatibility

OLA-SMF has no legacy Keyfire importer. Byte strings such as
`KEYFIRE-HELICON-LYRICS` or `KEYFIRE-HELICON-AUDIO-LYRICS-POC` are not OLA
magic and MUST NOT be interpreted as OLA. Products may import ordinary standard
lyric events independently.
