mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
# Conflicts: # src/audio/player.test.ts # src/audio/player.ts
This commit is contained in:
commit
3422d45eeb
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, shouldEndOnStall } from "./player.js";
|
||||
import { buildFfmpegArgs, shouldUsePowerShellDownload, cleanupTempDir, shouldEndOnStall, volumeToFactor } from "./player.js";
|
||||
|
||||
function getHeadersArg(args: string[]): string {
|
||||
const idx = args.indexOf("-headers");
|
||||
@@ -89,6 +89,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";
|
||||
|
||||
+18
-2
@@ -130,6 +130,21 @@ export function shouldEndOnStall(
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a 0-100 volume value to a linear PCM gain factor (#84).
|
||||
*
|
||||
* Continuous and strictly monotonic over [0,100]: 0 at vol 0 and exactly 1.0 at
|
||||
* vol 100. The previous mapping was a two-piece step — 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). This single curve keeps
|
||||
* the low end gentle but ramps smoothly toward full loudness near the top, so the
|
||||
* slider feels proportional with no dead zone and no discontinuity at 100.
|
||||
*/
|
||||
export function volumeToFactor(volume: number): number {
|
||||
const x = Math.max(0, Math.min(100, volume)) / 100;
|
||||
return 0.2 * x + 0.8 * Math.pow(x, 8);
|
||||
}
|
||||
|
||||
export interface PlayerEvents {
|
||||
frame: (opusFrame: Buffer) => void;
|
||||
trackEnd: () => void;
|
||||
@@ -552,8 +567,9 @@ export class AudioPlayer extends EventEmitter {
|
||||
}
|
||||
|
||||
private applyVolume(pcm: Buffer): Buffer {
|
||||
if (this.volume === 100) return Buffer.from(pcm);
|
||||
const factor = (this.volume / 100) * 0.2;
|
||||
const factor = volumeToFactor(this.volume);
|
||||
// factor === 1 only at volume 100; skip the per-sample loop at full loudness.
|
||||
if (factor >= 1) return Buffer.from(pcm);
|
||||
const out = Buffer.alloc(pcm.length);
|
||||
for (let i = 0; i < pcm.length; i += 2) {
|
||||
let sample = Math.round(pcm.readInt16LE(i) * factor);
|
||||
|
||||
Reference in new issue
Block a user