Sequence data is a structure for storing and transferring sequences of timed events such as music. Sequences can be stringified to human readable JSON or serialized to binary data.
This specification defines a minimal set of events closely aligned with the features needed to control the WebAudio API, transmittable via MIDI 1.0 (with some resolution loss), MIDI 2.0 or OSC.
Consumers of Sequence data are expected to silently ignore unsupported event types, allowing the set of events to be extended for other applications.
- Specification of the format of Sequence data (this README)
- Reference implementation of an iterable
Sequenceobject - Reference implementation of an
Eventobject - MusicXML to Sequence converter
- ATProto record converter with binary serializer for events arrays
- ATProto lexicon schema for publishing sequences as PDS records
The Sequence format defines two data structures, a Sequence object and an
Event array.
Note
Sequence data describes all times and durations in beats. Beat values are
arbitrary, and depend on the rate of playback of a sequence. A sequence
playing back at a rate of 1 is running at 1 beat per second, so it is
following absolute time.
Here are the first two bars of Dolphin Dance represented as a sequence in JSON:
{
"name": "Dolphin Dance",
"events": [
[0, "meter", 4, 1],
[0, "rate", 2, "step"],
[2, "note", 76, 0.8, 0.5],
[2.5, "note", 77, 0.6, 0.5],
[3, "note", 79, 1, 0.5],
[3.5, "note", 74, 1, 3.5],
[10, "note", 76, 1, 0.5],
[0, "chord", "C", "∆", 4],
[4, "chord", "G", "-", 4]
]
}A sequence, at its simplest, is an object with an events array.
{
"events": [...]
}events – ARRAY
An array of events.
Sequences may also have the properties:
{
"id": 0,
"url": "https://...",
"name": "My Sequence",
"events": [...],
"sequences": [...],
"credits": [...],
"tags": [...],
}id – STRING
in any array of sequences it must be unique, and is used to identify the sequence
for playback. A top level sequence does not require an id.
url – URL STRING, optional
Canonical location of this sequence.
name – STRING, optional
An arbitrary string.
sequences – ARRAY, optional
An array of sequence objects. Sequences are played back by "sequence" events
in the events array. They are referred to by id. If there are no "sequence"
events in the events array, the property sequences is not required.
credits – ARRAY, optional
An array of objects containing details of contributors, of the form
{ name, role, url }.
tags – ARRAY, optional
An array of strings.
[beat, type, ...]beat – FLOAT
Describes a point in time from the start of the sequence in beats.
type – STRING
The event type, determines the length of the event array and the structure of
the rest of its values:
| beat | type | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
beat |
"note" |
pitch |
dynamic |
duration |
|
beat |
"param" |
name |
value |
curve |
duration |
beat |
"rate" |
number |
|||
beat |
"meter" |
duration |
divisor |
||
beat |
"chord" |
root |
hsid |
duration |
|
beat |
"clef" |
name |
|||
beat |
"key" |
name |
|||
beat |
"sequence" |
id |
target |
duration |
|
beat |
"text" |
string |
duration |
||
beat |
"start" |
reserved | |||
beat |
"stop" |
reserved |
[beat, "note", name, dynamic, duration]name – FLOAT [0-127] or STRING
Represents the pitch of a note.
If name is a number, it is a MIDI note number, but may be a float and so can
represent any frequency. MIDI note number 69 is 440Hz. If name is a string
it is an arbitrary pitch name. Implementations must accept at least the 128
pitch names 'C0' - 'G9', and the use of both the hash # and the unicode
sharp ♯, and both the small letter b and the unicode flat ♭ in their
spellings, but output only the unicode spellings in any Sequence data output.
dynamic – FLOAT [0-1] | STRING ["-ndB"] | STRING ["ppp"-"fff"]
Represents the force of the note's attack.
A dynamic larger than 1 is permissible, but negative dynamic is invalid.
duration – FLOAT [0-n]
Represents the duration of the note in beats.
[beat, "param", name, value]
[beat, "param", name, value, curve]
[beat, "param", name, value, "target", duration]name – STRING
The name of the param to control.
In a WebAudio context this would typically map to an AudioParam on the
instrument being targetted.
value – FLOAT
The destination value of the param. If curve is "hold" has no effect.
curve – STRING "step", "linear", "exponential", "target" or "hold"
The ramp to use for transition to value. This parameter is optional. If it is
not present the event describes a "step" curve. If curve is "target" the
event requires a fifth parameter:
duration – FLOAT
The T60 decay time of a "target" curve with a value of 0.
Note
The WebAudio API defines a time constant as the time it takes for audio to reach 63.2% of its new value, where sequence data prefers a T60 decay time.
[beat, "rate", rate]
[beat, "rate", rate, curve]
[beat, "rate", rate, "target", duration]rate – FLOAT
Rate of playback of a sequence. Nominally in beats per second, but sequences may
be played from other sequences, and rates are accumulative. If sequence A is
playing at rate 2 and contains sequence B playing at rate 1.5, sequence B is
playing at an absolute rate of 3, or 3 beats per second, a tempo of 90bpm.
curve – STRING, optional
One of "step", "linear", "exponential" or "target".
Represents the type of ramp to use to transition to the new rate. Where curve
is "target" a duration is required:
duration – STRING, optional
Where curve is "target", represents the target duration of the target curve.
Where there is no "rate" event at beat 0, consumers should assume a playback
rate of 2, as if there were an initial [0, "rate", 2] event in the data. A
rate of 2 is a tempo of 120bpm.
[beat, "meter", duration, division]duration – INT
The duration of a bar, in beats.
division – INT
The duration of a division, in beats.
Here are some common time signatures as meter events:
| time | event |
|---|---|
| 4/4 | [0, "meter", 4, 1] |
| 3/4 | [0, "meter", 3, 1] |
| 6/8 | [0, "meter", 3, 1.5] |
| 2/4 | [0, "meter", 2, 1] |
| 7/8 | [0, "meter", 3.5, 1.5] |
| 7/8 | [0, "meter", 3.5, 2] |
A meter event MUST occur at a beat that is a full bar from a previous meter event. The second event here is valid:
[0, "meter", 4, 1]
[4, "meter", 3, 1]Where here it is invalid:
[0, "meter", 4, 1]
[2, "meter", 3, 1]Consumers may choose to recover from invalid "meter" events by pushing them to
the start of the following bar, or choose to throw an error.
Meter events have no effect on the rate of the beat clock (although they may
have an effect on a metronome or rhythm generator). Where no "meter" event is
defined at beat 0 consumers should assume a default meter of 4/4 - ie,
[0, "meter", 4, 1].
[beat, "chord", root, id, duration]root – INT [0-11] | STRING ["A♭"-"G♯"], represents the root of a chord.
Where root is a number it represents root note as a MIDI number 0-11.
Where root is a string it must be a root note name, ie. C, C♯, D ...
A, B♭, B.
hsid – INT, represents a harmonic structure.
A Harmonic Structure ID (HSID) is an integer that identifies, can be encoded
from, and can be decoded to, an array of ascending note numbers. All chords,
modes and scales, and a vast number of larger harmonic structures, have an HSID.
A single note always has an HSID of 0 and simple intervals map so that a
semitone [0, 1] has HSID 1, a second [0, 2] has HSID 2 and so on.
HSIDs encode intervals between notes using base 36 maths. In JavaScript, 64-bit
numbers safely carry integers up to Number.MAX_SAFE_INTEGER. This imposes 2
constraints:
- Consecutive note numbers can not have an interval any greater 35
- Harmonic structures are limited to 11 note numbers (10 intervals)
Tip
Using BigInt it is possible to identify any arbitrary number of notes as an
HSID. The implementations in this repository use standard JavaScript numbers.
Several HSIDs are associated with named chord symbols. When events are stringified to JSON their HSIDs are replaced with these names.
| Symbol | HSID | Meaning |
|---|---|---|
"∆♯11" |
187996 | 4th mode of the major scale (lydian) |
"∆" |
5296 | 1st mode of the major scale (ionian) |
"7" |
4000 | 5th mode of the major scale (myxolydian) |
"-7" |
4035 | 2nd mode of the major scale (dorian) |
"-♭6" |
94755 | 6th mode of the major scale (aoelian) |
"7sus♭9" |
142705 | 3rd mode of the major scale (phrygian) |
"ø" |
5295 | 7th mode of the major scale (locrian) |
"7♯11" |
63874730 | 4th mode of melodic minor |
"-∆" |
124387526 | 1st mode of melodic minor |
"7♭13" |
122706650 | 5th mode of melodic minor |
"13sus♭9" |
63921385 | 2nd mode of melodic minor |
"ø9" |
124340870 | 6th mode of melodic minor |
"∆♯4♯5" |
122707946 | 3rd mode of melodic minor |
"7alt" |
124386265 | 7th mode of melodic minor |
"-∆♭6" |
183174086 | 1st mode of harmonic minor |
"7♭9♭13" |
122706685 | 5th mode of harmonic minor |
"∆♭6" |
183172826 | 1st mode of harmonic major |
"°" |
4417439366 | Diminished whole tone / half tone |
"7♭9" |
2299488985 | Diminished half tone / whole tone |
"+7" |
3455210 | Whole tone |
duration – FLOAT, the duration of the chord in beats.
[beat, "key", name]name – STRING
The name of a major key, a capital letter followed optionally by an accidental,
as in "A♭", "A", "A♯", "B♭", "B", "C", and so on up to "G♯".
Represents a visual key change in written notation only. Does not affect how a performance sounds.
Note
Harmonic generators should read "chord" events to generate sound based on
modes, scales and chords.
[beat, "sequence", sequenceId, targetId, duration]sequenceId – STRING
The id of a sequence found in the sequences array
targetId – STRING
The id of an instrument to play the sequence through.
duration – FLOAT
The duration in beats to play the sequence.
Renders a sequence from the sequences array. For example, this event plays the
sequence "my-sequence" at beat 0.5 for 3 beats:
[0.5, "sequence", "my-sequence", 3]Caution
TBD. It is not clear exactly how to spec targetId to select a target instrument
in an interoperable manner. In Soundstage, it refers to the id of a node in the
nodes array, where nodes are WebAudio nodes in the Soundstage graph.
[beat, "text", string, duration]string – STRING
A string of text.
duration – FLOAT
The duration in beats that the text spans.
[beat, "start", identifier, value]Reserved event name. Basically, both "note" and "sequence" events, which
have duration, may be decomposed into matching "start" and "stop" events
without duration in internal implementations. Neither should appear in exported
SequenceJSON.
[beat, "stop", identifier, value]Reserved event name. See "start".
- Soundstage is a WebAudio wrapper and playback sequencer that consumes and outputs Sequence JSON.
- Scribe is a music notation interpreter and HTML renderer that consumes and outputs Sequence JSON. It also parses ABC notation to Sequence JSON, as well as a sequence text format that is basically Sequence JSON without any of the JSON syntax or quote marks, just spaces between values.
- OSC spec: http://opensseqoundcontrol.org/spec-1_0
- OSC example messages: http://opensoundcontrol.org/files/OSC-Demo.pdf
- Music XML: http://www.musicxml.com/for-developers/
- VexFlow: http://www.vexflow.com/