feat: build reproducible dataset editor
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
function writeAscii(view, offset, value) {
|
||||
for (let index = 0; index < value.length; index += 1) view.setUint8(offset + index, value.charCodeAt(index));
|
||||
}
|
||||
|
||||
export const MAX_PCM_WAV_BYTES = 384 * 1024 * 1024;
|
||||
|
||||
export function encodeMonoPcm16Wav(samples, sampleRate) {
|
||||
if (!Number.isInteger(sampleRate) || sampleRate < 1 || sampleRate > 0xffffffff) {
|
||||
throw new Error(`WAV sample rate가 올바르지 않습니다: ${sampleRate}`);
|
||||
}
|
||||
if (!samples || !Number.isSafeInteger(samples.length)) {
|
||||
throw new Error("WAV samples는 길이가 있는 배열이어야 합니다.");
|
||||
}
|
||||
const bytesPerSample = 2;
|
||||
const dataByteLength = samples.length * bytesPerSample;
|
||||
if (!Number.isSafeInteger(dataByteLength) || dataByteLength > 0xffffffff - 36) {
|
||||
throw new Error("PCM16 WAV가 RIFF 4 GiB 한도를 넘습니다.");
|
||||
}
|
||||
if (44 + dataByteLength > MAX_PCM_WAV_BYTES) {
|
||||
throw new Error(`PCM16 WAV가 ${(MAX_PCM_WAV_BYTES / 1024 ** 2).toFixed(0)} MiB 메모리 한도를 넘습니다.`);
|
||||
}
|
||||
const buffer = new ArrayBuffer(44 + dataByteLength);
|
||||
const view = new DataView(buffer);
|
||||
writeAscii(view, 0, "RIFF");
|
||||
view.setUint32(4, 36 + dataByteLength, true);
|
||||
writeAscii(view, 8, "WAVE");
|
||||
writeAscii(view, 12, "fmt ");
|
||||
view.setUint32(16, 16, true);
|
||||
view.setUint16(20, 1, true);
|
||||
view.setUint16(22, 1, true);
|
||||
view.setUint32(24, sampleRate, true);
|
||||
view.setUint32(28, sampleRate * bytesPerSample, true);
|
||||
view.setUint16(32, bytesPerSample, true);
|
||||
view.setUint16(34, 16, true);
|
||||
writeAscii(view, 36, "data");
|
||||
view.setUint32(40, dataByteLength, true);
|
||||
for (let index = 0; index < samples.length; index += 1) {
|
||||
if (!Number.isFinite(samples[index])) throw new Error(`WAV sample ${index}가 유한한 숫자가 아닙니다.`);
|
||||
const value = Math.max(-1, Math.min(1, samples[index]));
|
||||
view.setInt16(44 + index * 2, value < 0 ? value * 0x8000 : value * 0x7fff, true);
|
||||
}
|
||||
return new Blob([buffer], { type: "audio/wav" });
|
||||
}
|
||||
Reference in New Issue
Block a user