57 lines
1.4 KiB
TypeScript
57 lines
1.4 KiB
TypeScript
import { createReadStream } from "fs";
|
|
|
|
export type SwapPoint = {
|
|
position_start: number;
|
|
duration: number;
|
|
loud: boolean;
|
|
label: string;
|
|
};
|
|
|
|
export default async function (
|
|
file: import("fs").PathLike,
|
|
threshold_at_point: number,
|
|
inertia_samples: number,
|
|
label: string
|
|
): Promise<SwapPoint[]> {
|
|
const stream = createReadStream(file);
|
|
let position = 0;
|
|
const results: SwapPoint[] = [];
|
|
let last_swap_position = 0;
|
|
let keep_loud_until = 0;
|
|
let was_loud_last_time = false;
|
|
return new Promise((resolve, reject) => {
|
|
stream.on("readable", () => {
|
|
let chunk: Buffer | null;
|
|
while ((chunk = stream.read()) !== null) {
|
|
for (let i = 0; i < chunk.byteLength; i++) {
|
|
position++;
|
|
const byte = chunk[i];
|
|
const volume = Math.abs(byte - 128);
|
|
if (position >= keep_loud_until) {
|
|
const is_loud: boolean = volume > threshold_at_point;
|
|
if (is_loud != was_loud_last_time) {
|
|
const swap_point = {
|
|
position_start: last_swap_position,
|
|
duration: position - last_swap_position,
|
|
loud: was_loud_last_time,
|
|
label,
|
|
};
|
|
results.push(swap_point);
|
|
last_swap_position = position;
|
|
was_loud_last_time = is_loud;
|
|
}
|
|
}
|
|
if (volume > threshold_at_point) {
|
|
keep_loud_until = position + inertia_samples;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
stream.on("end", () => {
|
|
resolve(results);
|
|
});
|
|
|
|
stream.on("error", reject);
|
|
});
|
|
}
|