digital watch can play beep sound
This commit is contained in:
parent
25fbb26fd7
commit
56467e5ea5
4 changed files with 28 additions and 7 deletions
|
|
@ -4,7 +4,10 @@ import digitalFont from "./digital-font.ttf";
|
||||||
import { Plant } from "../Plant";
|
import { Plant } from "../Plant";
|
||||||
import { RaisedEvent } from "@/statecharts/runtime_types";
|
import { RaisedEvent } from "@/statecharts/runtime_types";
|
||||||
|
|
||||||
|
import sndBeep from "./beep.wav";
|
||||||
import "./DigitalWatch.css";
|
import "./DigitalWatch.css";
|
||||||
|
import { useAudioContext } from "@/App/useAudioContext";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
type DigitalWatchState = {
|
type DigitalWatchState = {
|
||||||
light: boolean;
|
light: boolean;
|
||||||
|
|
@ -12,10 +15,12 @@ type DigitalWatchState = {
|
||||||
m: number;
|
m: number;
|
||||||
s: number;
|
s: number;
|
||||||
alarm: boolean;
|
alarm: boolean;
|
||||||
|
beep: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
type DigitalWatchProps = {
|
type DigitalWatchProps = {
|
||||||
state: DigitalWatchState,
|
state: DigitalWatchState,
|
||||||
|
speed: number
|
||||||
callbacks: {
|
callbacks: {
|
||||||
onTopLeftPressed: () => void;
|
onTopLeftPressed: () => void;
|
||||||
onTopRightPressed: () => 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 twoDigits = (n: number) => n < 0 ? " " : ("0"+n.toString()).slice(-2);
|
||||||
const hhmmss = `${twoDigits(h)}:${twoDigits(m)}:${twoDigits(s)}`;
|
const hhmmss = `${twoDigits(h)}:${twoDigits(m)}:${twoDigits(s)}`;
|
||||||
|
|
||||||
|
const [playSound, preloadAudio] = useAudioContext(speed);
|
||||||
|
|
||||||
|
preloadAudio(sndBeep);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (beep) {
|
||||||
|
playSound(sndBeep, false);
|
||||||
|
}
|
||||||
|
}, [beep])
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<style>{`
|
<style>{`
|
||||||
@font-face{
|
@font-face{
|
||||||
|
|
@ -78,6 +93,7 @@ export const DigitalWatchPlant: Plant<DigitalWatchState> = {
|
||||||
{ kind: "event", event: "setS", paramName: 's' },
|
{ kind: "event", event: "setS", paramName: 's' },
|
||||||
{ kind: "event", event: "setLight", paramName: 'lightOn'},
|
{ kind: "event", event: "setLight", paramName: 'lightOn'},
|
||||||
{ kind: "event", event: "setAlarm", paramName: 'alarmOn'},
|
{ kind: "event", event: "setAlarm", paramName: 'alarmOn'},
|
||||||
|
{ kind: "event", event: "beep", paramName: 'beep'},
|
||||||
],
|
],
|
||||||
outputEvents: [
|
outputEvents: [
|
||||||
{ kind: "event", event: "topLeftPressed" },
|
{ kind: "event", event: "topLeftPressed" },
|
||||||
|
|
@ -95,6 +111,7 @@ export const DigitalWatchPlant: Plant<DigitalWatchState> = {
|
||||||
h: 12,
|
h: 12,
|
||||||
m: 0,
|
m: 0,
|
||||||
s: 0,
|
s: 0,
|
||||||
|
beep: false,
|
||||||
},
|
},
|
||||||
reduce: (inputEvent: RaisedEvent, state: DigitalWatchState) => {
|
reduce: (inputEvent: RaisedEvent, state: DigitalWatchState) => {
|
||||||
if (inputEvent.name === "setH") {
|
if (inputEvent.name === "setH") {
|
||||||
|
|
@ -118,9 +135,12 @@ export const DigitalWatchPlant: Plant<DigitalWatchState> = {
|
||||||
if (inputEvent.name === "unsetAlarm") {
|
if (inputEvent.name === "unsetAlarm") {
|
||||||
return { ...state, alarm: false };
|
return { ...state, alarm: false };
|
||||||
}
|
}
|
||||||
|
if (inputEvent.name === "beep") {
|
||||||
|
return { ...state, beep: inputEvent.param };
|
||||||
|
}
|
||||||
return state; // unknown event - ignore it
|
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"}),
|
onTopLeftPressed: () => raiseEvent({name: "topLeftPressed"}),
|
||||||
onTopRightPressed: () => raiseEvent({name: "topRightPressed"}),
|
onTopRightPressed: () => raiseEvent({name: "topRightPressed"}),
|
||||||
onBottomRightPressed: () => raiseEvent({name: "bottomRightPressed"}),
|
onBottomRightPressed: () => raiseEvent({name: "bottomRightPressed"}),
|
||||||
|
|
|
||||||
BIN
src/App/Plant/DigitalWatch/beep.wav
Normal file
BIN
src/App/Plant/DigitalWatch/beep.wav
Normal file
Binary file not shown.
|
|
@ -13,7 +13,7 @@ import { RaisedEvent } from "@/statecharts/runtime_types";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
import "./Microwave.css";
|
import "./Microwave.css";
|
||||||
import { useAudioContext } from "./useAudioContext";
|
import { useAudioContext } from "../../useAudioContext";
|
||||||
|
|
||||||
export type MagnetronState = "on" | "off";
|
export type MagnetronState = "on" | "off";
|
||||||
export type DoorState = "open" | "closed";
|
export type DoorState = "open" | "closed";
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { memoize } from "@/util/util";
|
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.
|
// 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 ctx = new AudioContext();
|
||||||
const hipass = ctx.createBiquadFilter();
|
const hipass = ctx.createBiquadFilter();
|
||||||
hipass.type = 'highpass';
|
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);
|
hipass.connect(ctx.destination);
|
||||||
return {
|
return {
|
||||||
ctx,
|
ctx,
|
||||||
|
|
@ -20,13 +20,14 @@ export function useAudioContext(speed: number) {
|
||||||
});
|
});
|
||||||
const [sounds, setSounds] = useState<AudioBufferSourceNode[]>([]);
|
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)
|
return fetch(url)
|
||||||
.then(res => res.arrayBuffer())
|
.then(res => res.arrayBuffer())
|
||||||
.then(buf => ctx.decodeAudioData(buf));
|
.then(buf => ctx.decodeAudioData(buf));
|
||||||
});
|
}), [ctx]);
|
||||||
|
|
||||||
function play(url: string, loop: boolean) {
|
function play(url: string, loop: boolean) {
|
||||||
|
console.log('play', url);
|
||||||
const srcPromise = url2AudioBuf(url)
|
const srcPromise = url2AudioBuf(url)
|
||||||
.then(audioBuf => {
|
.then(audioBuf => {
|
||||||
const src = ctx.createBufferSource();
|
const src = ctx.createBufferSource();
|
||||||
Loading…
Add table
Add a link
Reference in a new issue