@datamoc/mw_games 0.17.0 → 0.18.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 +39 -0
- package/README.md +1 -1
- package/dist/audio/Channels.d.ts +198 -0
- package/dist/audio/Channels.d.ts.map +1 -0
- package/dist/audio/Channels.js +456 -0
- package/dist/audio/Channels.js.map +1 -0
- package/dist/audio/Midi.d.ts +71 -9
- package/dist/audio/Midi.d.ts.map +1 -1
- package/dist/audio/Midi.js +107 -15
- package/dist/audio/Midi.js.map +1 -1
- package/dist/audio/MidiRender.d.ts +57 -0
- package/dist/audio/MidiRender.d.ts.map +1 -0
- package/dist/audio/MidiRender.js +261 -0
- package/dist/audio/MidiRender.js.map +1 -0
- package/dist/audio/SoundFont.d.ts +64 -0
- package/dist/audio/SoundFont.d.ts.map +1 -0
- package/dist/audio/SoundFont.js +219 -0
- package/dist/audio/SoundFont.js.map +1 -0
- package/dist/audio/index.d.ts +9 -2
- package/dist/audio/index.d.ts.map +1 -1
- package/dist/audio/index.js +4 -1
- package/dist/audio/index.js.map +1 -1
- package/dist/mw_games.global.js +10 -10
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
- package/tools/csp.mjs +10 -1
- package/tools/sbom.mjs +3 -1
package/dist/audio/Midi.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { playTone } from './Synth.js';
|
|
2
2
|
const DEFAULT_TEMPO = 500000; // 120 BPM
|
|
3
|
+
/** RPG Maker XP/VX/Ace loop a MIDI from this controller to the end (whole file when absent) */
|
|
4
|
+
const LOOP_CONTROLLER = 111;
|
|
3
5
|
/**
|
|
4
6
|
* Reads format 0/1 Standard MIDI File bytes into a flat, tick-ordered event list.
|
|
5
7
|
*
|
|
@@ -62,6 +64,7 @@ export function parseMidi(data) {
|
|
|
62
64
|
throw new Error('SMPTE-based MIDI timing is not supported');
|
|
63
65
|
const ticksPerQuarter = division;
|
|
64
66
|
const events = [];
|
|
67
|
+
let loopStartTick = null;
|
|
65
68
|
for (let t = 0; t < trackCount; t++) {
|
|
66
69
|
const chunkId = readAscii(4);
|
|
67
70
|
const chunkLength = readUint32();
|
|
@@ -104,11 +107,24 @@ export function parseMidi(data) {
|
|
|
104
107
|
const isNoteOn = type === 0x90 && velocity > 0;
|
|
105
108
|
events.push({ tick, type: isNoteOn ? 'noteOn' : 'noteOff', note, velocity, channel });
|
|
106
109
|
}
|
|
107
|
-
else if (type ===
|
|
108
|
-
|
|
110
|
+
else if (type === 0xb0) {
|
|
111
|
+
const controller = bytes[offset++];
|
|
112
|
+
const value = bytes[offset++];
|
|
113
|
+
events.push({ tick, type: 'control', channel, controller, value });
|
|
114
|
+
if (controller === LOOP_CONTROLLER && loopStartTick === null)
|
|
115
|
+
loopStartTick = tick;
|
|
109
116
|
}
|
|
110
|
-
else if (type === 0xc0
|
|
111
|
-
|
|
117
|
+
else if (type === 0xc0) {
|
|
118
|
+
const program = bytes[offset++];
|
|
119
|
+
events.push({ tick, type: 'program', channel, program });
|
|
120
|
+
}
|
|
121
|
+
else if (type === 0xe0) {
|
|
122
|
+
const lsb = bytes[offset++];
|
|
123
|
+
const msb = bytes[offset++];
|
|
124
|
+
events.push({ tick, type: 'pitchBend', channel, value: ((msb << 7) | lsb) - 8192 });
|
|
125
|
+
}
|
|
126
|
+
else if (type === 0xa0 || type === 0xd0) {
|
|
127
|
+
offset += type === 0xa0 ? 2 : 1; //key and channel pressure: timing only, never voiced
|
|
112
128
|
}
|
|
113
129
|
else {
|
|
114
130
|
throw new Error(`unsupported MIDI status byte 0x${statusByte.toString(16)}`);
|
|
@@ -117,30 +133,105 @@ export function parseMidi(data) {
|
|
|
117
133
|
}
|
|
118
134
|
}
|
|
119
135
|
events.sort((a, b) => a.tick - b.tick);
|
|
120
|
-
return { ticksPerQuarter, events };
|
|
136
|
+
return { ticksPerQuarter, events, loopStartTick };
|
|
137
|
+
}
|
|
138
|
+
/** the file's tempo map: each entry gives the playback time at its tick */
|
|
139
|
+
function tempoMap(file) {
|
|
140
|
+
const map = [{ tick: 0, time: 0, microsecondsPerQuarter: DEFAULT_TEMPO }];
|
|
141
|
+
for (const event of file.events) {
|
|
142
|
+
if (event.type !== 'tempo')
|
|
143
|
+
continue;
|
|
144
|
+
const last = map[map.length - 1];
|
|
145
|
+
map.push({
|
|
146
|
+
tick: event.tick,
|
|
147
|
+
time: last.time + ((event.tick - last.tick) * last.microsecondsPerQuarter) / file.ticksPerQuarter / 1_000_000,
|
|
148
|
+
microsecondsPerQuarter: event.microsecondsPerQuarter,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
return map;
|
|
152
|
+
}
|
|
153
|
+
/** playback seconds at a tick, honouring every tempo change up to it */
|
|
154
|
+
function tickToSeconds(map, ticksPerQuarter, tick) {
|
|
155
|
+
let entry = map[0];
|
|
156
|
+
for (const candidate of map) {
|
|
157
|
+
if (candidate.tick <= tick)
|
|
158
|
+
entry = candidate;
|
|
159
|
+
else
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
return entry.time + ((tick - entry.tick) * entry.microsecondsPerQuarter) / ticksPerQuarter / 1_000_000;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Seconds from the start of playback at which the file loops (its controller-111
|
|
166
|
+
* marker through the file's own tempo map), or null when the file carries no marker
|
|
167
|
+
* and loops from the start instead.
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```ts
|
|
171
|
+
* import { parseMidi, midiLoopStart } from '@datamoc/mw_games/audio';
|
|
172
|
+
*
|
|
173
|
+
* declare const midiBytes: ArrayBuffer;
|
|
174
|
+
*
|
|
175
|
+
* const file = parseMidi(midiBytes);
|
|
176
|
+
* console.log(midiLoopStart(file)); // seconds, or null with no loop marker
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
export function midiLoopStart(file) {
|
|
180
|
+
if (file.loopStartTick === null)
|
|
181
|
+
return null;
|
|
182
|
+
return tickToSeconds(tempoMap(file), file.ticksPerQuarter, file.loopStartTick);
|
|
121
183
|
}
|
|
122
184
|
/**
|
|
123
185
|
* Resolves a parsed file's tick-based events into real-time seconds, honouring tempo
|
|
124
186
|
* changes and pairing each note-on with its matching note-off to find a duration. A
|
|
125
187
|
* note-on with no matching note-off (a malformed or truncated file) still sounds, for a
|
|
126
|
-
* short default duration, rather than being dropped silently.
|
|
188
|
+
* short default duration, rather than being dropped silently. Each note carries the
|
|
189
|
+
* channel voice in effect when it starts (program, bank, combined volume/expression
|
|
190
|
+
* gain, pan), so a sampled renderer can voice it without re-reading the events.
|
|
127
191
|
*/
|
|
128
192
|
export function scheduleMidi(file) {
|
|
193
|
+
const map = tempoMap(file);
|
|
194
|
+
const channels = Array.from({ length: 16 }, () => ({
|
|
195
|
+
program: 0,
|
|
196
|
+
bank: 0,
|
|
197
|
+
volume: 100,
|
|
198
|
+
expression: 127,
|
|
199
|
+
pan: 64,
|
|
200
|
+
}));
|
|
201
|
+
const voiceOf = (channel) => {
|
|
202
|
+
const state = channels[channel] ?? channels[0];
|
|
203
|
+
return {
|
|
204
|
+
program: state.program,
|
|
205
|
+
bank: state.bank,
|
|
206
|
+
gain: (state.volume / 127) * (state.expression / 127),
|
|
207
|
+
pan: (state.pan - 64) / 64,
|
|
208
|
+
};
|
|
209
|
+
};
|
|
129
210
|
const notes = [];
|
|
130
211
|
const active = new Map();
|
|
131
|
-
let tempo = DEFAULT_TEMPO;
|
|
132
|
-
let lastTick = 0;
|
|
133
|
-
let time = 0;
|
|
134
212
|
for (const event of file.events) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (event.type === '
|
|
138
|
-
|
|
213
|
+
if (event.type === 'tempo' || event.type === 'pitchBend')
|
|
214
|
+
continue;
|
|
215
|
+
if (event.type === 'program') {
|
|
216
|
+
(channels[event.channel] ?? channels[0]).program = event.program;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (event.type === 'control') {
|
|
220
|
+
const state = channels[event.channel] ?? channels[0];
|
|
221
|
+
if (event.controller === 0)
|
|
222
|
+
state.bank = event.value;
|
|
223
|
+
else if (event.controller === 7)
|
|
224
|
+
state.volume = event.value;
|
|
225
|
+
else if (event.controller === 10)
|
|
226
|
+
state.pan = event.value;
|
|
227
|
+
else if (event.controller === 11)
|
|
228
|
+
state.expression = event.value;
|
|
139
229
|
continue;
|
|
140
230
|
}
|
|
231
|
+
const time = tickToSeconds(map, file.ticksPerQuarter, event.tick);
|
|
141
232
|
const key = `${event.channel}:${event.note}`;
|
|
142
233
|
if (event.type === 'noteOn') {
|
|
143
|
-
active.set(key, { time, velocity: event.velocity });
|
|
234
|
+
active.set(key, { time, velocity: event.velocity, voice: voiceOf(event.channel) });
|
|
144
235
|
}
|
|
145
236
|
else {
|
|
146
237
|
const start = active.get(key);
|
|
@@ -151,6 +242,7 @@ export function scheduleMidi(file) {
|
|
|
151
242
|
note: event.note,
|
|
152
243
|
velocity: start.velocity,
|
|
153
244
|
channel: event.channel,
|
|
245
|
+
...start.voice,
|
|
154
246
|
});
|
|
155
247
|
active.delete(key);
|
|
156
248
|
}
|
|
@@ -158,7 +250,7 @@ export function scheduleMidi(file) {
|
|
|
158
250
|
}
|
|
159
251
|
for (const [key, start] of active) {
|
|
160
252
|
const [channel, note] = key.split(':').map(Number);
|
|
161
|
-
notes.push({ time: start.time, duration: 0.3, note, velocity: start.velocity, channel });
|
|
253
|
+
notes.push({ time: start.time, duration: 0.3, note, velocity: start.velocity, channel, ...start.voice });
|
|
162
254
|
}
|
|
163
255
|
return notes.sort((a, b) => a.time - b.time);
|
|
164
256
|
}
|
package/dist/audio/Midi.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Midi.js","sourceRoot":"","sources":["../../src/audio/Midi.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Midi.js","sourceRoot":"","sources":["../../src/audio/Midi.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type MidiFile } from './Midi.ts';
|
|
2
|
+
import type { SoundFont } from './SoundFont.ts';
|
|
3
|
+
/**
|
|
4
|
+
* A Standard MIDI File rendered to stereo PCM frames, the same bridge the RPG Maker
|
|
5
|
+
* player crosses with an offline audio context: browsers cannot decode MIDI, so the
|
|
6
|
+
* file is synthesized once, faster than real time, and what comes out is an ordinary
|
|
7
|
+
* buffered track with a loop region, ready for a `Channel`, a seek and a pitch and
|
|
8
|
+
* pan control that MIDI bytes on their own could never answer.
|
|
9
|
+
*
|
|
10
|
+
* Two voicings. With a `SoundFont` every note plays the real instrument sample for
|
|
11
|
+
* its bank, program, key and velocity, with the font's loops, envelope, tuning and
|
|
12
|
+
* pan. Without one a small General MIDI approximation voices it instead: each program
|
|
13
|
+
* family maps to a waveform and envelope recipe and channel 10 is a noise and sine
|
|
14
|
+
* drum kit. Both honour channel volume, expression and pan per note; the synth keeps
|
|
15
|
+
* melody, rhythm and structure while its timbre stays approximate, which is why a
|
|
16
|
+
* SoundFont makes such a difference. Pitch bend is parsed and exposed on the file's
|
|
17
|
+
* events but voiced unbent here.
|
|
18
|
+
*/
|
|
19
|
+
export interface RenderMidiOptions {
|
|
20
|
+
/** voices every note from these samples; without one the built-in synth plays */
|
|
21
|
+
soundfont?: SoundFont | null;
|
|
22
|
+
/** output sample rate in Hz */
|
|
23
|
+
sampleRate?: number;
|
|
24
|
+
/** master level, 0 to 1 */
|
|
25
|
+
gain?: number;
|
|
26
|
+
/** hard cap on rendered seconds; longer tails are cut */
|
|
27
|
+
maxDuration?: number;
|
|
28
|
+
}
|
|
29
|
+
export interface RenderedMidi {
|
|
30
|
+
sampleRate: number;
|
|
31
|
+
left: Float32Array;
|
|
32
|
+
right: Float32Array;
|
|
33
|
+
/** seconds the loop jumps back to: the file's controller-111 marker, else 0 */
|
|
34
|
+
loopStart: number;
|
|
35
|
+
/** seconds the loop wraps from: the end of the render */
|
|
36
|
+
loopEnd: number;
|
|
37
|
+
/** total rendered seconds, equal to loopEnd */
|
|
38
|
+
duration: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Renders a parsed MIDI file to stereo PCM frames: one offline pass, then the result
|
|
42
|
+
* plays, loops, seeks and re-pitches like any decoded track. Deterministic: the same
|
|
43
|
+
* file and options always produce the same frames, so a test can render and assert
|
|
44
|
+
* without any audio hardware.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* import { parseMidi, renderMidiToBuffer } from '@datamoc/mw_games/audio';
|
|
49
|
+
*
|
|
50
|
+
* declare const midiBytes: ArrayBuffer;
|
|
51
|
+
*
|
|
52
|
+
* const rendered = renderMidiToBuffer(parseMidi(midiBytes));
|
|
53
|
+
* console.log(rendered.duration, rendered.loopStart, rendered.loopEnd);
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare function renderMidiToBuffer(file: MidiFile, options?: RenderMidiOptions): RenderedMidi;
|
|
57
|
+
//# sourceMappingURL=MidiRender.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MidiRender.d.ts","sourceRoot":"","sources":["../../src/audio/MidiRender.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,QAAQ,EAAsB,MAAM,WAAW,CAAC;AAC5G,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,gBAAgB,CAAC;AAEhE;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,iBAAiB;IACjC,iFAAiF;IACjF,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7B,+BAA+B;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,YAAY,CAAC;IACpB,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;CACjB;AAMD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,GAAE,iBAAsB,GAAG,YAAY,CAiChG"}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { midiLoopStart, noteToFrequency, scheduleMidi } from './Midi.js';
|
|
2
|
+
const DEFAULT_SAMPLE_RATE = 22050;
|
|
3
|
+
const DEFAULT_MASTER_GAIN = 0.35;
|
|
4
|
+
const DEFAULT_MAX_DURATION = 8 * 60;
|
|
5
|
+
/**
|
|
6
|
+
* Renders a parsed MIDI file to stereo PCM frames: one offline pass, then the result
|
|
7
|
+
* plays, loops, seeks and re-pitches like any decoded track. Deterministic: the same
|
|
8
|
+
* file and options always produce the same frames, so a test can render and assert
|
|
9
|
+
* without any audio hardware.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { parseMidi, renderMidiToBuffer } from '@datamoc/mw_games/audio';
|
|
14
|
+
*
|
|
15
|
+
* declare const midiBytes: ArrayBuffer;
|
|
16
|
+
*
|
|
17
|
+
* const rendered = renderMidiToBuffer(parseMidi(midiBytes));
|
|
18
|
+
* console.log(rendered.duration, rendered.loopStart, rendered.loopEnd);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function renderMidiToBuffer(file, options = {}) {
|
|
22
|
+
const sampleRate = options.sampleRate ?? DEFAULT_SAMPLE_RATE;
|
|
23
|
+
const master = options.gain ?? DEFAULT_MASTER_GAIN;
|
|
24
|
+
const maxDuration = options.maxDuration ?? DEFAULT_MAX_DURATION;
|
|
25
|
+
if (!(sampleRate > 0))
|
|
26
|
+
throw new Error('render sample rate must be positive');
|
|
27
|
+
if (!(master >= 0))
|
|
28
|
+
throw new Error('render gain must not be negative');
|
|
29
|
+
if (!(maxDuration > 0))
|
|
30
|
+
throw new Error('render max duration must be positive');
|
|
31
|
+
const notes = scheduleMidi(file).filter((note) => note.time < maxDuration);
|
|
32
|
+
if (notes.length === 0)
|
|
33
|
+
throw new Error('MIDI file has no notes');
|
|
34
|
+
const tail = notes.reduce((latest, note) => Math.max(latest, note.time + note.duration), 0);
|
|
35
|
+
const duration = Math.min(maxDuration, tail + 1.5);
|
|
36
|
+
const frames = Math.max(1, Math.ceil(duration * sampleRate));
|
|
37
|
+
const left = new Float32Array(frames);
|
|
38
|
+
const right = new Float32Array(frames);
|
|
39
|
+
const loopStart = Math.min(midiLoopStart(file) ?? 0, Math.max(0, duration - 0.1));
|
|
40
|
+
const soundfont = options.soundfont ?? null;
|
|
41
|
+
const voiceCache = new Map();
|
|
42
|
+
for (const note of notes) {
|
|
43
|
+
const startFrame = Math.floor(note.time * sampleRate);
|
|
44
|
+
if (startFrame >= frames)
|
|
45
|
+
continue;
|
|
46
|
+
const peak = master * Math.max(0.02, (note.velocity / 127) * note.gain);
|
|
47
|
+
const voices = soundfont ? sampledVoices(soundfont, voiceCache, note) : [];
|
|
48
|
+
if (voices.length > 0) {
|
|
49
|
+
for (const voice of voices) {
|
|
50
|
+
renderSampled(left, right, sampleRate, note, voice, peak, startFrame, frames);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
renderSynth(left, right, sampleRate, note, peak, startFrame, frames);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return { sampleRate, left, right, loopStart, loopEnd: duration, duration };
|
|
58
|
+
}
|
|
59
|
+
/** layered SoundFont voices for a note, memoized: drums read bank 128 whatever CC0 says */
|
|
60
|
+
function sampledVoices(soundfont, cache, note) {
|
|
61
|
+
const bank = note.channel === 9 ? 128 : note.bank;
|
|
62
|
+
const key = `${bank}:${note.program}:${note.note}:${note.velocity >> 3}`;
|
|
63
|
+
let voices = cache.get(key);
|
|
64
|
+
if (!voices) {
|
|
65
|
+
voices = soundfont.voices(bank, note.program, note.note, note.velocity);
|
|
66
|
+
cache.set(key, voices);
|
|
67
|
+
}
|
|
68
|
+
return voices;
|
|
69
|
+
}
|
|
70
|
+
/** equal-power stereo gains for a pan in -1 (left) to 1 (right) */
|
|
71
|
+
function equalPower(pan) {
|
|
72
|
+
const angle = ((Math.max(-1, Math.min(1, pan)) + 1) * Math.PI) / 4;
|
|
73
|
+
return [Math.cos(angle), Math.sin(angle)];
|
|
74
|
+
}
|
|
75
|
+
/** one sampled voice, mixed additively into the render */
|
|
76
|
+
function renderSampled(left, right, sampleRate, note, voice, peak, startFrame, frameCount) {
|
|
77
|
+
const data = voice.sample.data;
|
|
78
|
+
if (data.length === 0)
|
|
79
|
+
return;
|
|
80
|
+
const ratio = 2 ** (((note.note - voice.rootKey) * 100 + voice.cents) / 1200);
|
|
81
|
+
const step = (ratio * voice.sample.rate) / sampleRate;
|
|
82
|
+
if (!(step > 0))
|
|
83
|
+
return;
|
|
84
|
+
const endTime = note.time + note.duration;
|
|
85
|
+
const attack = Math.max(0.002, voice.attack);
|
|
86
|
+
const decayEnd = attack + voice.hold + Math.min(voice.decay, 30);
|
|
87
|
+
const release = Math.max(0.03, Math.min(voice.release, 4));
|
|
88
|
+
const sampleSeconds = data.length / voice.sample.rate;
|
|
89
|
+
//Drums ignore note-off: the sample rings out. Melodic voices release at note-off.
|
|
90
|
+
const heldUntil = note.channel === 9
|
|
91
|
+
? Math.max(endTime, note.time + Math.min(2, sampleSeconds))
|
|
92
|
+
: Math.max(endTime, note.time + attack);
|
|
93
|
+
const heldLen = heldUntil - note.time;
|
|
94
|
+
const level = peak * voice.gain;
|
|
95
|
+
const sustainLevel = level * voice.sustain;
|
|
96
|
+
const [gainLeft, gainRight] = equalPower(note.pan + voice.pan);
|
|
97
|
+
const looping = voice.loop && voice.sample.loopEnd > voice.sample.loopStart;
|
|
98
|
+
const loopSpan = voice.sample.loopEnd - voice.sample.loopStart;
|
|
99
|
+
const lastFrame = Math.min(frameCount, startFrame + Math.ceil((heldUntil + release + 0.02 - note.time) * sampleRate));
|
|
100
|
+
let position = 0;
|
|
101
|
+
for (let frame = startFrame; frame < lastFrame; frame++) {
|
|
102
|
+
const t = frame / sampleRate - note.time;
|
|
103
|
+
let envelope;
|
|
104
|
+
if (t < attack)
|
|
105
|
+
envelope = level * (t / attack);
|
|
106
|
+
else if (t < attack + voice.hold)
|
|
107
|
+
envelope = level;
|
|
108
|
+
else if (t < decayEnd) {
|
|
109
|
+
envelope =
|
|
110
|
+
level +
|
|
111
|
+
(sustainLevel - level) * ((t - attack - voice.hold) / Math.max(1e-6, decayEnd - attack - voice.hold));
|
|
112
|
+
}
|
|
113
|
+
else if (t < heldLen)
|
|
114
|
+
envelope = sustainLevel;
|
|
115
|
+
else if (t < heldLen + release)
|
|
116
|
+
envelope = sustainLevel * (1 - (t - heldLen) / release);
|
|
117
|
+
else
|
|
118
|
+
envelope = 0;
|
|
119
|
+
if (looping && position >= voice.sample.loopEnd) {
|
|
120
|
+
position = voice.sample.loopStart + ((position - voice.sample.loopStart) % loopSpan);
|
|
121
|
+
}
|
|
122
|
+
const floored = Math.floor(position);
|
|
123
|
+
const frac = Math.min(1, Math.max(0, position - floored));
|
|
124
|
+
let value;
|
|
125
|
+
if ((!looping && position >= data.length) || floored < 0)
|
|
126
|
+
value = 0;
|
|
127
|
+
else {
|
|
128
|
+
const first = data[Math.min(floored, data.length - 1)];
|
|
129
|
+
const second = data[Math.min(floored + 1, data.length - 1)];
|
|
130
|
+
value = first + (second - first) * frac;
|
|
131
|
+
}
|
|
132
|
+
left[frame] += value * envelope * gainLeft;
|
|
133
|
+
right[frame] += value * envelope * gainRight;
|
|
134
|
+
position += step;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** program family to synthesis recipe: pianos pluck, organs hold, strings swell */
|
|
138
|
+
function recipeFor(program) {
|
|
139
|
+
if (program < 8)
|
|
140
|
+
return { wave: 'triangle', attack: 0.005, decay: 1.2, sustain: 0.25, release: 0.2, detune: 0 };
|
|
141
|
+
if (program < 16)
|
|
142
|
+
return { wave: 'sine', attack: 0.003, decay: 0.8, sustain: 0.1, release: 0.5, detune: 0 };
|
|
143
|
+
if (program < 24) {
|
|
144
|
+
return { wave: 'square', attack: 0.01, decay: 0.1, sustain: 0.7, release: 0.08, detune: 0, cutoff: 2500 };
|
|
145
|
+
}
|
|
146
|
+
if (program < 32) {
|
|
147
|
+
return { wave: 'sawtooth', attack: 0.004, decay: 0.6, sustain: 0.15, release: 0.15, detune: 0, cutoff: 3000 };
|
|
148
|
+
}
|
|
149
|
+
if (program < 40)
|
|
150
|
+
return { wave: 'triangle', attack: 0.005, decay: 0.4, sustain: 0.5, release: 0.1, detune: 0 };
|
|
151
|
+
if (program < 56) {
|
|
152
|
+
return { wave: 'sawtooth', attack: 0.12, decay: 0.2, sustain: 0.8, release: 0.3, detune: 6, cutoff: 3500 };
|
|
153
|
+
}
|
|
154
|
+
if (program < 80) {
|
|
155
|
+
return { wave: 'sawtooth', attack: 0.04, decay: 0.15, sustain: 0.75, release: 0.12, detune: 0, cutoff: 4500 };
|
|
156
|
+
}
|
|
157
|
+
if (program < 88) {
|
|
158
|
+
return { wave: 'square', attack: 0.01, decay: 0.1, sustain: 0.8, release: 0.1, detune: 0, cutoff: 3800 };
|
|
159
|
+
}
|
|
160
|
+
if (program < 104) {
|
|
161
|
+
return { wave: 'sawtooth', attack: 0.25, decay: 0.3, sustain: 0.7, release: 0.5, detune: 8, cutoff: 2200 };
|
|
162
|
+
}
|
|
163
|
+
return { wave: 'triangle', attack: 0.005, decay: 0.5, sustain: 0.2, release: 0.2, detune: 0 };
|
|
164
|
+
}
|
|
165
|
+
function oscillate(wave, phase) {
|
|
166
|
+
switch (wave) {
|
|
167
|
+
case 'sine':
|
|
168
|
+
return Math.sin(phase);
|
|
169
|
+
case 'square':
|
|
170
|
+
return Math.sin(phase) >= 0 ? 1 : -1;
|
|
171
|
+
case 'sawtooth': {
|
|
172
|
+
const cycles = phase / (2 * Math.PI);
|
|
173
|
+
return 2 * (cycles - Math.floor(cycles)) - 1;
|
|
174
|
+
}
|
|
175
|
+
case 'triangle': {
|
|
176
|
+
const cycles = phase / (2 * Math.PI);
|
|
177
|
+
return 4 * Math.abs(cycles - Math.floor(cycles) - 0.5) - 1;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/** attack-decay-sustain-release level multiplier, 0 to 1, for a note held `held` seconds */
|
|
182
|
+
function adsr(t, attack, decay, sustain, held, release) {
|
|
183
|
+
if (t < attack)
|
|
184
|
+
return t / attack;
|
|
185
|
+
if (t < attack + decay)
|
|
186
|
+
return 1 - (1 - sustain) * ((t - attack) / Math.max(1e-6, decay));
|
|
187
|
+
if (t < held)
|
|
188
|
+
return sustain;
|
|
189
|
+
if (t < held + release)
|
|
190
|
+
return sustain * (1 - (t - held) / release);
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
/** deterministic pseudo-random sample in [-1, 1]: the same seed always gives the same noise */
|
|
194
|
+
function noiseAt(seed, index) {
|
|
195
|
+
let h = Math.imul(seed ^ index, 2654435761) >>> 0;
|
|
196
|
+
h = Math.imul(h ^ (h >>> 15), 2246822519) >>> 0;
|
|
197
|
+
h = Math.imul(h ^ (h >>> 13), 3266489917) >>> 0;
|
|
198
|
+
h ^= h >>> 16;
|
|
199
|
+
return ((h >>> 0) / 4294967295) * 2 - 1;
|
|
200
|
+
}
|
|
201
|
+
/** one built-in synth voice, or the drum kit on channel 10, mixed additively */
|
|
202
|
+
function renderSynth(left, right, sampleRate, note, peak, startFrame, frameCount) {
|
|
203
|
+
if (note.channel === 9) {
|
|
204
|
+
renderDrum(left, right, sampleRate, note, peak, startFrame, frameCount);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const recipe = recipeFor(note.program);
|
|
208
|
+
const frequency = noteToFrequency(note.note) * 2 ** (recipe.detune / 1200);
|
|
209
|
+
const held = Math.max(note.duration, recipe.attack + 0.01);
|
|
210
|
+
const release = Math.max(0.02, recipe.release);
|
|
211
|
+
const lastFrame = Math.min(frameCount, startFrame + Math.ceil((held + release + 0.02) * sampleRate));
|
|
212
|
+
const [gainLeft, gainRight] = equalPower(note.pan);
|
|
213
|
+
const filtered = recipe.cutoff !== undefined;
|
|
214
|
+
const coefficient = filtered
|
|
215
|
+
? 1 - Math.exp((-2 * Math.PI * Math.min(recipe.cutoff, frequency * 8 + 800)) / sampleRate)
|
|
216
|
+
: 0;
|
|
217
|
+
let lowpass = 0;
|
|
218
|
+
let phase = 0;
|
|
219
|
+
const phaseStep = (2 * Math.PI * frequency) / sampleRate;
|
|
220
|
+
for (let frame = startFrame; frame < lastFrame; frame++) {
|
|
221
|
+
const t = frame / sampleRate - note.time;
|
|
222
|
+
const value = oscillate(recipe.wave, phase);
|
|
223
|
+
phase += phaseStep;
|
|
224
|
+
lowpass = filtered ? lowpass + coefficient * (value - lowpass) : value;
|
|
225
|
+
const envelope = peak * adsr(t, recipe.attack, recipe.decay, recipe.sustain, held, release);
|
|
226
|
+
left[frame] += lowpass * envelope * gainLeft;
|
|
227
|
+
right[frame] += lowpass * envelope * gainRight;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/** channel 10: kicks thump, snares and hats hiss, keyed by General MIDI drum note */
|
|
231
|
+
function renderDrum(left, right, sampleRate, note, peak, startFrame, frameCount) {
|
|
232
|
+
const [gainLeft, gainRight] = equalPower(note.pan);
|
|
233
|
+
const seed = note.note * 7919 + startFrame;
|
|
234
|
+
if (note.note === 35 || note.note === 36 || note.note < 45) {
|
|
235
|
+
//Kick: a sine dropping 150 Hz to 45 Hz, decaying exponentially.
|
|
236
|
+
const level = peak * 1.4;
|
|
237
|
+
const lastFrame = Math.min(frameCount, startFrame + Math.ceil(0.27 * sampleRate));
|
|
238
|
+
let phase = 0;
|
|
239
|
+
for (let frame = startFrame; frame < lastFrame; frame++) {
|
|
240
|
+
const t = frame / sampleRate - note.time;
|
|
241
|
+
const frequency = t < 0.12 ? 150 * (45 / 150) ** (t / 0.12) : 45;
|
|
242
|
+
phase += (2 * Math.PI * frequency) / sampleRate;
|
|
243
|
+
const envelope = level * (0.001 / level) ** Math.min(1, t / 0.22);
|
|
244
|
+
left[frame] += Math.sin(phase) * envelope * gainLeft;
|
|
245
|
+
right[frame] += Math.sin(phase) * envelope * gainRight;
|
|
246
|
+
}
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const snare = note.note === 38 || note.note === 40;
|
|
250
|
+
const length = snare ? 0.16 : note.note >= 49 ? 0.5 : 0.06;
|
|
251
|
+
const level = peak * (snare ? 0.9 : 0.5);
|
|
252
|
+
const lastFrame = Math.min(frameCount, startFrame + Math.ceil((length + 0.02) * sampleRate));
|
|
253
|
+
for (let frame = startFrame; frame < lastFrame; frame++) {
|
|
254
|
+
const t = frame / sampleRate - note.time;
|
|
255
|
+
const envelope = level * (0.001 / level) ** Math.min(1, t / length);
|
|
256
|
+
const value = noiseAt(seed, frame - startFrame) * envelope;
|
|
257
|
+
left[frame] += value * gainLeft;
|
|
258
|
+
right[frame] += value * gainRight;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=MidiRender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MidiRender.js","sourceRoot":"","sources":["../../src/audio/MidiRender.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A SoundFont 2 reader: presets to instruments to sample zones, enough to play
|
|
3
|
+
* General MIDI music with real samples. Supported: key and velocity ranges, root key
|
|
4
|
+
* and tuning, sample loop modes, the volume envelope (attack, hold, decay, sustain,
|
|
5
|
+
* release), pan and attenuation, with the global-zone and preset-plus-instrument
|
|
6
|
+
* layering rules. Not supported: modulators, filters and LFOs, 24-bit samples, or
|
|
7
|
+
* stereo-linked sample pairs beyond playing each side as its own mono voice.
|
|
8
|
+
*
|
|
9
|
+
* A SoundFont file is only data (recorded samples plus preset tables), so reading one
|
|
10
|
+
* is ordinary format engineering; the licence that matters is the font's own, checked
|
|
11
|
+
* before it ships, never here.
|
|
12
|
+
*/
|
|
13
|
+
/** one mono sample: raw frames plus its loop region in frames and native rate */
|
|
14
|
+
export interface SoundFontSample {
|
|
15
|
+
data: Float32Array;
|
|
16
|
+
rate: number;
|
|
17
|
+
loopStart: number;
|
|
18
|
+
loopEnd: number;
|
|
19
|
+
}
|
|
20
|
+
/** how one layered voice plays its sample for a note */
|
|
21
|
+
export interface SoundFontVoice {
|
|
22
|
+
sample: SoundFontSample;
|
|
23
|
+
rootKey: number;
|
|
24
|
+
/** tuning offset in cents, applied on top of the root key */
|
|
25
|
+
cents: number;
|
|
26
|
+
loop: boolean;
|
|
27
|
+
/** linear level multiplier from attenuation layering */
|
|
28
|
+
gain: number;
|
|
29
|
+
/** stereo position, -1 (left) to 1 (right) */
|
|
30
|
+
pan: number;
|
|
31
|
+
/** envelope stages in seconds, except sustain which is a level multiplier */
|
|
32
|
+
attack: number;
|
|
33
|
+
hold: number;
|
|
34
|
+
decay: number;
|
|
35
|
+
sustain: number;
|
|
36
|
+
release: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The samples behind a SoundFont file: one call per note returns the layered voices
|
|
40
|
+
* for its bank, program, key and velocity. A game ships its own file (parsed here)
|
|
41
|
+
* and hands the result wherever samples are needed; nothing here fetches or picks one.
|
|
42
|
+
*/
|
|
43
|
+
export interface SoundFont {
|
|
44
|
+
voices(bank: number, program: number, key: number, velocity: number): SoundFontVoice[];
|
|
45
|
+
hasPreset(bank: number, program: number): boolean;
|
|
46
|
+
readonly presetCount: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Reads SoundFont 2 bytes into layered preset voices.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* import { parseSoundFont, parseMidi, renderMidiToBuffer } from '@datamoc/mw_games/audio';
|
|
54
|
+
*
|
|
55
|
+
* declare const soundfontBytes: ArrayBuffer;
|
|
56
|
+
* declare const midiBytes: ArrayBuffer;
|
|
57
|
+
*
|
|
58
|
+
* const font = parseSoundFont(soundfontBytes);
|
|
59
|
+
* const rendered = renderMidiToBuffer(parseMidi(midiBytes), { soundfont: font });
|
|
60
|
+
* console.log(font.presetCount, rendered.duration);
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare function parseSoundFont(data: ArrayBuffer | ArrayBufferView): SoundFont;
|
|
64
|
+
//# sourceMappingURL=SoundFont.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SoundFont.d.ts","sourceRoot":"","sources":["../../src/audio/SoundFont.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAoBH,iFAAiF;AACjF,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CAChB;AAQD,wDAAwD;AACxD,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACzB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,EAAE,CAAC;IACvF,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAClD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAmBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,eAAe,GAAG,SAAS,CA6L7E"}
|