mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-08-13 04:09:26 +00:00
Clean release snapshot
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Minimal PCM WAV parser for Node.js test environments.
|
||||
* Supports: mono/stereo, 16-bit and 24-bit signed PCM (audio format 1).
|
||||
* Mixes all channels down to mono and returns a normalized Float32Array in [-1, 1].
|
||||
*/
|
||||
function parseWav(nodeBuffer) {
|
||||
// Node.js Buffer.buffer is a pooled ArrayBuffer; slice to get an exact view.
|
||||
const ab = nodeBuffer.buffer.slice(
|
||||
nodeBuffer.byteOffset,
|
||||
nodeBuffer.byteOffset + nodeBuffer.byteLength
|
||||
);
|
||||
const view = new DataView(ab);
|
||||
const bytes = new Uint8Array(ab);
|
||||
|
||||
function fourCC(offset) {
|
||||
return String.fromCharCode(bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3]);
|
||||
}
|
||||
|
||||
if (fourCC(0) !== 'RIFF' || fourCC(8) !== 'WAVE') {
|
||||
throw new Error('Not a valid WAV file');
|
||||
}
|
||||
|
||||
let audioFormat = 0, numChannels = 0, sampleRate = 0, bitsPerSample = 0;
|
||||
let dataStart = -1, dataSize = 0;
|
||||
|
||||
let offset = 12;
|
||||
while (offset + 8 <= ab.byteLength) {
|
||||
const id = fourCC(offset);
|
||||
const size = view.getUint32(offset + 4, true);
|
||||
if (id === 'fmt ') {
|
||||
audioFormat = view.getUint16(offset + 8, true);
|
||||
numChannels = view.getUint16(offset + 10, true);
|
||||
sampleRate = view.getUint32(offset + 12, true);
|
||||
bitsPerSample = view.getUint16(offset + 22, true);
|
||||
} else if (id === 'data') {
|
||||
dataStart = offset + 8;
|
||||
dataSize = size;
|
||||
break;
|
||||
}
|
||||
offset += 8 + size + (size & 1); // chunks are word-aligned
|
||||
}
|
||||
|
||||
if (dataStart === -1) throw new Error('No data chunk found in WAV file');
|
||||
if (audioFormat !== 1) throw new Error(`Only PCM WAV supported (audio format ${audioFormat})`);
|
||||
if (bitsPerSample !== 16 && bitsPerSample !== 24) {
|
||||
throw new Error(`Only 16-bit and 24-bit PCM supported (got ${bitsPerSample}-bit)`);
|
||||
}
|
||||
|
||||
const bytesPerSample = bitsPerSample >> 3;
|
||||
const bytesPerFrame = numChannels * bytesPerSample;
|
||||
const nFrames = Math.floor(dataSize / bytesPerFrame);
|
||||
if (dataStart + nFrames * bytesPerFrame > ab.byteLength) {
|
||||
throw new Error('WAV data chunk extends beyond end of file');
|
||||
}
|
||||
const samples = new Float32Array(nFrames);
|
||||
|
||||
for (let i = 0; i < nFrames; i++) {
|
||||
let sum = 0;
|
||||
for (let ch = 0; ch < numChannels; ch++) {
|
||||
const byteOffset = dataStart + i * bytesPerFrame + ch * bytesPerSample;
|
||||
if (bitsPerSample === 16) {
|
||||
sum += view.getInt16(byteOffset, true);
|
||||
} else {
|
||||
// 24-bit: read 3 bytes little-endian, sign-extend from bit 23.
|
||||
const lo = bytes[byteOffset];
|
||||
const mi = bytes[byteOffset + 1];
|
||||
const hi = bytes[byteOffset + 2];
|
||||
const raw = (lo | (mi << 8) | (hi << 16));
|
||||
sum += raw & 0x800000 ? raw - 0x1000000 : raw;
|
||||
}
|
||||
}
|
||||
const scale = bitsPerSample === 16 ? 32768.0 : 8388608.0;
|
||||
samples[i] = (sum / numChannels) / scale;
|
||||
}
|
||||
return { samples, sampleRate };
|
||||
}
|
||||
|
||||
module.exports = { parseWav };
|
||||
Reference in New Issue
Block a user