Skip to content

Commit f7073f7

Browse files
author
Oskar Widmark
committed
fix: update sound player
1 parent 0602016 commit f7073f7

File tree

7 files changed

+117
-43
lines changed

7 files changed

+117
-43
lines changed

package-lock.json

Lines changed: 44 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"@mui/material": "^6.4.4",
1717
"react": "^19.0.0",
1818
"react-dom": "^19.0.0",
19-
"use-sound": "^5.0.0"
19+
"tone": "^15.1.22"
2020
},
2121
"devDependencies": {
2222
"@eslint/js": "^9.19.0",

src/App.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
sleep,
1919
sortNameToSortType,
2020
timeScale,
21+
toHz,
2122
} from './utils';
2223
import { SideDrawer } from './SideDrawer';
2324
import {
@@ -35,9 +36,8 @@ import { SortingAlgorithmSelect } from './SortingAlgorithmSelect';
3536
import { TimeSlider } from './TimeSlider';
3637

3738
type Props = {
38-
playSound: () => void;
39+
playSound: (params: { frequency: number; duration?: string }) => void;
3940
stopSounds: () => void;
40-
setSoundPitch: (value: number) => void;
4141
};
4242

4343
class App extends React.Component<Props> {
@@ -272,10 +272,9 @@ class App extends React.Component<Props> {
272272
playSoundForColumn = (arr: SortValue[], i: number) => {
273273
if (!this.state.shouldPlaySound) return;
274274

275-
this.props.setSoundPitch(
276-
(arr[i].value * 7) / this.state.settings.columnNbr + 3,
277-
);
278-
this.props.playSound();
275+
this.props.playSound({
276+
frequency: toHz(arr[i].value, this.state.settings.columnNbr),
277+
});
279278
};
280279

281280
toggleDisplaySettings = () => {

src/AppWithSound.tsx

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,11 @@
1-
import React, { useEffect } from 'react';
1+
import React from 'react';
22
import App from './App';
3-
import useSound from 'use-sound';
4-
import triangle from './triangle.mp3';
3+
import { useSoundPlayer } from './useSoundPlayer';
54

65
export function AppWithSound(): React.ReactElement {
7-
const [playbackRate, setPlaybackRate] = React.useState(1.0);
8-
9-
const [play, { stop }] = useSound(triangle, {
10-
playbackRate,
6+
const { play, stop } = useSoundPlayer({
7+
type: 'triangle',
118
});
129

13-
useEffect(() => {
14-
stop();
15-
}, [stop]);
16-
17-
return (
18-
<App playSound={play} stopSounds={stop} setSoundPitch={setPlaybackRate} />
19-
);
10+
return <App playSound={play} stopSounds={stop} />;
2011
}

src/triangle.mp3

-51.6 KB
Binary file not shown.

src/useSoundPlayer.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { useEffect, useRef, useCallback, RefObject } from 'react';
2+
import * as Tone from 'tone';
3+
import { NonCustomOscillatorType } from 'tone/build/esm/source/oscillator/OscillatorInterface';
4+
5+
type PlayParams = {
6+
frequency: number;
7+
duration?: string;
8+
};
9+
10+
export function useSoundPlayer({
11+
type = 'sine' as NonCustomOscillatorType,
12+
} = {}) {
13+
const synthRef: RefObject<Tone.Synth | null> = useRef(null);
14+
const startedRef = useRef(false);
15+
16+
// create the Synth and connect it to the master output
17+
useEffect(() => {
18+
const synth = new Tone.Synth({
19+
oscillator: { type },
20+
envelope: { attack: 0.05, decay: 0, sustain: 1, release: 0.05 },
21+
}).toDestination();
22+
23+
synthRef.current = synth;
24+
return () => {
25+
synth.dispose();
26+
};
27+
}, [type]);
28+
29+
// ensure AudioContext is resumed once on first play
30+
const ensureStarted = useCallback(async () => {
31+
if (!startedRef.current) {
32+
await Tone.start();
33+
startedRef.current = true;
34+
}
35+
}, []);
36+
37+
const play = useCallback(
38+
async ({ frequency }: PlayParams) => {
39+
await ensureStarted();
40+
const synth = synthRef.current;
41+
if (!synth) return;
42+
43+
// stop any currently playing note
44+
synth.triggerRelease();
45+
46+
// trigger new tone for 2 seconds max
47+
synth.triggerAttackRelease(frequency, 2);
48+
},
49+
[ensureStarted],
50+
);
51+
52+
const stop = useCallback(() => {
53+
synthRef.current?.triggerRelease();
54+
}, []);
55+
56+
return { play, stop };
57+
}

src/utils.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,8 @@ export const sortNameToSortType: Record<SortName, string> = {
5959
[SortName.BitonicSort]: SortType.Comparison,
6060
[SortName.BullySort]: SortType.Comparison,
6161
};
62+
63+
// something that sounds good
64+
export const toHz = (value: number, columnNbr: number) => {
65+
return (440 * value) / columnNbr + 200;
66+
};

0 commit comments

Comments
 (0)