@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.
@@ -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 === 0xa0 || type === 0xb0 || type === 0xe0) {
108
- offset += 2;
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 || type === 0xd0) {
111
- offset += 1;
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
- time += ((event.tick - lastTick) * tempo) / file.ticksPerQuarter / 1_000_000;
136
- lastTick = event.tick;
137
- if (event.type === 'tempo') {
138
- tempo = event.microsecondsPerQuarter;
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
  }
@@ -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"}