From ea1e0ff7684941697de84583710d8c10e41c185f Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 5 Dec 2025 14:58:40 -0800 Subject: [PATCH 1/2] feat: Add support for playing beeps --- core/workspace_audio.ts | 61 +++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/core/workspace_audio.ts b/core/workspace_audio.ts index 1759b30edbb..d4ad433fcd8 100644 --- a/core/workspace_audio.ts +++ b/core/workspace_audio.ts @@ -124,20 +124,11 @@ export class WorkspaceAudio { * @param opt_volume Volume of sound (0-1). */ play(name: string, opt_volume?: number) { - if (this.muted) { - return; - } + if (!this.isPlayingAllowed()) return; + const sound = this.sounds.get(name); if (sound) { - // Don't play one sound on top of another. - const now = new Date(); - if ( - this.lastSound !== null && - now.getTime() - this.lastSound.getTime() < SOUND_LIMIT - ) { - return; - } - this.lastSound = now; + this.lastSound = new Date(); let mySound; if (userAgent.IPAD || userAgent.ANDROID) { // Creating a new audio node causes lag in Android and iPad. Android @@ -168,4 +159,50 @@ export class WorkspaceAudio { getMuted(): boolean { return this.muted; } + + /** + * Returns whether or not playing sounds is currently allowed. + * + * @returns False is audio is muted or a sound has just been played, otherwise + * true. + */ + private isPlayingAllowed() { + const now = new Date(); + + if ( + this.getMuted() || + (this.lastSound !== null && + now.getTime() - this.lastSound.getTime() < SOUND_LIMIT) + ) { + return false; + } + return true; + } + + /** + * Plays a brief beep at the given frequency. + * + * @param tone The frequency of the beep to play. + */ + beep(tone: number) { + if (!this.isPlayingAllowed()) return; + this.lastSound = new Date(); + + const context = new AudioContext(); + + const oscillator = context.createOscillator(); + oscillator.type = 'sine'; + oscillator.frequency.setValueAtTime(tone, context.currentTime); + + const gainNode = context.createGain(); + gainNode.gain.setValueAtTime(0, context.currentTime); + gainNode.gain.linearRampToValueAtTime(0.5, context.currentTime + 0.01); // Fade in + gainNode.gain.linearRampToValueAtTime(0, context.currentTime + 0.2); // Fade out + + oscillator.connect(gainNode); + gainNode.connect(context.destination); + + oscillator.start(context.currentTime); + oscillator.stop(context.currentTime + 0.2); + } } From 8a8d45e3c417eddf6b8ad5647dec3282ef20cca6 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 8 Dec 2025 08:16:08 -0800 Subject: [PATCH 2/2] chore: Fix typo --- core/workspace_audio.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/workspace_audio.ts b/core/workspace_audio.ts index d4ad433fcd8..ff70c2776aa 100644 --- a/core/workspace_audio.ts +++ b/core/workspace_audio.ts @@ -163,7 +163,7 @@ export class WorkspaceAudio { /** * Returns whether or not playing sounds is currently allowed. * - * @returns False is audio is muted or a sound has just been played, otherwise + * @returns False if audio is muted or a sound has just been played, otherwise * true. */ private isPlayingAllowed() {