Sprites Sequencer Media Storage

A sequencer item stores a data object beside the shared metadata in the record. Its media type is sequencer: a tune assembled from reusable blocks, each block a cell volume of the platform's channels by beats-per-bar by bars, each cell an optional note with any effects the channel allows. Sampled audio is a separate waveform media type.

Sequencer Storage

Data

The data object holds the whole tune. The channels are not stored in the item; they come from the platform's Sprites.Platform.<name>.Sequencer descriptor, so a stored tune stays small and portable and the editor reads the channel layout from the platform.

FieldTypeDescription
formatStringThe media type, "sequencer".
platformStringThe platform id, such as "c64", whose channel layout and capabilities the tune targets.
tempoObjectThe timing and block size. See Tempo.
blocksArrayThe block definitions, each a cell volume of channels by beats-per-bar by bars. See Blocks.
tuneArrayThe arrangement: which block plays in each slot. See Tune.

Tempo

One tempo applies to the whole tune, and it fixes the block size: every block is beatsPerBar × barsPerBlock beats, so all blocks share one shape.

FieldTypeDescription
bpmNumberBeats per minute.
beatsPerBarNumberBeats in a bar.
barsPerBlockNumberBars in a block. A block holds beatsPerBar × barsPerBlock beats in all; the beats per bar size each block's beat dimension and the bars per block its bar dimension.

Blocks

A block is a pattern: a three dimensional cell volume of channels across, beats within a bar down, and bars deep, the Sprites.Grid.Three shape. Keeping the beats and the bars on their own axes means extending the beats per bar adds a beat to every bar and extending the bars per block adds a bar, each landing in its own dimension. Blocks are defined once and reused; many tune slots can point at the same block, and editing it changes every slot that uses it. Each block has a stable id so the tune can reference it even as blocks are added or removed.

FieldTypeDescription
idNumberA stable identifier, referenced from the tune.
gridObjectThe cell volume, a { w, h, d, cells } object: w is the channel count, h the beats per bar, d the bars per block, and cells a flat array of length w × h × d packed x (channel), then y (beat in bar), then z (bar).

The cell at a channel, a beat within its bar, and a bar sits at cells[channel + beatInBar × w + bar × w × h]. A cell that is undefined means nothing plays there, so each entry is a Cell or undefined.

Tune

The tune is the arrangement, an ordered list of slots. Each slot holds the array index of the block that plays there, or undefined for an empty slot. The same block index may appear in many slots.

ElementTypeDescription
slotNumber or undefinedThe index into blocks that plays in this slot, or undefined for an empty slot.

The last slot is always undefined, an empty slot at the end so the tune can always be extended. Editing an empty slot creates a new block, points the slot at it, and appends a fresh empty slot beyond.

Cell

A cell is what one channel does on one beat. The note is optional and universal; the other fields appear only where the channel's capabilities allow them, so a cell never carries data a channel cannot use.

FieldTypeDescription
optionalNoteNumberThe note as a semitone (middle C is 60, as in MIDI). Absent when the cell has no note.
optionalFinetuneNumberA microtuning offset, only on channels whose pitch capability has a finetune range.
optionalInstrumentNumberThe chosen instrument index, only on channels that select an instrument (a MIDI program, or later a waveform).
effectsArrayThe effects applied on this cell, none to the channel's allowed maximum. See Effect.

Effect

An effect is one capability applied on a cell. Its type is a capability id from the platform's channel descriptor, and its params hold that capability's parameters, each within the range the platform declares. Only capabilities the channel supports may appear, and no more than the channel's effect limit.

FieldTypeDescription
typeStringThe capability id, such as "vibrato", "arpeggio", "duty" or "filter".
paramsObjectThe parameters for that capability, keyed by parameter name, each value within the platform's declared range.

For now effects are treated as independent. How effects that interact, or that the hardware merges, are combined is left to a later revision.

Example

A small C64 tune: one block of four beats over three voices, played in the first slot, with the always-present empty slot at the end. Voice 1 holds a two-note phrase, one note carrying a vibrato effect.

{
  "format": "sequencer",
  "platform": "c64",
  "tempo": { "bpm": 125, "beatsPerBar": 4, "barsPerBlock": 1 },
  "blocks": [
    {
      "id": 1,
      "grid": {
        "w": 3, "h": 4, "d": 1,
        "cells": [
          { "optionalNote": 60, "effects": [] }, null, null,
          null, null, null,
          { "optionalNote": 67, "effects": [ { "type": "vibrato", "params": { "speed": 6, "depth": 2 } } ] }, null, null,
          null, null, null
        ]
      }
    }
  ],
  "tune": [ 0, null ]
}
The block grid is a { w, h, d, cells } volume: 3 channels wide, 4 beats per bar, 1 bar. cells is flat, packed channel then beat then bar, so channel 0 beat 0 is cells[0] and channel 0 beat 2 is cells[6]. An empty cell or slot is undefined; shown as null here because JSON has no undefined. The trailing empty tune slot keeps the tune extendable.