important feature: use Web Audio API to get microwave sounds just right.
This commit is contained in:
parent
a5afcd5908
commit
f3a9656891
3 changed files with 47 additions and 21 deletions
|
|
@ -399,7 +399,7 @@ export function App() {
|
||||||
flex: '0 0 content',
|
flex: '0 0 content',
|
||||||
overflowY: "auto",
|
overflowY: "auto",
|
||||||
overflowX: "visible",
|
overflowX: "visible",
|
||||||
maxWidth: '50vw',
|
maxWidth: 'min(400px,50vw)',
|
||||||
}}>
|
}}>
|
||||||
<div className="stackVertical" style={{height:'100%'}}>
|
<div className="stackVertical" style={{height:'100%'}}>
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -12,3 +12,7 @@ rect.microwaveButtonHelper:active {
|
||||||
fill: red;
|
fill: red;
|
||||||
fill-opacity: 0.5;
|
fill-opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rect.microwaveDoorHelper {
|
||||||
|
fill-opacity: 0;
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,7 @@ import sndBell from "./bell.wav";
|
||||||
import sndRunning from "./running.wav";
|
import sndRunning from "./running.wav";
|
||||||
import { Plant } from "../Plant";
|
import { Plant } from "../Plant";
|
||||||
import { RaisedEvent } from "@/statecharts/runtime_types";
|
import { RaisedEvent } from "@/statecharts/runtime_types";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
import "./Microwave.css";
|
import "./Microwave.css";
|
||||||
|
|
||||||
|
|
@ -82,23 +82,54 @@ const DOOR_Y0 = 68;
|
||||||
const DOOR_WIDTH = 353;
|
const DOOR_WIDTH = 353;
|
||||||
const DOOR_HEIGHT = 217;
|
const DOOR_HEIGHT = 217;
|
||||||
|
|
||||||
|
const ctx = new AudioContext();
|
||||||
|
|
||||||
|
function fetchAudioBuffer(url: string): Promise<AudioBuffer> {
|
||||||
|
return fetch(url).then(res => {
|
||||||
|
return res.arrayBuffer();
|
||||||
|
}).then(buf => {
|
||||||
|
return ctx.decodeAudioData(buf);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function playAudioBufer(buf: AudioBuffer, loop: boolean) {
|
||||||
|
const src = ctx.createBufferSource();
|
||||||
|
src.buffer = buf;
|
||||||
|
src.connect(ctx.destination);
|
||||||
|
if (loop) src.loop = true;
|
||||||
|
src.start();
|
||||||
|
return () => src.stop();
|
||||||
|
}
|
||||||
|
|
||||||
export function Magnetron({state: {timeDisplay, bell, magnetron}, callbacks}: MicrowaveProps) {
|
export function Magnetron({state: {timeDisplay, bell, magnetron}, callbacks}: MicrowaveProps) {
|
||||||
const [door, setDoor] = useState<DoorState>("closed");
|
const [door, setDoor] = useState<DoorState>("closed");
|
||||||
const [playBell, setPlayBell] = useState(false);
|
|
||||||
|
|
||||||
// a bit hacky: when the bell-state changes to true, we play the bell sound for 610 ms...
|
const bufRunningPromise = useRef(fetchAudioBuffer(sndRunning));
|
||||||
|
const bufBellPromise = useRef(fetchAudioBuffer(sndBell));
|
||||||
|
|
||||||
|
const refSndBell = useRef<HTMLAudioElement>(null);
|
||||||
|
const refSndRunning = useRef<HTMLAudioElement>(null);
|
||||||
|
|
||||||
|
|
||||||
|
// a bit hacky: when the bell-state changes to true, we play the bell sound...
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let timeout: NodeJS.Timeout;
|
|
||||||
if (bell) {
|
if (bell) {
|
||||||
setPlayBell(true);
|
bufBellPromise.current.then(buf => {
|
||||||
timeout = setTimeout(() => {
|
playAudioBufer(buf, false);
|
||||||
setPlayBell(false);
|
})
|
||||||
}, 610);
|
|
||||||
}
|
}
|
||||||
return () => { if (timeout) clearTimeout(timeout); };
|
|
||||||
}, [bell]);
|
}, [bell]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (magnetron === "on") {
|
||||||
|
const stop = bufRunningPromise.current.then(buf => {
|
||||||
|
return playAudioBufer(buf, true);
|
||||||
|
});
|
||||||
|
return () => stop.then(stop => stop());
|
||||||
|
}
|
||||||
|
return () => {};
|
||||||
|
}, [magnetron])
|
||||||
|
|
||||||
preload(imgSmallClosedOff, {as: "image"});
|
preload(imgSmallClosedOff, {as: "image"});
|
||||||
preload(imgSmallClosedOn, {as: "image"});
|
preload(imgSmallClosedOn, {as: "image"});
|
||||||
preload(imgSmallOpenedOff, {as: "image"});
|
preload(imgSmallOpenedOff, {as: "image"});
|
||||||
|
|
@ -122,7 +153,7 @@ export function Magnetron({state: {timeDisplay, bell, magnetron}, callbacks}: Mi
|
||||||
src: url(${fontDigital});
|
src: url(${fontDigital});
|
||||||
}
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
<svg width={520} height={348}>
|
<svg style={{maxWidth: 520}} width='100%' height='auto' viewBox="0 0 520 348">
|
||||||
<image xlinkHref={imgs[door][magnetron]} width={520} height={348}/>
|
<image xlinkHref={imgs[door][magnetron]} width={520} height={348}/>
|
||||||
|
|
||||||
<rect className="microwaveButtonHelper" x={START_X0} y={START_Y0} width={BUTTON_WIDTH} height={BUTTON_HEIGHT}
|
<rect className="microwaveButtonHelper" x={START_X0} y={START_Y0} width={BUTTON_WIDTH} height={BUTTON_HEIGHT}
|
||||||
|
|
@ -135,20 +166,11 @@ export function Magnetron({state: {timeDisplay, bell, magnetron}, callbacks}: Mi
|
||||||
onMouseDown={() => callbacks.incTimePressed()}
|
onMouseDown={() => callbacks.incTimePressed()}
|
||||||
onMouseUp={() => callbacks.incTimeReleased()}
|
onMouseUp={() => callbacks.incTimeReleased()}
|
||||||
/>
|
/>
|
||||||
<rect className="microwaveButtonHelper" x={DOOR_X0} y={DOOR_Y0} width={DOOR_WIDTH} height={DOOR_HEIGHT}
|
<rect className="microwaveDoorHelper" x={DOOR_X0} y={DOOR_Y0} width={DOOR_WIDTH} height={DOOR_HEIGHT} onMouseDown={() => door === "open" ? closeDoor() : openDoor()}
|
||||||
onMouseDown={() => door === "open" ? closeDoor() : openDoor()}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<text x={472} y={106} textAnchor="end" fontFamily="digital-font" fontSize={24} fill="lightgreen">{timeDisplay}</text>
|
<text x={472} y={106} textAnchor="end" fontFamily="digital-font" fontSize={24} fill="lightgreen">{timeDisplay}</text>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
{magnetron === "on" && <audio hidden autoPlay loop>
|
|
||||||
<source src={sndRunning} type="audio/wav"/>
|
|
||||||
</audio>}
|
|
||||||
|
|
||||||
{playBell && <audio hidden autoPlay>
|
|
||||||
<source src={sndBell} type="audio/wav"/>
|
|
||||||
</audio>}
|
|
||||||
</>;
|
</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue