'use client'; import { useState, useEffect, useCallback, useRef } from 'react'; import { EngineState, LayerName, Genre } from '@/types/audio'; const defaultState: EngineState = { isPlaying: false, isInitialized: false, bpm: 90, swing: 0.15, currentStep: 0, currentSection: 'intro', genre: 'hiphop', duration: 3, instruments: { drums: 'acoustic', bass: 'synth', brass: 'trumpet', piano: 'grand', chords: 'pad', ambient: 'rain', }, volumes: { master: 0.8, drums: 0.8, bass: 0.6, brass: 0.4, piano: 0.5, chords: 0.6, ambient: 0.4, }, muted: { drums: false, bass: false, brass: true, piano: true, chords: false, ambient: false, }, }; export function useAudioEngine() { const [state, setState] = useState(defaultState); const [currentStep, setCurrentStep] = useState(0); const engineRef = useRef(null); const isInitializingRef = useRef(false); const getEngine = useCallback(async () => { if (typeof window === 'undefined') return null; if (!engineRef.current) { const { default: audioEngine } = await import('@/lib/audio/audioEngine'); engineRef.current = audioEngine; } return engineRef.current; }, []); const initialize = useCallback(async () => { if (isInitializingRef.current) return; isInitializingRef.current = true; try { const engine = await getEngine(); if (!engine) return; engine.setCallbacks({ onStepChange: (step) => { setCurrentStep(step); }, onStateChange: (newState) => { setState(newState); }, }); await engine.initialize(); setState(engine.getState()); } finally { isInitializingRef.current = false; } }, [getEngine]); const togglePlayback = useCallback(async () => { const engine = await getEngine(); if (!engine) return; if (!state.isInitialized) { await initialize(); } const currentState = engine.getState(); if (currentState.isPlaying) { engine.pause(); } else { await engine.play(); } }, [getEngine, state.isInitialized, initialize]); const stop = useCallback(async () => { const engine = await getEngine(); if (!engine) return; engine.stop(); setCurrentStep(0); }, [getEngine]); const generateNewBeat = useCallback(async () => { const engine = await getEngine(); if (!engine) return; if (!state.isInitialized) { await initialize(); } engine.generateNewBeat(); }, [getEngine, state.isInitialized, initialize]); const setGenre = useCallback(async (genre: Genre) => { const engine = await getEngine(); if (!engine) return; if (!state.isInitialized) { await initialize(); } engine.setGenre(genre); }, [getEngine, state.isInitialized, initialize]); const setDuration = useCallback(async (minutes: number) => { const engine = await getEngine(); if (!engine) return; engine.setDuration(minutes); }, [getEngine]); const setInstrument = useCallback(async (layer: LayerName, instrument: string) => { const engine = await getEngine(); if (!engine) return; if (!state.isInitialized) { await initialize(); } engine.setInstrument(layer, instrument); }, [getEngine, state.isInitialized, initialize]); const setBpm = useCallback(async (bpm: number) => { const engine = await getEngine(); if (!engine) return; engine.setBpm(bpm); }, [getEngine]); const setSwing = useCallback(async (swing: number) => { const engine = await getEngine(); if (!engine) return; engine.setSwing(swing); }, [getEngine]); const setMasterVolume = useCallback(async (volume: number) => { const engine = await getEngine(); if (!engine) return; engine.setMasterVolume(volume); }, [getEngine]); const setLayerVolume = useCallback(async (layer: LayerName, volume: number) => { const engine = await getEngine(); if (!engine) return; engine.setLayerVolume(layer, volume); }, [getEngine]); const toggleMute = useCallback(async (layer: LayerName) => { const engine = await getEngine(); if (!engine) return; engine.toggleMute(layer); }, [getEngine]); useEffect(() => { return () => { // Don't dispose on unmount }; }, []); return { state, currentStep, initialize, togglePlayback, stop, generateNewBeat, setGenre, setDuration, setInstrument, setBpm, setSwing, setMasterVolume, setLayerVolume, toggleMute, }; }