diff --git a/packages/superdough/reverbGen.mjs b/packages/superdough/reverbGen.mjs index cac5d24a..49429937 100644 --- a/packages/superdough/reverbGen.mjs +++ b/packages/superdough/reverbGen.mjs @@ -70,82 +70,6 @@ reverbGen.generateGraph = function (data, width, height, min, max) { return canvas; }; -/** Saves an AudioBuffer as a 16-bit WAV file on the client's host - file system. Normalizes it to peak at +-32767, and optionally - truncates it if there's a lot of "silence" at the end. - - @param {!AudioBuffer} buffer The buffer to save. - @param {string} name Name of file to create. - @param {number?} opt_minTail Defines what counts as "silence" for - auto-truncating the buffer. If there is a point past which every - value of every channel is less than opt_minTail, then the buffer - is truncated at that point. This is expressed as an integer, - applying to the post-normalized and integer-converted - buffer. The default is 0, meaning don't truncate. */ -reverbGen.saveWavFile = function (buffer, name, opt_minTail) { - var bitsPerSample = 16; - var bytesPerSample = 2; - var sampleRate = buffer.sampleRate; - var numChannels = buffer.numberOfChannels; - var channels = getAllChannelData(buffer); - var numSampleFrames = channels[0].length; - var scale = 32767; - // Find normalization constant. - var max = 0; - for (var i = 0; i < numChannels; i++) { - for (var j = 0; j < numSampleFrames; j++) { - max = Math.max(max, Math.abs(channels[i][j])); - } - } - if (max) { - scale = 32767 / max; - } - // Find truncation point. - if (opt_minTail) { - var truncateAt = 0; - for (var i = 0; i < numChannels; i++) { - for (var j = 0; j < numSampleFrames; j++) { - var absSample = Math.abs(Math.round(scale * channels[i][j])); - if (absSample > opt_minTail) { - truncateAt = j; - } - } - } - numSampleFrames = truncateAt + 1; - } - var sampleDataBytes = bytesPerSample * numChannels * numSampleFrames; - var fileBytes = sampleDataBytes + 44; - var arrayBuffer = new ArrayBuffer(fileBytes); - var dataView = new DataView(arrayBuffer); - dataView.setUint32(0, 1179011410, true); // "RIFF" - dataView.setUint32(4, fileBytes - 8, true); // file length - dataView.setUint32(8, 1163280727, true); // "WAVE" - dataView.setUint32(12, 544501094, true); // "fmt " - dataView.setUint32(16, 16, true); // fmt chunk length - dataView.setUint16(20, 1, true); // PCM format - dataView.setUint16(22, numChannels, true); // NumChannels - dataView.setUint32(24, sampleRate, true); // SampleRate - var bytesPerSampleFrame = numChannels * bytesPerSample; - dataView.setUint32(28, sampleRate * bytesPerSampleFrame, true); // ByteRate - dataView.setUint16(32, bytesPerSampleFrame, true); // BlockAlign - dataView.setUint16(34, bitsPerSample, true); // BitsPerSample - dataView.setUint32(36, 1635017060, true); // "data" - dataView.setUint32(40, sampleDataBytes, true); - for (var j = 0; j < numSampleFrames; j++) { - for (var i = 0; i < numChannels; i++) { - dataView.setInt16(44 + j * bytesPerSampleFrame + i * bytesPerSample, Math.round(scale * channels[i][j]), true); - } - } - var blob = new Blob([arrayBuffer], { type: 'audio/wav' }); - var url = window.URL.createObjectURL(blob); - var linkEl = document.createElement('a'); - linkEl.href = url; - linkEl.download = name; - linkEl.style.display = 'none'; - document.body.appendChild(linkEl); - linkEl.click(); -}; - /** Applies a constantly changing lowpass filter to the given sound. @private