Skip to main content

音频级别标准化

理想情况下,您可以使用录音界面中的音频响度计来确保录音的音频级别保持一致。

如果您需要在事后均衡音频级别,您可以使用以下脚本:

note

这是一项破坏性操作 - 您的录音将被覆盖。
在运行此操作之前,请提交您的更改。

normalize.ts
tsx
import { $ } from "bun";
import { renameSync } from "fs";
import { WEBCAM_PREFIX } from "./config/cameras";
type FfmpegVolumeOutput = {
input_i: string;
input_tp: string;
input_lra: string;
input_thresh: string;
output_i: string;
output_tp: string;
output_lra: string;
output_thresh: string;
normalization_type: string;
target_offset: string;
};
// Set your composition ID here
const id = "euro";
const files = await $`ls public/${id}`.quiet();
const webcamFiles = files.stdout
.toString("utf8")
.split("\n")
.filter((f) => f.startsWith(WEBCAM_PREFIX));
const decibelValues: number[] = [];
for (const file of webcamFiles) {
const path = `public/${id}/${file}`;
const cmd =
await $`ffmpeg -hide_banner -i ${path} -af loudnorm=I=-23:LRA=7:print_format=json -f null -`.quiet();
const output = cmd.stderr.toString("utf8");
const lines = output.split("\n");
const indexOfLineBeforeStart = lines.findIndex((line) =>
line.includes("[Parsed_loudnorm_0 @"),
);
const remaining = lines.slice(indexOfLineBeforeStart + 1);
const indexOfOut = remaining.findIndex((i) => i.startsWith("[out#0"));
const actual = indexOfOut === -1 ? remaining : remaining.slice(0, indexOfOut);
const json = JSON.parse(actual.join("\n")) as FfmpegVolumeOutput;
console.log(path, `${json.input_i}dB`);
decibelValues.push(parseFloat(json.input_i));
}
const average = decibelValues.reduce((a, b) => a + b, 0) / decibelValues.length;
console.log("Average", `${average}dB`);
const toApply = Math.max(average, -20);
console.log("Applying", `${toApply}dB`);
for (const file of webcamFiles) {
const path = `public/${id}/${file}`;
const copiedPath = `public/${id}/normalized-${file}`;
await $`ffmpeg -hide_banner -i ${path} -af loudnorm=I=${toApply}:LRA=7:TP=-2.0 -c:v copy ${copiedPath} -y`;
renameSync(copiedPath, path);
}
normalize.ts
tsx
import { $ } from "bun";
import { renameSync } from "fs";
import { WEBCAM_PREFIX } from "./config/cameras";
type FfmpegVolumeOutput = {
input_i: string;
input_tp: string;
input_lra: string;
input_thresh: string;
output_i: string;
output_tp: string;
output_lra: string;
output_thresh: string;
normalization_type: string;
target_offset: string;
};
// Set your composition ID here
const id = "euro";
const files = await $`ls public/${id}`.quiet();
const webcamFiles = files.stdout
.toString("utf8")
.split("\n")
.filter((f) => f.startsWith(WEBCAM_PREFIX));
const decibelValues: number[] = [];
for (const file of webcamFiles) {
const path = `public/${id}/${file}`;
const cmd =
await $`ffmpeg -hide_banner -i ${path} -af loudnorm=I=-23:LRA=7:print_format=json -f null -`.quiet();
const output = cmd.stderr.toString("utf8");
const lines = output.split("\n");
const indexOfLineBeforeStart = lines.findIndex((line) =>
line.includes("[Parsed_loudnorm_0 @"),
);
const remaining = lines.slice(indexOfLineBeforeStart + 1);
const indexOfOut = remaining.findIndex((i) => i.startsWith("[out#0"));
const actual = indexOfOut === -1 ? remaining : remaining.slice(0, indexOfOut);
const json = JSON.parse(actual.join("\n")) as FfmpegVolumeOutput;
console.log(path, `${json.input_i}dB`);
decibelValues.push(parseFloat(json.input_i));
}
const average = decibelValues.reduce((a, b) => a + b, 0) / decibelValues.length;
console.log("Average", `${average}dB`);
const toApply = Math.max(average, -20);
console.log("Applying", `${toApply}dB`);
for (const file of webcamFiles) {
const path = `public/${id}/${file}`;
const copiedPath = `public/${id}/normalized-${file}`;
await $`ffmpeg -hide_banner -i ${path} -af loudnorm=I=${toApply}:LRA=7:TP=-2.0 -c:v copy ${copiedPath} -y`;
renameSync(copiedPath, path);
}

这将计算所有录音的平均响度,并编辑每个文件,使其具有与平均响度相同的响度。

使用以下命令执行:

shell
bun normalize.ts
shell
bun normalize.ts