mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
fix(audio): smooth, monotonic volume curve (#84)
applyVolume() mapped 0-100 with a two-piece, discontinuous curve: gain = (vol/100)*0.2 for vol<100 (so the whole 0-99 range only spanned 0..0.198, making 80->99 feel flat) then a raw passthrough at vol===100 (a ~5x jump to full loudness). That produced the reported dead zone + sudden ear-blast at 100. Replace it with a single continuous, strictly-monotonic curve volumeToFactor(v) = 0.2*x + 0.8*x^8 (x = v/100): 0 at 0, exactly 1.0 at 100, no flat region and no discontinuity, so the slider feels proportional and full loudness is still reserved at 100. Extracted as an exported pure function and unit-tested (boundaries, strict monotonicity, dead-zone removal, no jump at 100). Note: per the maintainer's note on #84 the >80% suppression was intentional ear-protection; this change makes the upper range (above ~75%) audibly louder than before in exchange for a proportional slider — applied per maintainer decision. Fixes #84 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
bea2f92508
commit
3802c90d2d
2 files changed
+50
-3
No files matched your search
@@ -2,7 +2,7 @@ import { describe, it, expect } from "vitest";
|
||||
import { mkdtempSync, writeFileSync, existsSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { buildFfmpegArgs, shouldUsePowerShellDownload, cleanupTempDir } from "./player.js";
|
||||
import { buildFfmpegArgs, shouldUsePowerShellDownload, cleanupTempDir, volumeToFactor } from "./player.js";
|
||||
|
||||
function getHeadersArg(args: string[]): string {
|
||||
const idx = args.indexOf("-headers");
|
||||
@@ -80,6 +80,37 @@ describe("buildFfmpegArgs", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("volumeToFactor (#84 smooth volume curve)", () => {
|
||||
it("is 0 at vol 0 and exactly 1.0 at vol 100 (full loudness still reserved at 100)", () => {
|
||||
expect(volumeToFactor(0)).toBe(0);
|
||||
expect(volumeToFactor(100)).toBe(1);
|
||||
});
|
||||
|
||||
it("clamps out-of-range input", () => {
|
||||
expect(volumeToFactor(-20)).toBe(0);
|
||||
expect(volumeToFactor(150)).toBe(1);
|
||||
});
|
||||
|
||||
it("is strictly monotonic across the whole range (no dead zone)", () => {
|
||||
for (let v = 0; v < 100; v++) {
|
||||
expect(volumeToFactor(v + 1)).toBeGreaterThan(volumeToFactor(v));
|
||||
}
|
||||
});
|
||||
|
||||
it("removes the old flat 80-99 dead zone", () => {
|
||||
// Old mapping moved only 0.16 -> 0.198 across 80..99; new curve climbs clearly.
|
||||
expect(volumeToFactor(99) - volumeToFactor(80)).toBeGreaterThan(0.3);
|
||||
});
|
||||
|
||||
it("removes the discontinuity at 100 (old jump was ~0.8)", () => {
|
||||
expect(volumeToFactor(100) - volumeToFactor(99)).toBeLessThan(0.1);
|
||||
});
|
||||
|
||||
it("keeps the low range gentle", () => {
|
||||
expect(volumeToFactor(50)).toBeLessThan(0.12);
|
||||
});
|
||||
});
|
||||
|
||||
describe("shouldUsePowerShellDownload", () => {
|
||||
const jdymusicUrl =
|
||||
"http://m801.music.126.net/20260507/abc/jdymusic/obj/xyz/song.mp3?vuutv=tok";
|
||||
|
||||
Reference in new issue
Block a user