mirror of
https://github.com/google/blockly.git
synced 2026-04-27 23:50:21 +02:00
feat: Add a method to play beep tones (#9612)
This commit is contained in:
@@ -83,24 +83,10 @@ export class WorkspaceAudio {
|
||||
* @param opt_volume Volume of sound (0-1).
|
||||
*/
|
||||
async play(name: string, opt_volume?: number) {
|
||||
if (this.muted || opt_volume === 0 || !this.context) {
|
||||
return;
|
||||
}
|
||||
if (!this.isPlayingAllowed() || opt_volume === 0) 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;
|
||||
|
||||
if (this.context.state === 'suspended') {
|
||||
await this.context.resume();
|
||||
}
|
||||
await this.prepareToPlay();
|
||||
|
||||
const source = this.context.createBufferSource();
|
||||
const gainNode = this.context.createGain();
|
||||
@@ -121,6 +107,73 @@ export class WorkspaceAudio {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays a beep at the given frequency.
|
||||
*
|
||||
* @param tone The frequency of the beep to play, in hertz.
|
||||
* @param duration The duration of the beep, in seconds. Defaults to 0.2.
|
||||
*/
|
||||
async beep(tone: number, duration = 0.2) {
|
||||
if (!this.isPlayingAllowed()) return;
|
||||
await this.prepareToPlay();
|
||||
|
||||
const oscillator = this.context.createOscillator();
|
||||
oscillator.type = 'sine';
|
||||
oscillator.frequency.setValueAtTime(tone, this.context.currentTime);
|
||||
|
||||
const gainNode = this.context.createGain();
|
||||
gainNode.gain.setValueAtTime(0, this.context.currentTime);
|
||||
// Fade in
|
||||
gainNode.gain.linearRampToValueAtTime(0.5, this.context.currentTime + 0.01);
|
||||
// Fade out
|
||||
gainNode.gain.linearRampToValueAtTime(
|
||||
0,
|
||||
this.context.currentTime + duration,
|
||||
);
|
||||
|
||||
oscillator.connect(gainNode);
|
||||
gainNode.connect(this.context.destination);
|
||||
|
||||
oscillator.start(this.context.currentTime);
|
||||
oscillator.stop(this.context.currentTime + duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not playing sounds is currently allowed.
|
||||
*
|
||||
* @returns False if audio is muted or a sound has just been played, otherwise
|
||||
* true.
|
||||
*/
|
||||
private isPlayingAllowed(
|
||||
this: WorkspaceAudio,
|
||||
): this is WorkspaceAudio & Required<{context: AudioContext}> {
|
||||
const now = new Date();
|
||||
|
||||
if (
|
||||
this.getMuted() ||
|
||||
!this.context ||
|
||||
(this.lastSound !== null &&
|
||||
now.getTime() - this.lastSound.getTime() < SOUND_LIMIT)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares to play audio by recording the time of the last play and resuming
|
||||
* the audio context.
|
||||
*/
|
||||
private async prepareToPlay(
|
||||
this: WorkspaceAudio & Required<{context: AudioContext}>,
|
||||
) {
|
||||
this.lastSound = new Date();
|
||||
|
||||
if (this.context.state === 'suspended') {
|
||||
await this.context.resume();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param muted If true, mute sounds. Otherwise, play them.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user