mic-ts
Version:
A simple stream wrapper for arecord (Linux (including Raspbian)) and sox (Mac/Windows). Returns a Passthrough stream object so that stream control like pause(), resume(), pipe(), etc. are all available.
91 lines (78 loc) • 2.31 kB
text/typescript
import { Transform, type TransformCallback } from "stream";
export class IsSilence extends Transform {
private debug: boolean;
private consecSilenceCount: number;
private numSilenceFramesExitThresh: number;
constructor(options: { debug: boolean }) {
super();
this.debug = options.debug || false;
this.consecSilenceCount = 0;
this.numSilenceFramesExitThresh = 0;
}
getNumSilenceFramesExitThresh() {
return this.numSilenceFramesExitThresh;
}
getConsecSilenceCount() {
return this.consecSilenceCount;
}
setNumSilenceFramesExitThresh(numFrames: number) {
this.numSilenceFramesExitThresh = numFrames;
}
incrConsecSilenceCount(): number {
this.consecSilenceCount++;
return this.consecSilenceCount;
}
resetConsecSilenceCount() {
this.consecSilenceCount = 0;
}
override _transform(
chunk: Buffer,
_: BufferEncoding,
callback: TransformCallback,
) {
let silenceLength = 0;
const consecutiveSilence = this.getConsecSilenceCount();
const numSilenceFramesExitThresh = this.getNumSilenceFramesExitThresh();
if (numSilenceFramesExitThresh) {
for (let i = 0; i < chunk.length; i += 2) {
let speechSample;
const next = chunk[i + 1];
if (next) {
if (next > 128) {
speechSample = (next - 256) * 256;
} else {
speechSample = next * 256;
}
speechSample += next;
}
if (speechSample && Math.abs(speechSample) > 2000) {
if (this.debug) {
console.log("Found speech block");
}
if (consecutiveSilence > numSilenceFramesExitThresh) {
this.emit("sound");
}
this.resetConsecSilenceCount();
break;
} else {
silenceLength++;
}
}
if (silenceLength === chunk.length / 2) {
const newConsecutiveSilence = this.incrConsecSilenceCount();
if (this.debug) {
console.log(
"Found silence block: %d of %d",
newConsecutiveSilence,
numSilenceFramesExitThresh,
);
}
if (newConsecutiveSilence === numSilenceFramesExitThresh) {
this.emit("silence");
}
}
}
this.push(chunk);
callback();
}
}