feat: scaffold realtime Korean voice assistant bot
This commit is contained in:
60
src/audio/pcm.ts
Normal file
60
src/audio/pcm.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
export class Stereo48kToMono16kDownsampler {
|
||||
private readonly pendingMono48k: number[] = [];
|
||||
|
||||
pushStereo48kChunk(chunk: Buffer): Int16Array {
|
||||
if (chunk.length < 4) {
|
||||
return new Int16Array();
|
||||
}
|
||||
|
||||
for (let offset = 0; offset + 3 < chunk.length; offset += 4) {
|
||||
const left = chunk.readInt16LE(offset);
|
||||
const right = chunk.readInt16LE(offset + 2);
|
||||
this.pendingMono48k.push(Math.round((left + right) / 2));
|
||||
}
|
||||
|
||||
const outputLength = Math.floor(this.pendingMono48k.length / 3);
|
||||
if (outputLength === 0) {
|
||||
return new Int16Array();
|
||||
}
|
||||
|
||||
const output = new Int16Array(outputLength);
|
||||
let readIndex = 0;
|
||||
for (let index = 0; index < outputLength; index += 1) {
|
||||
const a = this.pendingMono48k[readIndex];
|
||||
const b = this.pendingMono48k[readIndex + 1];
|
||||
const c = this.pendingMono48k[readIndex + 2];
|
||||
output[index] = Math.round((a + b + c) / 3);
|
||||
readIndex += 3;
|
||||
}
|
||||
|
||||
this.pendingMono48k.splice(0, readIndex);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
export function int16ArrayToFloat32(input: Int16Array): Float32Array {
|
||||
const output = new Float32Array(input.length);
|
||||
for (let index = 0; index < input.length; index += 1) {
|
||||
output[index] = input[index] / 32768;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
export function float32ToPcm16Buffer(input: Float32Array): Buffer {
|
||||
const buffer = Buffer.allocUnsafe(input.length * 2);
|
||||
for (let index = 0; index < input.length; index += 1) {
|
||||
const value = Math.max(-1, Math.min(1, input[index]));
|
||||
const scaled = value < 0 ? value * 32768 : value * 32767;
|
||||
buffer.writeInt16LE(Math.round(scaled), index * 2);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
export function takeFrame(source: number[], frameSize: number): Int16Array | null {
|
||||
if (source.length < frameSize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const values = source.splice(0, frameSize);
|
||||
return Int16Array.from(values);
|
||||
}
|
||||
Reference in New Issue
Block a user