digital watch can play beep sound

This commit is contained in:
Joeri Exelmans 2025-10-26 13:44:23 +01:00
parent 25fbb26fd7
commit 56467e5ea5
4 changed files with 28 additions and 7 deletions

View file

@ -4,7 +4,10 @@ import digitalFont from "./digital-font.ttf";
import { Plant } from "../Plant";
import { RaisedEvent } from "@/statecharts/runtime_types";
import sndBeep from "./beep.wav";
import "./DigitalWatch.css";
import { useAudioContext } from "@/App/useAudioContext";
import { useEffect } from "react";
type DigitalWatchState = {
light: boolean;
@ -12,10 +15,12 @@ type DigitalWatchState = {
m: number;
s: number;
alarm: boolean;
beep: boolean;
}
type DigitalWatchProps = {
state: DigitalWatchState,
speed: number
callbacks: {
onTopLeftPressed: () => void;
onTopRightPressed: () => void;
@ -28,10 +33,20 @@ type DigitalWatchProps = {
},
}
export function DigitalWatch({state: {light, h, m, s, alarm}, callbacks}: DigitalWatchProps) {
export function DigitalWatch({state: {light, h, m, s, alarm, beep}, speed, callbacks}: DigitalWatchProps) {
const twoDigits = (n: number) => n < 0 ? " " : ("0"+n.toString()).slice(-2);
const hhmmss = `${twoDigits(h)}:${twoDigits(m)}:${twoDigits(s)}`;
const [playSound, preloadAudio] = useAudioContext(speed);
preloadAudio(sndBeep);
useEffect(() => {
if (beep) {
playSound(sndBeep, false);
}
}, [beep])
return <>
<style>{`
@font-face{
@ -78,6 +93,7 @@ export const DigitalWatchPlant: Plant<DigitalWatchState> = {
{ kind: "event", event: "setS", paramName: 's' },
{ kind: "event", event: "setLight", paramName: 'lightOn'},
{ kind: "event", event: "setAlarm", paramName: 'alarmOn'},
{ kind: "event", event: "beep", paramName: 'beep'},
],
outputEvents: [
{ kind: "event", event: "topLeftPressed" },
@ -95,6 +111,7 @@ export const DigitalWatchPlant: Plant<DigitalWatchState> = {
h: 12,
m: 0,
s: 0,
beep: false,
},
reduce: (inputEvent: RaisedEvent, state: DigitalWatchState) => {
if (inputEvent.name === "setH") {
@ -118,9 +135,12 @@ export const DigitalWatchPlant: Plant<DigitalWatchState> = {
if (inputEvent.name === "unsetAlarm") {
return { ...state, alarm: false };
}
if (inputEvent.name === "beep") {
return { ...state, beep: inputEvent.param };
}
return state; // unknown event - ignore it
},
render: (state, raiseEvent) => <DigitalWatch state={state} callbacks={{
render: (state, raiseEvent, speed) => <DigitalWatch state={state} speed={speed} callbacks={{
onTopLeftPressed: () => raiseEvent({name: "topLeftPressed"}),
onTopRightPressed: () => raiseEvent({name: "topRightPressed"}),
onBottomRightPressed: () => raiseEvent({name: "bottomRightPressed"}),

Binary file not shown.

View file

@ -13,7 +13,7 @@ import { RaisedEvent } from "@/statecharts/runtime_types";
import { useEffect, useState } from "react";
import "./Microwave.css";
import { useAudioContext } from "./useAudioContext";
import { useAudioContext } from "../../useAudioContext";
export type MagnetronState = "on" | "off";
export type DoorState = "open" | "closed";

View file

@ -1,5 +1,5 @@
import { memoize } from "@/util/util";
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
// I was trying to get the 'microwave running' sound to play gapless on Chrome, and the Web Audio API turned out to be the only thing that worked properly. It has some nice bonus features as well, such as setting the playback rate, and audio filters.
@ -11,7 +11,7 @@ export function useAudioContext(speed: number) {
const ctx = new AudioContext();
const hipass = ctx.createBiquadFilter();
hipass.type = 'highpass';
hipass.frequency.value = 20; // let's not blow up anyone's speakers
hipass.frequency.value = 20; // Hz (let's not blow up anyone's speakers)
hipass.connect(ctx.destination);
return {
ctx,
@ -20,13 +20,14 @@ export function useAudioContext(speed: number) {
});
const [sounds, setSounds] = useState<AudioBufferSourceNode[]>([]);
const url2AudioBuf: (url:string) => Promise<AudioBuffer> = memoize((url: string) => {
const url2AudioBuf: (url:string) => Promise<AudioBuffer> = useCallback(memoize((url: string) => {
return fetch(url)
.then(res => res.arrayBuffer())
.then(buf => ctx.decodeAudioData(buf));
});
}), [ctx]);
function play(url: string, loop: boolean) {
console.log('play', url);
const srcPromise = url2AudioBuf(url)
.then(audioBuf => {
const src = ctx.createBufferSource();