Krach, Geräusch, Klang, Struktur

Neusik: Endlich eine spezifizierte domänenspezifische Sprache

Dieses Dokument ist auf Englisch. Englisch ist heute zwar auch nicht mehr so angesagt, aber ich erreiche so mehr Menschen als mit meiner Muttersprache.

Die gewählte Lizenz der Referenzimplementierung "Sompyler" (GPL v3) ermöglicht es mir nicht, die Verwendung im Zusammenhang mit KI zu verbieten, und das ist eigentlich auch gut so. Allerdings werde ich wenig motiviert sein, Support-Tickets zu beantworten, die mir das Gefühl geben, dass ich einer KI zuliefere.

KI ist ein Werkzeug, ja? Ein Werkzeug wie ein Taser in ner Kinderhand. Nein, ich bin und ich bleibe skeptisch und wenn es KI-Nutzern teuer wird, den RFC samt allen Code aus dem Gitlab-Repository zu verarbeiten, um was auch immer damit anzustellen, hält sich mein Mitleid in Grenzen.

Das so als Präambel. Viel Spaß beim Lesen der ca. 1900 Zeilen, die wirklich nicht mehr sind als nötig. Ich hoffe dennoch, dass sie für Entwickler und manche nerdige Musiker verständlich sind und sich etwaige von diesen darauf angesetzte KIs nicht in Memory-Leaks oder Endlosschleifen verstricken. Denn dafür ginge um so mehr Strom drauf, der den kommenden Generationen fehlt.

Sound and Music Radically Description Modelling Language

This document specifies the SMRDML or Ne(RDM)usik Language for text-based sound and music modelling. Despite inspiration from "Request For Comments" style, it has nothing to do and is not associated with the IETF RFC standards process.

Status(es) of the document: Informational, Draft.

0. Contents

  1. Introduction
    1. What is not the subject
    2. What it is about
    3. Conventions
      1. Normative Language
      2. User roles
      3. Section numbering scheme
      4. Upper-case names
        1. Convential types vs. Placeholders
        2. IDENTIFIER
        3. MAYBE_LIST\<T>
        4. REVERSED_DBFS
        5. SHAPE
        6. PITCH
        7. PATH
      5. Quoting
      6. ABNF
  2. Document Structure
    1. Underlying formats
  3. Associated Files
    1. Intonation
      1. Key properties
      2. Intervals
      3. Tone names
      4. Scale types
      5. Chord types
    2. Instrument
      1. Variations
        1. Basic properties
          1. Oscillator primitive
          2. Attack envelope segment
          3. Decay/Sustain envelope segment
          4. Tail envelope segment
          5. Release envelope segment
          6. Amplitude modulation
          7. Frequency modulation
          8. Frequency variation
          9. Wave shape
        2. Labelled property groups
          1. Inheritance from a "base"
          2. "@"-References
        3. Variation properties
          1. "VOLUMES"
          2. "SPREAD"
          3. "PROFILE"
          4. "TIMBRE"
          5. "MORPH"
          6. "RAILSBACK_CURVE"
      2. Attributes
        1. Implicit attributes
      3. Unification mechanism
        1. Merging
        2. Stacking
        3. Implied PROFILE
    3. Room reverberation
      1. "levels"
      2. "delays"
      3. "frequency_lanes"
      4. "border"
      5. "jitter"
      6. "deldiffs"
      7. "diffusion"
  4. Score File
    1. Metadata
      1. "title"
      2. "composer"
      3. "source"
      4. "encrypter"
      5. Other attributes
    2. Stage
      1. Voices
      2. Orchestra cone
    3. Articles
      1. Name
      2. Attributes
      3. Inheritance
    4. Embedded associated specifications
      1. "NOT_CHANGED_SINCE" (instrument only)
    5. Tuning
    6. Measure
      1. Properties
        1. Implied properties
        2. Tuning and Harmony
        3. "stress_pattern"
        4. "beats_per_minute"
        5. "lower_stress_bound"
        6. "upper_stress_bound"
        7. "elasticks_pattern"
        8. "elasticks_shape"
        9. Measure-bound uninherited properties
          1. Identifier
          2. "cut"
          3. "skip"
          4. "repeat_unmentioned_voices
          5. "is_last"
          6. "offset_seconds"
      2. Per-voice indications
        1. Voice- and measure-bound
          1. Properties
          2. Articles
        2. Named material
        3. Offsets
          1. Settings MAPPING as first LIST ELEMENT
          2. Multi-tick offsets
    7. Multimeasure
      1. "_loop" KEY
      2. Vertical bar(s) separator |
      3. Quantifier *n
      4. Back-reference by %n
  5. Stem Notes and Properties
    1. Specification
    2. Length and weight on note level
    3. Chains
      1. Articles and extensions
      2. Length and Overlength
      3. Weight
      4. Intonation flags
      5. Relative Pitch indication
      6. Clauses
      7. Parallel and sequencial orders
    4. Inheritance of Attributes
  6. Material Lines
    1. Syntax
    2. Slicing

1. Introduction

1.1. What is not the subject

The subject of this RFC is not yet another fully-featured, maybe even Turing-complete, audio programing language like CSound. The audio description language is not modular but monolithic. E.g. modular, graphical like PD or Max4Live is a totally different approach that might suit some folks better.

This specification does not describe a notation language either. Plain notation systems do not include sound description but rely on synthesizers. Examples of such languages are ABC, Lilypond, MIDI or MusicXML.

Modelling of human language and voice synthesis is beyond scope, and so is singing. Of course, trying to use the language described herein for natural human sound and utterance may be a tough endeavour on your own. Phonetics and articulation modelling would impose requirements the language is not designed to meet.

Development of the language described herein has been started considerably long before the hype of LLM and AI. Optimization of the language for this kind of automatic digestion is not focussed, but compatibility with deterministic processing.

1.2. What it is about

Sound and Music Radically Description Model, "NeRDMusik" or, shorter, "Neusik" is a exemplary manifestation of languages conveying all necessary textual information representing audio-data in a manner comparable to vectorized versus pixel-based graphical work. The format enables a corresponding fully deterministic machine or program to render an audio file ready to load into an audio playback application or a graphical Digital Audio Workstation as a sample. While processing, no user interaction is expected, i.e. these programs work as kind of filters, closely in the sense of the classical unix philosophy.

The user that renders the score with an implementation decides on the sampling rate, bit depth and file format of the resulting audio file.

The user that creates the score aims at design of arrangement, composition, positions of voices on the virtual stage (panorama), room characteristics, instrumental sound characteristics.

The knowledge of the underlying format, either JSON or YAML, is required to realize score-files in that language described, as it builds upon these hierarchical serialization languages. It is a compatible subset or application of both.

1.3. Conventions

1.3.1. Normative Language

The key-words "MUST", "MUST NOT", "MAY", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "REQUIRED", "RECOMMENDED" and "OPTIONAL" have the meaning as described in RFC 2119 if, and only if they are upper-case.

1.3.2. User roles

This RFC distinguishes following types of users:

The encrypter and the renderer are often the same person that can play both roles while debugging the score.

1.3.3. Section numbering scheme

The section numbering scheme is hierarchical. E.g. "3.2" is after "3.1", "3.1.5" is in between, as is commonly used.

Alphabetic suffixes signify mutually exclusive concepts, variants or options. They cannot be applied both one after the other.

Examples:
"3.1.a. JSON encoding"
"3.1.b. YAML encoding"

The suffixes .a and .b signify that the encrypter MUST decide between both underlying formats and, in this case, stick to the chosen format in the flow of the entire document. In other cases, change is a matter of style, consistence and convenience.

Thus, suffixed sections do not require the reader to have understood prior sections on the same level. The encrypter MAY choose on the basis of the section heading.

1.3.4. Uppercase names

Besides the modifiers described in section 2.1, all names used in this document that are written in all upper-case belong to one of two categories:

1.3.4.1. Types and Placeholders
1.3.4.2. IDENTIFIER

IDENTIFIER is defined as a special STRING that

1.3.4.3. MAYBE_LIST\<T>

MAYBE_LIST<T> is used to specify that the same concept may be applied as singleton or as a list of elements of type T with T denoting a conventional type or a placeholder. How a list is realized depends on the chosen underlying format. Implementations MUST therefore expect a list or a singleton value of type T.

T may be a union type with a sequence of type names separated by vertical bars. MAYBE_LIST\<T1|T2> represents a singleton value of either type 1 or type 2, or a list where each element is either of type 1 or 2. Type 1 and 2 must be unambiguously distinguishable for the interpreting implementation.

1.3.4.4. REVERSED_DBFS

dBFS is the sound engineers' abbreviation of decibel full scale. dBFS=0 is the maximum sound volume of the playback system. Positive values are mostly an error. REVERSED_DBFS is an INTEGER-type convention to avoid errors resulting from forgotten negative signs.

An implementation MUST convert a value of type REVERSED_DBFS by the formula dBFS = REVERSED_DBFS - 100. It is a NON_NEGATIVE_INT up to value 100. The effect of greater values is left unspecified. An implementation is RECOMMENDED to normalize sound volume levels, whatever their maximum be, to the linear range of -1..+1 if not instructed otherwise by the renderer, via command options or property settings within the program.

1.3.4.5. SHAPE

Shapes indicate nodes of a bézier curve envelope, used in many contexts within this specification. The ";" separates "x,y" pairs of coordinates.

 SHAPE = [PREFIX (":" / ";")] Node 1*(";" Node)
 Node  = x "," y ["*" z] ["!"]
 x     = NON_NEGATIVE_INT

x must be larger than x in any preceeding pairs.

 y     = NON_NEGATIVE_INT
 z     = POSITIVE_INT     ; > 1

Z is the weight of the node, projected on the Z-axis, and a final exclamation mark signals a hard edge, i.e. the y-value MUST be yielded by the bèzier resolution algorithm precisely at that position in relation to last x coordinate.

In the following specification, SHAPE may be PREFIXed by other placeholders introducing base properties of the shape confined to a specific context where this type is applied. The separator between the prefix and the shape is either ":" or ";", depending on whether it defines the initial coordinate.

1.3.4.6. PITCH

1.3.4.6.a Pitch Name

Pitch names are looked up in an intonation file as described in Section 3.1. They are case-sensitive.

PITCH = STRING [*1"&" (CHORD / SCALE)] *(("+" / "-") INTEGER Unit)
Unit  = "k" / "c" / "t"

The unit is "k" when the PITCH is modified by key number, "c" when the base frequency is adjusted by +/-n cent. In theory, however only meaningful beyond the context of score-file processing, there is "t" unit to modify the base tone of a chosen inequally tempered scale explicit or implied by the chord.

If the tone name part does not end in a digit, and for chords like major and major-seventh and -nineth and any further the name of which starts with a number, the ampersand (&) MUST prefix the chord. The OPTIONAL chord indication subsets the meaning of unit "k" (key) to the tones of the chord.

If the initial letter of the chord is upper-case, the implementation MUST regard it as a scale indication, therefore look it up in the scales section of the intonation or, if it is added or overwritten by the encrypter, in the score file.

1.3.4.6.b Key position
PITCH =/ INTEGER

As an INTEGER number, depending on context the pitch is either addressed as sequential number of a key in a standard 88-key keyboard, starting at 1 = A0. In named material though, when at least one initial stem-note key position of an element is "0", the key positions are calculated in relation of the stem note selected where the named material is referenced.

1.3.4.6.c Caret position
PITCH =/ "^" NON_NEGATIVE_INT

The caret position is resolved relative to current harmony indicated in "tuning" property of a measure. ^0 is A0 for scales with the base tone A, ^7 is A1 for a heptatonic scale with base tone A. ^0 is C0 (sic!) for scales with base tone C. This tone does not exist on most piano keyboards.

The octave range from ^0 always denotes the mostly incomplete sub-contra octave. For heptatonic scales, the encrypter can select octaves by adding n * 7 to the leftmost key of the base tone of the selected scale. C8 is at ^56 for a C-based scale.

For the chromatic scale, caret position still differs from the key position by the relation to a base tone.

Tuning and/or harmony is changed as described in Section 4.6.1.2..

1.3.4.6.d Frequency in Hz
PITCH =/ FLOAT

The implementation MAY support FLOATs where pitch is expected. The unit MUST be implied Hertz. Yet, implementations SHOULD rather provide intonation algorithms so literal Hz values are not needed.

1.3.4.7. PATH
PATH = [[PROTO ":"] "/"] IDENTIFIER 1*( "/" IDENTIFIER ) ["." FILEENDING]
PROTO = 1*CHAR
FILEENDING = 1*CHAR

If FILEENDING is omitted, the i.ementation MUST add it depending on the context:

FILEENDING = "spl" ("i" / "r" / "s" / "t")
    ; i Instrument specification
    ; r Room specification
    ; s Score file
    ; t intonation specification

If beginning with "/" or with a disk label or network protocol name, the path MUST be interpreted as an absolute path or URI to download from. If used, the score-file is no longer self-contained, but relative paths beginning with "./" or "../" make the score-file no longer really self-contained, too. The implementation MUST NOT set the working directory before-hand to resolve these files, but follow the guidelines of the operating system.

Otherwise, PATHs MUST be interpreted relatively from the directory of the score-file processed, and in the case the files are not found there, fallback the INSTALLDIR of the implementation.

1.3.5. Quoting

Quotes are used to signify that the quoted content is to be entered literally. Quoted tokens do not represent variables. Quotes do not convey assumptions whether tokens need to be quoted or escaped in the underlying format.

1.3.6. ABNF

The description of syntax rules follows the Augmented Backus-Naur-Form (BNF) as described in [RFC 5234]. Within syntax rules, upper case rule names that are neither conventional types nor placeholders, will be found in Appendix A of RFC 5234.

These syntax rules not only serve as examples but also specify conventional types in the described language:

NON_NEGATIVE_INT = 1*DIGIT
IDENTIFIER       = 1*uc-diacr-char *(DIGIT / c-diacr-char)
uc-diacr-char    = (%x41-5a / %x61-7a / %xc0-d6 / %xd8-1f5)
                   ; upper- and lower-case latin letters
                   ; can have diacritics
                   ; implementations MAY support other alphabets.

As an informal extension of ABNF, alternatively to = a rule can be assigned by : if that rule corresponds to a MAPPING KEY of the same name. The right-hand side of colon and space specifies the MAPPING VALUE.

2. Document Structure

The document structure strongly depends from the chosen underlying format.

2.1. Underlying Formats

As the language is fundamentally hierarchical, it leverages hierarchical serialisation formats. The following ones are assumed compatible. An implementation MAY additionally support whatever serialization format deemed appropriate. It MAY follow the specs much as possible as if it were JSON.

2.1.a. JSON encoding

An implementation MUST identify a file starting with the two-byte sequence {" as JSON data. So, only mapping is supported as top-level composition type. The mapping must have at least two KEYs with their VALUEs: "stage" and "measures". The implementation is RECOMMENDED to utilize a dedicated JSON parser.

Because the implementation MUST seek the read cursor of file back on to 0 (start of file) after examining the first two bytes not validating for JSON, it SHOULD deny reading from unseekable stream sources like unix pipes.

2.1.b. YAML encoding

If the check for JSON described is not successful, and any additionally supported format cannot be recognized from the two bytes either, an implementation MUST regard the file as YAML-formatted. The implementation MAY check for %YAML, --- and newline, or any metadata MAPPING KEY, and deny the payload otherwise. measures top-level key of the mapping is OPTIONAL. If existent and not a sequence of measure mappings, it SHOULD be a mapping of basically implicit measure properties implied for all measure-bound properties omitted.

The measure-associated data is, in contrary to the JSON format, realized as separate consecutive documents in the YAML stream, with each introduced by --- and newline.

The implementation SHOULD utilize a dedicated YAML parser module that supports at least YAML 1.1. For security reasons, it MUST forbid custom types, allowed by YAML, by using safe loading routines.

3. Associated Files

3.1. Intonation

The intonation specification file contains data for the intonation algorithm that resolves the pitch indications in a score file into a base frequency.

The implementation SHOULD provide a default file to use when the score file does not have a "tuning" MAPPING with a "base" property.

3.1.1. Key properties

3.1.2. Intervals

Intervals are defined in KEY "intervals" as well as in the "intervals" section where secondary choices can be named and referenced by "tuning", "intervals" in the score.

intervals = base "^1/" steps / step 1*(" " step)
base      = POSITIVE_INT ; recommended: 2 (octave = 2*f)
steps     = POSITIVE_INT ; recommended: 12 (tones)
step      = FLOAT / POSITIVE_INT / n ":" m / dividend "/" divisor
n         = POSITIVE_INT
m         = POSITIVE_INT
dividend  = POSITIVE_INT
divisor   = POSITIVE_INT

Concerning the step format, consistency is RECOMMENDED for all scale tones. Whatever the format, the items indicate the frequency ratio to the preceeding tone. POSITIVE_INT items are expressed in cent. FLOAT items are relational factors.

3.1.3. Tone names

The tone name listings cannot be overwritten in a score file. They SHALL be imported from the intonation specification.

In the "tones" section of the intonation file the entry rules are

entry = name assign tone 1*(1*SP tone)
assign = *SP "=" *SP ; prescribed by ini file format
name = 1*wchar [ "_" OCTAVE_NUMBER ]
wchar = ALPHA / "_"
tone = "-" / 1*NSP ; non-space

If the name contains an octave number, the implementation MUST expect at least one tone name set, with multiple grouped by common wchar part, for each octave separately. They SHALL be counted from 0 upwards. Tones for which a tone name set does not provide a consistent name MUST be substituted by a dash. Every tone name set has the same count of steps.

To names of tone name sets without count MUST be appended the octave number counted from 0 upwards, where they are applied in the score.

3.1.4. Scale types

In the "scales" section of the intonation specification, all KEYs MUST follow the rule

scale-type-label = 1*a-z

The VALUE of the scale-type KEY is a consecutive chain of key offsets each related to the preceding one. The first item of each VALUE is related to the last of the preceding lower octave.

The default intonation specification SHALL provide "chr" scale type with steps number of ones, to select all keys in the octave.

3.1.5. Chord types

In the "chords" section of the intonation specification, all KEYs MUST start with the letter "X". The syntax of the VALUEs:

VALUE = "0" (1*SP POSITIVE_INT)

Every indicated number indicates how many steps add to the previous tone to reach the next tone in the selected subset. The remaining tones in the scale are masked. When a scale is indicated, the implementation MUST skip them.

The "0" represents the base tone applied, whatever the chord. In contrary to the scale definitions, in the chords every integer indicates the key distance to the base tone.

3.2. Instrument

The instrument defines the sound characteristics of a voice. The same instrument can be used for multiple voices configured differently regarding position on stage, and with different set of articles.

If on the top-level of the specification MAPPING there are informational metadata items, the variation(s) described must reside as VALUE of the KEY "character".

3.2.1. Variation

A variation is a structure of properties that configures the setup of the tone-specific sound generator. Its realization depends on an optional attribute that corresponds to the usage of an article in the score for which that attribute is set or yields from a set bézier curve x-position related to a given tick position in the measure.

Variations are a MAYBE_LIST\<VARIATION>. If a singleton, the implementation MUST reject any attribute indication described in section 3.2.2. The single variation is the root variation.

In a list, all variations without an attribute indication will be stacked to the root variation. Stacking is the process where properties of variations defined below overwrite those defined in a variation above with the same name on the same level. For "PROFILE" and "MORPH" composite properties, special conditions apply.

The MAPPING KEYs imply by their form the type of the specified property:

BASIC = CHAR [CHAR]
GROUPLABEL = 3*LCCHAR   ; lower-case char
PROPERTY = "VOLUMES" / "SPREAD" / "TIMBRE" / "PROFILE"
         / "MORPH" / "RAILSBACK_CURVE"
3.2.1.1. Basic properties

The KEYs of the Variation or Profile item property MAPPING in the subset of single or pairs of upper-case letters are the basic properties.

3.2.1.1.1. Oscillator primitive

There are six primitive oscillator types an implementation MUST provide:

The default of KEY "O" is "sine".

3.2.1.1.2. Attack envelope segment
A = DURATION:SHAPE
DURATION = FLOAT ; seconds

The FLOAT value is the attack time. The SHAPE should end in the maximum y-value of the curve.

3.2.1.1.3. Decay/Sustain envelope segment
S = NOMINAL_DURATION ":" START;SHAPE
NOMINAL_DURATION = FLOAT ; can be extended or shrinked depending on
                         ; the requested overall length, minus A duration
START = POSITIVE_INT

Extension on this takes place on the last spline between the penultimate and last node. The last node MUST not go lower than 0. Reaching 0, another spline MUST be implicitly appended that follows on 0 plateau to fill up the requested length. Shrinking is done by cutting the curve from the right-hand side.

3.2.1.1.4. Tail envelope segment
T = DURATION ":" START;SHAPE

The Decay/Sustain curve and the tail curve are cross-merged, with the tail fitted to the requested tone duration. The tail and sustain curves are aligned at their right-hand endpoints. The tail is processed only if it touches or intersects the sustain curve.

A new node is created at the point of contact or intersection, and the portion of the tail preceding this point is removed. The remaining tail replaces the corresponding section of the sustain curve over the same x-range. If the resulting curve does not reach y=0 y=0 within the nominal tone duration, the Release phase is applied.

3.2.1.1.5. Release envelope segment
R = DURATION ":" START;SHAPE

The final y-coordinate of the shape MUST be 0. The Release curve MUST be scaled proportionally along both axes to render the tone fading from the endpoint of the sustain or tail segment, beginning after the nominal tone duration.

During rendering, the release phase MUST overlap with tones attacked subsequently. The release phase MUST NOT be applied if the sustain or tail segment reaches y=0, or is extended to reach y=0, within the nominal tone duration.

An overlength property of a stem-note SHALL be realized by inserting a constant plateau segment at the specified relative X/Y position, allowing the Release phase to extend the tone to the indicated overall duration. The syntax is defined in stem-note properties.

This mechanism allows the rendering of piano-like variable sustain-pedal effects with reasonable fidelity.

3.2.1.1.6. Amplitude modulation
AM = FREQUENCY ["f" / "F"] ["@" OSC] [ "[" SHAPE "]" ] ";" MOD ":" BASE
FREQUENCY = POSITIVE_INT / FLOAT
OSC = "sine" / "sawtooth" / "square" / "triangle" / "noise" / "slopy"
OSC =/ LABEL ; property group label from where to construct an oscillator
MOD = POSITIVE_INT
BASE = POSITIVE_INT

"f" after the carrier frequency means factor of base frequency, F means additional multiplication with the ordinal number of the partial.

3.2.1.1.7. Frequency modulation

Frequency modulation is defined like amplitude modulation:

FM = FREQUENCY ["f" / "F"] ["@" OSC] [ "[" SHAPE "]" ] ";" MOD ":" BASE
3.2.1.1.8. Frequency variation
FV = BASE [("+" / "-") MIN] [("+" / "-") MAX] ";" SHAPE
BASE = NON_NEGATIVE_INT

Where the y-values of the SHAPE equal BASE, the heard base frequency is the octave of the nominal base frequency of the tone. Generalized, f = 2^(y/BASE).

3.2.1.1.9. Wave shape
WS = CENTER;SHAPE
CENTER = POSITIVE_INT

The initial x-coordinate should be 0. The minimum y-coordinate should be 0, the maximum 2*CENTER. Otherwise, this waveshape would not use the full dBFS span reserved.

3.2.1.2. Labelled property groups

A property group groups any subset of basic properties under its KEY of a MAPPING.

 LABEL: MAPPING
     ; all base properties are optional here, as long any one is defined.
     "O": IDENTIFIER / "@" LABEL ; with "@" oscillator is constructed
     "A": ...                    ; i.e. includes AM, FM, FV and/or WS
     ...
     "FM": "@" LABEL  ; e.g. FM MAY be inherited from another labelled
     "WS": MAPPING    ; group. properties may actually inherit from more 
        "@" LABEL_1: POSITIVE_INT ; than one group. Each must be assigned
        "@" LABEL_2: POSITIVE_INT ; an interpolational relative weight.
        ...
     "other": "@" LABEL ; group or its "parent" or closest "ancestor"
                        ; OPTIONAL "other" concerns any unmentioned.
3.2.1.2.1. Inheritance from a "base"

Labelled groups in subvariations inherit from the labelled group of the same name in any ancestor (sub-)variation and in any variations listed before them that are not tied to an attribute ("ATTR" key).

3.2.1.2.2. "@"-References

"@" references are looked up in the current variation, in any variations defined before on the same level, that are not tied to an attribute. If none found, the next ancestor level is searched in the same way, and so forth. Also, the referred labelled groups are filled up, all containing references resolved, recursively.

The implementation MUST observe that the references are not circular when processing an instrument specification file. It MUST raise an error if it detects a circular dependency or an irresoluble reference.

"@" with an oscillator name is implicit: A reference without will just resolve to the basic oscillator primitive. With "@" before the name, it will also consider any modulation, frequency variation and waveshape, incorporated in the derived oscillator function.

3.2.1.3. Variation properties
3.2.1.3.1. "VOLUMES"
"VOLUMES": LIST / RESOLUTION:SHAPE
ELEMENT    = INTEGER
RESOLUTION = POSITIVE_INT
3.2.1.3.2. "SPREAD"
"SPREAD": LIST / RESOLUTION:SHAPE
ELEMENT = INTEGER
RESOLUTION = POSITIVE_INT

A SPREAD contains deviations from the natural overtone series in cent from the first partial onwards. The deviations cumulate.

3.2.1.3.3. "PROFILE"
"PROFILE": LIST
ELEMENT = MAYBE_LIST<REVERSED_DBFS> / REVERSED_DBFS "@" LABEL / MAPPING

Contents of the MAPPING:

If a match contains partial seqnums with "n" marker, these are evaluated as division rules. Associated properties refer to the partials the cardinal number of which is, reduced by the right ±POSITIVE_INT, divisible by the left POSITIVE_INT.

The PROFILEs may merge dependently from the path of evaluated variations. The Profile built up when the sound generator is constructed must contain dedicated elements for the first partial, i.e. the fundamental, and the last partial must be included as POSITIVE_INT without "n". Any element with match greater INTEGER with "n" SHALL be ignored.

3.2.1.3.4. "TIMBRE"
"TIMBRE": SPECTRUM_WIDTH:SHAPE
SPECTRUM_WIDTH = POSITIVE_INT

The timbre defines a resonance corpus by which the volumes of the partials depends on the base frequency. So the instrument sounds more natural.

3.2.1.3.5. "MORPH"
"MORPH": LIST
ELEMENT = PARTIAL_SEQNUMS SP [ WEIGHT ":" ] SHAPE
WEIGHT = POSITIVE_INT

The PARTIAL_SEQNUMS address the partials to further shape after rendering. The WEIGHT is 1 by default. Greater values influence in how much a shape participates if multiple elements relate to the same partial.

Like the PROFILEs, MORPHs merge, too.

3.2.1.3.6. "RAILSBACK_CURVE"
"RAILSBACK_CURVE": LIST
ELEMENT =
- minimum base frequency
- maximum base frequency
- 88*INTEGER | "88:" SHAPE
  ; deviations from the base frequency of each key, in cent

To find the deviation for a key, its position MUST be calculated from its nominal base frequency.

The author assumes that only a good piano tuner can make the settings so it sounds alright. Other people may be challenged to use RAILSBACK_CURVE and SPREAD and keeping the voice in tune.

3.2.2. Attributes

The MAPPING of the variation may include:

"ATTR": NAME [ "=" STRING 1*("|" STRING) ]

As a simple name, the MAPPING must contain at least two numeric values, a minimum and maximum in between an input value can yield an interpolated variation in between.

By the right-hand part, the input value of the attribute can select the subvariations to stack onto the base variation. If the input value is a list of such labels, not the order of the list is relevant, but rather the order in the definition of "|"-separated VALUE after the =.

3.2.2.1. Implicit attributes

Following attributes are always propagated to the tree of variations. The encrypter does not need to declare them explicitly:

stress SHOULD be overwritten by the implementation when set explicitly.

3.2.3. Unification mechanism

3.2.3.1 Merging

If a numeric target ATTR value requires interpolation between two edge-values i.e. their subvariations in a variation, sound generators MUST be set-up for both twigs, and these sound generators MUST be merged partial-wise.

If the target value is greater than the greatest edge-value defined in the variation, its subvariation MUST be taken as is. Likewise, if the target value is less than the lowest defined edge-value, its subvariation MUST be taken as is. If the target value matches an edge-value as is, the variation MUST be taken as is.

Stacked variations with "PROFILE", "TIMBRE", and/or "MORPH" properties in either MUST both set up a sound generator and the sound generators MUST be unified in the way that their partial groups are brought in-line in that the partials from the sound generator from the later-defined variation, grouped by their cardinal number, replace the properties of the partials of the sound generator from the earlier-defined variation.

3.2.3.2. Stacking

Independently from that, the ELEMENTS of the PROFILE and/or MORPH of the later-defined variation stack up onto the ELEMENTS of PROFILE and/or MORPH of the earlier variation. Properties of the later variation PROFILE ELEMENTs and the shapes of the later variation MORPH ELEMENTs replace those of the earlier variation.

If none of the concerning variation properties are found in at least one of both variations to be unified, basic properties of the later variation replace those of the earlier variation. Likewise, the properties of the labelled groups with the same name overlay in that manner.

3.2.3.3. Implied PROFILE

If the later-defined variation has no PROFILE and also does not inherit one from its ancestors, the implied PROFILE has only a fundamental and so has the unified sound generator.

3.3. Room reverberation

Because room is just an analogue concept of the corpus of an instrument, i.e. a second, outer separated close parcel of athmosphere surrounding both the "orchestra" and the virtual audience, it is in scope of the model. Hence, reverberation is excepted from sound effects that are basically beyond scope, best achieved by VST plugins.

Because the renderer may choose to not use the reverberation algorithm of the implementation, they SHOULD be able to issue rendering of single voices instead, to import the rendered audio files into a Digital Audio Workstation of their choice.

The implementation MAY support reverberation. If it does, it MUST read "room" reverberation specification in a referenced file or embedded in the score file. If it does not support reverberation, it MUST at least warn the renderer that file references or embedded specifications, if given, are ignored.

room: PATH / MAPPING
      ; path to file with contents like MAPPING.
      ; File ending ".splr"

Properties other than those defined in the subsections MUST NOT occur and be processed. They SHOULD be denied.

3.3.1. "levels"

levels: POSITIVE_INT:SHAPE / LEFT "|" RIGHT / MAPPING
  left: LEFT
  right: RIGHT
LEFT  = POSITIVE_INT:SHAPE
RIGHT = POSITIVE_INT:SHAPE

The mandatory property "levels" describes the number and the REVERSED_DBFS volumes of the delays. The shape applied to a sound can depend on the position of the voice on stage, relative to the listener. It is weight-averaged accordingly.

3.3.2. "delays"

delays: SECONDS:SHAPE / LEFT "|" RIGHT / MAPPING
  left: LEFT
  right: RIGHT
SECONDS = FLOAT ; duration of reverberation decay
LEFT = SECONDS:SHAPE
RIGHT = SECONDS:SHAPE

The decay time in SECONDS roughly correlates to the t60 time as a concept in acoustical science if the final levels y-coordinate is at 40, because dBFS = 40 - 100 = -60. The shape indicates for each delay the distance to the preceeding, related to the overall decay time.

3.3.3. "frequency_lanes"

freq_lanes: LIST    ; frequency band-wise decay over time
    - BANDS:SHAPE   ; first element: BANDs of EQ spectrum
    1*(- DIST:SHAPE)

By this property the materials of the room are roughly modelled in regard to their quality.

BANDS indicates the number of spectral bands of the reflection (versus damping) equalizer. DIST, put in relation to the DIST of the final element, indicates which adjacent pair of shapes are weight-averaged, and how, to shape the gradient of reflection in the spectral band of each ordinal number, in relation to its respective initial value.

3.3.4. "border"

border: MSECONDS:SHAPE
MSECONDS = POSITIVE_INT ; milliseconds

The "border" property is used to realize the Haas effect. It should be limited to experiments with psycho-acoustical sound source localization. The shape indicates the gradient of the interaural level difference of sounds from the shadow ("leeward") side of the head to the ear. MSECONDS is recommended to be set to 35. The width of the shape will be projected on the properly delayed levels. The border shape MUST be average-weighted with a constant 1.0-plateau shape depending on the position of the voice on stage between sharply from the shadow-side ("leeward"; 1.0) to central balance (0.0).

Informational NOTE: The property "border" is named thus in regard to the naive model of the listener's head as a wall of zero thickness along the forehead-neck axis. It separates the "soundward" from the "leeward" side.

Key is the initial y-coordinate basis indicated by having the shape start with

BORDER_SHAPE = m "+" N ";0," y 1*(";" x "," y)

m is the basis added to each y-coordinate. N is the maximum among all y-coordinates, any larger than N would yield values > 1.0. The value is substracted from 1.0 and the result multiplies the Haas time (35ms recommended), by which the delay for the soundward side ear is left-shifted on the time axis compared to the leeward side ear.

3.3.5. "jitter"

jitter: SHAPE

The shape of the optional property indicates the gradient of the share of the extent in which the original delay level is randomized. A value of 1.0 indicates that the delay-level is reset to a value between 0 and the double value of the original value. A value of 0 will render the original level of the delay unchanged.

3.3.6. "deldiffs"

deldiffs: LEFT "|" RIGHT / MAPPING
   left: PATTERN
   right: PATTERN
LEFT: PATTERN
RIGHT: PATTERN

PATTERN is a stressor pattern defined in Section 4.6.1.3.0. The values cycled through indicate how much the delays are shifted on the time axis, additionally to what is defined by "border".

3.3.7. "diffusion"

diffusion: PATTERN

The diffusion MUST be implemented as an additional equalizer applied to each delay, but to set it as a comb filter, as is recommended, is the business of the user defining the reverb.

4. Score File

4.1. Metadata

4.1.1. "title"

This should be the song title of the original composition / song if composer and encrypter is not the same person. Any personal title or addition to the original title should be KEYed something like "edition", "version" or whateveryou like.

4.1.2. "composer"

The original composer. According to e.g. German copyright law ("Urheberrecht" in the author's non-authoritative understanding) the original composer SHALL be either the same as the encrypter or for more than seventy years dead or they MUST have licensed their work to the encrypter for any encryption / encoding edits. The encrypter SHALL refer to their jurisdiction.

4.1.3. "source"

If the score file is based on someones work (music sheet), there needs to be a source to cite here, to be fair.

4.1.4. "encrypter"

The name of the person who creates the score file.

4.1.5. Other attributes

Other attributes MAY be disregarded by the implementation. They SHALL not influence the PCM values of the rendering in any way.

4.2. Stage

The stage is a MAPPING of voice definitions. The KEY are the voice names to be found in the measure MAPPINGs. The VALUEs are either MAPPINGs or STRING.

4.2.1. Voices and Instruments

4.2.1.a. Voice Definition as MAPPING

IDENTIFIER:
    direction: LEFT|RIGHT
    distance: DISTANCE
    instrument: Instrument
    articles: MAPPING    ; s. Section 4.3.
      ; Properties may overwrite or extend the general properties there.
      ; are the base for all measure-bound indications
    tuning: MAPPING      ; voice-level tuning properties, excluding all
                         ; composite properties of general tuning mapping
LEFT = NON_NEGATIVE_INT
RIGHT = NON_NEGATIVE_INT
Instrument = IDENTIFIER | PATH   ; imply file ending: ".spli"
    ; path relative to directory of the score file

If the Instrument is an IDENTIFIER, the specification must be embedded into the score file.

4.2.1.b. Voice Definition as STRING

IDENTIFIER: LEFT|RIGHT DISTANCE [Instrument]

Measure-global but voice-specific articles are not supported.

4.2.2. Orchestra Cone

stage:
  _space: space-behind "|" extend-width : shrink-width
space-behind: POSITIVE_INT
extend-width: POSITIVE_INT
shrink-width: POSITIVE_INT

The orchestra cone restricted by the space behind, reducing the relative distance to the listener, evening out differences in volume, and the relation of extend-width and shrink-width. Equal values for last both result in an 2 x 45° angled stage cone.

4.3. Articles

articles: MAPPING
    LABEL_1:
        ATTR_1: VALUE_1 / CONTINUUM_1
        ATTR_2: VALUE_2 / CONTINUUM_2
        ATTR_N: ...
    LABEL_2: ...

Articles, as an general abstract term re-coined in the context of this specification, are the concept corresponding to note heads inspired from traditional music notation.

Actually, they are LABELled groups of attribute settings for the tone-specifically configured sound generator.

4.3.1. Name

The KEYs of the "articles" MAPPING are of IDENTIFIER type.

4.3.1.a. Single-Letter

If it is a single character long, it can be used instead of "o" that by default symbolizes a new attacked tone in a chain.

4.3.1.b. Extension

Word labels represent articles the attributes of which overwrite the attributes of the same name from, or extend articles applied earlier for the same tone.

An extension is attached by a prefixed colon.

4.3.2. Attributes

If an attribute set by an article is not found somewhere in the associated instrument specification, the implementation SHOULD raise an error. If an attribute is not evaluated because of the other attributes defined by the article, rendering the path through the tree surpassing the relevant variation, the implementation MAY warn.

4.3.2.a. As Static Value

VALUE = INTEGER / FLOAT / MAYBE_LIST<STRING> / BOOL

If the VALUE is numeric, the variation in the instrument specification with the corresponding attribute must be numeric, that is, must have at least two subvariations bounds to edge-values in the range in between the sound generator gets interpolated properties.

If the VALUE is STRING or a LIST of string, the variation of this attribute in the instrument specification is expected to have stackable subvariations . The order of overlapping is fixed by the attribute description in the instrument specification.

If the VALUE is of type BOOL, there must be a variation with that ATTR property set to VALUE. This variation will be evaluated, and any variation preceeding that have no ATTR property as well.

The implementation MUST raise an error on type mismatch.

4.3.2.b. As Continuum

An numeric attribute of an article can be defined as a continuum.

CONTINUUM = START "-" END / START;SHAPE ; last Y-coordinate is END
START = NON_NEGATIVE_INT

Which value is passed to the sound generator depends on the position of the tone in question within the measure.

4.3.2.c. As LPU-Pattern
LPU = "L:" SHAPE ";P:" STRESSOR ";U:" SHAPE

The syntax of a stressor is defined exactly like stress_pattern for a measure, just without the "L:" and the "U:" part. See section 4.6.1.3 for details. The stressor cycles through discrete values from tick to tick between the lower and upper boundaries.

4.3.3. Inheritance

Properties of stem notes with chains not (re-)defined on chord or note level are inherited from the article redefinitions in

in that order.

As a virtual property of an article MAPPING, OPTIONAL KEY "-important" has a LIST of property labels. These are not defaults but overwrite their associated VALUE to every voice, voice part in a measure and stem note with chain for which there is a redefinition of that article property. The implementation MUST deny property names not existing as KEY among the properties defined in MAPPING of the article.

Properties of stem notes are applied directly to these if without chain, or to all notes of a chain defined, overwriting properties of all articles unless they are overwrite-flagged for the respective article from upper levels. Gradient or LPU-style properties of chord and stem note level are related to the length of the chain instead of the entire measure when that length is explicitly indicated.

"Stacked variation" properties flagged "-important" include in their VALUE LIST which labelled subvariations participate no matter if listed in redefinition of lower levels. These stack labels MUST be added to the note property collected, the VALUES of these properties MUST be LISTs.

The flow of overwrites is in the opposite direction of inheritance, i.e. from stem note with chain to global article definition.

Users are advised to use overwrites for preliminary aural analysis only. Published scores should not include '-important' slots in article definitions of any level.

4.3.3.1 Definite Properties

Properties of stem notes with chain or without, as well as properties in article with undefined label (null, None) MAY NOT be redefined on lower levels, so the lower always inherit properties from the upper.

4.4. Embedded associated specifications

Instrument specifications not referenced by PATH must be defined in the document (YAML: the initial document) as:

 "instrument " (NAME / IDENTIFIER): MAPPING
    ; the voice identifier replaces optional name

The VALUE of KEY "room" can be either a PATH to a room/reverb description file or a MAPPING of the parameters from which to infer an impulse response model.

4.4.1. "NOT_CHANGED_SINCE" (instrument only)

Because an embedded instrument specification has no modified file timestamp, it should have in its MAPPING:

"NOT_CHANGED_SINCE": DATE
"character":
    ; ...
DATE = YYYY-MM-DD HH:MM:SS

4.5. Tuning

tuning: PATH / MAPPING
   base: PATH
   ; following properties are optional
   ref_key_offset: INTEGER
   base_frequency: FLOAT
   intervals: STRING
   ...
   chords:
      ; chords to add or to overwrite
   scales:
      ; scales to add or to overwrite
   ; tones – must be imported from the base

The general tuning properties except chords, scales and tones i.e. the composite ones may be overwritten on voice-level tuning.

4.6. Measure

Musically relevant settings are gathered in the "_meta" MAPPING. If the MAPPING is empty, the slot can be omitted.

4.6.1. Properties

4.6.1.1. Implied properties

Not all properties need to be defined in every measure. But defining and varying them from measure to measure can render an audio that sounds like a lively performance.

4.6.1.1.a. Implied from previous measure

If JSON is the underlying format, or else YAML without "measure" MAPPING in the initial document, properties not redefined are implied from the previous measure. The first measure MUST define all properties shared with, i.e. not re-defined in the following ones.

4.6.1.1.b. From "measures" score property

If YAML is the underlying format and "measures" MAPPING is defined in the initial document, its properties are inherited to all "_meta" MAPPINGs in the measure documents.

If JSON is the underlying format, "measures" is used as slot for the measure objects themselves. Only inheritance from previous measures is feasible then.

4.6.1.2. Tuning and Harmony

In "_meta" MAPPING, "tuning" property is defined as follows:

"tuning": 1*(*SP "." [POSITIVE_INT] / [shift-base] [scale-type])
shift-base = ("+"/"-") POSITIVE_INT / "0"
scale-type = 1*ALPHA

For every tick in the measure, tuning indicates if the base tone is changed and / or the scale type to validate against.

The base tone is only relevant for tempered (non-TET) scales. The implementation MUST calculate the diff value related to the preceeding base tone.

4.6.1.3. "stress_pattern"
"_meta":
    "stress_pattern": subdivision *(";" division)
    division    = subdivision *("/" subdivision)
    subdivision = POSITIVE_INT / level 1*("," level)
    level       = POSITIVE_INT / high "-" low
    high        = POSITIVE_INT
    low         = POSITIVE_INT ; < high

The stress pattern is REQUIRED for the first measure or in the "measures" property in the first YAML document. It defines the metric profile of the music. Without it, or if the first and only subdivision is expressed by a POSITIV_INT, this denotes the number of ticks the measure is long and all ticks have the same stress. This may sound good in mechanic music styles at most.

Subdivisions are cycled through for every stage of preceeding division. That means "/" separator cannot be used before the first ";".

The first tick marks the first beat of the measure. In many music styles it is the strongest one. To achieve that, in every division the first level should be set to the maximum of the division.

4.6.1.4. "beats_per_minute"

The VALUE variants of the "beats_per_minute" property accord to that for the articles:

"beats_per_minute": POSITIVE_INT / START "-" END / START;SHAPE
START = POSITIVE_INT
4.6.1.5. "lower_stress_bound"
"lower_stress_bound": POSITIVE_INT / START "-" END / START;SHAPE

The implementation MUST observe that lower_stress_bound is for all ticks of the measure actually lower than "upper_stress_bound".

4.6.1.6. "upper_stress_bound"
"upper_stress_bound": POSITIVE_INT / START "-" END / START;SHAPE

The implementation MUST observe that lower_stress_bound is for all ticks of the measure actually lower than "upper_stress_bound".

4.6.1.7. "elasticks_pattern"

Syntax is defined like for stress_pattern, but the semantics refer to the relative lengths of the ticks the tones endure.

4.6.1.8. "elasticks_shape"
"elasticks_shape": START;SHAPE

The START is the initial y-coordinate. All why-coordinates relate to their maximum. On ticks with their ratio at 1.0, the elasticks_pattern influences them to there full extend, while ticks under ratio at 0.0 (y=0) are of same length to their adjacent ones.

4.6.1.9. Measure-bound uninherited properties

These properties are not inherited to following measures and cannot be overwritten for voices.

4.6.1.9.1. Identifier
"_id": IDENTIFIER

That property is optional. The default is incrementation of an integer, beginning with 1. Even measures with identifier get that counter, but the implementation SHALL NOT use it to refer to the measure, but always the identifier.

4.6.1.9.2. "cut"
"_meta":
  "cut": INTEGER

If the "cut" is positive, the first INTEGER ticks do not consume time in the resulting audio. If it is negative, the last -INTEGER ticks are ignored. Ignored ticks MUST NOT be occupied as offsets by notes.

4.6.1.9.3. "skip"
"_meta":
   "skip": BOOL

Decides if the measure is processed and occupies playing time in the resulting audio. It is not just muted.

4.6.1.9.4. "repeat_unmentioned_voices"
"_meta":
   "repeat_unmentioned_voices": BOOL

Decides that all voices that are omitted repeat the content of the previous measure. The repetition can advance over multiple measures.

4.6.1.9.5. "is_last"
"_meta":
   "is_last": BOOL

If a measure has a property "is_last": TRUE, the implementation MUST finish rendering audio after processing it, and output the audio file of the processed length.

4.6.1.9.6. "offset_seconds"
"offset_seconds": POSITIVE_INT

The implementation MUST put an empty time-span of POSITIVE_INT seconds between the net length of the longest lasting note of the previous measure and the first note of this, or since start of the track.

4.6.2. Per-voice indications

The KEY in the measure MAPPING MUST be validated to be the name of a voice. The VALUE is either STRING, a MAPPING, or a MAYBE_LIST\<MAPPING> with each item containing a "pitch" (or "P") property qualifying it as a note specification. A STRING MUST be internally converted to a MAPPING with offset KEY 0 and the original VALUE.

4.6.2.1. Voice- and measure-bound
4.6.2.1.1. Properties
"_meta":
     ; all properties are OPTIONAL
     ; not supported here: "beats_per_minute"
     "stress_pattern": PATTERN
     "lower_stress_bound": REVERSED_DBFS / CONTINUUM
     "upper_stress_bound": REVERSED_DBFS / CONTINUUM
     "elasticks_pattern": PATTERN
     "elasticks_shape": SHAPE

Properties defined or implied in the "meta" slot of the measure level but omitted in the voice-level MUST be taken from the measure level.

4.6.2.1.2. Articles

Voice-bound and measure-bound article attributes overwrite attributes of the same name defined for global articles and global voice-bound articles. They can have likewise static values and continua. See Section 4.3. for details.

4.6.2.2. Named material
NAME: MAYBE-LIST<STEM-NOTE/MATERIAL-LINE>

Material lines (s. Section 6) incorporate seamlessly, without hints to the reference relation, any included material refs. If those referred named materials are changed afterwards, there MUST NOT be any impact on earlier referring material lines.

4.6.2.3. Offsets
OFFSET: MAYBE-LIST<STEM-NOTE>
OFFSET = NUMBER

The encrypter SHOULD use caution with negative values for offsets. These the listener will hear in a preceeding measure, but the actual distance will depend on the beats_per_minute setting active for the measure where the offset and content is specified. The implementation SHOULD warn about negative offsets in the first measure or if erroneous "cut" settings post-pone offsets to the end of the score.

4.6.2.3.1. Settings MAPPING as first LIST ELEMENT

If an offset has a LIST of VALUEs and the first ELEMENT is a MAPPING without PITCH entry, the implementation MUST handle its contents as settings related to all notes within.

There are special settings in this context:

Other properties MUST be passed to the STEM-NOTE or MATERIAL-LINE.

4.6.2.3.2. Multi-tick offsets

To know the full specification of offsets is optional even if neat to use for certain styles of music. Generally, there may be some felt benefit to quantified chain clauses:

OFFSET =/ offset-interval *("," offset-interval)
offset-interval = POSITIVE_INT [ "+" POSITIVE_INT "*" POSITIVE_INT]

The last ticks an offset addresses MUST be allowed given the length of the measure. Otherwise, the implementation MUST raise an error.

4.7. Multimeasure

In multimeasures, the VALUEs of

can be a vertical-bar-separated. A sequence of the parts is cycled through by every step of advance through that group of measures. For each measure within, all items as listed above are gathered and the measure composed from them

4.7.1. "_loop" KEY

"_loop": POSITIVE_INT

The _loop count MUST be greater-or-equal than the count of parts in all concerning items. The implementation MUST raise an error for items with exceeding number of parts.

4.7.2. Vertical bar(s) separator |

VSEP = 1*SP 1*"|" 1*SP ; 1*M"|"
IVSEP = VSEP ; 1*N"|" with N < M

A separator is defined by VSEP, including surrounding spaces. Relative precedence is determined by the number of consecutive "|" characters. Within the scope of a separator, any contained separator MUST have fewer consecutive "|".

4.7.3. Quantifier *n

REPEATED-UNIT = MEASURE-S VSEP "*" POSITIVE_INT
MEASURE-S = MEASURE *(IVSEP MEASURE)
             ; not supported by ABNF

The quantifier indicates the number of repetitions. The first, literal occurrence is not included. The comment to IVSEP is vital, cannot expressed in ABNF, unfortunately.

*N is a measure of its own in regard of these syntax rules. After a run of bars a quantifier relates to the whole part delimited by runs that long.

4.7.4. Back-reference by %n

BACK-REF = MEASURE VSEP "%" POSITIVE_INT

The POSITIVE_INT indicates the repetition of the n-th literal measure in that line.

%N counts as a measure of its own in regard to these syntax rules. It can only address atomic literal measures number-ordered by occurrence in a multi-measure line. This is in contrary to *N as described in the last section.

5. Stem Note and Properties

A STEM-LINE ELEMENT consists of one STEM-NOTE as a MAPPING or one or more STEM-NOTE as a STRING.

5.1. Specification

5.1.a. as a MAPPING

A stem note in MAPPING form must contain a slot with KEY "pitch" or "P", its VALUE is a PITCH.

Either a "length" ("L") property or a "chain" property is REQUIRED. An omitted length is implied from the chain, or if it is omitted, too, it equals 1.

5.1.a.1. Co-pitch properties

There are two optional properties associated to pitch, and which can be used in article definitions, too.

5.1.a.1.1 "extra_adj_pitch"

VALUE is INTEGER. Implicitly adjusts the key as an incorporated rel_pitch ±n chromatic octave steps. Best used in article stacks for additional parallel pitches that shall not alter the rel_pitch cursor when used in a chain, or for cyclic changing tones in voices with short sounds (e.g. mandoline). To be used with caution, though.

5.1.a.1.2. "adj_pitch_cent_per_key"

VALUE is INTEGER and the definition is only useful when a "chain" slot is included in a MAPPING, with "extra_adj_pitch", or in article definitions. That amount in cent, multiplied with rel_pitch, is added to the stem-note pitch.

In an article definition it can be SHAPEd, too, for microtonally dynamic effects.

5.1.a.2. Overlength

An "overlength" can be levelled down in dependency of harmonic environment, just the same way a pianist can use the sustain pedal for articulation.

damp: FLOAT ; value range 0..[1, shapeable on measure-level

The damp note property indicates by how much, as a relational share < 1, a virtual damper falls back down when releasing the key. If greater or equal 1, tone is damped as normal, the overlength property is void. The implementation MUST handle this case as if "overlength" was not indicated at all. If X = 0, the implementation SHOULD handle it differently from just augmenting the net length, as by releasing the key, the sound cannot be shaped by the sustain phase any longer.

5.1.a.2. Weight

A "weight" can also be KEYed "W", its VALUE is a POSITIVE_INT.

Additional stress is indicated in KEY "adj_stress" and its VALUE is REVERSED_DBFS.

5.1.a.3. write_to

An OPTIONAL property is not related to the audible aspects of the note:

"write_to": MAYBE_LIST<IDENTIFIER>

The "write_to" IDENTIFIERs are names for materials. This is an equivalent option to using material name offsets. The advantage of the latter is that those names can be used in the same measure. The implementation MUST observe that "write_to" IDENTIFIERs are not read from in a material line in the same measure. This shall simply guard against strong negative impacts on clarity.

5.1.a.4 Positional attributes

These optional properties expression direction and distance move the tone on the stage. It cannot change the position while sounding until release, though.

They can be defined to an article as a SHAPE. Initial y-coordinate, without explicit x=0, should be set to:

y0 = "-" n "+" p
n  = POSITIVE_INT
p  = POSITIVE_INT

By SHAPEs, at least tones expressed by the same article in the chain "move" on stage during the measure.

5.1.a.4.1. Direction
_LRpos: FLOAT ; -1..+1

Leftmost is -1, rightmost is +1. The extremes relate to the bounds spanned by stage/_SPACE indication.

5.1.a.4.2. Distance
_Zpos = FLOAT ; -1..+1

-1 is close to the listener, +1 most distant. The extremes relate to the bounds spanned by stage/_SPACE.

5.1.a.5. Other Attributes

Other Attributes of the Form

KEY = ALPHA [ALPHA]

are passed as base properties to the synthesizer code that MUST impose them onto every partial of the sound generator.

If it complies to the rule

KEY = 3*ALPHA

it must be evaluated as an attribute like one for an article.

5.1.b. as a STRING

STEM-NOTE = PITCH [intonation] [SP length] [SP weight] [SP chain] [SP ">" write_to]
intonation = "!" / "?"
length = POSITIVE_INT [":" POSITIVE_INT]
weight = POSITIVE_INT signed_integer
signed_integer = ("+" / "-") REVERSED_DBFS

Intonation flags to PITCH, besides having the same meaning as for the chain explained below, they are implied for all chained notes without flag ("fallback").

5.1.b.1. Stem-Notes in an Element

Multiple stem-notes can be combined in a single ELEMENT. For a stem note in STRING form, following another without explicit own properties (none of length, weight, and chain) MUST adopt these properties implicitly from the last precedent stem note that has got any of them defined.

ELEMENT = STEM-NOTE *((SP 1*";" / 1*",") SP STEM-NOTE) [" <" MATERIAL-LINE ]

A material line again MAY pass back into stem-note mode by the same separators semi-colon or comma. See next section 6, where also runs of consecutive separators are explained.

Informational NOTE: The optional ending is not supported by the reference implementation, yet. See also section 6, editorial note at the start.

5.1.b.1.a. Separator ;

The separator consisting of space(!), semicolon, and space resets the line offset to that of the last comma+space separator. It coordinates the following stem-note so they are posisitioned in parallel.

5.1.b.1.b. Separator ,

The comma separator coordinates stem-notes serially one after another.

5.2. Length and weight on note level

If length is expressed with a simple integer, the real length of a chain, if given, must be divisible without remainder or vice versa, else the length must indicate the real length "as is" and the integer after the colon indicates the target length of the chain.

The weight indication is marked with a sign between the relative weight and the added volume. The relative weight is a share value by which all tones with the same offset, whatever their emitting voice, are adjusted in volume.

5.3. Chains

A chain may consist of multiple semicolon+space subchains. Parallel subchains MUST have equal length. This goes for the top-level as well as for nested chains.

chain         = subchain *("; " subchain)
subchain      = clause *(SP clause)
pause         = "." [POSITIVE_INT]
clause        = ( 1*(article_stack [length] / pause)
                / "(" [real_length ":" SP] chain ")" [length]
                ) [quantifier]

article_stack = extended_article *(";" extended_article)
real_length   = POSITIVE_INT
length        = "_" (*"_" / POSITIVE_INT) [("," / ";") POSITIVE_INT)

quantifier    = *1SP "*" ( *(*1SP "*") / *1SP POSITIVE_INT)
              ; the variant with multiple "*" (no INT) serves visual
              ; overview by aligning them vertically with other items

An article stack co-ordinates stacked notes, i.e. notes with the same offset. Likewise, a chain can consist of multiple subchains with the same offset. They MUST have the same length, though.

Observe that space separates clauses. Any quantifier multiplies the preceding clause. A quantifier can imply space before the following clause, so it is OPTIONAL.

The implementation MUST raise an error if real_length does not match total length of the nested chain, or if length + 1 and total length (or vice versa) do not divide without remainder but real_length is omitted.

5.3.1. Articles and extensions

extended_article = (uc-diacr-char / ["_"]) *(":" IDENTIFIER)
                   [mod_pitch] [adj_rev_dbfs] [tune_flag]
mod_pitch        = "=" / ("+" / "-") [*SAME_SIGN / POSITIVE_INT]
adj_rev_dbfs     = "^" ("+" / "-") POSITIVE_INT
tune_flag        = "?" / "!"

SAME_SIGN equals the numeric sign applied, i.e. "+" or "-" used in mod_pitch. Instead of multiplication of the sign, you can use a number.

The extended article short-cut "_" is OPTIONAL only before mod_pitch. If a single or multiple tick length "_" indication without number is before and no mod_pitch is after it, whitespace must in between, as a side-effect this results in separate clauses.

5.3.2. Length and Overlength

For notes longer than one tick, one or more adjacent underlines after the article signify that. Instead of chains of length underlines, the encrypter may use a number following a single length underline.

Following an underline length, "," attaches an optional overlength that is not included into the offset of any notes next in the chain. Instead of ",", ";" without adjacent space does the same, plus implies reduced overlength for the next notes, so by their release they all end on the same tick, except for any nominally longer.

The length can be adjusted by special attribute "adj_length". The position of a note can be moved by "shift". Unit of both is seconds.

5.3.3. Adjusted stress

Additional REVERSED_DBFS is signified by a caret. Weight relative to other notes cannot be expressed within the chain, only before on stem-note level or by article specification properties "weight" and/or "adj_stress".

The relevant stress of a note is that of the strongest tick covered within the first half of the positioned note length, and on which no other note of the voice starts.

5.3.4. Intonation flags

If a "tuning" with scale indications are set in "_meta" of the measure, the implementation MUST observe that all notes in the region under a governing scale actually are in that scale. However, by attaching an exclamation mark the check is deactivated for that note. By attaching a question mark, the note – when off-scale – MUST be automatically adjusted to the next in-scale tone.

5.3.5. Relative Pitch indication

Like for length, any "+" or "-" can either be chained or followed by a number. "=" resets the pitch to the stem note. Without pitch indication, a note adopts the same pitch of the note it follows

5.3.6. Parenthesis Clauses

If "=" is in a clause between a pair of parentheses, it is reset to the pitch of the last note before the opening parenthesis. Any note after the closing parenthesis MUST ignore pitch alterations from within.

A length indication adjacent to the closing parenthesis relates to it as if it was a note. The real length of the clause, i.e. the total length of the subchains (counted up to the first semicolon with space before the closing parenthesis) within MUST divide the outer length indication without remainder, or vice versa. Otherwise, the real length MUST be indicated explicitly after the opening parenthesis. A required but missing real length indication MUST raise an error.

5.3.7. Parallel and sequencial orders

A ";" with succeeding, but without preceeding space, resets the offset of the next clause to the beginning of the parenthesis clause or the beginning of the chain. All parts of a parallel clause or chain MUST have the same length. The implementation MUST raise an error otherwise.

A ";" without space at either side parallelizes on the level of the single tone. A run of ";"-separated notes start at the same offset and share the same length indication at their end. Other appendices relate to their single note before.

A "," without space at either side MUST separate a note from the other, if the former has extensions but no appendices. A single comma beyond these conditions, and without either a number or space after MUST be denied by the implementation.

5.4. Inheritance of Attributes

A special article extension "all" inherits all contained attributes to all notes of the voice in the current measure, no matter if in a chain or as a MAPPING, if the extension is defined for the voice, or for all voices otherwise, and to all measures if defined in top-level "articles" MAPPING slot.

Attributes defined specifically for a voice, if global or for the measure, take precedence to top-level article definitions.

Attributes MUST be inherited to all chained notes with note head "o", not to MAPPING notes without chain, if they are defined in an article MAPPING under KEY "o". This works accordingly for any other letter.

Attributes defined for an extension are inherited for all chained notes with that ":"-prefixed extension.

6. Material Lines

Non-authorative note

If an ELEMENT starts with "<" instead of a stem-note, the syntax and meaning is much different. Currently, only a (very) "Simple material clause" [SMC] as the full content of an ELEMENT is supported by the reference implementation Sompyler. Development currently focusses "Complex material clauses" [CMC].

As long as you cannot find a draft specification of it in the "master" branch of the official repository, consider that development private and in no way binding in respect to a upcoming feature set a compliant implementation is expected to support.

For the time being, Sompyler SHALL promote de-patternizing of music, let the melodic variety prosper within a piece.

6.1. Syntax

SMC = "<" *SP material-ref *("," *SP material-ref)
material-ref = (MATERIAL-NAME / [MATERIAL-NAME] slice) [":" PITCH]

6.2. Slicing

A MATERIAL-NAME is looked up in the current measure or the one most recently passed measure where it has defined as named material MAPPING slot. The implementation SHOULD warn the encrypter on the first change of a material in total length, i.e. when a name is reused for a material of different length. The implementation MUST deny unknown names.

slice = "[" ["+" / "-"] OFFSET ("+" LENGTH / ":" END-BEFORE-INDEX) ["+" / "-"]
         [ ":" [["+" / "-"] STEPPING] [":" OUT-LENGTH] ] ["r" / "f" / "rf"] "]"

By using STEPPING, OUT-LENGTH (shrinking, stretching) and "r" (reverse) and "f" (flip) flags, elaborated variation of material is possible. A slice is appended to a name or a PITCH.

"+" and "-" denote how the implementation MUST handle cases where indices address a tick within the duration of tones. "+" lets the touched tone reach over the nominal boundaries of the material, "-" has it replaced by pause. The "+" between OFFSET and LENGTH has not got that semantics, but is a cue of distinction from <END-BEFORE-INDEX>.