PageSourceSearch

https://slowdownpractice.com/assets/notation/json_codec-1d560403.js

js slowdownpractice.com collected 2026-10-02 00:57:51 UTC 9,519 bytes, 271 lines download raw bytes

1import { Pitch } from "notation/pitch";
2import { Duration } from "notation/duration";
3import {
4  Note,
5  Rest,
6  Tuplet,
7  Chord,
8  GraceNote,
9  Measure,
10  Score,
11} from "notation/score";
12
13// ── Score → JSON ─────────────────────────────────────────────────────
14
15export function scoreToJson(score) {
16  const json = {
17    version: 2,
18    clef: score.clef,
19    key: score.key,
20    time: [...score.timeSignature],
21    tempo: score.tempo,
22    measures: score.measures.map((m) => measureToJson(m, score.timeSignature)),
23  };
24  if (score.title != null) json.title = score.title;
25  if (score.subtitle != null) json.subtitle = score.subtitle;
26  if (score.composer != null) json.composer = score.composer;
27  if (score.parts) json.parts = score.parts;
28  if (score.staves) json.staves = score.staves.map((s) => ({ ...s }));
29  if (score.pickupBeats != null) json.pickup_beats = score.pickupBeats;
30  return json;
31}
32
33function measureToJson(measure, scoreTimeSig) {
34  const json = {
35    elements: measure.elements.map(elementToJson),
36  };
37  // Per-measure key signature (null = inherit)
38  if (measure.keySignature != null) {
39    json.key_signature = measure.keySignature;
40  }
41  // Per-measure time signature (only when differs from score default)
42  const [sNum, sDen] = scoreTimeSig;
43  const [mNum, mDen] = measure.timeSignature;
44  if (mNum !== sNum || mDen !== sDen) {
45    json.time_signature = [mNum, mDen];
46  }
47  if (measure.barlineType && measure.barlineType !== "normal") {
48    json.barline_type = measure.barlineType;
49  }
50  if (measure.volta) json.volta = measure.volta;
51  if (measure.navigationMark) json.navigation_mark = measure.navigationMark;
52  if (measure.rehearsalMark) json.rehearsal_mark = measure.rehearsalMark;
53  if (measure.systemBreak) json.system_break = true;
54  if (measure.isPickup) json.is_pickup = true;
55  if (measure.tempoChange) {
56    json.tempo_change = { ...measure.tempoChange };
57  }
58  if (measure.clef) json.clef = measure.clef;
59  if (measure.section) json.section = measure.section;
60  return json;
61}
62
63function elementToJson(el) {
64  if (el instanceof GraceNote) return graceNoteToJson(el);
65  if (el instanceof Chord) return chordToJson(el);
66  if (el instanceof Note) return noteToJson(el);
67  if (el instanceof Rest) return restToJson(el);
68  if (el instanceof Tuplet) return tupletToJson(el);
69  throw new Error(`Unknown element type: ${el.constructor.name}`);
70}
71
72function noteToJson(note) {
73  const h = {
74    type: "note",
75    pitch: note.pitch.toString(),
76    dur: note.duration.toShorthand(),
77  };
78  if (note.accidental) h.acc = note.accidental;
79  if (note.tie) h.tie = note.tie;
80  if (note.slurs?.length) h.slurs = note.slurs.map((s) => ({ ...s }));
81  if (note.articulations.length) h.articulations = [...note.articulations];
82  if (note.beamGroup != null) h.beam_group = note.beamGroup;
83  if (note.textAbove) h.text_above = note.textAbove;
84  if (note.textBelow) h.text_below = note.textBelow;
85  if (note.chordSymbol) h.chord_symbol = note.chordSymbol;
86  if (note.slash) h.slash = true;
87  if (note.hairpin) h.hairpin = note.hairpin;
88  if (note.ottava) h.ottava = note.ottava;
89  if (note.fingering != null) h.fingering = note.fingering;
90  if (note.lyric) h.lyric = note.lyric;
91  if (note.pedal) h.pedal = note.pedal;
92  if (note.dynamic) h.dynamic = note.dynamic;
93  if (note.voice != null) h.voice = note.voice;
94  if (note.staff != null) h.staff = note.staff;
95  if (note.part != null) h.part = note.part;
96  return h;
97}
98
99function chordToJson(chord) {
100  const h = {
101    type: "chord",
102    pitches: chord.pitches.map((p) => p.toString()),
103    dur: chord.duration.toShorthand(),
104  };
105  if (chord.accidentals.length) h.accidentals = [...chord.accidentals];
106  if (chord.tie) h.tie = chord.tie;
107  if (chord.slurs?.length) h.slurs = chord.slurs.map((s) => ({ ...s }));
108  if (chord.articulations.length) h.articulations = [...chord.articulations];
109  if (chord.beamGroup != null) h.beam_group = chord.beamGroup;
110  if (chord.textAbove) h.text_above = chord.textAbove;
111  if (chord.textBelow) h.text_below = chord.textBelow;
112  if (chord.chordSymbol) h.chord_symbol = chord.chordSymbol;
113  if (chord.slash) h.slash = true;
114  if (chord.hairpin) h.hairpin = chord.hairpin;
115  if (chord.ottava) h.ottava = chord.ottava;
116  if (chord.fingering != null) h.fingering = chord.fingering;
117  if (chord.lyric) h.lyric = chord.lyric;
118  if (chord.pedal) h.pedal = chord.pedal;
119  if (chord.dynamic) h.dynamic = chord.dynamic;
120  if (chord.voice != null) h.voice = chord.voice;
121  if (chord.staff != null) h.staff = chord.staff;
122  if (chord.part != null) h.part = chord.part;
123  return h;
124}
125
126function restToJson(rest) {
127  const h = { type: "rest", dur: rest.duration.toShorthand() };
128  if (rest.chordSymbol) h.chord_symbol = rest.chordSymbol;
129  if (rest.dynamic) h.dynamic = rest.dynamic;
130  if (rest.voice != null) h.voice = rest.voice;
131  if (rest.staff != null) h.staff = rest.staff;
132  if (rest.part != null) h.part = rest.part;
133  return h;
134}
135
136function graceNoteToJson(grace) {
137  const h = {
138    type: "grace_note",
139    pitch: grace.pitch.toString(),
140    dur: grace.duration.toShorthand(),
141    grace_type: grace.graceType,
142  };
143  if (grace.accidental) h.acc = grace.accidental;
144  if (grace.staff != null) h.staff = grace.staff;
145  if (grace.part != null) h.part = grace.part;
146  return h;
147}
148
149function tupletToJson(tuplet) {
150  return {
151    type: "tuplet",
152    ratio: [...tuplet.ratio],
153    notes: tuplet.notes.map(elementToJson),
154  };
155}
156
157// ── JSON → Score ─────────────────────────────────────────────────────
158
159export function jsonToScore(json) {
160  const time = json.time || [4, 4];
161  const measures = (json.measures || []).map((m) => parseMeasure(m, time));
162
163  return new Score({
164    measures,
165    key: json.key || "C",
166    clef: json.clef || "treble",
167    tempo: json.tempo ?? 120,
168    timeSignature: time,
169    title: json.title ?? null,
170    subtitle: json.subtitle ?? null,
171    composer: json.composer ?? null,
172    parts: json.parts || null,
173    staves: json.staves || null,
174    pickupBeats: json.pickup_beats ?? null,
175  });
176}
177
178function parseMeasure(json, scoreTimeSig) {
179  const elements = (json.elements || []).map(parseElement);
180  // Per-measure time signature: use explicit override, else inherit score default
181  const timeSignature = json.time_signature || scoreTimeSig;
182  return new Measure({
183    elements,
184    timeSignature,
185    keySignature: json.key_signature ?? null,
186    barlineType: json.barline_type || "normal",
187    volta: json.volta ?? null,
188    navigationMark: json.navigation_mark ?? null,
189    rehearsalMark: json.rehearsal_mark ?? null,
190    systemBreak: json.system_break || false,
191    isPickup: json.is_pickup || false,
192    tempoChange: json.tempo_change ?? null,
193    clef: json.clef ?? null,
194    section: json.section ?? null,
195  });
196}
197
198function parseElement(json) {
199  switch (json.type) {
200    case "note":
201      return new Note({
202        pitch: json.pitch,
203        duration: Duration.fromShorthand(json.dur),
204        accidental: json.acc || null,
205        tie: json.tie || null,
206        slurs: json.slurs || [],
207        articulations: json.articulations || [],
208        beamGroup: json.beam_group ?? null,
209        textAbove: json.text_above || null,
210        textBelow: json.text_below || null,
211        chordSymbol: json.chord_symbol || null,
212        slash: json.slash || false,
213        hairpin: json.hairpin || null,
214        ottava: json.ottava || null,
215        fingering: json.fingering ?? null,
216        lyric: json.lyric || null,
217        pedal: json.pedal || null,
218        dynamic: json.dynamic || null,
219        voice: json.voice ?? null,
220        staff: json.staff ?? null,
221        part: json.part ?? null,
222      });
223    case "chord":
224      return new Chord({
225        pitches: json.pitches,
226        duration: Duration.fromShorthand(json.dur),
227        accidentals: json.accidentals || [],
228        tie: json.tie || null,
229        slurs: json.slurs || [],
230        articulations: json.articulations || [],
231        beamGroup: json.beam_group ?? null,
232        textAbove: json.text_above || null,
233        textBelow: json.text_below || null,
234        chordSymbol: json.chord_symbol || null,
235        slash: json.slash || false,
236        hairpin: json.hairpin || null,
237        ottava: json.ottava || null,
238        fingering: json.fingering ?? null,
239        lyric: json.lyric || null,
240        pedal: json.pedal || null,
241        dynamic: json.dynamic || null,
242        voice: json.voice ?? null,
243        staff: json.staff ?? null,
244        part: json.part ?? null,
245      });
246    case "rest":
247      return new Rest({
248        duration: Duration.fromShorthand(json.dur),
249        chordSymbol: json.chord_symbol || null,
250        dynamic: json.dynamic || null,
251        voice: json.voice ?? null,
252        staff: json.staff ?? null,
253        part: json.part ?? null,
254      });
255    case "grace_note":
256      return new GraceNote({
257        pitch: json.pitch,
258        duration: json.dur ? Duration.fromShorthand(json.dur) : "eighth",
259        accidental: json.acc || null,
260        graceType: json.grace_type || "acciaccatura",
261        staff: json.staff ?? null,
262        part: json.part ?? null,
263      });
264    case "tuplet": {
265      const notes = (json.notes || []).map(parseElement);
266      return new Tuplet({ ratio: json.ratio, notes });
267    }
268    default:
269      throw new Error(`Unknown element type: ${json.type}`);
270  }
271}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.