swaralipi-js

Spec reference

Version 0.9.0. Validate with parseSwaralipi(json) (throws) or safeParseSwaralipi(json).

Document shape

{
  "version": "0.1.0",
  "meta": { "title": "…", "taal": { "id": "dadra", "numBeats": 6 }, "tonic": "C" },
  "parts": [
    { "name": "asthayi", "rows": [
      { "notes": [ /* one object per cell, left to right */ ] }
    ] }
  ]
}

Document → parts[] → rows[] → notes[]. meta.title is required; name/label/taal/tonic are optional.

Note kinds

Each note carries exactly one of these, plus optional flags:

FieldMeaning
svara: [octave, letter]a pitch — letter ∈ s r g m p d n, octave ∈ ati-mandra mandra madhyam taar ati-taar
sustain: trueআ-কার vowel hold (with svara = melisma)
rest: trueবিরাম (silence)
bar: "dari"barline — dari (।) / single (I) / double (II) / quad (end)
raw: "…"verbatim source passthrough (lossless fallback)

Akarmatrik extensions (flags)

FlagMeaning
komal / tivraflat / sharp
microtone: "alpakomal" | "atikomal"below komal
durationMatra: 0.5fractional beat (½, ¼ …)
lyric: "অ"per-syllable lyric (column-aligned)
kan / reshgrace before / after — one [octave, letter], or a list of notes for a multi-swar grace
meendglide / slur
brackets repeat / () skip / [] alt-on-repeat
above / belowrecursive annotation notes

লয় — tempo tiers

A row may carry lay: "drut" | "madhya" | "vilambit", which holds until another row changes it. meta.bpm is the দ্রুত (fast) tempo; the other two play at a fraction of it — 0.75 and 0.5 by default. Override per document with meta.laySpeeds, or per call with the player's / exporter's laySpeeds option. A document with no lay anywhere plays exactly as it did before the field existed.

{ "meta": { "bpm": 120, "laySpeeds": { "vilambit": 0.4 } },
  "parts": [ { "rows": [
    { "lay": "vilambit", "notes": [ … ] },   // this row on, at 0.4 × 120
    { "notes": [ … ] },                      // still বিলম্বিত
    { "lay": "drut", "notes": [ … ] }        // back to 120
  ] } ] }

The player changes the tabla with it: each stretch gets the recorded loop at its own tempo, or the nearest one time-stretched (pitch unchanged), so the drum never drifts against the melody.

তালফেরতা — changing taal

A row may also carry taal (same shape as meta.taal) and an optional printed taalName. It holds until another row changes it; meta.taal is the opening taal. taal: null switches to মুক্তছন্দ (the accompaniment rests). It is independent of lay: a row may change either, both or neither.

{ "meta": { "taal": { "id": "dadra", "numBeats": 6, "bhaags": [3, 3] } },
  "parts": [ { "rows": [
    { "notes": [ … ] },                                              // দাদরা
    { "taal": { "id": "shashthi", "numBeats": 6, "bhaags": [2, 4] },
      "taalName": "ষষ্ঠী", "lay": "drut", "notes": [ … ] },         // ষষ্ঠী, দ্রুত
    { "taal": { "id": "kehrwa", "numBeats": 8, "bhaags": [4, 4] },
      "notes": [ … ] }                                               // কাহারবা, still দ্রুত
  ] } ] }

The viewer prints the change as a centred line between systems, as স্বরবিতান does; the player swaps the tabla loop (or click, drum pattern) on that row, and the staff view changes its time signature there.

Example

{ "svara": ["madhyam", "m"], "lyric": "অ" }      // pitch + lyric
{ "svara": ["madhyam", "p"], "komal": true }     // flat
{ "sustain": true, "lyric": "৹" }                // আ-কার hold
{ "bar": "single" }                              // দাঁড়ি

Worked examples: akarone, octaves, microtones, matra, brackets. Full schema: src/spec/schema.ts.