From e6a8747d41180da64fa696d1dd1760c435015d76 Mon Sep 17 00:00:00 2001 From: Bruce Berrios <58147810+Bruception@users.noreply.github.com> Date: Mon, 26 Sep 2022 04:41:31 -0400 Subject: [PATCH] yyyriyriy ppp[i6riy (#3603) Bruception * Add new synth click sounds * Use key codes instead * Fix Sound preview * Check for caps lock * Add new quote - imperial march --- backend/src/api/schemas/config-schema.ts | 4 +- .../ts/commandline/lists/sound-on-click.ts | 48 +++++++ frontend/src/ts/config.ts | 2 +- .../src/ts/controllers/sound-controller.ts | 128 ++++++++++++++++++ frontend/src/ts/types/types.d.ts | 18 ++- frontend/static/html/pages/settings.html | 32 +++++ frontend/static/quotes/english.json | 6 + 7 files changed, 235 insertions(+), 3 deletions(-) diff --git a/backend/src/api/schemas/config-schema.ts b/backend/src/api/schemas/config-schema.ts index f4b59f270..fd8462794 100644 --- a/backend/src/api/schemas/config-schema.ts +++ b/backend/src/api/schemas/config-schema.ts @@ -75,7 +75,9 @@ const CONFIG_SCHEMA = joi.object({ singleListCommandLine: joi.string().valid("manual", "on"), capsLockWarning: joi.boolean(), playSoundOnError: joi.boolean(), - playSoundOnClick: joi.string().valid("off", ..._.range(1, 8).map(_.toString)), + playSoundOnClick: joi + .string() + .valid("off", ..._.range(1, 11).map(_.toString)), soundVolume: joi.string().valid("0.1", "0.5", "1.0"), startGraphsAtZero: joi.boolean(), showOutOfFocusWarning: joi.boolean(), diff --git a/frontend/src/ts/commandline/lists/sound-on-click.ts b/frontend/src/ts/commandline/lists/sound-on-click.ts index ab8d02c5a..f11ca3969 100644 --- a/frontend/src/ts/commandline/lists/sound-on-click.ts +++ b/frontend/src/ts/commandline/lists/sound-on-click.ts @@ -97,6 +97,54 @@ const subgroup: MonkeyTypes.CommandsSubgroup = { SoundController.playClick(); }, }, + { + id: "setSoundOnClick8", + display: "sine", + configValue: "8", + hover: (): void => { + SoundController.playNote("KeyQ", "sine"); + }, + exec: (): void => { + UpdateConfig.setPlaySoundOnClick("8"); + SoundController.playNote("KeyQ", "sine"); + }, + }, + { + id: "setSoundOnClick9", + display: "sawtooth", + configValue: "9", + hover: (): void => { + SoundController.playNote("KeyQ", "sawtooth"); + }, + exec: (): void => { + UpdateConfig.setPlaySoundOnClick("9"); + SoundController.playNote("KeyQ", "sawtooth"); + }, + }, + { + id: "setSoundOnClick10", + display: "square", + configValue: "10", + hover: (): void => { + SoundController.playNote("KeyQ", "square"); + }, + exec: (): void => { + UpdateConfig.setPlaySoundOnClick("10"); + SoundController.playNote("KeyQ", "square"); + }, + }, + { + id: "setSoundOnClick11", + display: "triangle", + configValue: "11", + hover: (): void => { + SoundController.playNote("KeyQ", "triangle"); + }, + exec: (): void => { + UpdateConfig.setPlaySoundOnClick("11"); + SoundController.playNote("KeyQ", "triangle"); + }, + }, ], }; diff --git a/frontend/src/ts/config.ts b/frontend/src/ts/config.ts index 641a4801a..6d05cfb3c 100644 --- a/frontend/src/ts/config.ts +++ b/frontend/src/ts/config.ts @@ -166,7 +166,7 @@ export function setPlaySoundOnClick( ): boolean { if ( !isConfigValueValid("play sound on click", val, [ - ["off", "1", "2", "3", "4", "5", "6", "7"], + ["off", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"], ]) ) { return false; diff --git a/frontend/src/ts/controllers/sound-controller.ts b/frontend/src/ts/controllers/sound-controller.ts index 9c6db70bb..0eaba9cec 100644 --- a/frontend/src/ts/controllers/sound-controller.ts +++ b/frontend/src/ts/controllers/sound-controller.ts @@ -2,6 +2,8 @@ import Config from "../config"; import Howler, { Howl } from "howler"; import * as ConfigEvent from "../observables/config-event"; import { randomElementFromArray } from "../utils/misc"; +import { leftState, rightState } from "../test/shift-tracker"; +import { capsState } from "../test/caps-warning"; interface ClickSounds { [key: string]: { @@ -233,8 +235,134 @@ export function previewClick(val: string): void { (clickSounds as ClickSounds)[val][0].sounds[0].play(); } +let currentCode = "KeyA"; + +$(document).on("keydown", (event) => { + currentCode = event.code || "KeyA"; +}); + +const notes = { + C: [16.35, 32.7, 65.41, 130.81, 261.63, 523.25, 1046.5, 2093.0, 4186.01], + Db: [17.32, 34.65, 69.3, 138.59, 277.18, 554.37, 1108.73, 2217.46, 4434.92], + D: [18.35, 36.71, 73.42, 146.83, 293.66, 587.33, 1174.66, 2349.32, 4698.64], + Eb: [19.45, 38.89, 77.78, 155.56, 311.13, 622.25, 1244.51, 2489.02, 4978.03], + E: [20.6, 41.2, 82.41, 164.81, 329.63, 659.26, 1318.51, 2637.02], + F: [21.83, 43.65, 87.31, 174.61, 349.23, 698.46, 1396.91, 2793.83], + Gb: [23.12, 46.25, 92.5, 185.0, 369.99, 739.99, 1479.98, 2959.96], + G: [24.5, 49.0, 98.0, 196.0, 392.0, 783.99, 1567.98, 3135.96], + Ab: [25.96, 51.91, 103.83, 207.65, 415.3, 830.61, 1661.22, 3322.44], + A: [27.5, 55.0, 110.0, 220.0, 440.0, 880.0, 1760.0, 3520.0], + Bb: [29.14, 58.27, 116.54, 233.08, 466.16, 932.33, 1864.66, 3729.31], + B: [30.87, 61.74, 123.47, 246.94, 493.88, 987.77, 1975.53, 3951.07], +}; + +type GetNoteFrequencyCallback = (octave: number) => number; + +function bindToNote( + noteFrequencies: number[], + octaveOffset = 0 +): GetNoteFrequencyCallback { + return (octave: number): number => { + return noteFrequencies[octave + octaveOffset]; + }; +} + +const codeToNote: Record = { + KeyZ: bindToNote(notes.C), + KeyS: bindToNote(notes.Db), + KeyX: bindToNote(notes.D), + KeyD: bindToNote(notes.Eb), + KeyC: bindToNote(notes.E), + KeyV: bindToNote(notes.F), + KeyG: bindToNote(notes.Gb), + KeyB: bindToNote(notes.G), + KeyH: bindToNote(notes.Ab), + KeyN: bindToNote(notes.A), + KeyJ: bindToNote(notes.Bb), + KeyM: bindToNote(notes.B), + Comma: bindToNote(notes.C, 1), + KeyL: bindToNote(notes.Db, 1), + Period: bindToNote(notes.D, 1), + Semicolon: bindToNote(notes.Eb, 1), + Slash: bindToNote(notes.E, 1), + KeyQ: bindToNote(notes.C, 1), + Digit2: bindToNote(notes.Db, 1), + KeyW: bindToNote(notes.D, 1), + Digit3: bindToNote(notes.Eb, 1), + KeyE: bindToNote(notes.E, 1), + KeyR: bindToNote(notes.F, 1), + Digit5: bindToNote(notes.Gb, 1), + KeyT: bindToNote(notes.G, 1), + Digit6: bindToNote(notes.Ab, 1), + KeyY: bindToNote(notes.A, 1), + Digit7: bindToNote(notes.Bb, 1), + KeyU: bindToNote(notes.B, 1), + KeyI: bindToNote(notes.C, 2), + Digit9: bindToNote(notes.Db, 2), + KeyO: bindToNote(notes.D, 2), + Digit0: bindToNote(notes.Eb, 2), + KeyP: bindToNote(notes.E, 2), + BracketLeft: bindToNote(notes.F, 2), + Equal: bindToNote(notes.Gb, 2), + BracketRight: bindToNote(notes.G, 2), +}; + +type DynamicClickSounds = Extract< + MonkeyTypes.PlaySoundOnClick, + "8" | "9" | "10" | "11" +>; +type SupportedOscillatorTypes = Exclude; + +const clickSoundIdsToOscillatorType: Record< + DynamicClickSounds, + SupportedOscillatorTypes +> = { + "8": "sine", + "9": "sawtooth", + "10": "square", + "11": "triangle", +}; + +const audioCtx = new AudioContext(); + +export function playNote( + codeOverride?: string, + oscillatorTypeOverride?: SupportedOscillatorTypes +): void { + currentCode = codeOverride ?? currentCode; + if (!(currentCode in codeToNote)) { + return; + } + + const baseOctave = 3; + const octave = baseOctave + (leftState || rightState || capsState ? 1 : 0); + const currentFrequency = codeToNote[currentCode](octave); + + const oscillatorNode = audioCtx.createOscillator(); + const gainNode = audioCtx.createGain(); + + oscillatorNode.type = + oscillatorTypeOverride ?? + clickSoundIdsToOscillatorType[ + Config.playSoundOnClick as DynamicClickSounds + ]; + gainNode.gain.value = parseFloat(Config.soundVolume) / 10; + + oscillatorNode.connect(gainNode); + gainNode.connect(audioCtx.destination); + + oscillatorNode.frequency.value = currentFrequency; + oscillatorNode.start(audioCtx.currentTime); + oscillatorNode.stop(audioCtx.currentTime + 0.15); +} + export function playClick(): void { if (Config.playSoundOnClick === "off") return; + if (Config.playSoundOnClick in clickSoundIdsToOscillatorType) { + playNote(); + return; + } + if (clickSounds === null) init(); const randomSound = randomElementFromArray( diff --git a/frontend/src/ts/types/types.d.ts b/frontend/src/ts/types/types.d.ts index 8f10bd142..487276503 100644 --- a/frontend/src/ts/types/types.d.ts +++ b/frontend/src/ts/types/types.d.ts @@ -87,8 +87,24 @@ declare namespace MonkeyTypes { 5 = typewriter 6 = osu 7 = hitmarker + 8 = sine + 9 = sawtooth + 10 = square + 11 = triangle */ - type PlaySoundOnClick = "off" | "1" | "2" | "3" | "4" | "5" | "6" | "7"; + type PlaySoundOnClick = + | "off" + | "1" + | "2" + | "3" + | "4" + | "5" + | "6" + | "7" + | "8" + | "9" + | "10" + | "11"; type SoundVolume = "0.1" | "0.5" | "1.0"; diff --git a/frontend/static/html/pages/settings.html b/frontend/static/html/pages/settings.html index e0f6e099f..449709389 100644 --- a/frontend/static/html/pages/settings.html +++ b/frontend/static/html/pages/settings.html @@ -894,6 +894,38 @@ > hitmarker +
+ sine +
+
+ sawtooth +
+
+ square +
+
+ triangle +
diff --git a/frontend/static/quotes/english.json b/frontend/static/quotes/english.json index 65966b789..11eb47b8a 100644 --- a/frontend/static/quotes/english.json +++ b/frontend/static/quotes/english.json @@ -35466,6 +35466,12 @@ "source": "Fight Club", "length": 827, "id": 6231 + }, + { + "text": "yyy riy riy ppp [i6 riy", + "source": "John Williams - The Imperial March", + "length": 23, + "id": 6232 } ] }