From 2490b33ff29ea7dbfa84fcb0971d29fc7358d889 Mon Sep 17 00:00:00 2001 From: Eli Manzo <96manzo.eli@gmail.com> Date: Sun, 27 Oct 2024 22:09:56 -0700 Subject: [PATCH 01/12] feat: added playSound function to simons game --- .../simon-game/src/app/util/playSound.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 workspaces/simon-game/src/app/util/playSound.ts diff --git a/workspaces/simon-game/src/app/util/playSound.ts b/workspaces/simon-game/src/app/util/playSound.ts new file mode 100644 index 00000000..1bfaafd6 --- /dev/null +++ b/workspaces/simon-game/src/app/util/playSound.ts @@ -0,0 +1,18 @@ +export const playSound = ( + context: BaseAudioContext, + frequency: number, + duration: number, + volume: number, +) => { + const oscillatorNode = context.createOscillator(); + oscillatorNode.frequency.setValueAtTime(frequency, context.currentTime); + + const gainNode = context.createGain(); + gainNode.gain.setValueAtTime(volume, context.currentTime); + + oscillatorNode.connect(gainNode); + gainNode.connect(context.destination); + + oscillatorNode.start(); + oscillatorNode.stop(context.currentTime + duration / 1000); +}; From d1feaeec52104fc776d332a29fe23ed92409d3c9 Mon Sep 17 00:00:00 2001 From: Eli Manzo <96manzo.eli@gmail.com> Date: Sun, 27 Oct 2024 22:15:29 -0700 Subject: [PATCH 02/12] chore: added some error handling --- .../simon-game/src/app/util/playSound.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/workspaces/simon-game/src/app/util/playSound.ts b/workspaces/simon-game/src/app/util/playSound.ts index 1bfaafd6..30f677a3 100644 --- a/workspaces/simon-game/src/app/util/playSound.ts +++ b/workspaces/simon-game/src/app/util/playSound.ts @@ -1,9 +1,29 @@ +/** + * Plays a sound using the Web Audio API. + * + * @param context - The audio context to use for generating the sound. + * @param frequency - The frequency of the sound in Hertz + * @param duration - The duration of the sound in milliseconds. + * @param volume - The volume of the sound, typically between 0 and 1. + */ export const playSound = ( context: BaseAudioContext, frequency: number, duration: number, volume: number, ) => { + if (frequency <= 0) { + throw new Error("Frequency must be a positive number."); + } + + if (duration <= 0) { + throw new Error("Duration must be a positive number."); + } + + if (volume < 0 || volume > 1) { + throw new Error("Volume must be between 0 and 1."); + } + const oscillatorNode = context.createOscillator(); oscillatorNode.frequency.setValueAtTime(frequency, context.currentTime); From 4af3aef21067dce431560e5977b0191f38bf74ce Mon Sep 17 00:00:00 2001 From: Eli Manzo <96manzo.eli@gmail.com> Date: Sun, 27 Oct 2024 22:38:38 -0700 Subject: [PATCH 03/12] chore: using AudioContext instead of BaseAudioContext as per guideline --- workspaces/simon-game/src/app/util/playSound.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workspaces/simon-game/src/app/util/playSound.ts b/workspaces/simon-game/src/app/util/playSound.ts index 30f677a3..bbf7d111 100644 --- a/workspaces/simon-game/src/app/util/playSound.ts +++ b/workspaces/simon-game/src/app/util/playSound.ts @@ -7,7 +7,7 @@ * @param volume - The volume of the sound, typically between 0 and 1. */ export const playSound = ( - context: BaseAudioContext, + context: AudioContext, frequency: number, duration: number, volume: number, From 3c7a842d5277647870b11313e8deaeb357589233 Mon Sep 17 00:00:00 2001 From: Eli Manzo <96manzo.eli@gmail.com> Date: Mon, 28 Oct 2024 21:12:11 -0700 Subject: [PATCH 04/12] feat: added some freq buttons to test the playSound function --- .../simon-game/src/app/components/App.tsx | 24 +++++++++++++++++++ workspaces/simon-game/src/app/constants.ts | 5 ++++ .../simon-game/src/app/util/playSound.ts | 6 ++--- 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 workspaces/simon-game/src/app/constants.ts diff --git a/workspaces/simon-game/src/app/components/App.tsx b/workspaces/simon-game/src/app/components/App.tsx index 895d9015..e049c44b 100644 --- a/workspaces/simon-game/src/app/components/App.tsx +++ b/workspaces/simon-game/src/app/components/App.tsx @@ -1,10 +1,34 @@ import React from "react"; +import { buttonSoundConfig } from "../constants.ts"; +import playSound from "../util/playSound.ts"; import { Box } from "./Box.tsx"; export function App() { + let audioContext: AudioContext | null = null; + + const handleFreqClick = (freq: number) => { + if(!audioContext) { + audioContext = new window.AudioContext(); + } + playSound( + audioContext, + freq, + buttonSoundConfig.duration, + buttonSoundConfig.volume, + ) + } + return (
+ {buttonSoundConfig.frequencies.map((freq, index) => ( + + ))} { +) { if (frequency <= 0) { throw new Error("Frequency must be a positive number."); } @@ -35,4 +35,4 @@ export const playSound = ( oscillatorNode.start(); oscillatorNode.stop(context.currentTime + duration / 1000); -}; +} From eefe6ad2727fbe71f3a823bd203089eb6a742d20 Mon Sep 17 00:00:00 2001 From: Eli Manzo <96manzo.eli@gmail.com> Date: Mon, 28 Oct 2024 21:24:19 -0700 Subject: [PATCH 05/12] chore: applying feedback --- .../simon-game/src/app/components/App.tsx | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/workspaces/simon-game/src/app/components/App.tsx b/workspaces/simon-game/src/app/components/App.tsx index e049c44b..65786fde 100644 --- a/workspaces/simon-game/src/app/components/App.tsx +++ b/workspaces/simon-game/src/app/components/App.tsx @@ -6,25 +6,19 @@ import { Box } from "./Box.tsx"; export function App() { let audioContext: AudioContext | null = null; - - const handleFreqClick = (freq: number) => { - if(!audioContext) { - audioContext = new window.AudioContext(); - } - playSound( - audioContext, - freq, - buttonSoundConfig.duration, - buttonSoundConfig.volume, - ) - } - return (
{buttonSoundConfig.frequencies.map((freq, index) => ( From 68c8772821153cb3a323c1264554a3729c22b46d Mon Sep 17 00:00:00 2001 From: Eli Manzo <96manzo.eli@gmail.com> Date: Mon, 28 Oct 2024 21:43:04 -0700 Subject: [PATCH 06/12] chore: adding audio context out of render --- workspaces/simon-game/src/app/components/App.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workspaces/simon-game/src/app/components/App.tsx b/workspaces/simon-game/src/app/components/App.tsx index 65786fde..62201e37 100644 --- a/workspaces/simon-game/src/app/components/App.tsx +++ b/workspaces/simon-game/src/app/components/App.tsx @@ -4,8 +4,9 @@ import playSound from "../util/playSound.ts"; import { Box } from "./Box.tsx"; +let audioContext: AudioContext | null = null; + export function App() { - let audioContext: AudioContext | null = null; return (
{buttonSoundConfig.frequencies.map((freq, index) => ( From 064314d16063b4726bc6ce032e53ecddd26e4e66 Mon Sep 17 00:00:00 2001 From: Eli Manzo <96manzo.eli@gmail.com> Date: Tue, 29 Oct 2024 00:30:11 -0700 Subject: [PATCH 07/12] feat: implementing sounds on click + fixed popping sounds from the playSound --- .../simon-game/src/app/components/App.tsx | 45 ++++++++++--------- .../simon-game/src/app/components/Box.tsx | 22 ++++++--- workspaces/simon-game/src/app/constants.ts | 7 ++- .../simon-game/src/app/util/playSound.ts | 13 ++++-- 4 files changed, 57 insertions(+), 30 deletions(-) diff --git a/workspaces/simon-game/src/app/components/App.tsx b/workspaces/simon-game/src/app/components/App.tsx index 62201e37..416463b5 100644 --- a/workspaces/simon-game/src/app/components/App.tsx +++ b/workspaces/simon-game/src/app/components/App.tsx @@ -1,38 +1,43 @@ import React from "react"; import { buttonSoundConfig } from "../constants.ts"; -import playSound from "../util/playSound.ts"; +import { playSound } from "../util/playSound.ts"; import { Box } from "./Box.tsx"; let audioContext: AudioContext | null = null; export function App() { + const handleOnClick = (freq: number) => + playSound( + (audioContext ??= new AudioContext()), + freq, + buttonSoundConfig.duration, + buttonSoundConfig.volume, + ); + return ( -
- {buttonSoundConfig.frequencies.map((freq, index) => ( - - ))} - +
+ handleOnClick(buttonSoundConfig.frequencies.red)} + /> + handleOnClick(buttonSoundConfig.frequencies.cobaltBlue) + } + /> + handleOnClick(buttonSoundConfig.frequencies.green)} + /> + handleOnClick(buttonSoundConfig.frequencies.yellow)} /> - -
); } diff --git a/workspaces/simon-game/src/app/components/Box.tsx b/workspaces/simon-game/src/app/components/Box.tsx index 41032b28..5c9194e5 100644 --- a/workspaces/simon-game/src/app/components/Box.tsx +++ b/workspaces/simon-game/src/app/components/Box.tsx @@ -5,18 +5,28 @@ type Props = { height?: number; width?: number; margin?: number; + handleClick: () => void; }; -export function Box(props: Props) { +export function Box({ + color = "lightblue", + height = 100, + width = 100, + margin, + handleClick, +}: Props) { return ( -
); } diff --git a/workspaces/simon-game/src/app/constants.ts b/workspaces/simon-game/src/app/constants.ts index 722da027..ff3d3842 100644 --- a/workspaces/simon-game/src/app/constants.ts +++ b/workspaces/simon-game/src/app/constants.ts @@ -1,5 +1,10 @@ export const buttonSoundConfig = { duration: 300, volume: 0.1, - frequencies: [261.63, 329.63, 392.0, 523.25], + frequencies: { + red: 261.63, + cobaltBlue: 329.63, + green: 392.0, + yellow: 523.25, + }, }; diff --git a/workspaces/simon-game/src/app/util/playSound.ts b/workspaces/simon-game/src/app/util/playSound.ts index f4c99609..1b1cd78b 100644 --- a/workspaces/simon-game/src/app/util/playSound.ts +++ b/workspaces/simon-game/src/app/util/playSound.ts @@ -6,12 +6,12 @@ * @param duration - The duration of the sound in milliseconds. * @param volume - The volume of the sound, typically between 0 and 1. */ -export default function playSound( +export const playSound = ( context: AudioContext, frequency: number, duration: number, volume: number, -) { +) => { if (frequency <= 0) { throw new Error("Frequency must be a positive number."); } @@ -30,9 +30,16 @@ export default function playSound( const gainNode = context.createGain(); gainNode.gain.setValueAtTime(volume, context.currentTime); + // Creates the smooth fades-in / fade-out sound effect (Avoids the popping sounds) + gainNode.gain.linearRampToValueAtTime(volume, context.currentTime + 0.01); + gainNode.gain.linearRampToValueAtTime( + 0, + context.currentTime + duration / 1000 - 0.01, + ); + oscillatorNode.connect(gainNode); gainNode.connect(context.destination); oscillatorNode.start(); oscillatorNode.stop(context.currentTime + duration / 1000); -} +}; From 6997466164b59e4558115cb4aac05e45a062d9fe Mon Sep 17 00:00:00 2001 From: Eli Manzo <96manzo.eli@gmail.com> Date: Tue, 29 Oct 2024 00:34:38 -0700 Subject: [PATCH 08/12] fix: linting --- workspaces/simon-game/src/app/components/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workspaces/simon-game/src/app/components/App.tsx b/workspaces/simon-game/src/app/components/App.tsx index 416463b5..9a2a0ed5 100644 --- a/workspaces/simon-game/src/app/components/App.tsx +++ b/workspaces/simon-game/src/app/components/App.tsx @@ -16,7 +16,7 @@ export function App() { ); return ( -
+
handleOnClick(buttonSoundConfig.frequencies.red)} From 707c315a2ae41fef6e636e61d6b8b209bbdfd1f5 Mon Sep 17 00:00:00 2001 From: Eli Manzo <96manzo.eli@gmail.com> Date: Tue, 29 Oct 2024 23:39:51 -0700 Subject: [PATCH 09/12] chore: applying PR feedback --- .../simon-game/src/app/components/App.tsx | 38 +++---------------- .../simon-game/src/app/components/Box.tsx | 12 +++--- workspaces/simon-game/src/app/constants.ts | 30 ++++++++++----- .../simon-game/src/app/util/playNote.ts | 5 +++ .../simon-game/src/app/util/playSound.ts | 34 ++++++++++------- 5 files changed, 57 insertions(+), 62 deletions(-) create mode 100644 workspaces/simon-game/src/app/util/playNote.ts diff --git a/workspaces/simon-game/src/app/components/App.tsx b/workspaces/simon-game/src/app/components/App.tsx index 9a2a0ed5..4a5c06dc 100644 --- a/workspaces/simon-game/src/app/components/App.tsx +++ b/workspaces/simon-game/src/app/components/App.tsx @@ -1,43 +1,15 @@ import React from "react"; -import { buttonSoundConfig } from "../constants.ts"; -import { playSound } from "../util/playSound.ts"; import { Box } from "./Box.tsx"; - -let audioContext: AudioContext | null = null; +import { playNote } from "../util/playNote.ts"; +import { config } from "../constants.ts"; export function App() { - const handleOnClick = (freq: number) => - playSound( - (audioContext ??= new AudioContext()), - freq, - buttonSoundConfig.duration, - buttonSoundConfig.volume, - ); - return (
- handleOnClick(buttonSoundConfig.frequencies.red)} - /> - - handleOnClick(buttonSoundConfig.frequencies.cobaltBlue) - } - /> - handleOnClick(buttonSoundConfig.frequencies.green)} - /> - handleOnClick(buttonSoundConfig.frequencies.yellow)} - /> + {config.boxes.map((box) => ( + playNote(box.frequency)} /> + ))}
); } diff --git a/workspaces/simon-game/src/app/components/Box.tsx b/workspaces/simon-game/src/app/components/Box.tsx index 5c9194e5..64e989ab 100644 --- a/workspaces/simon-game/src/app/components/Box.tsx +++ b/workspaces/simon-game/src/app/components/Box.tsx @@ -5,7 +5,7 @@ type Props = { height?: number; width?: number; margin?: number; - handleClick: () => void; + onClick: () => void; }; export function Box({ @@ -13,20 +13,20 @@ export function Box({ height = 100, width = 100, margin, - handleClick, + onClick, }: Props) { return (