File size: 2,909 Bytes
b1cc7ae |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
// AudioUtils.ts
export class AudioUtils {
static async createPCM16Data(audioBuffer: AudioBuffer): Promise<ArrayBuffer> {
const numChannels = 1; // Mono
const sampleRate = 16000; // Target sample rate
const format = 1; // PCM
const bitDepth = 16;
// Resample if needed
let samples = audioBuffer.getChannelData(0);
if (audioBuffer.sampleRate !== sampleRate) {
samples = await this.resampleAudio(samples, audioBuffer.sampleRate, sampleRate);
}
const dataLength = samples.length * (bitDepth / 8);
const headerLength = 44;
const totalLength = headerLength + dataLength;
const buffer = new ArrayBuffer(totalLength);
const view = new DataView(buffer);
// Write WAV header
this.writeString(view, 0, 'RIFF');
view.setUint32(4, totalLength - 8, true);
this.writeString(view, 8, 'WAVE');
this.writeString(view, 12, 'fmt ');
view.setUint32(16, 16, true);
view.setUint16(20, format, true);
view.setUint16(22, numChannels, true);
view.setUint32(24, sampleRate, true);
view.setUint32(28, sampleRate * numChannels * (bitDepth / 8), true);
view.setUint16(32, numChannels * (bitDepth / 8), true);
view.setUint16(34, bitDepth, true);
this.writeString(view, 36, 'data');
view.setUint32(40, dataLength, true);
// Write audio data
this.floatTo16BitPCM(view, 44, samples);
return buffer;
}
static writeString(view: DataView, offset: number, string: string): void {
for (let i = 0; i < string.length; i++) {
view.setUint8(offset + i, string.charCodeAt(i));
}
}
static floatTo16BitPCM(view: DataView, offset: number, input: Float32Array): void {
for (let i = 0; i < input.length; i++, offset += 2) {
const s = Math.max(-1, Math.min(1, input[i]));
view.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}
}
static async resampleAudio(
audioData: Float32Array,
originalSampleRate: number,
targetSampleRate: number
): Promise<Float32Array> {
const originalLength = audioData.length;
const ratio = targetSampleRate / originalSampleRate;
const newLength = Math.round(originalLength * ratio);
const result = new Float32Array(newLength);
for (let i = 0; i < newLength; i++) {
const position = i / ratio;
const index = Math.floor(position);
const fraction = position - index;
if (index + 1 < originalLength) {
result[i] = audioData[index] * (1 - fraction) + audioData[index + 1] * fraction;
} else {
result[i] = audioData[index];
}
}
return result;
}
}
export default AudioUtils;
|