-
Notifications
You must be signed in to change notification settings - Fork 12
Writing Wave Files
spessasus edited this page Sep 17, 2024
·
2 revisions
SpessaSynth has a helper function for writing wave files.
Converts an audio buffer into a fully valid wave file.
const file = audioBufferToWav(audioBuffer, normalizeAudio = true, channelOffset = 0, metadata = {}, loop = undefined);
-
audioBuffer
-AudioBuffer
- the buffer to write. -
normalizeAudio
- optionalboolean
- if true, the gain of the entire song will be adjusted so the max sample is always 32767 or min is always -32768 (whichever is greater). Recommended. -
channelOffset
- optionalnumber
- if the buffer has more than 2 channels, you can specify the channel offset to use. This is especially useful in one output mode -
metadata
- optionalObject
described below. All options are string and are optional:-
title
- the song's title -
artist
- the song's artist -
album
- the song's album -
genre
- the song's genre
-
-
loop
- optionalObject
that will write loop points to the file (using thecue
chunk)-
start
- start time in seconds -
end
- end time in seconds
-
The metadata uses the INFO
chunk to write the information. It is encoded with utf-8
This example code shows how to save MIDI to a wav file with loop points.
const parsedMid = new MIDI(midiBinary, "unnamed.mid");
const sampleRate = 44100; // hz
const durationInSamples = sampleRate * parsedMid.duration;
const context = new OfflineAudioContext({
numberOfChannels: 2,
samplerate: sampleRate,
length: durationInSamples
});
// remember to add the module!
await context.audioWorklet.addModule("worklet_processor.min.js");
const synth = new Synthetizer(
context.destination, // play directly to output
soundfontBinary,
false,
{
parsedMIDI: parsedMid,
oneOutput: false,
snapshot: undefined,
loopCount: 0,
},
/*
use the default effects.
NOTE: it is HIGHLY recommended that you provide the impulse response here as mentioned in Synthetizer page,
but it's omitted for simplicity
*/
undefined
);
// start rendering
const buffer = await context.startRendering();
// calculate loop points
// the file skips to the first note on event,
// but the loop points are absolute.
// So we need to adjust them
const startOffset = MIDIticksToSeconds(parsedMid.firstNoteOn, parsedMid);
const loopStart = MIDIticksToSeconds(parsedMid.loop.start, parsedMid) - startOffset;
const loopEnd = MIDIticksToSeconds(parsedMid.loop.end, parsedMid) - startOffset;
// create the WAV file
const wav = audioBufferToWav(
buffer,
true, // normalize audio
0, // channel offset
{ title: parsedMid.midiName }, // add some metadata
{ start: loopStart, end: loopEnd}
);
// save the file
const a = document.createElement("a");
a.href = URL.createObjectURL(wav);
a.download = parsedMid.midiName + ".wav";
a.click();
For a real use-case, see src/website/manager/export_audio.js
.
Tip
If you encounter any errors in this documentation, please open an issue!
Warning
Make sure you always update worklet_processor.min.js
along with the npm package!