@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.
- package/CHANGELOG.md +38 -0
- package/LICENSE +28 -0
- package/README.md +103 -2
- package/dist/errors.d.ts +45 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +36 -0
- package/dist/errors.js.map +1 -0
- package/dist/file/_meta-types.d.ts +33 -0
- package/dist/file/_meta-types.d.ts.map +1 -0
- package/dist/file/_meta-types.js +52 -0
- package/dist/file/_meta-types.js.map +1 -0
- package/dist/file/midi-file.d.ts +68 -0
- package/dist/file/midi-file.d.ts.map +1 -0
- package/dist/file/midi-file.js +2 -0
- package/dist/file/midi-file.js.map +1 -0
- package/dist/file/midi-meta-event.d.ts +74 -0
- package/dist/file/midi-meta-event.d.ts.map +1 -0
- package/dist/file/midi-meta-event.js +2 -0
- package/dist/file/midi-meta-event.js.map +1 -0
- package/dist/file/parse-midi-file.d.ts +29 -0
- package/dist/file/parse-midi-file.d.ts.map +1 -0
- package/dist/file/parse-midi-file.js +265 -0
- package/dist/file/parse-midi-file.js.map +1 -0
- package/dist/file/print-midi-file.d.ts +35 -0
- package/dist/file/print-midi-file.d.ts.map +1 -0
- package/dist/file/print-midi-file.js +184 -0
- package/dist/file/print-midi-file.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/message/_midi-status.d.ts +19 -0
- package/dist/message/_midi-status.d.ts.map +1 -0
- package/dist/message/_midi-status.js +66 -0
- package/dist/message/_midi-status.js.map +1 -0
- package/dist/message/encode-midi-message.d.ts +21 -0
- package/dist/message/encode-midi-message.d.ts.map +1 -0
- package/dist/message/encode-midi-message.js +93 -0
- package/dist/message/encode-midi-message.js.map +1 -0
- package/dist/message/is-midi-note-release.d.ts +15 -0
- package/dist/message/is-midi-note-release.d.ts.map +1 -0
- package/dist/message/is-midi-note-release.js +15 -0
- package/dist/message/is-midi-note-release.js.map +1 -0
- package/dist/message/midi-message-decoder.d.ts +67 -0
- package/dist/message/midi-message-decoder.d.ts.map +1 -0
- package/dist/message/midi-message-decoder.js +254 -0
- package/dist/message/midi-message-decoder.js.map +1 -0
- package/dist/message/midi-message-encoder.d.ts +43 -0
- package/dist/message/midi-message-encoder.d.ts.map +1 -0
- package/dist/message/midi-message-encoder.js +49 -0
- package/dist/message/midi-message-encoder.js.map +1 -0
- package/dist/message/midi-message.d.ts +111 -0
- package/dist/message/midi-message.d.ts.map +1 -0
- package/dist/message/midi-message.js +2 -0
- package/dist/message/midi-message.js.map +1 -0
- package/dist/timeline/compose-midi-timeline.d.ts +42 -0
- package/dist/timeline/compose-midi-timeline.d.ts.map +1 -0
- package/dist/timeline/compose-midi-timeline.js +87 -0
- package/dist/timeline/compose-midi-timeline.js.map +1 -0
- package/package.json +62 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# @ac-kit/format-midi
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 992cbbb: New package: MIDI 1.0, from the bytes on a live port to the time in seconds of
|
|
8
|
+
every event in a Standard MIDI File.
|
|
9
|
+
|
|
10
|
+
- `MidiMessage` models every MIDI 1.0 message — the seven Channel Voice
|
|
11
|
+
messages (Channel Mode as `controlChange` 120–127), System Common including
|
|
12
|
+
`sysEx`, and System Real-Time — with `MidiChannelMessage`,
|
|
13
|
+
`MidiSystemCommonMessage` and `MidiSystemRealTimeMessage` naming the groups.
|
|
14
|
+
`encodeMidiMessage` writes one with every field range-checked, and
|
|
15
|
+
`isMidiNoteRelease` treats a note-on with velocity 0 as the note-off
|
|
16
|
+
receivers take it for.
|
|
17
|
+
- `MidiMessageDecoder` reads a live byte stream the way a MIDI receiver does:
|
|
18
|
+
running status, real-time bytes returned the moment they arrive even inside
|
|
19
|
+
another message or a SysEx, SysEx ended by F7 or by any other status, and
|
|
20
|
+
every violation — stray data, a message cut short, an undefined status, a
|
|
21
|
+
lone F7, a SysEx over `maxSysExLength` (1 MiB by default) — a recoverable
|
|
22
|
+
`MidiStreamError` after which it resynchronises. `MidiMessageEncoder` writes
|
|
23
|
+
messages back, optionally with running status.
|
|
24
|
+
- `parseMidiFile` reads a Standard MIDI File (RP-001) into its format, time
|
|
25
|
+
division (metrical or SMPTE) and tracks of channel, SysEx (F0 and F7 forms)
|
|
26
|
+
and meta events, every RP-001 meta type by name and text kept as bytes. It
|
|
27
|
+
skips unknown chunks and extra header bytes, accepts a track without End of
|
|
28
|
+
Track as it is, and throws `MidiFileError` with the byte offset on malformed
|
|
29
|
+
input. `printMidiFile` writes the file back byte for byte, with or without
|
|
30
|
+
running status.
|
|
31
|
+
- `composeMidiTimeline` places every event on one axis with its tick and
|
|
32
|
+
seconds: format 0 and 1 tracks merged by tick under every Set Tempo event,
|
|
33
|
+
format 2 tracks timed independently, SMPTE divisions at a fixed tick length.
|
|
34
|
+
|
|
35
|
+
### Patch Changes
|
|
36
|
+
|
|
37
|
+
- Updated dependencies [6254a3f]
|
|
38
|
+
- @ac-kit/format-core@0.1.3
|
package/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Anthony Champagne and contributors
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,104 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @ac-kit/format-midi
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
MIDI 1.0 in plain data: the messages a device sends and receives, decoded from
|
|
4
|
+
and encoded to a live byte stream; Standard MIDI Files, parsed and written back
|
|
5
|
+
byte for byte; and the time, in seconds, of every event in a file.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { ByteAccumulator } from "@ac-kit/core";
|
|
9
|
+
import { DecodeStream } from "@ac-kit/format-core";
|
|
10
|
+
import {
|
|
11
|
+
MidiMessageDecoder,
|
|
12
|
+
composeMidiTimeline,
|
|
13
|
+
parseMidiFile,
|
|
14
|
+
} from "@ac-kit/format-midi";
|
|
15
|
+
|
|
16
|
+
// A live port: running status, real-time bytes anywhere, SysEx of any length.
|
|
17
|
+
const messages = port.readable.pipeThrough(
|
|
18
|
+
new DecodeStream(new MidiMessageDecoder(), {
|
|
19
|
+
buffer: new ByteAccumulator(65_536),
|
|
20
|
+
onError: (error) => console.warn(error),
|
|
21
|
+
}),
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
// A file: every event with its tick and its time in seconds.
|
|
25
|
+
for (const { tick, seconds, event } of composeMidiTimeline(parseMidiFile(bytes))) {
|
|
26
|
+
// …
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
It opens no device: read bytes from wherever the platform exposes MIDI — an
|
|
31
|
+
ALSA raw MIDI node, a serial port, a USB-MIDI endpoint, Web MIDI — and write
|
|
32
|
+
bytes back the same way.
|
|
33
|
+
|
|
34
|
+
## Messages
|
|
35
|
+
|
|
36
|
+
`MidiMessage` is a union discriminated by `type`, following the _MIDI 1.0
|
|
37
|
+
Detailed Specification_: the seven Channel Voice messages, System Common
|
|
38
|
+
(`sysEx`, `timeCodeQuarterFrame`, `songPositionPointer`, `songSelect`,
|
|
39
|
+
`tuneRequest`) and System Real-Time (`timingClock`, `start`, `continue`, `stop`,
|
|
40
|
+
`activeSensing`, `systemReset`). `MidiChannelMessage`,
|
|
41
|
+
`MidiSystemCommonMessage` and `MidiSystemRealTimeMessage` name the three groups.
|
|
42
|
+
|
|
43
|
+
Values are the ones on the wire, with two exceptions: `pitchBend` is -8192–8191
|
|
44
|
+
with 0 at the centre, and a `sysEx` holds its payload without the F0 and F7
|
|
45
|
+
around it. Channel Mode messages are `controlChange` with controller 120–127, as
|
|
46
|
+
on the wire. A note-on with velocity 0 stays a `noteOn`; `isMidiNoteRelease`
|
|
47
|
+
answers whether a message releases a note in either form.
|
|
48
|
+
|
|
49
|
+
`encodeMidiMessage` writes one message, checking every field's range.
|
|
50
|
+
|
|
51
|
+
## Streams
|
|
52
|
+
|
|
53
|
+
`MidiMessageDecoder` is a `Decoder` from `@ac-kit/format-core`, so it runs under
|
|
54
|
+
`DecodeStream`, `decodeAll` or any other driver. It reads a stream the way a
|
|
55
|
+
MIDI receiver does:
|
|
56
|
+
|
|
57
|
+
- data bytes after a channel message reuse its status (running status), until
|
|
58
|
+
a System Common message or a SysEx cancels it;
|
|
59
|
+
- a real-time byte is returned the moment it arrives, even in the middle of
|
|
60
|
+
another message or of a SysEx, which then carries on;
|
|
61
|
+
- a SysEx ends at F7 or at any other status byte;
|
|
62
|
+
- stray data bytes, a message cut short, an undefined status (F4, F5, F9, FD),
|
|
63
|
+
a lone F7 and a SysEx over `maxSysExLength` (1 MiB by default) are
|
|
64
|
+
recoverable `error` resu rather than the driver's buffer, so the buffer only
|
|
65
|
+
ever holds a few bytes beyond the chunk just received. One instance serves
|
|
66
|
+
exactly one stream; `reset` decoding resumes at the next status byte.
|
|
67
|
+
|
|
68
|
+
The decoder keeps a message interrupted by a real-time byte, and a SysEx in
|
|
69
|
+
progress, in its own state, so one instance serves exactly one stream; `reset`
|
|
70
|
+
clears it.
|
|
71
|
+
|
|
72
|
+
`MidiMessageEncoder` is the matching `Encoder`, with an optional
|
|
73
|
+
`runningStatus`.
|
|
74
|
+
|
|
75
|
+
## Standard MIDI Files
|
|
76
|
+
|
|
77
|
+
`parseMidiFile` reads a Standard MIDI File (RP-001) into a `MidiFile`: its
|
|
78
|
+
`format` (0, 1 or 2), its `timeDivision` (ticks per quarter note, or SMPTE
|
|
79
|
+
frames and ticks per frame) and its tracks of `{ deltaTime, event }`. An event
|
|
80
|
+
is a channel message, an F0 or F7 SysEx event with its bytes as stored, or a
|
|
81
|
+
`MidiMetaEvent` — every meta type of RP-001 by name, the others as `unknown`.
|
|
82
|
+
Text meta events keep their bytes, because the standard does not say which
|
|
83
|
+
encoding they use.
|
|
84
|
+
|
|
85
|
+
It skips chunks of unknown type and extra header bytes, and accepts a track
|
|
86
|
+
that does not end with End of Track, without adding one. A malformed file throws
|
|
87
|
+
`MidiFileError`, a `SyntaxError` carrying the byte `offset` it gave up at.
|
|
88
|
+
|
|
89
|
+
`printMidiFile` writes a `MidiFile` back, with `runningStatus` as an option. The
|
|
90
|
+
events are written as given and none is added, so a track built by hand needs
|
|
91
|
+
its own End of Track. A field out of range is a `RangeError`.
|
|
92
|
+
|
|
93
|
+
## Timeline
|
|
94
|
+
|
|
95
|
+
`composeMidiTimeline` lists every event of a file with its `trackIndex`, `tick`
|
|
96
|
+
and `seconds`, in playing order. Tracks of a format 0 or 1 file are merged by
|
|
97
|
+
tick, under every Set Tempo event in any track. Tracks of a format 2 file are
|
|
98
|
+
independent sequences: each is timed on its own and they follow one another.
|
|
99
|
+
An SMPTE division gives each tick a fixed length, with frame rate 29 meaning
|
|
100
|
+
29.97.
|
|
101
|
+
|
|
102
|
+
See the
|
|
103
|
+
[generated API docs](https://anthochamp.github.io/node-essentials/api/format-midi/)
|
|
104
|
+
for the full reference.
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a {@link MidiStreamError} reports:
|
|
3
|
+
*
|
|
4
|
+
* - `strayData` — data bytes with no status to give them meaning: nothing was
|
|
5
|
+
* received yet, or a System Common or SysEx message cancelled running
|
|
6
|
+
* status.
|
|
7
|
+
* - `incompleteMessage` — a status byte arrived before the data bytes of the
|
|
8
|
+
* previous message were all received; the partial message is dropped.
|
|
9
|
+
* - `undefinedStatus` — one of the status bytes MIDI 1.0 leaves undefined: F4 and
|
|
10
|
+
* F5 (System Common) or F9 and FD (System Real-Time).
|
|
11
|
+
* - `unexpectedEndOfExclusive` — an F7 (End of Exclusive) with no SysEx open.
|
|
12
|
+
* - `sysExTooLong` — a SysEx payload exceeded the decoder's `maxSysExLength`; the
|
|
13
|
+
* rest of it, up to its end, is discarded.
|
|
14
|
+
*/
|
|
15
|
+
export type MidiStreamErrorReason = "strayData" | "incompleteMessage" | "undefinedStatus" | "unexpectedEndOfExclusive" | "sysExTooLong";
|
|
16
|
+
/**
|
|
17
|
+
* A recoverable violation in a live MIDI byte stream, reported by
|
|
18
|
+
* {@link MidiMessageDecoder} as an `error` decode result. The offending bytes
|
|
19
|
+
* are consumed and decoding resumes at the next status byte, the way a MIDI
|
|
20
|
+
* receiver resynchronises.
|
|
21
|
+
*/
|
|
22
|
+
export declare class MidiStreamError extends SyntaxError {
|
|
23
|
+
/** What kind of violation was found. */
|
|
24
|
+
readonly reason: MidiStreamErrorReason;
|
|
25
|
+
constructor(message: string,
|
|
26
|
+
/** What kind of violation was found. */
|
|
27
|
+
reason: MidiStreamErrorReason);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A Standard MIDI File is malformed: a chunk or event is truncated, a
|
|
31
|
+
* variable-length quantity is invalid, a data byte has no running status to
|
|
32
|
+
* apply to, or a meta event's length does not match its type.
|
|
33
|
+
*
|
|
34
|
+
* Thrown by {@link parseMidiFile}. A model built by the caller that
|
|
35
|
+
* {@link printMidiFile} cannot write — a field out of range, a message that is
|
|
36
|
+
* not a channel message — is a `RangeError` instead.
|
|
37
|
+
*/
|
|
38
|
+
export declare class MidiFileError extends SyntaxError {
|
|
39
|
+
/** Byte offset in the file of the structure the parser gave up at. */
|
|
40
|
+
readonly offset: number;
|
|
41
|
+
constructor(message: string,
|
|
42
|
+
/** Byte offset in the file of the structure the parser gave up at. */
|
|
43
|
+
offset: number, options?: ErrorOptions);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,qBAAqB,GAC9B,WAAW,GACX,mBAAmB,GACnB,iBAAiB,GACjB,0BAA0B,GAC1B,cAAc,CAAC;AAElB;;;;;GAKG;AACH,qBAAa,eAAgB,SAAQ,WAAW;IAG9C,wCAAwC;IACxC,QAAQ,CAAC,MAAM,EAAE,qBAAqB;IAHvC,YACC,OAAO,EAAE,MAAM;IACf,wCAAwC;IAC/B,MAAM,EAAE,qBAAqB,EAItC;CACD;AAED;;;;;;;;GAQG;AACH,qBAAa,aAAc,SAAQ,WAAW;IAG5C,sEAAsE;IACtE,QAAQ,CAAC,MAAM,EAAE,MAAM;IAHxB,YACC,OAAO,EAAE,MAAM;IACf,sEAAsE;IAC7D,MAAM,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE,YAAY,EAItB;CACD"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A recoverable violation in a live MIDI byte stream, reported by
|
|
3
|
+
* {@link MidiMessageDecoder} as an `error` decode result. The offending bytes
|
|
4
|
+
* are consumed and decoding resumes at the next status byte, the way a MIDI
|
|
5
|
+
* receiver resynchronises.
|
|
6
|
+
*/
|
|
7
|
+
export class MidiStreamError extends SyntaxError {
|
|
8
|
+
reason;
|
|
9
|
+
constructor(message,
|
|
10
|
+
/** What kind of violation was found. */
|
|
11
|
+
reason) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.reason = reason;
|
|
14
|
+
this.name = "MidiStreamError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* A Standard MIDI File is malformed: a chunk or event is truncated, a
|
|
19
|
+
* variable-length quantity is invalid, a data byte has no running status to
|
|
20
|
+
* apply to, or a meta event's length does not match its type.
|
|
21
|
+
*
|
|
22
|
+
* Thrown by {@link parseMidiFile}. A model built by the caller that
|
|
23
|
+
* {@link printMidiFile} cannot write — a field out of range, a message that is
|
|
24
|
+
* not a channel message — is a `RangeError` instead.
|
|
25
|
+
*/
|
|
26
|
+
export class MidiFileError extends SyntaxError {
|
|
27
|
+
offset;
|
|
28
|
+
constructor(message,
|
|
29
|
+
/** Byte offset in the file of the structure the parser gave up at. */
|
|
30
|
+
offset, options) {
|
|
31
|
+
super(`${message} (at byte ${offset})`, options);
|
|
32
|
+
this.offset = offset;
|
|
33
|
+
this.name = "MidiFileError";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAqBA;;;;;GAKG;AACH,MAAM,OAAO,eAAgB,SAAQ,WAAW;IAIrC,MAAM;IAHhB,YACC,OAAe;IACf,wCAAwC;IAC/B,MAA6B;QAEtC,KAAK,CAAC,OAAO,CAAC,CAAC;sBAFN,MAAM;QAGf,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAC/B,CAAC;CACD;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,aAAc,SAAQ,WAAW;IAInC,MAAM;IAHhB,YACC,OAAe;IACf,sEAAsE;IAC7D,MAAc,EACvB,OAAsB;QAEtB,KAAK,CAAC,GAAG,OAAO,aAAa,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC;sBAHxC,MAAM;QAIf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC7B,CAAC;CACD"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { MidiMetaEvent } from "./midi-meta-event.js";
|
|
2
|
+
export type TextMetaType_ = Exclude<Extract<MidiMetaEvent, {
|
|
3
|
+
data: Uint8Array;
|
|
4
|
+
}>["type"], "sequencerSpecific" | "unknown">;
|
|
5
|
+
export declare const META_SEQUENCE_NUMBER_ = 0;
|
|
6
|
+
export declare const META_CHANNEL_PREFIX_ = 32;
|
|
7
|
+
export declare const META_MIDI_PORT_ = 33;
|
|
8
|
+
export declare const META_END_OF_TRACK_ = 47;
|
|
9
|
+
export declare const META_SET_TEMPO_ = 81;
|
|
10
|
+
export declare const META_SMPTE_OFFSET_ = 84;
|
|
11
|
+
export declare const META_TIME_SIGNATURE_ = 88;
|
|
12
|
+
export declare const META_KEY_SIGNATURE_ = 89;
|
|
13
|
+
export declare const META_SEQUENCER_SPECIFIC_ = 127;
|
|
14
|
+
export declare const TEXT_META_TYPES_: Readonly<Record<number, TextMetaType_>>;
|
|
15
|
+
export declare const TEXT_META_CODES_: {
|
|
16
|
+
readonly text: 1;
|
|
17
|
+
readonly copyright: 2;
|
|
18
|
+
readonly trackName: 3;
|
|
19
|
+
readonly instrumentName: 4;
|
|
20
|
+
readonly lyric: 5;
|
|
21
|
+
readonly marker: 6;
|
|
22
|
+
readonly cuePoint: 7;
|
|
23
|
+
readonly programName: 8;
|
|
24
|
+
readonly deviceName: 9;
|
|
25
|
+
};
|
|
26
|
+
/** Every meta type a member other than `unknown` spells. */
|
|
27
|
+
export declare const KNOWN_META_TYPES_: ReadonlySet<number>;
|
|
28
|
+
/**
|
|
29
|
+
* SMPTE frame rates by the 2-bit code in bits 5–6 of an SMPTE Offset's hour
|
|
30
|
+
* byte.
|
|
31
|
+
*/
|
|
32
|
+
export declare const SMPTE_FRAME_RATES_: readonly [24, 25, 29, 30];
|
|
33
|
+
//# sourceMappingURL=_meta-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_meta-types.d.ts","sourceRoot":"","sources":["../../src/file/_meta-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,MAAM,aAAa,GAAG,OAAO,CAClC,OAAO,CAAC,aAAa,EAAE;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,CAAC,MAAM,CAAC,EACpD,mBAAmB,GAAG,SAAS,CAC/B,CAAC;AAIF,eAAO,MAAM,qBAAqB,IAAO,CAAC;AAC1C,eAAO,MAAM,oBAAoB,KAAO,CAAC;AACzC,eAAO,MAAM,eAAe,KAAO,CAAC;AACpC,eAAO,MAAM,kBAAkB,KAAO,CAAC;AACvC,eAAO,MAAM,eAAe,KAAO,CAAC;AACpC,eAAO,MAAM,kBAAkB,KAAO,CAAC;AACvC,eAAO,MAAM,oBAAoB,KAAO,CAAC;AACzC,eAAO,MAAM,mBAAmB,KAAO,CAAC;AACxC,eAAO,MAAM,wBAAwB,MAAO,CAAC;AAE7C,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAUpE,CAAC;AAEF,eAAO,MAAM,gBAAgB;mBACtB,CAAI;wBACC,CAAI;wBACJ,CAAI;6BACC,CAAI;oBACb,CAAI;qBACH,CAAI;uBACF,CAAI;0BACD,CAAI;yBACL,CAAI;CACiC,CAAC;AAEnD,4DAA4D;AAC5D,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAWhD,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,kBAAkB,YAAI,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAU,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Meta event types of RP-001, with 0x08 and 0x09 from RP-019 and 0x21 from the
|
|
2
|
+
// MMA's later addition (Program Name, Device Name, MIDI Port).
|
|
3
|
+
export const META_SEQUENCE_NUMBER_ = 0x00;
|
|
4
|
+
export const META_CHANNEL_PREFIX_ = 0x20;
|
|
5
|
+
export const META_MIDI_PORT_ = 0x21;
|
|
6
|
+
export const META_END_OF_TRACK_ = 0x2f;
|
|
7
|
+
export const META_SET_TEMPO_ = 0x51;
|
|
8
|
+
export const META_SMPTE_OFFSET_ = 0x54;
|
|
9
|
+
export const META_TIME_SIGNATURE_ = 0x58;
|
|
10
|
+
export const META_KEY_SIGNATURE_ = 0x59;
|
|
11
|
+
export const META_SEQUENCER_SPECIFIC_ = 0x7f;
|
|
12
|
+
export const TEXT_META_TYPES_ = {
|
|
13
|
+
0x01: "text",
|
|
14
|
+
0x02: "copyright",
|
|
15
|
+
0x03: "trackName",
|
|
16
|
+
0x04: "instrumentName",
|
|
17
|
+
0x05: "lyric",
|
|
18
|
+
0x06: "marker",
|
|
19
|
+
0x07: "cuePoint",
|
|
20
|
+
0x08: "programName",
|
|
21
|
+
0x09: "deviceName",
|
|
22
|
+
};
|
|
23
|
+
export const TEXT_META_CODES_ = {
|
|
24
|
+
text: 0x01,
|
|
25
|
+
copyright: 0x02,
|
|
26
|
+
trackName: 0x03,
|
|
27
|
+
instrumentName: 0x04,
|
|
28
|
+
lyric: 0x05,
|
|
29
|
+
marker: 0x06,
|
|
30
|
+
cuePoint: 0x07,
|
|
31
|
+
programName: 0x08,
|
|
32
|
+
deviceName: 0x09,
|
|
33
|
+
};
|
|
34
|
+
/** Every meta type a member other than `unknown` spells. */
|
|
35
|
+
export const KNOWN_META_TYPES_ = new Set([
|
|
36
|
+
META_SEQUENCE_NUMBER_,
|
|
37
|
+
...Object.values(TEXT_META_CODES_),
|
|
38
|
+
META_CHANNEL_PREFIX_,
|
|
39
|
+
META_MIDI_PORT_,
|
|
40
|
+
META_END_OF_TRACK_,
|
|
41
|
+
META_SET_TEMPO_,
|
|
42
|
+
META_SMPTE_OFFSET_,
|
|
43
|
+
META_TIME_SIGNATURE_,
|
|
44
|
+
META_KEY_SIGNATURE_,
|
|
45
|
+
META_SEQUENCER_SPECIFIC_,
|
|
46
|
+
]);
|
|
47
|
+
/**
|
|
48
|
+
* SMPTE frame rates by the 2-bit code in bits 5–6 of an SMPTE Offset's hour
|
|
49
|
+
* byte.
|
|
50
|
+
*/
|
|
51
|
+
export const SMPTE_FRAME_RATES_ = [24, 25, 29, 30];
|
|
52
|
+
//# sourceMappingURL=_meta-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_meta-types.js","sourceRoot":"","sources":["../../src/file/_meta-types.ts"],"names":[],"mappings":"AAOA,+EAA+E;AAC/E,+DAA+D;AAC/D,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAC1C,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC;AACzC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;AACpC,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AACvC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;AACpC,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AACvC,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC;AACzC,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC;AACxC,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAE7C,MAAM,CAAC,MAAM,gBAAgB,GAA4C;IACxE,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,gBAAgB;IACtB,IAAI,EAAE,OAAO;IACb,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,aAAa;IACnB,IAAI,EAAE,YAAY;CAClB,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC/B,IAAI,EAAE,IAAI;IACV,SAAS,EAAE,IAAI;IACf,SAAS,EAAE,IAAI;IACf,cAAc,EAAE,IAAI;IACpB,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,QAAQ,EAAE,IAAI;IACd,WAAW,EAAE,IAAI;IACjB,UAAU,EAAE,IAAI;CACiC,CAAC;AAEnD,4DAA4D;AAC5D,MAAM,CAAC,MAAM,iBAAiB,GAAwB,IAAI,GAAG,CAAC;IAC7D,qBAAqB;IACrB,GAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC;IAClC,oBAAoB;IACpB,eAAe;IACf,kBAAkB;IAClB,eAAe;IACf,kBAAkB;IAClB,oBAAoB;IACpB,mBAAmB;IACnB,wBAAwB;CACxB,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAU,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { MidiChannelMessage } from "../message/midi-message.js";
|
|
2
|
+
import type { MidiMetaEvent } from "./midi-meta-event.js";
|
|
3
|
+
/**
|
|
4
|
+
* How a Standard MIDI File counts time in its delta times.
|
|
5
|
+
*
|
|
6
|
+
* - `metrical` — ticks per quarter note, so a tick's length follows the tempo.
|
|
7
|
+
* - `timecode` — ticks per SMPTE frame, independent of tempo. A `framesPerSecond`
|
|
8
|
+
* of 29 means 30 drop-frame, 29.97 frames per second.
|
|
9
|
+
*/
|
|
10
|
+
export type MidiTimeDivision = {
|
|
11
|
+
type: "metrical";
|
|
12
|
+
/** 1–32767. */
|
|
13
|
+
ticksPerQuarterNote: number;
|
|
14
|
+
} | {
|
|
15
|
+
type: "timecode";
|
|
16
|
+
framesPerSecond: 24 | 25 | 29 | 30;
|
|
17
|
+
/** 1–255. */
|
|
18
|
+
ticksPerFrame: number;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* One event of a track, with the bytes it was stored as.
|
|
22
|
+
*
|
|
23
|
+
* - `channel` — a channel message, stored without running status or with it.
|
|
24
|
+
* - `sysEx` — an F0 event: `data` is the stored bytes after the length, which
|
|
25
|
+
* normally end with F7. A SysEx split over several events has its first part
|
|
26
|
+
* here and the rest in `sysExEscape` events.
|
|
27
|
+
* - `sysExEscape` — an F7 event: `data` is sent as is, which carries a SysEx
|
|
28
|
+
* continuation or any bytes not otherwise expressible, real-time ones
|
|
29
|
+
* included.
|
|
30
|
+
* - `meta` — a meta event (FF), never sent to a device.
|
|
31
|
+
*/
|
|
32
|
+
export type MidiFileEvent = {
|
|
33
|
+
kind: "channel";
|
|
34
|
+
message: MidiChannelMessage;
|
|
35
|
+
} | {
|
|
36
|
+
kind: "sysEx";
|
|
37
|
+
data: Uint8Array;
|
|
38
|
+
} | {
|
|
39
|
+
kind: "sysExEscape";
|
|
40
|
+
data: Uint8Array;
|
|
41
|
+
} | {
|
|
42
|
+
kind: "meta";
|
|
43
|
+
meta: MidiMetaEvent;
|
|
44
|
+
};
|
|
45
|
+
/** An event and the ticks elapsed since the previous one in its track. */
|
|
46
|
+
export type MidiTrackEvent = {
|
|
47
|
+
/** 0–268 435 455 (0x0FFFFFFF), the most a 4-byte quantity holds. */
|
|
48
|
+
deltaTime: number;
|
|
49
|
+
event: MidiFileEvent;
|
|
50
|
+
};
|
|
51
|
+
/** One `MTrk` chunk. */
|
|
52
|
+
export type MidiTrack = {
|
|
53
|
+
/** In file order. A well-formed track ends with an `endOfTrack` meta event. */
|
|
54
|
+
events: MidiTrackEvent[];
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* A Standard MIDI File (RP-001).
|
|
58
|
+
*
|
|
59
|
+
* `format` says how the tracks relate: 0 is a single track holding every
|
|
60
|
+
* channel, 1 is simultaneous tracks played together, 2 is independent
|
|
61
|
+
* single-track sequences.
|
|
62
|
+
*/
|
|
63
|
+
export type MidiFile = {
|
|
64
|
+
format: 0 | 1 | 2;
|
|
65
|
+
timeDivision: MidiTimeDivision;
|
|
66
|
+
tracks: MidiTrack[];
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=midi-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"midi-file.d.ts","sourceRoot":"","sources":["../../src/file/midi-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GACzB;IACA,IAAI,EAAE,UAAU,CAAC;IACjB,eAAe;IACf,mBAAmB,EAAE,MAAM,CAAC;CAC3B,GACD;IACA,IAAI,EAAE,UAAU,CAAC;IACjB,eAAe,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IACnC,aAAa;IACb,aAAa,EAAE,MAAM,CAAC;CACrB,CAAC;AAEL;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,aAAa,GACtB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC;AAEzC,0EAA0E;AAC1E,MAAM,MAAM,cAAc,GAAG;IAC5B,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,aAAa,CAAC;CACrB,CAAC;AAEF,wBAAwB;AACxB,MAAM,MAAM,SAAS,GAAG;IACvB,+EAA+E;IAC/E,MAAM,EAAE,cAAc,EAAE,CAAC;CACzB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,GAAG;IACtB,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClB,YAAY,EAAE,gBAAgB,CAAC;IAC/B,MAAM,EAAE,SAAS,EAAE,CAAC;CACpB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"midi-file.js","sourceRoot":"","sources":["../../src/file/midi-file.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A meta event of a Standard MIDI File track (RP-001), discriminated by `type`.
|
|
3
|
+
*
|
|
4
|
+
* The text events keep their bytes: the standard does not say which character
|
|
5
|
+
* encoding they use, and files in the wild use ASCII, Latin-1, Shift JIS and
|
|
6
|
+
* UTF-8 alike. Decode them with the encoding the file is known to use.
|
|
7
|
+
*/
|
|
8
|
+
export type MidiMetaEvent = {
|
|
9
|
+
type: "sequenceNumber";
|
|
10
|
+
/**
|
|
11
|
+
* 0–65535, or `undefined` for the zero-length form, which numbers the
|
|
12
|
+
* sequence by its position in the file.
|
|
13
|
+
*/
|
|
14
|
+
number: number | undefined;
|
|
15
|
+
} | {
|
|
16
|
+
type: "text" | "copyright" | "trackName" | "instrumentName" | "lyric" | "marker" | "cuePoint" | "programName" | "deviceName";
|
|
17
|
+
/** The text, in an unspecified encoding. */
|
|
18
|
+
data: Uint8Array;
|
|
19
|
+
} | {
|
|
20
|
+
type: "channelPrefix";
|
|
21
|
+
/** 0–15: the channel the following SysEx and meta events relate to. */
|
|
22
|
+
channel: number;
|
|
23
|
+
} | {
|
|
24
|
+
type: "midiPort";
|
|
25
|
+
/** 0–255: the output port the track's events go to. */
|
|
26
|
+
port: number;
|
|
27
|
+
} | {
|
|
28
|
+
type: "endOfTrack";
|
|
29
|
+
} | {
|
|
30
|
+
type: "setTempo";
|
|
31
|
+
/** Length of a quarter note, 0–16 777 215 µs; 500 000 is 120 bpm. */
|
|
32
|
+
microsecondsPerQuarterNote: number;
|
|
33
|
+
} | {
|
|
34
|
+
type: "smpteOffset";
|
|
35
|
+
/** Frame rate, encoded in the hour byte; 29 means 30 drop-frame (29.97). */
|
|
36
|
+
frameRate: 24 | 25 | 29 | 30;
|
|
37
|
+
/** 0–23 in practice; 0–31 fits the hour byte. */
|
|
38
|
+
hours: number;
|
|
39
|
+
/** 0–59 in practice; 0–255 fits the byte. */
|
|
40
|
+
minutes: number;
|
|
41
|
+
/** 0–59 in practice; 0–255 fits the byte. */
|
|
42
|
+
seconds: number;
|
|
43
|
+
/** Below the frame rate in practice; 0–255 fits the byte. */
|
|
44
|
+
frames: number;
|
|
45
|
+
/** Hundredths of a frame, 0–99 in practice; 0–255 fits the byte. */
|
|
46
|
+
fractionalFrames: number;
|
|
47
|
+
} | {
|
|
48
|
+
type: "timeSignature";
|
|
49
|
+
/** Beats per bar, 0–255. */
|
|
50
|
+
numerator: number;
|
|
51
|
+
/** The beat's note value as a power of two: 2 is a quarter note. */
|
|
52
|
+
denominatorPower: number;
|
|
53
|
+
/** MIDI clocks (24 per quarter note) per metronome click, 0–255. */
|
|
54
|
+
clocksPerClick: number;
|
|
55
|
+
/** Notated 32nd notes per MIDI quarter note, normally 8. */
|
|
56
|
+
thirtySecondNotesPerQuarter: number;
|
|
57
|
+
} | {
|
|
58
|
+
type: "keySignature";
|
|
59
|
+
/** Sharps when positive, flats when negative, -7–7. */
|
|
60
|
+
sharpsFlats: number;
|
|
61
|
+
/** Whether the key is minor rather than major. */
|
|
62
|
+
minor: boolean;
|
|
63
|
+
} | {
|
|
64
|
+
type: "sequencerSpecific";
|
|
65
|
+
/** The payload, manufacturer ID first. */
|
|
66
|
+
data: Uint8Array;
|
|
67
|
+
} | {
|
|
68
|
+
type: "unknown";
|
|
69
|
+
/** A meta type, 0–127, that none of the other members spells. */
|
|
70
|
+
metaType: number;
|
|
71
|
+
/** The payload, as stored. */
|
|
72
|
+
data: Uint8Array;
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=midi-meta-event.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"midi-meta-event.d.ts","sourceRoot":"","sources":["../../src/file/midi-meta-event.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GACtB;IACA,IAAI,EAAE,gBAAgB,CAAC;IACvB;;;OAGG;IACH,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B,GACD;IACA,IAAI,EACD,MAAM,GACN,WAAW,GACX,WAAW,GACX,gBAAgB,GAChB,OAAO,GACP,QAAQ,GACR,UAAU,GACV,aAAa,GACb,YAAY,CAAC;IAChB,4CAA4C;IAC5C,IAAI,EAAE,UAAU,CAAC;CAChB,GACD;IACA,IAAI,EAAE,eAAe,CAAC;IACtB,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;CACf,GACD;IACA,IAAI,EAAE,UAAU,CAAC;IACjB,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;CACZ,GACD;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IACA,IAAI,EAAE,UAAU,CAAC;IACjB,qEAAqE;IACrE,0BAA0B,EAAE,MAAM,CAAC;CAClC,GACD;IACA,IAAI,EAAE,aAAa,CAAC;IACpB,4EAA4E;IAC5E,SAAS,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IAC7B,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,gBAAgB,EAAE,MAAM,CAAC;CACxB,GACD;IACA,IAAI,EAAE,eAAe,CAAC;IACtB,4BAA4B;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,gBAAgB,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,cAAc,EAAE,MAAM,CAAC;IACvB,4DAA4D;IAC5D,2BAA2B,EAAE,MAAM,CAAC;CACnC,GACD;IACA,IAAI,EAAE,cAAc,CAAC;IACrB,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,KAAK,EAAE,OAAO,CAAC;CACd,GACD;IACA,IAAI,EAAE,mBAAmB,CAAC;IAC1B,0CAA0C;IAC1C,IAAI,EAAE,UAAU,CAAC;CAChB,GACD;IACA,IAAI,EAAE,SAAS,CAAC;IAChB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,IAAI,EAAE,UAAU,CAAC;CAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"midi-meta-event.js","sourceRoot":"","sources":["../../src/file/midi-meta-event.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { MidiFile } from "./midi-file.js";
|
|
2
|
+
/**
|
|
3
|
+
* Parses a Standard MIDI File (RP-001) into its header and tracks, every event
|
|
4
|
+
* kept with the bytes it was stored as.
|
|
5
|
+
*
|
|
6
|
+
* Tolerates what RP-001 asks readers to tolerate: an `MThd` chunk longer than 6
|
|
7
|
+
* bytes (the extra bytes are skipped) and chunks of an unknown type (skipped
|
|
8
|
+
* whole). Running status is applied within a track and cancelled by SysEx and
|
|
9
|
+
* meta events.
|
|
10
|
+
*
|
|
11
|
+
* Reads the tracks as they are, without repair: the track count in the header
|
|
12
|
+
* is not checked against the `MTrk` chunks present, every `MTrk` chunk becomes
|
|
13
|
+
* a track, and a track that does not end with End of Track — common in files
|
|
14
|
+
* written by hand-rolled tools — is accepted with nothing appended, so
|
|
15
|
+
* {@link printMidiFile} writes it back unchanged.
|
|
16
|
+
*
|
|
17
|
+
* Time complexity: O(n) in `bytes.length`. Memory: O(n); every payload is
|
|
18
|
+
* copied, so the result does not alias `bytes`.
|
|
19
|
+
*
|
|
20
|
+
* @param bytes - The whole file.
|
|
21
|
+
* @returns The file's format, time division and tracks.
|
|
22
|
+
* @throws {MidiFileError} When the file has no `MThd` header, a chunk or event
|
|
23
|
+
* is truncated, a variable-length quantity is overlong or longer than 4
|
|
24
|
+
* bytes, a data byte has no running status, a status byte other than a
|
|
25
|
+
* channel, SysEx or meta one appears in a track, or a known meta event has
|
|
26
|
+
* the wrong length or an out-of-range field.
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseMidiFile(bytes: Uint8Array): MidiFile;
|
|
29
|
+
//# sourceMappingURL=parse-midi-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-midi-file.d.ts","sourceRoot":"","sources":["../../src/file/parse-midi-file.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EACX,QAAQ,EAKR,MAAM,gBAAgB,CAAC;AA6RxB;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,QAAQ,CAuCzD"}
|