@ac-kit/format-midi 0.0.0-stage → 0.1.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.
Files changed (60) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/LICENSE +28 -0
  3. package/README.md +103 -2
  4. package/dist/errors.d.ts +45 -0
  5. package/dist/errors.d.ts.map +1 -0
  6. package/dist/errors.js +36 -0
  7. package/dist/errors.js.map +1 -0
  8. package/dist/file/_meta-types.d.ts +33 -0
  9. package/dist/file/_meta-types.d.ts.map +1 -0
  10. package/dist/file/_meta-types.js +52 -0
  11. package/dist/file/_meta-types.js.map +1 -0
  12. package/dist/file/midi-file.d.ts +68 -0
  13. package/dist/file/midi-file.d.ts.map +1 -0
  14. package/dist/file/midi-file.js +2 -0
  15. package/dist/file/midi-file.js.map +1 -0
  16. package/dist/file/midi-meta-event.d.ts +74 -0
  17. package/dist/file/midi-meta-event.d.ts.map +1 -0
  18. package/dist/file/midi-meta-event.js +2 -0
  19. package/dist/file/midi-meta-event.js.map +1 -0
  20. package/dist/file/parse-midi-file.d.ts +29 -0
  21. package/dist/file/parse-midi-file.d.ts.map +1 -0
  22. package/dist/file/parse-midi-file.js +265 -0
  23. package/dist/file/parse-midi-file.js.map +1 -0
  24. package/dist/file/print-midi-file.d.ts +35 -0
  25. package/dist/file/print-midi-file.d.ts.map +1 -0
  26. package/dist/file/print-midi-file.js +184 -0
  27. package/dist/file/print-midi-file.js.map +1 -0
  28. package/dist/index.d.ts +12 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +12 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/message/_midi-status.d.ts +19 -0
  33. package/dist/message/_midi-status.d.ts.map +1 -0
  34. package/dist/message/_midi-status.js +66 -0
  35. package/dist/message/_midi-status.js.map +1 -0
  36. package/dist/message/encode-midi-message.d.ts +21 -0
  37. package/dist/message/encode-midi-message.d.ts.map +1 -0
  38. package/dist/message/encode-midi-message.js +93 -0
  39. package/dist/message/encode-midi-message.js.map +1 -0
  40. package/dist/message/is-midi-note-release.d.ts +15 -0
  41. package/dist/message/is-midi-note-release.d.ts.map +1 -0
  42. package/dist/message/is-midi-note-release.js +15 -0
  43. package/dist/message/is-midi-note-release.js.map +1 -0
  44. package/dist/message/midi-message-decoder.d.ts +67 -0
  45. package/dist/message/midi-message-decoder.d.ts.map +1 -0
  46. package/dist/message/midi-message-decoder.js +254 -0
  47. package/dist/message/midi-message-decoder.js.map +1 -0
  48. package/dist/message/midi-message-encoder.d.ts +43 -0
  49. package/dist/message/midi-message-encoder.d.ts.map +1 -0
  50. package/dist/message/midi-message-encoder.js +49 -0
  51. package/dist/message/midi-message-encoder.js.map +1 -0
  52. package/dist/message/midi-message.d.ts +111 -0
  53. package/dist/message/midi-message.d.ts.map +1 -0
  54. package/dist/message/midi-message.js +2 -0
  55. package/dist/message/midi-message.js.map +1 -0
  56. package/dist/timeline/compose-midi-timeline.d.ts +42 -0
  57. package/dist/timeline/compose-midi-timeline.d.ts.map +1 -0
  58. package/dist/timeline/compose-midi-timeline.js +87 -0
  59. package/dist/timeline/compose-midi-timeline.js.map +1 -0
  60. package/package.json +62 -3
@@ -0,0 +1,265 @@
1
+ import { ByteReader, getUint32Be } from "@ac-kit/core";
2
+ import { VarintIncompleteError, readVlq } from "@ac-kit/format-varint";
3
+ import { MidiFileError } from "../errors.js";
4
+ import { channelDataLength_, createChannelMessage_, SYSEX_END_, SYSEX_START_, } from "../message/_midi-status.js";
5
+ import { META_CHANNEL_PREFIX_, META_END_OF_TRACK_, META_KEY_SIGNATURE_, META_MIDI_PORT_, META_SEQUENCE_NUMBER_, META_SEQUENCER_SPECIFIC_, META_SET_TEMPO_, META_SMPTE_OFFSET_, META_TIME_SIGNATURE_, SMPTE_FRAME_RATES_, TEXT_META_TYPES_, } from "./_meta-types.js";
6
+ const MTHD_ = 1297377380;
7
+ const MTRK_ = 1297379947;
8
+ const META_EVENT_ = 0xff;
9
+ /** RP-001 caps a variable-length quantity at 4 bytes, 0x0FFFFFFF. */
10
+ const MAX_QUANTITY_BYTES_ = 4;
11
+ function hex_(byte) {
12
+ return `0x${byte.toString(16).padStart(2, "0")}`;
13
+ }
14
+ function readQuantity_(reader, base, what) {
15
+ const start = reader.position;
16
+ let value;
17
+ try {
18
+ value = readVlq(reader);
19
+ }
20
+ catch (error) {
21
+ throw new MidiFileError(error instanceof VarintIncompleteError
22
+ ? `${what} is truncated`
23
+ : `${what} is not a valid variable-length quantity`, base + start, { cause: error });
24
+ }
25
+ if (reader.position - start > MAX_QUANTITY_BYTES_) {
26
+ throw new MidiFileError(`${what} is longer than 4 bytes`, base + start);
27
+ }
28
+ return value;
29
+ }
30
+ function readPayload_(reader, base, what) {
31
+ const length = readQuantity_(reader, base, `${what} length`);
32
+ if (length > reader.remaining) {
33
+ throw new MidiFileError(`${what} of ${length} bytes overruns its track`, base + reader.position);
34
+ }
35
+ return reader.read(length).slice();
36
+ }
37
+ function parseMetaEvent_(metaType, data, offset) {
38
+ const requireLength = (expected) => {
39
+ if (data.length !== expected) {
40
+ throw new MidiFileError(`meta event ${hex_(metaType)} must be ${expected} bytes long, not ${data.length}`, offset);
41
+ }
42
+ };
43
+ switch (metaType) {
44
+ case META_SEQUENCE_NUMBER_:
45
+ if (data.length === 0) {
46
+ return { type: "sequenceNumber", number: undefined };
47
+ }
48
+ requireLength(2);
49
+ return { type: "sequenceNumber", number: getUint32Be(data, 0, 2) };
50
+ case META_CHANNEL_PREFIX_:
51
+ requireLength(1);
52
+ if (data[0] > 0x0f) {
53
+ throw new MidiFileError(`channel prefix ${data[0]} is not a channel 0–15`, offset);
54
+ }
55
+ return { type: "channelPrefix", channel: data[0] };
56
+ case META_MIDI_PORT_:
57
+ requireLength(1);
58
+ return { type: "midiPort", port: data[0] };
59
+ case META_END_OF_TRACK_:
60
+ requireLength(0);
61
+ return { type: "endOfTrack" };
62
+ case META_SET_TEMPO_:
63
+ requireLength(3);
64
+ return {
65
+ type: "setTempo",
66
+ microsecondsPerQuarterNote: getUint32Be(data, 0, 3),
67
+ };
68
+ case META_SMPTE_OFFSET_: {
69
+ requireLength(5);
70
+ const hourByte = data[0];
71
+ if (hourByte > 0x7f) {
72
+ throw new MidiFileError("SMPTE offset hour byte has its reserved top bit set", offset);
73
+ }
74
+ return {
75
+ type: "smpteOffset",
76
+ frameRate: SMPTE_FRAME_RATES_[hourByte >> 5],
77
+ hours: hourByte & 0x1f,
78
+ minutes: data[1],
79
+ seconds: data[2],
80
+ frames: data[3],
81
+ fractionalFrames: data[4],
82
+ };
83
+ }
84
+ case META_TIME_SIGNATURE_:
85
+ requireLength(4);
86
+ return {
87
+ type: "timeSignature",
88
+ numerator: data[0],
89
+ denominatorPower: data[1],
90
+ clocksPerClick: data[2],
91
+ thirtySecondNotesPerQuarter: data[3],
92
+ };
93
+ case META_KEY_SIGNATURE_: {
94
+ requireLength(2);
95
+ const sharpsFlats = (data[0] << 24) >> 24;
96
+ if (sharpsFlats < -7 || sharpsFlats > 7 || data[1] > 1) {
97
+ throw new MidiFileError(`key signature ${sharpsFlats}/${data[1]} is not -7–7 and 0 or 1`, offset);
98
+ }
99
+ return { type: "keySignature", sharpsFlats, minor: data[1] === 1 };
100
+ }
101
+ case META_SEQUENCER_SPECIFIC_:
102
+ return { type: "sequencerSpecific", data };
103
+ default: {
104
+ const textType = TEXT_META_TYPES_[metaType];
105
+ if (textType !== undefined) {
106
+ return { type: textType, data };
107
+ }
108
+ if (metaType > 0x7f) {
109
+ throw new MidiFileError(`meta event type ${hex_(metaType)} is above 0x7F`, offset);
110
+ }
111
+ return { type: "unknown", metaType, data };
112
+ }
113
+ }
114
+ }
115
+ function parseEvent_(reader, base, runningStatus) {
116
+ const offset = base + reader.position;
117
+ const first = reader.peekByte();
118
+ if (first === META_EVENT_) {
119
+ reader.readByte();
120
+ if (reader.atEnd) {
121
+ throw new MidiFileError("meta event type is truncated", offset);
122
+ }
123
+ const metaType = reader.readByte();
124
+ const data = readPayload_(reader, base, "meta event");
125
+ // RP-001: SysEx and meta events cancel running status.
126
+ return {
127
+ event: { kind: "meta", meta: parseMetaEvent_(metaType, data, offset) },
128
+ runningStatus: 0,
129
+ };
130
+ }
131
+ if (first === SYSEX_START_ || first === SYSEX_END_) {
132
+ reader.readByte();
133
+ const data = readPayload_(reader, base, "SysEx event");
134
+ return {
135
+ event: first === SYSEX_START_
136
+ ? { kind: "sysEx", data }
137
+ : { kind: "sysExEscape", data },
138
+ runningStatus: 0,
139
+ };
140
+ }
141
+ if (first > SYSEX_START_) {
142
+ throw new MidiFileError(`status ${hex_(first)} is not allowed in a track`, offset);
143
+ }
144
+ let status = runningStatus;
145
+ if (first >= 0x80) {
146
+ status = reader.readByte();
147
+ }
148
+ else if (status === 0) {
149
+ throw new MidiFileError(`data byte ${hex_(first)} with no running status`, offset);
150
+ }
151
+ const length = channelDataLength_(status);
152
+ if (reader.remaining < length) {
153
+ throw new MidiFileError("channel message is truncated", offset);
154
+ }
155
+ const data1 = reader.readByte();
156
+ const data2 = length === 2 ? reader.readByte() : 0;
157
+ if (data1 > 0x7f || data2 > 0x7f) {
158
+ throw new MidiFileError(`channel message ${hex_(status)} has a data byte above 0x7F`, offset);
159
+ }
160
+ return {
161
+ event: {
162
+ kind: "channel",
163
+ message: createChannelMessage_(status, data1, data2),
164
+ },
165
+ runningStatus: status,
166
+ };
167
+ }
168
+ function parseTrack_(bytes, base) {
169
+ const reader = new ByteReader(bytes);
170
+ const events = [];
171
+ let runningStatus = 0;
172
+ while (!reader.atEnd) {
173
+ const deltaTime = readQuantity_(reader, base, "delta time");
174
+ if (reader.atEnd) {
175
+ throw new MidiFileError("track ends after a delta time", base + reader.position);
176
+ }
177
+ const parsed = parseEvent_(reader, base, runningStatus);
178
+ runningStatus = parsed.runningStatus;
179
+ events.push({ deltaTime, event: parsed.event });
180
+ }
181
+ return { events };
182
+ }
183
+ function parseTimeDivision_(value) {
184
+ if ((value & 32768) === 0) {
185
+ if (value === 0) {
186
+ throw new MidiFileError("time division of 0 ticks per quarter note", 12);
187
+ }
188
+ return { type: "metrical", ticksPerQuarterNote: value };
189
+ }
190
+ // The high byte is the frame rate as a negative two's-complement number.
191
+ const framesPerSecond = 256 - (value >> 8);
192
+ if (framesPerSecond !== 24 &&
193
+ framesPerSecond !== 25 &&
194
+ framesPerSecond !== 29 &&
195
+ framesPerSecond !== 30) {
196
+ throw new MidiFileError(`SMPTE time division of ${framesPerSecond} frames per second is not 24, 25, 29 or 30`, 12);
197
+ }
198
+ const ticksPerFrame = value & 0xff;
199
+ if (ticksPerFrame === 0) {
200
+ throw new MidiFileError("time division of 0 ticks per frame", 13);
201
+ }
202
+ return { type: "timecode", framesPerSecond, ticksPerFrame };
203
+ }
204
+ /**
205
+ * Parses a Standard MIDI File (RP-001) into its header and tracks, every event
206
+ * kept with the bytes it was stored as.
207
+ *
208
+ * Tolerates what RP-001 asks readers to tolerate: an `MThd` chunk longer than 6
209
+ * bytes (the extra bytes are skipped) and chunks of an unknown type (skipped
210
+ * whole). Running status is applied within a track and cancelled by SysEx and
211
+ * meta events.
212
+ *
213
+ * Reads the tracks as they are, without repair: the track count in the header
214
+ * is not checked against the `MTrk` chunks present, every `MTrk` chunk becomes
215
+ * a track, and a track that does not end with End of Track — common in files
216
+ * written by hand-rolled tools — is accepted with nothing appended, so
217
+ * {@link printMidiFile} writes it back unchanged.
218
+ *
219
+ * Time complexity: O(n) in `bytes.length`. Memory: O(n); every payload is
220
+ * copied, so the result does not alias `bytes`.
221
+ *
222
+ * @param bytes - The whole file.
223
+ * @returns The file's format, time division and tracks.
224
+ * @throws {MidiFileError} When the file has no `MThd` header, a chunk or event
225
+ * is truncated, a variable-length quantity is overlong or longer than 4
226
+ * bytes, a data byte has no running status, a status byte other than a
227
+ * channel, SysEx or meta one appears in a track, or a known meta event has
228
+ * the wrong length or an out-of-range field.
229
+ */
230
+ export function parseMidiFile(bytes) {
231
+ if (bytes.length < 8 || getUint32Be(bytes, 0) !== MTHD_) {
232
+ throw new MidiFileError("not a Standard MIDI File: no MThd chunk", 0);
233
+ }
234
+ const headerLength = getUint32Be(bytes, 4);
235
+ if (headerLength < 6) {
236
+ throw new MidiFileError(`MThd length ${headerLength} is below 6`, 4);
237
+ }
238
+ if (headerLength > bytes.length - 8) {
239
+ throw new MidiFileError("MThd chunk is truncated", 0);
240
+ }
241
+ const format = getUint32Be(bytes, 8, 2);
242
+ if (format !== 0 && format !== 1 && format !== 2) {
243
+ throw new MidiFileError(`format ${format} is not 0, 1 or 2`, 8);
244
+ }
245
+ const timeDivision = parseTimeDivision_(getUint32Be(bytes, 12, 2));
246
+ const tracks = [];
247
+ let offset = 8 + headerLength;
248
+ while (offset < bytes.length) {
249
+ if (bytes.length - offset < 8) {
250
+ throw new MidiFileError("chunk header is truncated", offset);
251
+ }
252
+ const type = getUint32Be(bytes, offset);
253
+ const length = getUint32Be(bytes, offset + 4);
254
+ const dataStart = offset + 8;
255
+ if (length > bytes.length - dataStart) {
256
+ throw new MidiFileError(`chunk of ${length} bytes is truncated`, offset);
257
+ }
258
+ if (type === MTRK_) {
259
+ tracks.push(parseTrack_(bytes.subarray(dataStart, dataStart + length), dataStart));
260
+ }
261
+ offset = dataStart + length;
262
+ }
263
+ return { format, timeDivision, tracks };
264
+ }
265
+ //# sourceMappingURL=parse-midi-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-midi-file.js","sourceRoot":"","sources":["../../src/file/parse-midi-file.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { MidiFile } from "./midi-file.js";
2
+ /** Options for {@link printMidiFile}. */
3
+ export type PrintMidiFileOptions = {
4
+ /**
5
+ * Omit a channel event's status byte when it repeats the previous channel
6
+ * event's in the same track, with no SysEx or meta event in between (RP-001
7
+ * running status). Defaults to `false`.
8
+ */
9
+ runningStatus?: boolean;
10
+ };
11
+ /**
12
+ * Writes a Standard MIDI File (RP-001): an `MThd` chunk, then one `MTrk` chunk
13
+ * per track.
14
+ *
15
+ * Writes the events exactly as given and adds none: a track without a final End
16
+ * of Track meta event is written without one, which most readers reject, so a
17
+ * caller building a file appends `{ deltaTime: 0, event: { kind: "meta", meta:
18
+ * { type: "endOfTrack" } } }` itself. SysEx payloads are written as stored, F7
19
+ * included or not. The header's track count is `tracks.length`.
20
+ *
21
+ * Writing the result of {@link parseMidiFile} gives back the same bytes when
22
+ * `runningStatus` matches how the file was written, unknown chunks and extra
23
+ * header bytes aside, which the parser drops.
24
+ *
25
+ * Time complexity: O(n) in the bytes written.
26
+ *
27
+ * @param file - The file to write.
28
+ * @param options - Whether to use running status.
29
+ * @returns A fresh buffer holding the file.
30
+ * @throws {RangeError} When a field is out of the range its encoding holds, a
31
+ * channel event holds a non-channel message, an `unknown` meta event uses a
32
+ * meta type another member spells, or there are more than 65535 tracks.
33
+ */
34
+ export declare function printMidiFile(file: MidiFile, options?: PrintMidiFileOptions): Uint8Array<ArrayBuffer>;
35
+ //# sourceMappingURL=print-midi-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"print-midi-file.d.ts","sourceRoot":"","sources":["../../src/file/print-midi-file.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,QAAQ,EAAmC,MAAM,gBAAgB,CAAC;AAGhF,yCAAyC;AACzC,MAAM,MAAM,oBAAoB,GAAG;IAClC;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AA6MF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,aAAa,CAC5B,IAAI,EAAE,QAAQ,EACd,OAAO,CAAC,EAAE,oBAAoB,GAC5B,UAAU,CAAC,WAAW,CAAC,CA6CzB"}
@@ -0,0 +1,184 @@
1
+ import { concatBytes, setUint32Be } from "@ac-kit/core";
2
+ import { encodeVlq } from "@ac-kit/format-varint";
3
+ import { encodeMidiMessage } from "../message/encode-midi-message.js";
4
+ import { KNOWN_META_TYPES_, META_CHANNEL_PREFIX_, META_END_OF_TRACK_, META_KEY_SIGNATURE_, META_MIDI_PORT_, META_SEQUENCE_NUMBER_, META_SEQUENCER_SPECIFIC_, META_SET_TEMPO_, META_SMPTE_OFFSET_, META_TIME_SIGNATURE_, SMPTE_FRAME_RATES_, TEXT_META_CODES_, } from "./_meta-types.js";
5
+ const MAX_QUANTITY_ = 268435455;
6
+ const EMPTY_ = new Uint8Array(0);
7
+ function uint_(field, value, maximum) {
8
+ if (!Number.isInteger(value) || value < 0 || value > maximum) {
9
+ throw new RangeError(`printMidiFile: ${field} must be an integer 0–${maximum}, got ${value}`);
10
+ }
11
+ return value;
12
+ }
13
+ function quantity_(field, value) {
14
+ return encodeVlq(uint_(field, value, MAX_QUANTITY_));
15
+ }
16
+ function timeDivisionWord_(division) {
17
+ if (division.type === "metrical") {
18
+ if (division.ticksPerQuarterNote === 0) {
19
+ throw new RangeError("printMidiFile: ticksPerQuarterNote must be at least 1");
20
+ }
21
+ return uint_("ticksPerQuarterNote", division.ticksPerQuarterNote, 32767);
22
+ }
23
+ if (!SMPTE_FRAME_RATES_.includes(division.framesPerSecond)) {
24
+ throw new RangeError(`printMidiFile: framesPerSecond must be 24, 25, 29 or 30, got ${division.framesPerSecond}`);
25
+ }
26
+ const ticksPerFrame = uint_("ticksPerFrame", division.ticksPerFrame, 0xff);
27
+ if (ticksPerFrame === 0) {
28
+ throw new RangeError("printMidiFile: ticksPerFrame must be at least 1");
29
+ }
30
+ return ((256 - division.framesPerSecond) << 8) | ticksPerFrame;
31
+ }
32
+ function metaPayload_(meta) {
33
+ switch (meta.type) {
34
+ case "sequenceNumber": {
35
+ if (meta.number === undefined) {
36
+ return [META_SEQUENCE_NUMBER_, EMPTY_];
37
+ }
38
+ const number = uint_("sequence number", meta.number, 65535);
39
+ return [META_SEQUENCE_NUMBER_, Uint8Array.of(number >> 8, number & 0xff)];
40
+ }
41
+ case "text":
42
+ case "copyright":
43
+ case "trackName":
44
+ case "instrumentName":
45
+ case "lyric":
46
+ case "marker":
47
+ case "cuePoint":
48
+ case "programName":
49
+ case "deviceName":
50
+ return [TEXT_META_CODES_[meta.type], meta.data];
51
+ case "channelPrefix":
52
+ return [
53
+ META_CHANNEL_PREFIX_,
54
+ Uint8Array.of(uint_("channel prefix", meta.channel, 0x0f)),
55
+ ];
56
+ case "midiPort":
57
+ return [
58
+ META_MIDI_PORT_,
59
+ Uint8Array.of(uint_("MIDI port", meta.port, 0xff)),
60
+ ];
61
+ case "endOfTrack":
62
+ return [META_END_OF_TRACK_, EMPTY_];
63
+ case "setTempo": {
64
+ const tempo = uint_("microsecondsPerQuarterNote", meta.microsecondsPerQuarterNote, 16777215);
65
+ return [
66
+ META_SET_TEMPO_,
67
+ Uint8Array.of(tempo >> 16, (tempo >> 8) & 0xff, tempo & 0xff),
68
+ ];
69
+ }
70
+ case "smpteOffset": {
71
+ const rateCode = SMPTE_FRAME_RATES_.indexOf(meta.frameRate);
72
+ if (rateCode === -1) {
73
+ throw new RangeError(`printMidiFile: SMPTE offset frameRate must be 24, 25, 29 or 30, got ${meta.frameRate}`);
74
+ }
75
+ return [
76
+ META_SMPTE_OFFSET_,
77
+ Uint8Array.of((rateCode << 5) | uint_("SMPTE offset hours", meta.hours, 0x1f), uint_("SMPTE offset minutes", meta.minutes, 0xff), uint_("SMPTE offset seconds", meta.seconds, 0xff), uint_("SMPTE offset frames", meta.frames, 0xff), uint_("SMPTE offset fractionalFrames", meta.fractionalFrames, 0xff)),
78
+ ];
79
+ }
80
+ case "timeSignature":
81
+ return [
82
+ META_TIME_SIGNATURE_,
83
+ Uint8Array.of(uint_("numerator", meta.numerator, 0xff), uint_("denominatorPower", meta.denominatorPower, 0xff), uint_("clocksPerClick", meta.clocksPerClick, 0xff), uint_("thirtySecondNotesPerQuarter", meta.thirtySecondNotesPerQuarter, 0xff)),
84
+ ];
85
+ case "keySignature":
86
+ if (!Number.isInteger(meta.sharpsFlats) ||
87
+ meta.sharpsFlats < -7 ||
88
+ meta.sharpsFlats > 7) {
89
+ throw new RangeError(`printMidiFile: sharpsFlats must be an integer -7–7, got ${meta.sharpsFlats}`);
90
+ }
91
+ return [
92
+ META_KEY_SIGNATURE_,
93
+ Uint8Array.of(meta.sharpsFlats & 0xff, meta.minor ? 1 : 0),
94
+ ];
95
+ case "sequencerSpecific":
96
+ return [META_SEQUENCER_SPECIFIC_, meta.data];
97
+ case "unknown":
98
+ if (KNOWN_META_TYPES_.has(uint_("metaType", meta.metaType, 0x7f))) {
99
+ throw new RangeError(`printMidiFile: meta type 0x${meta.metaType.toString(16)} has its own member, not "unknown"`);
100
+ }
101
+ return [meta.metaType, meta.data];
102
+ default: {
103
+ const unknown = meta;
104
+ throw new RangeError(`printMidiFile: unknown meta event type ${String(unknown.type)}`);
105
+ }
106
+ }
107
+ }
108
+ function pushEvent_(parts, event, previousStatus, runningStatus) {
109
+ switch (event.kind) {
110
+ case "channel": {
111
+ const bytes = encodeMidiMessage(event.message);
112
+ const status = bytes[0];
113
+ if (status >= 0xf0) {
114
+ throw new RangeError(`printMidiFile: a channel event holds a "${event.message.type}" message`);
115
+ }
116
+ parts.push(runningStatus && status === previousStatus ? bytes.subarray(1) : bytes);
117
+ return status;
118
+ }
119
+ case "sysEx":
120
+ case "sysExEscape":
121
+ parts.push(Uint8Array.of(event.kind === "sysEx" ? 0xf0 : 0xf7), quantity_("SysEx length", event.data.length), event.data);
122
+ return 0;
123
+ case "meta": {
124
+ const [metaType, data] = metaPayload_(event.meta);
125
+ parts.push(Uint8Array.of(0xff, metaType), quantity_("meta event length", data.length), data);
126
+ return 0;
127
+ }
128
+ default: {
129
+ const unknown = event;
130
+ throw new RangeError(`printMidiFile: unknown event kind ${String(unknown.kind)}`);
131
+ }
132
+ }
133
+ }
134
+ /**
135
+ * Writes a Standard MIDI File (RP-001): an `MThd` chunk, then one `MTrk` chunk
136
+ * per track.
137
+ *
138
+ * Writes the events exactly as given and adds none: a track without a final End
139
+ * of Track meta event is written without one, which most readers reject, so a
140
+ * caller building a file appends `{ deltaTime: 0, event: { kind: "meta", meta:
141
+ * { type: "endOfTrack" } } }` itself. SysEx payloads are written as stored, F7
142
+ * included or not. The header's track count is `tracks.length`.
143
+ *
144
+ * Writing the result of {@link parseMidiFile} gives back the same bytes when
145
+ * `runningStatus` matches how the file was written, unknown chunks and extra
146
+ * header bytes aside, which the parser drops.
147
+ *
148
+ * Time complexity: O(n) in the bytes written.
149
+ *
150
+ * @param file - The file to write.
151
+ * @param options - Whether to use running status.
152
+ * @returns A fresh buffer holding the file.
153
+ * @throws {RangeError} When a field is out of the range its encoding holds, a
154
+ * channel event holds a non-channel message, an `unknown` meta event uses a
155
+ * meta type another member spells, or there are more than 65535 tracks.
156
+ */
157
+ export function printMidiFile(file, options) {
158
+ const runningStatus = options?.runningStatus ?? false;
159
+ const header = Uint8Array.of(0x4d, 0x54, 0x68, 0x64, 0, 0, 0, 6, 0, uint_("format", file.format, 2), 0, 0, 0, 0);
160
+ const trackCount = uint_("track count", file.tracks.length, 65535);
161
+ header[10] = trackCount >> 8;
162
+ header[11] = trackCount & 0xff;
163
+ const division = timeDivisionWord_(file.timeDivision);
164
+ header[12] = division >> 8;
165
+ header[13] = division & 0xff;
166
+ const parts = [header];
167
+ for (const track of file.tracks) {
168
+ const chunkHeader = Uint8Array.of(0x4d, 0x54, 0x72, 0x6b, 0, 0, 0, 0);
169
+ parts.push(chunkHeader);
170
+ const first = parts.length;
171
+ let previousStatus = 0;
172
+ for (const { deltaTime, event } of track.events) {
173
+ parts.push(quantity_("deltaTime", deltaTime));
174
+ previousStatus = pushEvent_(parts, event, previousStatus, runningStatus);
175
+ }
176
+ let length = 0;
177
+ for (let index = first; index < parts.length; index++) {
178
+ length += parts[index].length;
179
+ }
180
+ setUint32Be(chunkHeader, 4, uint_("track length", length, 4294967295));
181
+ }
182
+ return concatBytes(parts);
183
+ }
184
+ //# sourceMappingURL=print-midi-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"print-midi-file.js","sourceRoot":"","sources":["../../src/file/print-midi-file.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export * from "./errors.js";
2
+ export * from "./file/midi-file.js";
3
+ export * from "./file/midi-meta-event.js";
4
+ export * from "./file/parse-midi-file.js";
5
+ export * from "./file/print-midi-file.js";
6
+ export * from "./message/encode-midi-message.js";
7
+ export * from "./message/is-midi-note-release.js";
8
+ export * from "./message/midi-message-decoder.js";
9
+ export * from "./message/midi-message-encoder.js";
10
+ export * from "./message/midi-message.js";
11
+ export * from "./timeline/compose-midi-timeline.js";
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,mCAAmC,CAAC;AAClD,cAAc,mCAAmC,CAAC;AAClD,cAAc,mCAAmC,CAAC;AAClD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qCAAqC,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ export * from "./errors.js";
2
+ export * from "./file/midi-file.js";
3
+ export * from "./file/midi-meta-event.js";
4
+ export * from "./file/parse-midi-file.js";
5
+ export * from "./file/print-midi-file.js";
6
+ export * from "./message/encode-midi-message.js";
7
+ export * from "./message/is-midi-note-release.js";
8
+ export * from "./message/midi-message-decoder.js";
9
+ export * from "./message/midi-message-encoder.js";
10
+ export * from "./message/midi-message.js";
11
+ export * from "./timeline/compose-midi-timeline.js";
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,mCAAmC,CAAC;AAClD,cAAc,mCAAmC,CAAC;AAClD,cAAc,mCAAmC,CAAC;AAClD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qCAAqC,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { MidiChannelMessage, MidiSystemRealTimeMessage } from "./midi-message.js";
2
+ export declare const SYSEX_START_ = 240;
3
+ export declare const TIME_CODE_QUARTER_FRAME_ = 241;
4
+ export declare const SONG_POSITION_POINTER_ = 242;
5
+ export declare const SONG_SELECT_ = 243;
6
+ export declare const TUNE_REQUEST_ = 246;
7
+ export declare const SYSEX_END_ = 247;
8
+ export declare const FIRST_REAL_TIME_ = 248;
9
+ /** The real-time message spelled by `status` (F8–FF), or `undefined` for F9/FD. */
10
+ export declare function realTimeMessage_(status: number): MidiSystemRealTimeMessage | undefined;
11
+ /** How many data bytes follow a channel status byte (80–EF). */
12
+ export declare function channelDataLength_(status: number): 1 | 2;
13
+ /**
14
+ * The channel message spelled by `status` (80–EF) and its data bytes. `data2`
15
+ * is ignored for the one-data-byte kinds. The caller guarantees every data byte
16
+ * is 0–127.
17
+ */
18
+ export declare function createChannelMessage_(status: number, data1: number, data2: number): MidiChannelMessage;
19
+ //# sourceMappingURL=_midi-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_midi-status.d.ts","sourceRoot":"","sources":["../../src/message/_midi-status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,kBAAkB,EAClB,yBAAyB,EACzB,MAAM,mBAAmB,CAAC;AAG3B,eAAO,MAAM,YAAY,MAAO,CAAC;AACjC,eAAO,MAAM,wBAAwB,MAAO,CAAC;AAC7C,eAAO,MAAM,sBAAsB,MAAO,CAAC;AAC3C,eAAO,MAAM,YAAY,MAAO,CAAC;AACjC,eAAO,MAAM,aAAa,MAAO,CAAC;AAClC,eAAO,MAAM,UAAU,MAAO,CAAC;AAC/B,eAAO,MAAM,gBAAgB,MAAO,CAAC;AAcrC,mFAAmF;AACnF,wBAAgB,gBAAgB,CAC/B,MAAM,EAAE,MAAM,GACZ,yBAAyB,GAAG,SAAS,CAIvC;AAED,gEAAgE;AAChE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,GAAG,CAAC,CAIxD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACpC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACX,kBAAkB,CAiCpB"}
@@ -0,0 +1,66 @@
1
+ // Status bytes of the MIDI 1.0 Detailed Specification, Table I-V.
2
+ export const SYSEX_START_ = 0xf0;
3
+ export const TIME_CODE_QUARTER_FRAME_ = 0xf1;
4
+ export const SONG_POSITION_POINTER_ = 0xf2;
5
+ export const SONG_SELECT_ = 0xf3;
6
+ export const TUNE_REQUEST_ = 0xf6;
7
+ export const SYSEX_END_ = 0xf7;
8
+ export const FIRST_REAL_TIME_ = 0xf8;
9
+ /** Real-time status byte → message type; F9 and FD are undefined. */
10
+ const REAL_TIME_TYPES_ = {
11
+ 0xf8: "timingClock",
12
+ 0xfa: "start",
13
+ 0xfb: "continue",
14
+ 0xfc: "stop",
15
+ 0xfe: "activeSensing",
16
+ 0xff: "systemReset",
17
+ };
18
+ /** The real-time message spelled by `status` (F8–FF), or `undefined` for F9/FD. */
19
+ export function realTimeMessage_(status) {
20
+ const type = REAL_TIME_TYPES_[status];
21
+ return type === undefined ? undefined : { type };
22
+ }
23
+ /** How many data bytes follow a channel status byte (80–EF). */
24
+ export function channelDataLength_(status) {
25
+ const kind = status & 0xf0;
26
+ return kind === 0xc0 || kind === 0xd0 ? 1 : 2;
27
+ }
28
+ /**
29
+ * The channel message spelled by `status` (80–EF) and its data bytes. `data2`
30
+ * is ignored for the one-data-byte kinds. The caller guarantees every data byte
31
+ * is 0–127.
32
+ */
33
+ export function createChannelMessage_(status, data1, data2) {
34
+ const channel = status & 0x0f;
35
+ switch (status & 0xf0) {
36
+ case 0x80:
37
+ return { type: "noteOff", channel, note: data1, velocity: data2 };
38
+ case 0x90:
39
+ return { type: "noteOn", channel, note: data1, velocity: data2 };
40
+ case 0xa0:
41
+ return {
42
+ type: "polyphonicKeyPressure",
43
+ channel,
44
+ note: data1,
45
+ pressure: data2,
46
+ };
47
+ case 0xb0:
48
+ return {
49
+ type: "controlChange",
50
+ channel,
51
+ controller: data1,
52
+ value: data2,
53
+ };
54
+ case 0xc0:
55
+ return { type: "programChange", channel, program: data1 };
56
+ case 0xd0:
57
+ return { type: "channelPressure", channel, pressure: data1 };
58
+ default:
59
+ return {
60
+ type: "pitchBend",
61
+ channel,
62
+ value: (data1 | (data2 << 7)) - 8192,
63
+ };
64
+ }
65
+ }
66
+ //# sourceMappingURL=_midi-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_midi-status.js","sourceRoot":"","sources":["../../src/message/_midi-status.ts"],"names":[],"mappings":"AAKA,kEAAkE;AAClE,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC;AACjC,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAC7C,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAC3C,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC;AACjC,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC;AAClC,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC;AAC/B,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAErC,qEAAqE;AACrE,MAAM,gBAAgB,GAElB;IACH,IAAI,EAAE,aAAa;IACnB,IAAI,EAAE,OAAO;IACb,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,eAAe;IACrB,IAAI,EAAE,aAAa;CACnB,CAAC;AAEF,mFAAmF;AACnF,MAAM,UAAU,gBAAgB,CAC/B,MAAc;IAEd,MAAM,IAAI,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAEtC,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;AAClD,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAChD,MAAM,IAAI,GAAG,MAAM,GAAG,IAAI,CAAC;IAE3B,OAAO,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CACpC,MAAc,EACd,KAAa,EACb,KAAa;IAEb,MAAM,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC;IAE9B,QAAQ,MAAM,GAAG,IAAI,EAAE,CAAC;QACvB,KAAK,IAAI;YACR,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QACnE,KAAK,IAAI;YACR,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QAClE,KAAK,IAAI;YACR,OAAO;gBACN,IAAI,EAAE,uBAAuB;gBAC7B,OAAO;gBACP,IAAI,EAAE,KAAK;gBACX,QAAQ,EAAE,KAAK;aACf,CAAC;QACH,KAAK,IAAI;YACR,OAAO;gBACN,IAAI,EAAE,eAAe;gBACrB,OAAO;gBACP,UAAU,EAAE,KAAK;gBACjB,KAAK,EAAE,KAAK;aACZ,CAAC;QACH,KAAK,IAAI;YACR,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC3D,KAAK,IAAI;YACR,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QAC9D;YACC,OAAO;gBACN,IAAI,EAAE,WAAW;gBACjB,OAAO;gBACP,KAAK,EAAE,CAAC,KAAK,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI;aACpC,CAAC;IACJ,CAAC;AACF,CAAC"}