@datamoc/mw_games 0.17.1 → 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.
@@ -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"}
@@ -0,0 +1,219 @@
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
+ const GENERATORS = {
14
+ keyRange: 43,
15
+ velRange: 44,
16
+ instrument: 41,
17
+ sampleId: 53,
18
+ rootKey: 58,
19
+ coarseTune: 51,
20
+ fineTune: 52,
21
+ sampleModes: 54,
22
+ attenuation: 48,
23
+ pan: 17,
24
+ attack: 34,
25
+ hold: 35,
26
+ decay: 36,
27
+ sustain: 37,
28
+ release: 38,
29
+ };
30
+ /** seconds for a SoundFont timecents value */
31
+ function timecents(value) {
32
+ return 2 ** (value / 1200);
33
+ }
34
+ /**
35
+ * Reads SoundFont 2 bytes into layered preset voices.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * import { parseSoundFont, parseMidi, renderMidiToBuffer } from '@datamoc/mw_games/audio';
40
+ *
41
+ * declare const soundfontBytes: ArrayBuffer;
42
+ * declare const midiBytes: ArrayBuffer;
43
+ *
44
+ * const font = parseSoundFont(soundfontBytes);
45
+ * const rendered = renderMidiToBuffer(parseMidi(midiBytes), { soundfont: font });
46
+ * console.log(font.presetCount, rendered.duration);
47
+ * ```
48
+ */
49
+ export function parseSoundFont(data) {
50
+ const bytes = data instanceof ArrayBuffer
51
+ ? new Uint8Array(data)
52
+ : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
53
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
54
+ const fourcc = (at) => String.fromCharCode(bytes[at], bytes[at + 1], bytes[at + 2], bytes[at + 3]);
55
+ if (fourcc(0) !== 'RIFF' || fourcc(8) !== 'sfbk')
56
+ throw new Error('not a SoundFont 2 file');
57
+ const chunks = new Map();
58
+ const walk = (start, end) => {
59
+ let at = start;
60
+ while (at + 8 <= end) {
61
+ const id = fourcc(at);
62
+ const size = view.getUint32(at + 4, true);
63
+ if (id === 'LIST')
64
+ walk(at + 12, at + 8 + size);
65
+ else
66
+ chunks.set(id, { at: at + 8, size });
67
+ at += 8 + size + (size & 1);
68
+ }
69
+ };
70
+ walk(12, bytes.length);
71
+ for (const required of ['phdr', 'pbag', 'pgen', 'inst', 'ibag', 'igen', 'shdr', 'smpl']) {
72
+ if (!chunks.has(required))
73
+ throw new Error(`SoundFont is missing "${required}"`);
74
+ }
75
+ const records = (name, size, read) => {
76
+ const chunk = chunks.get(name);
77
+ const out = [];
78
+ for (let at = chunk.at; at + size <= chunk.at + chunk.size; at += size)
79
+ out.push(read(at));
80
+ return out;
81
+ };
82
+ const generators = (name) => records(name, 4, (at) => ({
83
+ oper: view.getUint16(at, true),
84
+ lo: bytes[at + 2],
85
+ hi: bytes[at + 3],
86
+ amount: view.getInt16(at + 2, true),
87
+ }));
88
+ const bags = (name) => records(name, 4, (at) => view.getUint16(at, true));
89
+ const presetHeaders = records('phdr', 38, (at) => ({
90
+ preset: view.getUint16(at + 20, true),
91
+ bank: view.getUint16(at + 22, true),
92
+ bag: view.getUint16(at + 24, true),
93
+ }));
94
+ const instrumentHeaders = records('inst', 22, (at) => ({ bag: view.getUint16(at + 20, true) }));
95
+ const sampleHeaders = records('shdr', 46, (at) => ({
96
+ start: view.getUint32(at + 20, true),
97
+ end: view.getUint32(at + 24, true),
98
+ loopStart: view.getUint32(at + 28, true),
99
+ loopEnd: view.getUint32(at + 32, true),
100
+ rate: view.getUint32(at + 36, true),
101
+ rootKey: bytes[at + 40],
102
+ correction: view.getInt8(at + 41),
103
+ type: view.getUint16(at + 44, true),
104
+ }));
105
+ const presetBags = bags('pbag');
106
+ const instrumentBags = bags('ibag');
107
+ const presetGens = generators('pgen');
108
+ const instrumentGens = generators('igen');
109
+ //Zones of one header entry; a first zone lacking the terminal generator is global.
110
+ const zonesOf = (headers, bagList, gens, index, terminal) => {
111
+ const first = headers[index].bag;
112
+ const last = headers[index + 1]?.bag ?? bagList.length - 1;
113
+ const zones = [];
114
+ let global = null;
115
+ for (let bag = first; bag < last; bag++) {
116
+ const map = new Map();
117
+ for (let g = bagList[bag]; g < (bagList[bag + 1] ?? gens.length); g++) {
118
+ map.set(gens[g].oper, gens[g]);
119
+ }
120
+ if (!map.has(terminal)) {
121
+ if (bag === first)
122
+ global = map;
123
+ continue;
124
+ }
125
+ zones.push({ gens: map, global });
126
+ }
127
+ return zones;
128
+ };
129
+ const generatorOf = (zone, oper) => zone.gens.get(oper) ?? zone.global?.get(oper) ?? null;
130
+ const smplChunk = chunks.get('smpl');
131
+ const smpl = new Int16Array(bytes.buffer.slice(bytes.byteOffset + smplChunk.at, bytes.byteOffset + smplChunk.at + smplChunk.size - (smplChunk.size & 1)));
132
+ const sampleCache = new Map();
133
+ const sampleOf = (id) => {
134
+ if (sampleCache.has(id))
135
+ return sampleCache.get(id);
136
+ const header = sampleHeaders[id];
137
+ //ROM samples live outside the file and cannot play
138
+ if (!header || header.end <= header.start || header.type & 0x8000) {
139
+ sampleCache.set(id, null);
140
+ return null;
141
+ }
142
+ const data = new Float32Array(header.end - header.start);
143
+ for (let index = 0; index < data.length; index++) {
144
+ data[index] = smpl[header.start + index] / 32768;
145
+ }
146
+ const sample = {
147
+ data,
148
+ rate: header.rate || 22050,
149
+ loopStart: header.loopStart - header.start,
150
+ loopEnd: header.loopEnd - header.start,
151
+ rootKey: header.rootKey === 255 ? 60 : header.rootKey,
152
+ correction: header.correction,
153
+ };
154
+ sampleCache.set(id, sample);
155
+ return sample;
156
+ };
157
+ const presets = new Map();
158
+ for (let index = 0; index < presetHeaders.length - 1; index++) {
159
+ presets.set(`${presetHeaders[index].bank}:${presetHeaders[index].preset}`, index);
160
+ }
161
+ //Zones that sound for (bank, program, key, velocity), each with its playback recipe.
162
+ function voices(bank, program, key, velocity) {
163
+ const presetIndex = presets.get(`${bank}:${program}`) ??
164
+ presets.get(`0:${program}`) ??
165
+ (bank === 128 ? presets.get('128:0') : undefined) ??
166
+ presets.get('0:0');
167
+ if (presetIndex === undefined)
168
+ return [];
169
+ const out = [];
170
+ const within = (zone, oper, value) => {
171
+ const generator = generatorOf(zone, oper);
172
+ return !generator || (value >= generator.lo && value <= generator.hi);
173
+ };
174
+ for (const presetZone of zonesOf(presetHeaders, presetBags, presetGens, presetIndex, GENERATORS.instrument)) {
175
+ if (!within(presetZone, GENERATORS.keyRange, key) || !within(presetZone, GENERATORS.velRange, velocity)) {
176
+ continue;
177
+ }
178
+ const instrument = generatorOf(presetZone, GENERATORS.instrument).amount;
179
+ if (!instrumentHeaders[instrument + 1])
180
+ continue;
181
+ for (const zone of zonesOf(instrumentHeaders, instrumentBags, instrumentGens, instrument, GENERATORS.sampleId)) {
182
+ if (!within(zone, GENERATORS.keyRange, key) || !within(zone, GENERATORS.velRange, velocity)) {
183
+ continue;
184
+ }
185
+ const sample = sampleOf(generatorOf(zone, GENERATORS.sampleId).amount);
186
+ if (!sample)
187
+ continue;
188
+ const both = (oper, fallback = 0) => (generatorOf(zone, oper)?.amount ?? fallback) + (generatorOf(presetZone, oper)?.amount ?? 0);
189
+ const root = generatorOf(zone, GENERATORS.rootKey)?.amount;
190
+ const modes = generatorOf(zone, GENERATORS.sampleModes)?.amount ?? 0;
191
+ out.push({
192
+ sample: {
193
+ data: sample.data,
194
+ rate: sample.rate,
195
+ loopStart: sample.loopStart,
196
+ loopEnd: sample.loopEnd,
197
+ },
198
+ rootKey: root !== undefined && root >= 0 ? root : sample.rootKey,
199
+ cents: both(GENERATORS.coarseTune) * 100 + both(GENERATORS.fineTune) + sample.correction,
200
+ loop: (modes & 3) === 1 || (modes & 3) === 3,
201
+ gain: 10 ** (-Math.max(0, both(GENERATORS.attenuation)) / 200),
202
+ pan: Math.max(-1, Math.min(1, both(GENERATORS.pan) / 500)),
203
+ attack: timecents(both(GENERATORS.attack, -12000)),
204
+ hold: timecents(both(GENERATORS.hold, -12000)),
205
+ decay: timecents(both(GENERATORS.decay, -12000)),
206
+ sustain: 10 ** (-Math.max(0, both(GENERATORS.sustain)) / 200),
207
+ release: timecents(both(GENERATORS.release, -12000)),
208
+ });
209
+ }
210
+ }
211
+ return out;
212
+ }
213
+ return {
214
+ voices,
215
+ hasPreset: (bank, program) => presets.has(`${bank}:${program}`) || presets.has(`0:${program}`),
216
+ presetCount: presets.size,
217
+ };
218
+ }
219
+ //# sourceMappingURL=SoundFont.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SoundFont.js","sourceRoot":"","sources":["../../src/audio/SoundFont.ts"],"names":[],"mappings":"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"}
@@ -10,8 +10,15 @@ export { Orchestrator } from './Orchestrator.ts';
10
10
  export type { OrchestratorState } from './Orchestrator.ts';
11
11
  export { synthesizeTone, playTone } from './Synth.ts';
12
12
  export type { Waveform, ToneOptions } from './Synth.ts';
13
- export { parseMidi, scheduleMidi, noteToFrequency, MidiPlayer } from './Midi.ts';
14
- export type { MidiFile, MidiEvent, MidiNoteEvent, MidiTempoEvent, ScheduledNote, MidiPlayerOptions } from './Midi.ts';
13
+ export { parseMidi, scheduleMidi, noteToFrequency, midiLoopStart, MidiPlayer } from './Midi.ts';
14
+ export type { MidiFile, MidiEvent, MidiNoteEvent, MidiTempoEvent, MidiProgramEvent, MidiControlEvent, MidiPitchBendEvent, MidiVoice, ScheduledNote, MidiPlayerOptions, } from './Midi.ts';
15
+ export { renderMidiToBuffer } from './MidiRender.ts';
16
+ export type { RenderMidiOptions, RenderedMidi } from './MidiRender.ts';
17
+ export { parseSoundFont } from './SoundFont.ts';
18
+ export type { SoundFont, SoundFontSample, SoundFontVoice } from './SoundFont.ts';
19
+ export { Channel, AudioBus } from './Channels.ts';
20
+ export type { LoopRegion, ChannelPlayOptions, ChannelState } from './Channels.ts';
21
+ export type { BusKind, BusTrack, SavedBusTrack, LoadedTrack, BusLoader, BusSnapshot, AudioBusOptions, } from './Channels.ts';
15
22
  export { AudioListener, SoundSource, audioGain, audioPan } from './Positional.ts';
16
23
  export type { AudioPoint, AudioFalloff, SoundSourceOptions } from './Positional.ts';
17
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audio/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtD,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACjF,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACtH,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAClF,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audio/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtD,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAChG,YAAY,EACX,QAAQ,EACR,SAAS,EACT,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,iBAAiB,GACjB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACjF,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAClD,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClF,YAAY,EACX,OAAO,EACP,QAAQ,EACR,aAAa,EACb,WAAW,EACX,SAAS,EACT,WAAW,EACX,eAAe,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAClF,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -4,6 +4,9 @@ export { Music } from './Music.js';
4
4
  export { createAudio } from './Playable.js';
5
5
  export { Orchestrator } from './Orchestrator.js';
6
6
  export { synthesizeTone, playTone } from './Synth.js';
7
- export { parseMidi, scheduleMidi, noteToFrequency, MidiPlayer } from './Midi.js';
7
+ export { parseMidi, scheduleMidi, noteToFrequency, midiLoopStart, MidiPlayer } from './Midi.js';
8
+ export { renderMidiToBuffer } from './MidiRender.js';
9
+ export { parseSoundFont } from './SoundFont.js';
10
+ export { Channel, AudioBus } from './Channels.js';
8
11
  export { AudioListener, SoundSource, audioGain, audioPan } from './Positional.js';
9
12
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/audio/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEjF,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/audio/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAahG,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAWlD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC"}