Skip to content

Song versions

This document defines the syntax and semantics of versions in neumaRk: a mechanism for representing multiple variants of the same song in a single file (alternative arrangements, reharmonizations of single sections, complete rewrites).

The user chooses which variant to view/perform through the UI; the preference is persistent in the user-index and not in the NRK file.


1. Definition

A version is an alternative variant of a portion of the song, delimited by a named block of the form:

%%NAME
… content …
%%end

There are two classes of blocks:

  • Default — block %%NAME without a label, is part of the linear flow of the song (it is the "canonical" version the reader sees by default);
  • Variant — block %%NAME "label" with a label, lives alongside the flow. It is activated explicitly by the user.

A variant replaces all the occurrences of the same-named default block during performance/rendering.

1.1 Minimal example

M) [Intro]
… original intro …

%%BRIDGE
M) [Bridge]
… original bridge …
%%end

M) [A]
… original final A …

%%BRIDGE "Bill Evans version"
M) [Bridge]
… Bill Evans bridge …
%%end

The user opens the song and sees the canonical version. By selecting "Bill Evans version" from the UI selector, the %%BRIDGE block is replaced by the variant; the rest of the song (Intro, A) remains unchanged.


2. Syntax

2.1 Opening the block

%%NAME                       default block
%%NAME "label"               variant block
  • %% must be at the beginning of the line (possibly preceded by spaces only, according to the general whitespace rules of neumaRk).
  • NAME is an identifier: one or more letters/digits/underscores, case-sensitive. No internal spaces.
  • "label" (optional, present only in variants) is a textual container "…" adjacent to the NAME, with a separating space. It admits the unified markup (neumaRk_text_markup.md).

2.2 Closing the block

%%end
  • %%end must also be at the beginning of the line.
  • It closes the most recently opened block.
  • A %%end without an open block produces warning W148.

2.3 Block content

A block contains one or more valid datapacks (see neumaRk_datapack.md). All the musical rules (markers, chords, notes, dynamics, etc.) apply normally inside the block.

2.4 Nesting not allowed

A %%NAME block cannot be opened inside another block. The parser produces warning W149 if it encounters %%X while a block is open.

2.5 Reserved: %%

The sequence %% at the beginning of a line is reserved for versions blocks. It is not allowed in other contexts of the language (NRK comments use //, see neumaRk_datapack.md for the spec of single-line comments).


3. Structural position

3.1 Standalone between datapacks

The %%NAME blocks live between musical datapacks, not inside them. The structure of the document is an alternating sequence of:

  • normal datapacks (flow common to all versions);
  • default %%NAME blocks (named sections of the flow);
  • variant %%NAME "label" blocks (variants of the named sections).
[datapack] [datapack] %%BRIDGE [datapack] %%end [datapack]
                     └─ default ─┘
[datapack] %%BRIDGE "Bill Evans" [datapack] %%end
          └─────────── variant ───────────┘

3.2 Position of variants

The variants %%NAME "label" may appear in any position of the document (recommended: immediately after the same-named default block, or at the end of the document). The matching is by name, not by position.


4. Substitution semantics

4.1 Fundamental rule

When the user activates the variant %%NAME "label", all the occurrences of the default block %%NAME in the document are replaced by the content of the variant.

The portions of the song outside blocks (normal datapacks) remain unchanged in all versions: they belong to the "common trunk".

4.2 Multiple occurrences of the default

If a default %%NAME block appears multiple times (e.g. AABA with three distinct %%A), a single variant %%NAME "label" replaces all the occurrences.

%%A
… A original …
%%end

%%B
… B …
%%end

%%A
… A original (second occurrence, may be musically identical
   or varied) …
%%end

%%A "miles"
… A Miles version …
%%end

Activating "miles": both default %%A are replaced by the Miles version. For per-position variants (e.g. only the second A is different), use distinct names: %%A1, %%A2.

4.3 Orthogonal M) markers

The markers of the M) line internal to a %%NAME block are independent of the block name. The parser does not require that M) [Bridge] appear inside %%BRIDGE: it is the author's convention to name them the same, but it is not constrained.

%%PEDAL
M) [A pedal]
… …
%%end

PEDAL is the name of the block (for the versions selector); A pedal is the marker of the section (for PLAY/FORM, render, navigation).

4.4 Total rewrites

For complete arrangements (e.g. "Round Midnight, Miles arrangement"), the author may enclose the entire song in a default %%NAME block (with a name of choice: %%SONG, %%MAIN, etc.) and provide the rewrite as a variant.

%%SONG
M) [Intro]
… complete original song …
M) [Outro]
…
%%end

%%SONG "Miles Davis arrangement"
M) [Intro Miles]
… complete Miles arrangement …
M) [Coda]
…
%%end

There is no reserved keyword for "the whole song": any name works, the author chooses the one they prefer.


5. Optional header HV)

The document header (neumaRk_header.md) admits a new optional entry HV) to explicitly declare the available versions and the default one:

HV) versions: [original, miles, jarrett] default=original

5.1 Syntax

HV) versions: [<label1>, <label2>, …] [default=<label>]
  • versions: mandatory keyword.
  • List of labels in square brackets, separated by commas.
  • default=<label> optional: specifies which variant to show at the first opening (in the absence of a user preference). In the absence of default=, the default is the default flow (%%NAME blocks without a label).

5.2 Functions of HV)

  • Documentation: makes the song versions explicit in the header.
  • UI ordering: the labels are presented in the UI selector in the declared order.
  • Named label of the default: without HV), the default is "unnamed"; with HV) it may receive a name (e.g. original) and appear in the selector together with the variants.

5.3 HV) optional

In the absence of HV), the variants are deduced from the %%NAME "label" blocks present in the document. The order is the order of appearance in the file. The default is the unlabeled flow.

5.4 Discrepancies

A label declared in HV) but absent from the document (or vice versa) is not an error: the UI selector shows only the variants actually present. It is the author's responsibility to maintain consistency.


6. User preference

The "current version" state is a user preference saved in the user-index Firestore (e.g. users/{uid}/song_view_state/{songId}.version).

  • At first opening, the document shows the default (flow without labeled %%NAME blocks, or whatever is declared in HV) default=).
  • The user changes version through the UI selector (badge with dropdown).
  • The choice is persistent for that specific song for that user.

The version state is never written into the NRK file: the file is immutable with respect to the reading preference.


7. Diagnostics

7.1 Diagnostic codes

Code Description
W147 %%NAME block not closed (missing %%end by end of document)
W148 Orphan %%end (no open block)
W149 %%NAME block nested inside another block
W150 Malformed HV) (expected versions: [list] [default=label])

7.2 Non-errors

  • Variant without a same-named default (%%X "label" but no %%X default): the variant is ignored during performance, but remains in the file. Render UI may flag it as "orphan".
  • Default without variants (%%X only): allowed; the block is a simple section "prepared for future variants".
  • Label %%X "label" repeated multiple times: the last wins (silently), or the render shows a UI warning.

8. Examples

8.1 Days of Wine and Roses with Bill Evans bridge

HT) Days of Wine and Roses
HC) Henry Mancini
HK) F
HM) 4/4
HV) versions: [original, bill_evans] default=original

M) [Intro]
… intro …

M) [A]
… A original …

%%BRIDGE
M) [Bridge]
… bridge original …
%%end

M) [A]
… final A original …

%%BRIDGE "bill_evans"
M) [Bridge]
… Bill Evans reharmonized bridge …
%%end

8.2 Round Midnight, total Miles rewrite

HT) Round Midnight
HC) Thelonious Monk
HV) versions: [original, miles] default=original

%%SONG
M) [Intro]
… standard intro …
M) [A]
… original A …
M) [B]
… original B …
M) [A]
… final A …
%%end

%%SONG "miles"
M) [Intro Miles]
… Miles intro …
M) [A]
… A with changed chords …
M) [B]
… B with added phrase …
M) [Coda]
… Miles coda …
%%end

The user chooses "miles" from the selector → the original %%SONG block is replaced by the rewrite.

8.3 AABA with A "miles" replacing all the A

%%A
… original A …
%%end

%%A
… (second occurrence, identical or varied) …
%%end

%%B
… B …
%%end

%%A
… final A …
%%end

%%A "miles"
… Miles version of the A …
%%end

Activating "miles": the three default %%A are replaced by the variant. The %%B remains unchanged.

8.4 Per-position variant (distinct names)

%%A1
… first A …
%%end

%%B
… B …
%%end

%%A2
… second A (slightly different) …
%%end

%%A2 "minor key"
… A2 in minor mode …
%%end

Only the second A is replaceable by the "minor key" variant. The first A is not involved because it has a different name (%%A1).


9. Summary

Concept Syntax Section
Default block %%NAME … %%end §2.1
Variant block %%NAME "label" … %%end §2.1
Block closing %%end §2.2
Block position standalone between datapacks, no nesting §3.1
Substitution variant replaces all default %%NAME §4.1
M) markers orthogonal to the block name §4.3
Total rewrite enclose the song in a single block (e.g. %%SONG) §4.4
Header HV) versions: [list] default=label (optional) §5
User preference user-index Firestore, not NRK §6

This document defines the song versions in neumaRk: a robust and granular mechanism for representing alternative arrangements, targeted reharmonizations and complete rewrites of the same song within a single file.