import { useEffect, useState, useRef, useCallback } from 'react'; import { Modal } from '@/components/modal'; import { Slider } from '@/components/slider'; import styles from './binaural.module.css'; interface BinauralProps { onClose: () => void; show: boolean; } interface Preset { baseFrequency: number; beatFrequency: number; name: string; } const presets: Preset[] = [ { baseFrequency: 100, beatFrequency: 2, name: 'Delta (Deep Sleep) 2 Hz' }, { baseFrequency: 100, beatFrequency: 5, name: 'Theta (Meditation) 5 Hz' }, { baseFrequency: 100, beatFrequency: 10, name: 'Alpha (Relaxation) 10 Hz' }, { baseFrequency: 100, beatFrequency: 20, name: 'Beta (Focus) 20 Hz' }, { baseFrequency: 100, beatFrequency: 40, name: 'Gamma (Cognition) 40 Hz' }, { baseFrequency: 440, beatFrequency: 10, name: 'Custom' }, ]; function computeBinauralBeatOscillatorFrequencies( baseFrequency: number, beatFrequency: number, ) { return { leftFrequency: baseFrequency - beatFrequency / 2, rightFrequency: baseFrequency + beatFrequency / 2, }; } export function BinauralModal({ onClose, show }: BinauralProps) { const [baseFrequency, setBaseFrequency] = useState(440); // Default to A4 note const [beatFrequency, setBeatFrequency] = useState(10); // Default to 10 Hz difference const [volume, setVolume] = useState(0.5); // Default volume at 50% const [isPlaying, setIsPlaying] = useState(false); const [selectedPreset, setSelectedPreset] = useState('Custom'); const audioContextRef = useRef(null); const leftOscillatorRef = useRef(null); const rightOscillatorRef = useRef(null); const gainNodeRef = useRef(null); const startSound = () => { if (isPlaying) return; // Initialize the AudioContext audioContextRef.current = new window.AudioContext(); const audioContext = audioContextRef.current; if (!audioContext) return; // Create a gain node for volume control gainNodeRef.current = audioContext.createGain(); gainNodeRef.current.gain.value = volume; // Set volume based on state // Create oscillators for left and right channels leftOscillatorRef.current = audioContext.createOscillator(); rightOscillatorRef.current = audioContext.createOscillator(); if ( !leftOscillatorRef.current || !rightOscillatorRef.current || !gainNodeRef.current ) return; const { leftFrequency, rightFrequency } = computeBinauralBeatOscillatorFrequencies(baseFrequency, beatFrequency); leftOscillatorRef.current.frequency.value = leftFrequency; rightOscillatorRef.current.frequency.value = rightFrequency; // Pan oscillators to left and right const leftPanner = audioContext.createStereoPanner(); leftPanner.pan.value = -1; const rightPanner = audioContext.createStereoPanner(); rightPanner.pan.value = 1; // Connect nodes leftOscillatorRef.current.connect(leftPanner).connect(gainNodeRef.current); rightOscillatorRef.current .connect(rightPanner) .connect(gainNodeRef.current); gainNodeRef.current.connect(audioContext.destination); // Start oscillators leftOscillatorRef.current.start(); rightOscillatorRef.current.start(); setIsPlaying(true); }; const stopSound = useCallback(() => { if (!isPlaying) return; leftOscillatorRef.current?.stop(); rightOscillatorRef.current?.stop(); audioContextRef.current?.close(); setIsPlaying(false); }, [isPlaying]); useEffect(() => { // Update gain node when volume changes if (gainNodeRef.current) { gainNodeRef.current.gain.value = volume; } }, [volume]); useEffect(() => { // Update base frequency for both left and right oscillators when it changes if (leftOscillatorRef.current && rightOscillatorRef.current) { const { leftFrequency, rightFrequency } = computeBinauralBeatOscillatorFrequencies(baseFrequency, beatFrequency); leftOscillatorRef.current.frequency.value = leftFrequency; rightOscillatorRef.current.frequency.value = rightFrequency; } }, [baseFrequency, beatFrequency]); useEffect(() => { // Cleanup when component unmounts return () => { if (isPlaying) { stopSound(); } }; }, [isPlaying, stopSound]); useEffect(() => { // Update frequencies when a preset is selected if (selectedPreset !== 'Custom') { const preset = presets.find(p => p.name === selectedPreset); if (preset) { setBaseFrequency(preset.baseFrequency); setBeatFrequency(preset.beatFrequency); } } }, [selectedPreset]); const handlePresetChange = (e: React.ChangeEvent) => { const selected = e.target.value; setSelectedPreset(selected); if (selected === 'Custom') { // Allow user to input custom frequencies return; } const preset = presets.find(p => p.name === selected); if (preset) { setBaseFrequency(preset.baseFrequency); setBeatFrequency(preset.beatFrequency); } }; return (

Binaural Beat

Binaural beat generator.

{selectedPreset === 'Custom' && ( <>
)}
); }