@@ -12,17 +12,8 @@ import { Play, Pause, Download, Settings, Music } from 'lucide-react';
1212import { useNoteBlockAudio } from './useNoteBlockAudio' ;
1313import { useVisualizer } from './useVisualizer' ;
1414import { presets } from './presets' ;
15- import { INSTRUMENT_PRESETS } from './instrumentPresets' ;
1615import TrackInstrumentPanel from './TrackInstrumentPanel' ;
1716
18- const NOTE_NAMES = [ 'C' , 'C#' , 'D' , 'D#' , 'E' , 'F' , 'F#' , 'G' , 'G#' , 'A' , 'A#' , 'B' ] ;
19- const BASE_NOTES : string [ ] = [ ] ;
20- for ( let octave = 2 ; octave <= 6 ; octave ++ ) {
21- for ( const name of NOTE_NAMES ) {
22- BASE_NOTES . push ( `${ name } ${ octave } ` ) ;
23- }
24- }
25-
2617function formatTime ( seconds : number ) : string {
2718 const m = Math . floor ( seconds / 60 ) ;
2819 const s = Math . floor ( seconds % 60 ) ;
@@ -35,12 +26,9 @@ export default function NoteBlockPlayer() {
3526
3627 const vizContainerRef = useRef < HTMLDivElement > ( null ) ;
3728 const vizInitializedRef = useRef ( false ) ;
38- const oggInputRef = useRef < HTMLInputElement > ( null ) ;
3929 const midiInputRef = useRef < HTMLInputElement > ( null ) ;
4030 const bgInputRef = useRef < HTMLInputElement > ( null ) ;
4131
42- const [ baseNote , setBaseNote ] = useState ( 'F#4' ) ;
43- const [ globalInstrument , setGlobalInstrument ] = useState ( 'harp' ) ;
4432 const [ presetIndex , setPresetIndex ] = useState ( '0' ) ;
4533 const [ settingsOpen , setSettingsOpen ] = useState ( false ) ;
4634 const [ tracksOpen , setTracksOpen ] = useState ( false ) ;
@@ -108,51 +96,12 @@ export default function NoteBlockPlayer() {
10896 }
10997 } , [ applyDetailOptions ] ) ;
11098
111- // Auto-load harp as default global instrument on mount
99+ // Auto-open tracks panel when MIDI is loaded
112100 useEffect ( ( ) => {
113- const loadDefault = async ( ) => {
114- try {
115- const preset = INSTRUMENT_PRESETS . find ( p => p . id === 'harp' ) ;
116- if ( ! preset ) return ;
117- const res = await fetch ( preset . oggUrl ) ;
118- const blob = await res . blob ( ) ;
119- const file = new File ( [ blob ] , 'harp.ogg' , { type : 'audio/ogg' } ) ;
120- await audio . loadSample ( file , preset . baseNote ) ;
121- setBaseNote ( preset . baseNote ) ;
122- } catch { /* silent */ }
123- } ;
124- loadDefault ( ) ;
125- // eslint-disable-next-line react-hooks/exhaustive-deps
126- } , [ ] ) ;
127-
128- const handleGlobalInstrumentChange = async ( value : string ) => {
129- setGlobalInstrument ( value ) ;
130- if ( value === 'custom' ) return ;
131- const preset = INSTRUMENT_PRESETS . find ( p => p . id === value ) ;
132- if ( ! preset ) return ;
133- try {
134- const res = await fetch ( preset . oggUrl ) ;
135- const blob = await res . blob ( ) ;
136- const file = new File ( [ blob ] , `${ preset . id } .ogg` , { type : 'audio/ogg' } ) ;
137- await ensureVisualizer ( ) ;
138- await audio . loadSample ( file , preset . baseNote ) ;
139- setBaseNote ( preset . baseNote ) ;
140- } catch { /* silent */ }
141- } ;
142-
143- const handleOggChange = async ( e : React . ChangeEvent < HTMLInputElement > ) => {
144- const file = e . target . files ?. [ 0 ] ;
145- if ( ! file ) return ;
146- setGlobalInstrument ( 'custom' ) ;
147- await ensureVisualizer ( ) ;
148- await audio . loadSample ( file , baseNote ) ;
149- } ;
150-
151- const handleBaseNoteChange = async ( value : string ) => {
152- setBaseNote ( value ) ;
153- await ensureVisualizer ( ) ;
154- await audio . reloadSample ( value ) ;
155- } ;
101+ if ( audio . trackInfos . length > 0 ) {
102+ setTracksOpen ( true ) ;
103+ }
104+ } , [ audio . trackInfos ] ) ;
156105
157106 const handleMidiChange = async ( e : React . ChangeEvent < HTMLInputElement > ) => {
158107 const file = e . target . files ?. [ 0 ] ;
@@ -188,13 +137,11 @@ export default function NoteBlockPlayer() {
188137 audio . seekTo ( value [ 0 ] ) ;
189138 } ;
190139
191- const hasTrackSamplers = audio . trackAssignments . some ( a => ! a . muted && a . instrumentId !== 'global' ) ;
192- const ready = ( audio . sampleLoaded || hasTrackSamplers ) && audio . midiLoaded ;
140+ const ready = audio . midiLoaded ;
193141
194142 return (
195143 < div className = "flex flex-col h-full gap-2" >
196144 { /* Hidden file inputs */ }
197- < input ref = { oggInputRef } type = "file" accept = ".ogg,audio/*" onChange = { handleOggChange } className = "hidden" />
198145 < input ref = { midiInputRef } type = "file" accept = ".mid,.midi" onChange = { handleMidiChange } className = "hidden" />
199146 < input ref = { bgInputRef } type = "file" accept = "image/*" onChange = { handleBgChange } className = "hidden" />
200147
@@ -257,45 +204,6 @@ export default function NoteBlockPlayer() {
257204
258205 < div className = "w-px h-4 bg-white/20" />
259206
260- { /* Global instrument selector */ }
261- < Select value = { globalInstrument } onValueChange = { handleGlobalInstrumentChange } >
262- < SelectTrigger className = "h-7 w-28 text-[11px] bg-transparent border-white/20 text-gray-100" >
263- < SelectValue />
264- </ SelectTrigger >
265- < SelectContent >
266- { INSTRUMENT_PRESETS . map ( p => (
267- < SelectItem key = { p . id } value = { p . id } className = "text-xs" > { p . name } </ SelectItem >
268- ) ) }
269- < SelectItem value = "custom" className = "text-xs" > Custom OGG...</ SelectItem >
270- </ SelectContent >
271- </ Select >
272-
273- { globalInstrument === 'custom' && (
274- < Button
275- variant = "ghost"
276- size = "sm"
277- className = "h-7 px-2 text-[11px] text-gray-200 hover:text-white hover:bg-white/15"
278- onClick = { ( ) => oggInputRef . current ?. click ( ) }
279- >
280- OGG { audio . sampleLoaded && < span className = "w-1.5 h-1.5 rounded-full bg-green-400 ml-1" /> }
281- </ Button >
282- ) }
283-
284- { globalInstrument === 'custom' && (
285- < Select value = { baseNote } onValueChange = { handleBaseNoteChange } >
286- < SelectTrigger className = "h-7 w-16 text-[11px] bg-transparent border-white/20 text-gray-100" >
287- < SelectValue />
288- </ SelectTrigger >
289- < SelectContent >
290- { BASE_NOTES . map ( note => (
291- < SelectItem key = { note } value = { note } className = "text-xs" > { note } </ SelectItem >
292- ) ) }
293- </ SelectContent >
294- </ Select >
295- ) }
296-
297- < div className = "w-px h-4 bg-white/20" />
298-
299207 < Button
300208 variant = "ghost"
301209 size = "sm"
@@ -314,7 +222,7 @@ export default function NoteBlockPlayer() {
314222 BG
315223 </ Button >
316224
317- { audio . trackInfos . length > 0 && (
225+ { audio . midiLoaded && (
318226 < >
319227 < div className = "w-px h-4 bg-white/20" />
320228 < Button
@@ -355,7 +263,7 @@ export default function NoteBlockPlayer() {
355263 </ div >
356264
357265 { /* Track instrument panel */ }
358- { tracksOpen && audio . trackInfos . length > 0 && (
266+ { tracksOpen && audio . midiLoaded && (
359267 < div className = "p-2 rounded border border-white/20 bg-black/40 backdrop-blur-sm" >
360268 < TrackInstrumentPanel
361269 trackInfos = { audio . trackInfos }
0 commit comments