feat(audio): volume в проекте, DnD, параллельные плейлисты
Громкость треков сцены/игры сохраняется в проекте; порядок через DnD; несколько плейлистов сразу; автоимя из файла; стоп превью при запуске сессии. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -110,8 +110,29 @@ export type SceneAudioRef = {
|
||||
assetId: AssetId;
|
||||
autoplay: boolean;
|
||||
loop: boolean;
|
||||
/** Громкость 0…1; дефолт на пульте при старте сессии. */
|
||||
volume: number;
|
||||
};
|
||||
|
||||
export function clampSceneAudioVolume(v: unknown): number {
|
||||
if (typeof v !== 'number' || !Number.isFinite(v)) return 1;
|
||||
return Math.max(0, Math.min(1, v));
|
||||
}
|
||||
|
||||
export function normalizeSceneAudioRef(raw: {
|
||||
assetId: AssetId;
|
||||
autoplay?: boolean;
|
||||
loop?: boolean;
|
||||
volume?: unknown;
|
||||
}): SceneAudioRef {
|
||||
return {
|
||||
assetId: raw.assetId,
|
||||
autoplay: Boolean(raw.autoplay),
|
||||
loop: Boolean(raw.loop),
|
||||
volume: clampSceneAudioVolume(raw.volume),
|
||||
};
|
||||
}
|
||||
|
||||
export type SceneMediaRefs = {
|
||||
videos: AssetId[];
|
||||
audios: SceneAudioRef[];
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
|
||||
import { clampSceneAudioVolume, normalizeSceneAudioRef } from '../../shared/types/domain';
|
||||
import type { AssetId } from '../../shared/types/ids';
|
||||
|
||||
void test('clampSceneAudioVolume clamps to 0…1', () => {
|
||||
assert.equal(clampSceneAudioVolume(0.5), 0.5);
|
||||
assert.equal(clampSceneAudioVolume(-1), 0);
|
||||
assert.equal(clampSceneAudioVolume(2), 1);
|
||||
assert.equal(clampSceneAudioVolume(undefined), 1);
|
||||
assert.equal(clampSceneAudioVolume(NaN), 1);
|
||||
});
|
||||
|
||||
void test('normalizeSceneAudioRef defaults volume to 1', () => {
|
||||
const id = 'a1' as AssetId;
|
||||
assert.deepEqual(normalizeSceneAudioRef({ assetId: id, autoplay: true, loop: false }), {
|
||||
assetId: id,
|
||||
autoplay: true,
|
||||
loop: false,
|
||||
volume: 1,
|
||||
});
|
||||
assert.deepEqual(normalizeSceneAudioRef({ assetId: id, autoplay: false, loop: true, volume: 0.25 }), {
|
||||
assetId: id,
|
||||
autoplay: false,
|
||||
loop: true,
|
||||
volume: 0.25,
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user