@jeffy-g/live-midi-types 0.10.1 → 0.11.0

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.
package/README.md CHANGED
@@ -1,164 +1,266 @@
1
- # **@jeffy-g/live-midi-types** — TypeScript type definitions for Ableton Live MIDI data projects.
1
+ # @jeffy-g/live-midi-types
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@jeffy-g/live-midi-types.svg)](https://www.npmjs.com/package/@jeffy-g/live-midi-types)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- Common TypeScript type definitions for working with Ableton Live MIDI data.
6
+ Shared TypeScript types and small runtime helpers for Ableton Live MIDI clip data, project summaries, and Standard MIDI Files.
7
7
 
8
- > ## Description
8
+ ## Scope
9
9
 
10
- This package provides a centralized collection of TypeScript type definitions for working with data extracted from Ableton Live Set (`.als`) files.
10
+ The package provides three related contracts:
11
11
 
12
- It is designed to ensure type safety and data consistency across projects that handle Ableton Live's MIDI data, such as the `live-midi-export` tool.
12
+ - beat-based MIDI events and clip data extracted from Ableton Live Sets;
13
+ - application-facing clip, track, and project summaries;
14
+ - numeric MIDI 1.0 SMF event types for parsers and writers.
13
15
 
14
- By providing a single source of truth for data structures, this library simplifies development and reduces errors when passing MIDI and project data between different modules.
16
+ The Ableton data shapes were reverse engineered from observed Live 11 and Live 12 `.als` documents. Ableton does not publish an official `.als` specification, so consumers should expect the model to grow as more real projects are inspected.
15
17
 
16
- > ## Type Origin and Gaps
17
-
18
- These definitions were **reverse engineered** from Ableton Live 11 `.als` files.
19
- Ableton publishes no official specification, so some fields may be missing or misinterpreted.
20
- If you encounter inaccuracies, please open an issue or pull request.
21
-
22
- > ## Directory Structure
23
-
24
- ```
25
- src/
26
- ├─ midi-event.ts # basic note, control change, and tempo events
27
- ├─ midi-clip.ts # builds on midi-event to describe clips
28
- ├─ project.ts # aggregates clips into a project
29
- ├─ ableton-colors.ts # color utilities
30
- └─ index.ts # public exports
31
- ```
32
-
33
- Dependencies flow upward: `midi-event` → `midi-clip` → `project`, while `ableton-colors` stands alone.
34
-
35
- > ## Installation
36
-
37
- You can install the package using npm or yarn:
18
+ ## Installation
38
19
 
39
20
  ```sh
40
21
  npm install @jeffy-g/live-midi-types
41
22
  ```
42
23
 
43
- or
24
+ ## Entry points
44
25
 
45
- ```sh
46
- yarn add @jeffy-g/live-midi-types
47
- ```
26
+ | Entry point | Contents |
27
+ |---|---|
28
+ | `@jeffy-g/live-midi-types` | Ableton MIDI events, clip data, project summaries, color helpers, and runtime utilities |
29
+ | `@jeffy-g/live-midi-types/midi10-smf-types` | MIDI 1.0 SMF header, event, file, and writer option types |
30
+ | `@jeffy-g/live-midi-types/midi10-smf-io` | MIDI 1.0 SMF parser, writer, and VLQ size helper |
31
+ | `@jeffy-g/live-midi-types/ESMFEventType` | Runtime numeric SMF event type constants |
48
32
 
49
- > ## Usage
33
+ ## Ableton MIDI clip data
50
34
 
51
- Import the types you need directly into your TypeScript files.
35
+ `TMidiClipData` stores beat-based source data. MIDI CC events are grouped by controller in `ccMap`; `knownCCEvents` determines which controller buckets are present and their traversal order.
52
36
 
53
37
  ```ts
54
- import type { TMidiClipData, NoteEvent, ControlChangeEvent, TempoEvent } from "@jeffy-g/live-midi-types";
55
-
56
- /** @type {NoteEvent} */
57
- const note = {
58
- time: 0.0,
59
- duration: 1.0,
38
+ import {
39
+ flattenCCEventMap,
40
+ type ControlChangeEvent,
41
+ type NoteEvent,
42
+ type TMidiClipData,
43
+ } from "@jeffy-g/live-midi-types";
44
+
45
+ const note: NoteEvent = {
46
+ time: 0,
47
+ duration: 1,
60
48
  pitch: 60,
61
- velocity: 100
49
+ velocity: 100,
62
50
  };
63
51
 
64
- /** @type {ControlChangeEvent} */
65
- const cc = {
52
+ const sustain: ControlChangeEvent = {
66
53
  time: 0.5,
67
54
  controller: 64,
68
55
  value: 127,
69
- source: "single"
70
- };
71
-
72
- /** @type {TempoEvent} */
73
- const tempo = {
74
- time: 0.0,
75
- bpm: 120
56
+ source: "linear",
76
57
  };
77
58
 
78
- /** @type {TMidiClipData} */
79
- const clip = {
80
- clipStartInBeats: 0,
81
- clipLength: 16,
59
+ const clip: TMidiClipData = {
60
+ clipStartInBeats: 8,
61
+ clipLength: 4,
82
62
  adjustTimeOftempee: 0,
83
- knownCCEvents: [64, 1],
63
+ knownCCEvents: [64],
84
64
  notes: [note],
85
- cc: [cc]
65
+ ccMap: {
66
+ "64": [sustain],
67
+ },
68
+ pitchBends: [
69
+ { time: 1, value: -4096 },
70
+ { time: 2, value: 4096, source: "bezier" },
71
+ ],
72
+ channelPressures: [
73
+ { time: 1.5, value: 96 },
74
+ ],
86
75
  };
76
+
77
+ const controlChanges = flattenCCEventMap(
78
+ clip.ccMap,
79
+ clip.knownCCEvents,
80
+ );
87
81
  ```
88
82
 
89
- Ableton Live color palette and utility functions:
83
+ ### Event value contracts
84
+
85
+ All event `time` values are floating point quarter-note beats relative to the start of the clip.
86
+
87
+ | Type | Value contract |
88
+ |---|---|
89
+ | `NoteEvent` | `duration` and `velocity` may be fractional; `pitch` is an integer from `0` to `127` |
90
+ | `ControlChangeEvent` | `controller` is an integer from `0` to `127`; `value` may remain fractional in the `0..127` range |
91
+ | `ChannelPressureEvent` | `value` may remain fractional in the `0..127` range |
92
+ | `PitchBendEvent` | signed, possibly fractional Live value from `-8192` to `8191` |
93
+ | `TempoEvent` | floating point BPM |
94
+
95
+ `BaseEvent.source` is optional interpolation metadata. It is either `"linear"` or `"bezier"` and is normally omitted for original or discrete events.
96
+
97
+ `TEnvelopeEvent` is the shared processing shape for Control Change, Channel Pressure, and Pitch Bend envelopes. Its `controller` property is present only for Control Change. Pitch Bend and Channel Pressure remain in their dedicated arrays and do not use negative controller numbers in serialized event data.
98
+
99
+ `TMidiClipData.cc?()` is an optional compatibility helper. New code should treat `ccMap` as the stored representation and call `flattenCCEventMap()` when it needs one time-sorted CC array.
100
+
101
+ ### Clip metadata
102
+
103
+ The following optional event collections were added in version 0.10:
104
+
105
+ - `pitchBends?: PitchBendEvent[]`
106
+ - `channelPressures?: ChannelPressureEvent[]`
107
+ - `meta?: MetaTextEvent[]`
108
+
109
+ The root entry point also exports `TimeSignatureEvent` and `KeySignatureEvent` for project-level musical metadata.
110
+
111
+ ## Project summaries
112
+
113
+ The project types add application IDs and display metadata to clip data. `TTrackInfo.clips` is a map keyed by each `TClipSummary.id`.
90
114
 
91
115
  ```ts
92
- import { abletonColorPalette, getColorFromIndex } from "@jeffy-g/live-midi-types";
116
+ import type {
117
+ TMidiClipData,
118
+ TClipSummary,
119
+ TParsedAbletonLiveSet,
120
+ TTrackInfo,
121
+ } from "@jeffy-g/live-midi-types";
122
+
123
+ declare const clip: TMidiClipData;
124
+
125
+ const clipSummary: TClipSummary<TMidiClipData> = {
126
+ originId: "0",
127
+ id: "clip-6e8c",
128
+ color: "0",
129
+ disabled: false,
130
+ clipName: "Piano",
131
+ trackName: "Track 1",
132
+ annotation: "",
133
+ ...clip,
134
+ };
93
135
 
94
- const color: string = getColorFromIndex(5); // "#1aff2f"
136
+ const track: TTrackInfo<TMidiClipData> = {
137
+ originId: "12",
138
+ id: "track-91d2",
139
+ name: "Track 1",
140
+ color: "0",
141
+ annotation: "",
142
+ clips: {
143
+ [clipSummary.id]: clipSummary,
144
+ },
145
+ };
146
+
147
+ const project: TParsedAbletonLiveSet<TMidiClipData> = {
148
+ alsName: "MyProject",
149
+ ticksPerQuarter: 480,
150
+ tracks: [track],
151
+ tempoAutomation: [{ time: 0, bpm: 120 }],
152
+ };
95
153
  ```
96
154
 
97
- Project & UI types:
155
+ `color` is the Ableton palette index stored as a string. Convert it to a CSS color with `getColorFromIndex()`.
156
+
157
+ ## MIDI 1.0 SMF types
158
+
159
+ SMF types use numeric `ESMFEventType` discriminants. Meta events do not carry a separate marker property; their numeric `type` identifies them. Import the runtime constants and type declarations from their dedicated entry points.
98
160
 
99
161
  ```ts
100
- import type { TClipSummary, TTrackInfo, TParsedAbletonLiveSet } from "@jeffy-g/live-midi-types";
101
-
102
- /** @type {TClipSummary<{custom: string}>} */
103
- const clipSummary = {
104
- id: "clip-XXXX",
105
- color: "#ff94a6",
106
- disabled: false,
107
- clipName: "Piano",
108
- trackName: "Track 1",
109
- custom: "meta"
162
+ import { ESMFEventType } from "@jeffy-g/live-midi-types/ESMFEventType";
163
+ import type {
164
+ MidiData,
165
+ MidiEndOfTrackEvent,
166
+ MidiNoteOnEvent,
167
+ } from "@jeffy-g/live-midi-types/midi10-smf-types";
168
+
169
+ const noteOn: MidiNoteOnEvent = {
170
+ deltaTime: 0,
171
+ type: ESMFEventType.noteOn,
172
+ channel: 0,
173
+ noteNumber: 60,
174
+ velocity: 100,
110
175
  };
111
176
 
112
- /** @type {TTrackInfo<{custom: string}>} */
113
- const trackInfo = {
114
- name: "Track 1",
115
- color: "#ff94a6",
116
- clips: {
117
- "Piano": clipSummary
118
- }
177
+ const endOfTrack: MidiEndOfTrackEvent = {
178
+ deltaTime: 480,
179
+ type: ESMFEventType.endOfTrack,
119
180
  };
120
181
 
121
- /** @type {TParsedAbletonLiveSet<{custom: string}>} */
122
- const project = {
123
- alsName: "MyProject",
124
- ticksPerQuarter: 480,
125
- tracks: [trackInfo]
182
+ const midi: MidiData = {
183
+ header: {
184
+ format: 0,
185
+ numTracks: 1,
186
+ ticksPerBeat: 480,
187
+ },
188
+ tracks: [[noteOn, endOfTrack]],
126
189
  };
127
190
  ```
128
191
 
129
- > ## Core Type Definitions (Reference)
192
+ ### SMF parser and writer
193
+
194
+ The codec entry point parses MIDI bytes into `MidiData` and writes the same numeric event contract back to a `Uint8Array`.
195
+
196
+ ```ts
197
+ import {
198
+ parseMidi,
199
+ writeMidi,
200
+ } from "@jeffy-g/live-midi-types/midi10-smf-io";
201
+
202
+ declare const source: Uint8Array;
203
+
204
+ const parsed = parseMidi(source);
205
+ const encoded = writeMidi(parsed, {
206
+ running: true,
207
+ });
208
+ ```
209
+
210
+ `getVarIntSize()` is also exported from this entry point for code that needs to calculate the encoded byte size of an SMF variable-length quantity.
130
211
 
131
- ### MIDI Event Types
212
+ The SMF contract includes:
132
213
 
133
- - **`NoteEvent`**: `{ time: number; duration: number; pitch: number; velocity: number; }` — Represents a single MIDI note. All values are float except pitch (int).
134
- - **`ControlChangeEvent`**: `{ time: number; controller: number; value: number; source?: "curve" | "single"; }` — MIDI CC message, with optional source type.
135
- - **`TempoEvent`**: `{ time: number; bpm: number; }` — Tempo change event.
214
+ - format 0, 1, and 2 headers;
215
+ - channel voice events, including Note On/Off, CC, Program Change, Channel Aftertouch, and signed Pitch Bend;
216
+ - tempo, time signature, key signature, text, and other meta events;
217
+ - SysEx, sequencer-specific, and unknown meta events;
218
+ - running-status and velocity-zero Note On writer options.
136
219
 
137
- ### MIDI Clip Types
220
+ SMF event values are wire-boundary values. In particular, `MidiPitchBendEvent.value` remains signed from `-8192` to `8191`; a writer performs the 14-bit unsigned conversion when encoding the two data bytes.
138
221
 
139
- - **`TMidiClipData`**: Represents all essential data for a single MIDI clip.
140
- - `clipStartInBeats`: Start time in beats.
141
- - `clipLength`: Duration in beats.
142
- - `adjustTimeOftempee`: Time adjustment for tempo mapping.
143
- - `knownCCEvents`: Array of CC numbers present in the clip.
144
- - `notes`: Array of `NoteEvent`.
145
- - `cc`: Array of `ControlChangeEvent`.
222
+ ## Runtime helpers
146
223
 
147
- ### Project & UI Types
224
+ The root entry point includes a small set of runtime exports:
148
225
 
149
- - **`TClipSummary<T>`**: Generic summary type for a clip, with `id`, `color`, `clipName`, `trackName`, and custom fields.
150
- - **`TTrackInfo<T>`**: Track info type, with `name`, `color`, and a collection of `TClipSummary` objects.
151
- - **`TParsedAbletonLiveSet<T>`**: Parsed project type, with `alsName`, `ticksPerQuarter`, and array of tracks.
226
+ ```ts
227
+ import {
228
+ abletonColorPalette,
229
+ eventsIs,
230
+ flattenCCEventMap,
231
+ getColorFromIndex,
232
+ version,
233
+ } from "@jeffy-g/live-midi-types";
234
+
235
+ const color = getColorFromIndex(5); // "#1aff2f"
236
+ ```
237
+
238
+ - `flattenCCEventMap()` flattens the listed controller buckets and sorts the result by event time.
239
+ - `eventsIs()` identifies note, CC, or tempo event arrays from their first event.
240
+ - `getColorFromIndex()` returns the Ableton palette color or `"#888"` for an unknown index.
241
+ - `version` exposes the package source version string.
152
242
 
153
- ### Ableton Color Utilities
243
+ ## Source layout
154
244
 
155
- - **`abletonColorPalette`**: Array of 70+ Ableton Live color hex codes.
156
- - **`getColorFromIndex(index: number): string`**: Returns color code for given index, fallback is gray ("#888").
245
+ ```text
246
+ src/
247
+ ├─ midi-event.ts # beat-based Ableton event contracts
248
+ ├─ midi-clip.ts # clip data and CC map flattening
249
+ ├─ project.ts # clip, track, and project summaries
250
+ ├─ midi10-smf-types.ts # MIDI 1.0 SMF type declarations
251
+ ├─ midi10-smf-io.ts # SMF codec entry point
252
+ ├─ smf-parser.ts # numeric SMF parser
253
+ ├─ smf-writer.ts # numeric SMF writer
254
+ ├─ ESMFEventType.ts # numeric SMF enum declarations
255
+ ├─ smf-event-type.ts # runtime numeric SMF constants
256
+ ├─ ableton-colors.ts # Live palette and color lookup
257
+ └─ index.ts # root package exports
258
+ ```
157
259
 
158
- > ## License
260
+ ## Related project
159
261
 
160
- This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
262
+ - [live-midi-export](https://github.com/jeffy-g/live-midi-export) extracts MIDI clips and project metadata from Ableton Live Sets.
161
263
 
162
- > ## Related Projects
264
+ ## License
163
265
 
164
- - [live-midi-export](https://github.com/jeffy-g/live-midi-export) — CLI tool for extracting MIDI clips from Ableton Live sets.
266
+ MIT
package/dist/index.d.ts CHANGED
@@ -12,4 +12,4 @@ export * from "./midi-event.js";
12
12
  export * from "./midi-clip.js";
13
13
  export * from "./project.js";
14
14
  export * from "./ableton-colors.js";
15
- export declare const version = "v0.10.1";
15
+ export declare const version = "v0.11.0";
package/dist/index.js CHANGED
@@ -12,4 +12,4 @@ export * from "./midi-event.js";
12
12
  export * from "./midi-clip.js";
13
13
  export * from "./project.js";
14
14
  export * from "./ableton-colors.js";
15
- export const version = "v0.10.1";
15
+ export const version = "v0.11.0";
@@ -31,8 +31,8 @@ export type TMidiClipData = {
31
31
  *
32
32
  * ```
33
33
  * // e.g. obtain `midiClip` object
34
- * // xpath: "/Ableton/LiveSet/Tracks/MidiTrack[0]/DeviceChain/MainSequencer/ClipTimeable/ArrangerAutomation/Events/MidiClip[0]"
35
- * const midiClip = Ableton.LiveSet.Tracks.MidiTrack[0].DeviceChain.MainSequencer.ClipTimeable.ArrangerAutomation.Events.MidiClip[0];
34
+ * // xpath: "/Ableton/LiveSet/Tracks/MidiTrack[1]/DeviceChain/MainSequencer/ClipTimeable/ArrangerAutomation/Events/MidiClip[1]"
35
+ * const midiClip = Ableton.LiveSet.Tracks.MidiTrack[1].DeviceChain.MainSequencer.ClipTimeable.ArrangerAutomation.Events.MidiClip[1];
36
36
  * // clip start position in Live arrangement view
37
37
  * const clipStart = midiClip.CurrentStart.Value;
38
38
  * // clip end position in Live arrangement view
@@ -57,10 +57,12 @@ export type TMidiClipData = {
57
57
  */
58
58
  notes: NoteEvent[];
59
59
  /**
60
- * Control change event map. (key: cc number)
60
+ * Control change event map. (key: cc number, `0..127`)
61
61
  * @version 0.8.0
62
62
  */
63
- ccMap: Record<string, ControlChangeEvent[]>;
63
+ ccMap: {
64
+ [ccNumber: `${number}`]: ControlChangeEvent[];
65
+ };
64
66
  /**
65
67
  * Array of extracted control change events. (flatten {@link TMidiClipData.ccMap __`ccMap`__}, sort by time)
66
68
  * + use `flattenCCEventMap` (recommended)
@@ -0,0 +1,12 @@
1
+ /*!
2
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3
+ // Copyright (C) 2026 jeffy-g <hirotom1107@gmail.com>
4
+ // Released under the MIT license
5
+ // https://opensource.org/licenses/mit-license.php
6
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
7
+ */
8
+ /**
9
+ * @file live-midi-types/src/midi10-smf-io.ts
10
+ */
11
+ export * from "./smf-parser.js";
12
+ export * from "./smf-writer.js";
@@ -0,0 +1,12 @@
1
+ /*!
2
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3
+ // Copyright (C) 2026 jeffy-g <hirotom1107@gmail.com>
4
+ // Released under the MIT license
5
+ // https://opensource.org/licenses/mit-license.php
6
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
7
+ */
8
+ /**
9
+ * @file live-midi-types/src/midi10-smf-io.ts
10
+ */
11
+ export * from "./smf-parser.js";
12
+ export * from "./smf-writer.js";
@@ -20,22 +20,20 @@ export interface MidiHeader {
20
20
  ticksPerBeat?: number;
21
21
  }
22
22
  export type TextEventTypesUnion = ESMFEventType.text | ESMFEventType.copyrightNotice | ESMFEventType.trackName | ESMFEventType.instrumentName | ESMFEventType.lyrics | ESMFEventType.marker | ESMFEventType.cuePoint;
23
- export interface MidiBaseEvent<T> {
23
+ export interface MidiBaseEvent<GEventType> {
24
24
  /**
25
25
  * serialize/deserialize by `writeVarInt/readVarInt`
26
26
  * + byte range are __`1 to 4`__ (unsigned integer)
27
27
  */
28
28
  deltaTime: number;
29
29
  /**
30
- * MUST be `ESMFEventType`
30
+ * Numeric event discriminator shared by channel, system-exclusive, and meta events.
31
+ * SHOULD be `ESMFEventType`.
31
32
  * @see {@link ESMFEventType}
32
33
  */
33
- type: T;
34
+ type: GEventType;
34
35
  }
35
- export interface MidiMetaEvent<T> extends MidiBaseEvent<T> {
36
- meta?: true;
37
- }
38
- export type MidiEndOfTrackEvent = MidiMetaEvent<ESMFEventType.endOfTrack>;
36
+ export type MidiEndOfTrackEvent = MidiBaseEvent<ESMFEventType.endOfTrack>;
39
37
  export type FrameRate = 24 | 25 | 29.97 | 30;
40
38
  export interface MidiSmpteOffsetMixins {
41
39
  frameRate: FrameRate;
@@ -45,7 +43,7 @@ export interface MidiSmpteOffsetMixins {
45
43
  frame: number;
46
44
  subFrame: number;
47
45
  }
48
- export type MidiSmpteOffsetEvent = MidiMetaEvent<ESMFEventType.smpteOffset> & MidiSmpteOffsetMixins;
46
+ export type MidiSmpteOffsetEvent = MidiBaseEvent<ESMFEventType.smpteOffset> & MidiSmpteOffsetMixins;
49
47
  export interface MidiTimeSignatureMixins {
50
48
  numerator: number;
51
49
  denominator: number;
@@ -54,47 +52,47 @@ export interface MidiTimeSignatureMixins {
54
52
  /** @todo whats this? */
55
53
  thirtyseconds: number;
56
54
  }
57
- export type MidiTimeSignatureEvent = MidiMetaEvent<ESMFEventType.timeSignature> & MidiTimeSignatureMixins;
55
+ export type MidiTimeSignatureEvent = MidiBaseEvent<ESMFEventType.timeSignature> & MidiTimeSignatureMixins;
58
56
  export interface MidiKeySignatureMixins {
59
57
  key: number;
60
58
  scale: number;
61
59
  }
62
- export type MidiKeySignatureEvent = MidiMetaEvent<ESMFEventType.keySignature> & MidiKeySignatureMixins;
60
+ export type MidiKeySignatureEvent = MidiBaseEvent<ESMFEventType.keySignature> & MidiKeySignatureMixins;
63
61
  export interface MidiDataMixins {
64
62
  data: ArrayLike<number>;
65
63
  }
66
64
  export type MidiSysExEvent = MidiBaseEvent<ESMFEventType.sysEx> & MidiDataMixins;
67
65
  export type MidiEndSysExEvent = MidiBaseEvent<ESMFEventType.endSysEx> & MidiDataMixins;
68
- export type MidiSequencerSpecificEvent = MidiMetaEvent<ESMFEventType.sequencerSpecific> & MidiDataMixins;
66
+ export type MidiSequencerSpecificEvent = MidiBaseEvent<ESMFEventType.sequencerSpecific> & MidiDataMixins;
69
67
  export interface MidiUnknownMixins {
70
68
  data: ArrayLike<number>;
71
69
  metatypeByte: number;
72
70
  }
73
- export type MidiUnknownEvent = MidiMetaEvent<ESMFEventType.unknownMeta> & MidiUnknownMixins;
71
+ export type MidiUnknownEvent = MidiBaseEvent<ESMFEventType.unknownMeta> & MidiUnknownMixins;
74
72
  export interface MidiNumberMixins {
75
73
  number: number;
76
74
  }
77
- export type MidiSequenceNumberEvent = MidiMetaEvent<ESMFEventType.sequenceNumber> & MidiNumberMixins;
75
+ export type MidiSequenceNumberEvent = MidiBaseEvent<ESMFEventType.sequenceNumber> & MidiNumberMixins;
78
76
  export interface MidiTextMixins {
79
77
  text: string;
80
78
  }
81
- export type MidiTextEvent = MidiMetaEvent<ESMFEventType.text> & MidiTextMixins;
82
- export type MidiLyricsEvent = MidiMetaEvent<ESMFEventType.lyrics> & MidiTextMixins;
83
- export type MidiMarkerEvent = MidiMetaEvent<ESMFEventType.marker> & MidiTextMixins;
84
- export type MidiCuePointEvent = MidiMetaEvent<ESMFEventType.cuePoint> & MidiTextMixins;
85
- export type MidiTrackNameEvent = MidiMetaEvent<ESMFEventType.trackName> & MidiTextMixins;
86
- export type MidiInstrumentNameEvent = MidiMetaEvent<ESMFEventType.instrumentName> & MidiTextMixins;
87
- export type MidiCopyrightNoticeEvent = MidiMetaEvent<ESMFEventType.copyrightNotice> & MidiTextMixins;
88
- export type MidiSetTempoEvent = MidiMetaEvent<ESMFEventType.setTempo> & {
79
+ export type MidiTextEvent = MidiBaseEvent<ESMFEventType.text> & MidiTextMixins;
80
+ export type MidiLyricsEvent = MidiBaseEvent<ESMFEventType.lyrics> & MidiTextMixins;
81
+ export type MidiMarkerEvent = MidiBaseEvent<ESMFEventType.marker> & MidiTextMixins;
82
+ export type MidiCuePointEvent = MidiBaseEvent<ESMFEventType.cuePoint> & MidiTextMixins;
83
+ export type MidiTrackNameEvent = MidiBaseEvent<ESMFEventType.trackName> & MidiTextMixins;
84
+ export type MidiInstrumentNameEvent = MidiBaseEvent<ESMFEventType.instrumentName> & MidiTextMixins;
85
+ export type MidiCopyrightNoticeEvent = MidiBaseEvent<ESMFEventType.copyrightNotice> & MidiTextMixins;
86
+ export type MidiSetTempoEvent = MidiBaseEvent<ESMFEventType.setTempo> & {
89
87
  /**
90
88
  * __`unsigned 24-bit integer`__
91
89
  */
92
90
  microsecondsPerBeat: number;
93
91
  };
94
- export type MidiPortPrefixEvent = MidiMetaEvent<ESMFEventType.portPrefix> & {
92
+ export type MidiPortPrefixEvent = MidiBaseEvent<ESMFEventType.portPrefix> & {
95
93
  port: number;
96
94
  };
97
- export type MidiChannelPrefixEvent = MidiMetaEvent<ESMFEventType.channelPrefix> & {
95
+ export type MidiChannelPrefixEvent = MidiBaseEvent<ESMFEventType.channelPrefix> & {
98
96
  channel: number;
99
97
  };
100
98
  export interface MidiNoteMixins {
@@ -121,7 +119,7 @@ export interface MidiControllerMixins {
121
119
  */
122
120
  value: number;
123
121
  }
124
- export interface MidiChannelEvent<T> extends MidiBaseEvent<T> {
122
+ export interface MidiChannelEvent<GEventType> extends MidiBaseEvent<GEventType> {
125
123
  running?: true;
126
124
  channel: number;
127
125
  }
@@ -168,6 +166,23 @@ export type MidiEvent =
168
166
  | MidiCopyrightNoticeEvent
169
167
  | MidiChannelAftertouchEvent
170
168
  | MidiSequencerSpecificEvent;
169
+ /**
170
+ * Common Utilities
171
+ */
172
+ export type WithAbsoluteTime = {
173
+ /**
174
+ * `absoluteTime` is same as `ticks`
175
+ */
176
+ absoluteTime: number;
177
+ };
178
+ /**
179
+ * MIDI Event Derivation
180
+ */
181
+ export type MidiEventWithAbsTime<GEvent extends MidiEvent = MidiEvent> = GEvent & WithAbsoluteTime;
182
+ /**
183
+ * MIDI Event Derivation
184
+ */
185
+ export type TTrackEvents<GEvent extends MidiEvent = MidiEvent> = Array<MidiEventWithAbsTime<GEvent>>;
171
186
  export interface MidiData {
172
187
  header: MidiHeader;
173
188
  tracks: MidiEvent[][];
package/dist/project.d.ts CHANGED
@@ -136,7 +136,9 @@ export type TTrackInfo<T extends Record<string, any>> = {
136
136
  /**
137
137
  * MIDI clips indexed by {@linkcode TClipSummary.id TClipSummary.id}
138
138
  */
139
- clips: Record<string, TClipSummary<T>>;
139
+ clips: {
140
+ [uuidLike: string]: TClipSummary<T>;
141
+ };
140
142
  /**
141
143
  * @since v0.10.0
142
144
  */
@@ -0,0 +1,22 @@
1
+ /*!
2
+ * Original Source: midi-file (https://github.com/carter-thaxton/midi-file/blob/master/lib/midi-parser.js)
3
+ * Original License: MIT License
4
+ *
5
+ * This file is a numeric-event reimplementation optimized for Uint8Array input.
6
+ * Copyright (c) 2026 jeffy-g
7
+ * Released under the MIT license.
8
+ */
9
+ /**
10
+ * @file src/smf-parser.ts
11
+ */
12
+ import type { MidiData } from "./midi10-smf-types.ts";
13
+ /**
14
+ * Parse a Standard MIDI File into numeric {@link ESMFEventType} events.
15
+ *
16
+ * The Uint8Array fast path parses all chunks through a shared cursor and does
17
+ * not copy complete track payloads. Other array-like inputs are normalized once.
18
+ *
19
+ * @param {ArrayLike<number> | ArrayBuffer} input
20
+ * @returns {MidiData}
21
+ */
22
+ export declare const parseMidi: (input: ArrayLike<number> | ArrayBuffer) => MidiData;