@sudobility/music_types 0.11.16 → 0.11.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,49 +1,68 @@
1
1
  /**
2
- * A neutral model of an Amiga tracker module, shaped by exactly what the
3
- * `.MOD` importer in music_lib reads — so that music_lib carries no byte
4
- * handling of its own, the same split `MidiFile` uses.
2
+ * A format-neutral model of a tracker module.
5
3
  *
6
- * Decoding stops at this shape deliberately. Turning periods into pitches and
7
- * speed/tempo into a `TempoMap` is musical work, so it lives in music_lib;
8
- * only the byte reading is platform-shaped, and even that is shared by all
9
- * three `MusicIo` implementations rather than reimplemented per platform.
4
+ * Was `ModFile`, shaped by exactly what ProTracker stores. That shape does not
5
+ * survive contact with the rest of the family: only MOD uses Amiga periods,
6
+ * only MOD has fixed 64-row patterns, and only MOD lets a sample stand in for
7
+ * an instrument. So the model states what every format agrees on and each
8
+ * decoder normalises its own quirks behind it — which is what keeps
9
+ * `trackerToScore` free of format branches.
10
+ *
11
+ * Decoding stops here deliberately. Turning this into a score is musical work
12
+ * and lives in music_lib; only the byte reading is platform-shaped, and even
13
+ * that is shared by all three `MusicIo` implementations rather than
14
+ * reimplemented per platform.
10
15
  */
11
- /** A sampled instrument slot. Names are free text and often decorative or empty. */
12
- export type ModSample = {
16
+ export type TrackerFormat = 'mod' | 's3m' | 'xm' | 'it' | 'dsm' | 'mptm';
17
+ /** One instrument slot. In MOD/S3M/DSM a sample *is* the instrument; XM, IT and MPTM put a layer above. */
18
+ export type TrackerInstrument = {
13
19
  index: number;
14
20
  name: string;
15
21
  };
16
22
  /**
17
23
  * One channel's cell in one row.
18
24
  *
19
- * `period` is the Amiga period value, not a pitch: 0 means "no note here",
20
- * which is why this is not an optional field. `sample` is 0 for "keep
21
- * whatever this channel was already playing".
25
+ * `note` is a MIDI note number rather than a period: MOD is the only format
26
+ * that stores periods, so converting in its decoder keeps the approximation
27
+ * that conversion involves in one place instead of leaking into shared code.
28
+ *
29
+ * `effect`/`param` are deliberately absent. Notation import reads exactly one
30
+ * thing from the effect column — speed and tempo — and *which* effect carries
31
+ * it is format knowledge (XM splits `F` at 0x20; S3M and IT use `A` and `T`).
32
+ * Each decoder normalises to `speed`/`bpm`, so nothing downstream branches on
33
+ * format.
22
34
  */
23
- export type ModCell = {
24
- sample: number;
25
- period: number;
26
- effect: number;
27
- param: number;
35
+ export type TrackerCell = {
36
+ /** 0 means "keep whatever this channel was already playing". */
37
+ instrument: number;
38
+ /** MIDI note number, `'off'` for an explicit release or cut, `null` for an empty cell. */
39
+ note: number | 'off' | null;
40
+ /** Ticks per row, where this cell changes it. */
41
+ speed?: number;
42
+ /** Beats per minute, where this cell changes it. */
43
+ bpm?: number;
44
+ /** `Dxx` — this row ends the pattern early. */
45
+ patternBreak?: boolean;
28
46
  };
29
- export type ModFile = {
47
+ export type TrackerModule = {
48
+ format: TrackerFormat;
30
49
  title: string;
31
50
  channels: number;
32
- samples: ModSample[];
51
+ instruments: TrackerInstrument[];
33
52
  /** Pattern indices in playback order; a pattern played three times appears three times. */
34
53
  order: number[];
35
- /** `patterns[pattern][row][channel]`. */
36
- patterns: ModCell[][][];
54
+ /** `patterns[p][row][channel]`. Row count varies per pattern — MOD is always 64, IT allows 200. */
55
+ patterns: TrackerCell[][][];
37
56
  };
38
57
  /**
39
- * Reading a `.MOD` file.
58
+ * Reading a tracker module.
40
59
  *
41
60
  * A capability for surface consistency — the app reaches every file format
42
61
  * through `getAppServices().io` — even though nothing about parsing is
43
62
  * platform-bound. All three implementations delegate to one shared module.
44
63
  */
45
- export interface ModCodec {
46
- /** Decode a ProTracker module. Throws on anything that is not one, rather than returning a garbage file that looks imported. */
47
- decode(bytes: ArrayBuffer): ModFile;
64
+ export interface TrackerCodec {
65
+ /** Sniffs the format from the bytes and decodes it. Throws on anything that is not one, rather than returning a garbage module that looks imported. */
66
+ decode(bytes: ArrayBuffer): TrackerModule;
48
67
  }
49
68
  //# sourceMappingURL=mod.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/platform/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,oFAAoF;AACpF,MAAM,MAAM,SAAS,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD;;;;;;GAMG;AACH,MAAM,MAAM,OAAO,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAExF,MAAM,MAAM,OAAO,GAAG;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,2FAA2F;IAC3F,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yCAAyC;IACzC,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;CACzB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,gIAAgI;IAChI,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC;CACrC"}
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/platform/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,MAAM,CAAC;AAEzE,2GAA2G;AAC3G,MAAM,MAAM,iBAAiB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhE;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAC;IACnB,0FAA0F;IAC1F,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAAC;IAC5B,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,aAAa,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,iBAAiB,EAAE,CAAC;IACjC,2FAA2F;IAC3F,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,mGAAmG;IACnG,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;CAC7B,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,uJAAuJ;IACvJ,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,aAAa,CAAC;CAC3C"}
@@ -1,12 +1,17 @@
1
1
  /**
2
- * A neutral model of an Amiga tracker module, shaped by exactly what the
3
- * `.MOD` importer in music_lib reads — so that music_lib carries no byte
4
- * handling of its own, the same split `MidiFile` uses.
2
+ * A format-neutral model of a tracker module.
5
3
  *
6
- * Decoding stops at this shape deliberately. Turning periods into pitches and
7
- * speed/tempo into a `TempoMap` is musical work, so it lives in music_lib;
8
- * only the byte reading is platform-shaped, and even that is shared by all
9
- * three `MusicIo` implementations rather than reimplemented per platform.
4
+ * Was `ModFile`, shaped by exactly what ProTracker stores. That shape does not
5
+ * survive contact with the rest of the family: only MOD uses Amiga periods,
6
+ * only MOD has fixed 64-row patterns, and only MOD lets a sample stand in for
7
+ * an instrument. So the model states what every format agrees on and each
8
+ * decoder normalises its own quirks behind it — which is what keeps
9
+ * `trackerToScore` free of format branches.
10
+ *
11
+ * Decoding stops here deliberately. Turning this into a score is musical work
12
+ * and lives in music_lib; only the byte reading is platform-shaped, and even
13
+ * that is shared by all three `MusicIo` implementations rather than
14
+ * reimplemented per platform.
10
15
  */
11
16
  export {};
12
17
  //# sourceMappingURL=mod.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mod.js","sourceRoot":"","sources":["../../src/platform/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
1
+ {"version":3,"file":"mod.js","sourceRoot":"","sources":["../../src/platform/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
@@ -15,9 +15,25 @@ export type TransportPlaybackState = 'stopped' | 'playing' | 'paused';
15
15
  * currently-sounding note ids changes; `onStateChange` fires on every
16
16
  * play/pause/stop transition, including ones the engine itself initiates.
17
17
  */
18
+ export type SoundingNote = {
19
+ /** The `NoteEvent.id` this voice came from, for notation highlighting. */
20
+ noteId: string;
21
+ /** Which track it is on, so a consumer can filter without searching the score. */
22
+ trackId: string;
23
+ /** Its sounding MIDI pitch, so a keyboard can light a key without resolving the event. */
24
+ midi: number;
25
+ };
18
26
  export type PlaybackObserver = {
19
27
  onPositionTick(tick: number): void;
20
- onActiveNotes(noteIds: string[]): void;
28
+ /**
29
+ * The notes currently sounding, whenever that set changes.
30
+ *
31
+ * Resolved rather than bare ids. The scheduler already knows each note's
32
+ * track and pitch — it scheduled them — and emitting only the id forced every
33
+ * consumer to search the whole score to get it back: `playingPitchesForTrack`
34
+ * was an O(score) scan per sounding note, twenty times a second.
35
+ */
36
+ onActiveNotes(notes: SoundingNote[]): void;
21
37
  onStateChange(state: TransportPlaybackState): void;
22
38
  /**
23
39
  * How far along the engine is in becoming able to make a sound.
@@ -1 +1 @@
1
- {"version":3,"file":"playback.d.ts","sourceRoot":"","sources":["../../src/platform/playback.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEtE;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACvC,aAAa,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACnD;;;;;;;;OAQG;IACH,iBAAiB,CAAC,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;CACpD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAClB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC9C;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GACnB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C,MAAM,WAAW,cAAc;IAC7B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,KAAK,IAAI,IAAI,CAAC;IACd,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAAC;IACxC,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACpD,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IACnD;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,mCAAmC;IACnC,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACrC,kDAAkD;IAClD,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACpE,gFAAgF;IAChF,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,4GAA4G;IAC5G,WAAW,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,GAAG,IAAI,CAAC;IACrD,OAAO,IAAI,IAAI,CAAC;CACjB"}
1
+ {"version":3,"file":"playback.d.ts","sourceRoot":"","sources":["../../src/platform/playback.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEtE;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC;IACf,kFAAkF;IAClF,OAAO,EAAE,MAAM,CAAC;IAChB,0FAA0F;IAC1F,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC;;;;;;;OAOG;IACH,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAC3C,aAAa,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACnD;;;;;;;;OAQG;IACH,iBAAiB,CAAC,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;CACpD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAClB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC9C;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GACnB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C,MAAM,WAAW,cAAc;IAC7B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,KAAK,IAAI,IAAI,CAAC;IACd,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAAC;IACxC,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACpD,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IACnD;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,mCAAmC;IACnC,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACrC,kDAAkD;IAClD,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACpE,gFAAgF;IAChF,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,4GAA4G;IAC5G,WAAW,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,GAAG,IAAI,CAAC;IACrD,OAAO,IAAI,IAAI,CAAC;CACjB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sudobility/music_types",
3
- "version": "0.11.16",
3
+ "version": "0.11.18",
4
4
  "description": "TypeScript types and Zod schemas for the ScoreSmith music API - scores, generation contracts, project payloads",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",