diff --git a/frontend/__tests__/root/config.spec.ts b/frontend/__tests__/root/config.spec.ts index f6ceacf8b..f208ede55 100644 --- a/frontend/__tests__/root/config.spec.ts +++ b/frontend/__tests__/root/config.spec.ts @@ -19,8 +19,8 @@ describe("Config", () => { expect(Config.setPlaySoundOnClick("invalid" as any)).toBe(false); }); it("setSoundVolume", () => { - expect(Config.setSoundVolume("0.1")).toBe(true); - expect(Config.setSoundVolume("1.0")).toBe(true); + expect(Config.setSoundVolume(0.1)).toBe(true); + expect(Config.setSoundVolume(1.0)).toBe(true); expect(Config.setSoundVolume("invalid" as any)).toBe(false); }); it("setDifficulty", () => { diff --git a/frontend/src/html/pages/settings.html b/frontend/src/html/pages/settings.html index ab0922570..4cc0680c5 100644 --- a/frontend/src/html/pages/settings.html +++ b/frontend/src/html/pages/settings.html @@ -581,10 +581,11 @@ sound volume
Change the volume of the sound effects.
-
- - - +
+
+
100
+ +
diff --git a/frontend/src/ts/commandline/lists/sound-volume.ts b/frontend/src/ts/commandline/lists/sound-volume.ts index e2ad27552..2cac406b8 100644 --- a/frontend/src/ts/commandline/lists/sound-volume.ts +++ b/frontend/src/ts/commandline/lists/sound-volume.ts @@ -10,7 +10,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = { display: "quiet", configValue: "0.1", exec: (): void => { - UpdateConfig.setSoundVolume("0.1"); + UpdateConfig.setSoundVolume(0.1); void SoundController.playClick(); }, }, @@ -19,7 +19,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = { display: "medium", configValue: "0.5", exec: (): void => { - UpdateConfig.setSoundVolume("0.5"); + UpdateConfig.setSoundVolume(0.5); void SoundController.playClick(); }, }, @@ -28,7 +28,17 @@ const subgroup: MonkeyTypes.CommandsSubgroup = { display: "loud", configValue: "1.0", exec: (): void => { - UpdateConfig.setSoundVolume("1.0"); + UpdateConfig.setSoundVolume(1.0); + void SoundController.playClick(); + }, + }, + { + id: "setSoundVolumeCustom", + display: "custom...", + input: true, + exec: ({ input }): void => { + if (input === undefined || input === "") return; + UpdateConfig.setSoundVolume(parseFloat(input)); void SoundController.playClick(); }, }, diff --git a/frontend/src/ts/config.ts b/frontend/src/ts/config.ts index 51052033b..6657b6238 100644 --- a/frontend/src/ts/config.ts +++ b/frontend/src/ts/config.ts @@ -182,6 +182,11 @@ export function setSoundVolume( val: ConfigSchemas.SoundVolume, nosave?: boolean ): boolean { + if (val < 0 || val > 1) { + Notifications.add("Sound volume must be between 0 and 1", 0); + val = 0.5; + } + if ( !isConfigValueValid("sound volume", val, ConfigSchemas.SoundVolumeSchema) ) { @@ -2176,6 +2181,10 @@ function replaceLegacyValues( configObj.liveAccStyle = val; } + if (typeof configObj.soundVolume === "string") { + configObj.soundVolume = parseFloat(configObj.soundVolume); + } + return configObj; } diff --git a/frontend/src/ts/constants/default-config.ts b/frontend/src/ts/constants/default-config.ts index 9b252847b..dccf78541 100644 --- a/frontend/src/ts/constants/default-config.ts +++ b/frontend/src/ts/constants/default-config.ts @@ -68,7 +68,7 @@ export default { capsLockWarning: true, playSoundOnError: "off", playSoundOnClick: "off", - soundVolume: "0.5", + soundVolume: 0.5, startGraphsAtZero: true, showOutOfFocusWarning: true, paceCaret: "off", diff --git a/frontend/src/ts/controllers/sound-controller.ts b/frontend/src/ts/controllers/sound-controller.ts index 58915da08..04a08777f 100644 --- a/frontend/src/ts/controllers/sound-controller.ts +++ b/frontend/src/ts/controllers/sound-controller.ts @@ -81,7 +81,7 @@ async function initErrorSound(): Promise { }, ], }; - Howler.volume(parseFloat(Config.soundVolume)); + Howler.volume(Config.soundVolume); } async function init(): Promise { @@ -387,7 +387,7 @@ async function init(): Promise { }, ], }; - Howler.volume(parseFloat(Config.soundVolume)); + Howler.volume(Config.soundVolume); } export async function previewClick(val: string): Promise { @@ -591,7 +591,7 @@ function playScale(scale: ValidScales, scaleMeta: ScaleData): void { const gainNode = audioCtx.createGain(); oscillatorNode.type = "sine"; - gainNode.gain.value = parseFloat(Config.soundVolume) / 10; + gainNode.gain.value = Config.soundVolume / 10; oscillatorNode.connect(gainNode); gainNode.connect(audioCtx.destination); oscillatorNode.frequency.value = currentFrequency; @@ -626,7 +626,7 @@ export function playNote( clickSoundIdsToOscillatorType[ Config.playSoundOnClick as DynamicClickSounds ]; - gainNode.gain.value = parseFloat(Config.soundVolume) / 10; + gainNode.gain.value = Config.soundVolume / 10; oscillatorNode.connect(gainNode); gainNode.connect(audioCtx.destination); @@ -695,5 +695,7 @@ function setVolume(val: number): void { ConfigEvent.subscribe((eventKey, eventValue) => { if (eventKey === "playSoundOnClick" && eventValue !== "off") void init(); - if (eventKey === "soundVolume") setVolume(parseFloat(eventValue as string)); + if (eventKey === "soundVolume") { + setVolume(parseFloat(eventValue as string)); + } }); diff --git a/frontend/src/ts/pages/settings.ts b/frontend/src/ts/pages/settings.ts index 0aa85e7e7..306fcf549 100644 --- a/frontend/src/ts/pages/settings.ts +++ b/frontend/src/ts/pages/settings.ts @@ -250,7 +250,7 @@ async function initGroups(): Promise { groups["soundVolume"] = new SettingsGroup( "soundVolume", UpdateConfig.setSoundVolume, - "button" + "range" ) as SettingsGroup; groups["playSoundOnError"] = new SettingsGroup( "playSoundOnError", diff --git a/packages/contracts/src/schemas/configs.ts b/packages/contracts/src/schemas/configs.ts index ace674f8b..f3c2e360e 100644 --- a/packages/contracts/src/schemas/configs.ts +++ b/packages/contracts/src/schemas/configs.ts @@ -120,7 +120,7 @@ export const PlaySoundOnClickSchema = z.enum([ ]); export type PlaySoundOnClick = z.infer; -export const SoundVolumeSchema = z.enum(["0.1", "0.5", "1.0"]); +export const SoundVolumeSchema = z.number().min(0).max(1); export type SoundVolume = z.infer; export const PaceCaretSchema = z.enum([