improved sound system 🔊

Created a volume control for all sfx on the application, and a custom hook to "connect" everthing.
This commit is contained in:
Guz
2022-08-08 19:24:55 -03:00
parent a4fc460038
commit 2011662392
11 changed files with 103 additions and 17 deletions

1
public/sw.js.map Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,29 @@
import { Slider } from '@mantine/core';
import useSfx from '~hooks/useSfx';
export default function VolumePicker() {
const { play, volume, setVolume } = useSfx('click.wav');
const steps = [
{ value: 0, label: '0' },
{ value: 25, label: '1' },
{ value: 50, label: '2' },
{ value: 75, label: '3' },
{ value: 100, label: '4' },
];
return (
<Slider
label={(v) => steps.find((s) => s.value == v)?.label}
onChangeEnd={(value) => {
setVolume(() =>
Number.parseFloat(`0.${steps.find((s) => s.value == value)?.label}`)
);
}}
defaultValue={steps.find((s) => s.label === `${volume * 10}`)?.value}
step={25}
marks={steps}
styles={{ markLabel: { display: 'none' } }}
/>
);
}

View File

@@ -1,19 +1,23 @@
import { IconMenu2, IconColorSwatch } from '@tabler/icons';
import {
IconMenu2,
IconColorSwatch,
IconVolume,
IconVolume2,
IconVolume3,
} from '@tabler/icons';
import { Menu as M, ActionIcon, Popover } from '@mantine/core';
import { useState } from 'react';
import { useSound } from 'use-sound';
import { SwitchTheme } from '~components/MantineUI';
import useSfx from '~hooks/useSfx';
import SchemePicker from './SchemePicker';
export { SchemePicker };
import VolumePicker from './VolumePicker';
export { SchemePicker, VolumePicker };
export default function Menu() {
const [opened, setOpened] = useState(false);
const [play] = useSound('/sounds/click.wav', {
format: ['wav'],
volume: 0.3,
});
const { play, volume } = useSfx('click.wav');
const playClick = (high: boolean) =>
play({ playbackRate: (high ? 3 : 1) + Math.random() });
@@ -37,6 +41,7 @@ export default function Menu() {
<M.Dropdown>
<M.Label>Menu</M.Label>
<M.Item icon={<SwitchTheme onChange={playClick} />}>
<p>Tema escuro</p>
</M.Item>
@@ -50,6 +55,22 @@ export default function Menu() {
</Popover.Dropdown>
</Popover>
</M.Item>
<M.Divider />
<M.Item
icon={
volume == 0 ? (
<IconVolume3 />
) : volume < 0.3 ? (
<IconVolume2 />
) : (
<IconVolume />
)
}
>
<VolumePicker />
</M.Item>
</M.Dropdown>
</M>
);

View File

@@ -1,8 +1,8 @@
import { Text } from '@mantine/core';
import { ReactNode, useEffect } from 'react';
import { motion, HTMLMotionProps, useAnimationControls } from 'framer-motion';
import useSound from 'use-sound';
import { Heart } from '~components/Specials';
import useSfx from '~hooks/useSfx';
import Handler from './Handler';
export { Handler };
@@ -39,8 +39,7 @@ export default function Message({
const animControls = useAnimationControls();
const [play] = useSound('/sounds/message_pop.wav', {
format: ['wav'],
const { play } = useSfx('message_pop.wav', {
sprite: {
pop0: [0, 300],
pop1: [600, 300],
@@ -48,7 +47,6 @@ export default function Message({
pop3: [1850, 300],
pop4: [2600, 300],
},
volume: 0.3,
});
useEffect(() => {

View File

@@ -1,12 +1,9 @@
import { IconHeart } from '@tabler/icons';
import { motion } from 'framer-motion';
import useSound from 'use-sound';
import useSfx from '~hooks/useSfx';
export default function Heart() {
const [play] = useSound('/sounds/heartbeat.wav', {
format: ['wav'],
volume: 0.3,
});
const { play } = useSfx('heartbeat.wav');
return (
<motion.div

39
src/hooks/useSfx.ts Normal file
View File

@@ -0,0 +1,39 @@
import { useLocalStorage } from '@mantine/hooks';
import { useSound } from 'use-sound';
import { SpriteMap } from 'use-sound/dist/types';
/**
* Custom hook to play sound effects.
*
* @param file The file name of the sound effect.
*/
export default function useSfx(
file: string,
config?: { format?: string[]; sprite?: SpriteMap }
) {
const [sfxVolume, setVolume] = useLocalStorage<number>({
key: 'sfx-volume',
defaultValue: 0.3,
});
/**
* Regex to extract the extension from file name.
*
* Thanks to Tomalak, on stackoverflow for the regex.
* https://stackoverflow.com/a/680982
* CC BY-SA 4.0
*/
const regExt = /(?:\.([^.]+))?$/;
const [play] = useSound(`/sounds/sfx/${file}`, {
format: config?.format ?? [regExt.exec(file)?.[1] ?? file.split('.').pop()],
volume: sfxVolume,
sprite: config?.sprite,
});
return {
play,
volume: sfxVolume,
setVolume,
};
}

View File

@@ -33,7 +33,7 @@ export default function App(props: AppProps) {
return (
<>
<Head>
<title>Page title</title>
<title>Hello.Kei</title>
<meta
name='viewport'
content='minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no, user-scalable=no, viewport-fit=cover'