Remove setInstrumentSelectorTrackId(null) from
setTrackInstrumentWithProgram. Modal stays open so user can
switch tracks and assign instruments without reopening.
Remove external track dropdown. Add select dropdown inside the
instrument selector modal between title and search box. Users
can switch tracks without closing the modal.
Synth button opens a dropdown listing all tracks instead of opening
the modal directly. Selecting a track opens the instrument selector
for that track. No need to close modal and click each track's Synth.
Auth success handler now eagerly loads instrumentSelectorData
via listPlugins + getSoundfontCatalog. The mount-time useEffect
runs before auth token is set, so it silently fails on new machines.
Remove hash verification + password reset logic. seed_admin() now
only creates the admin account if it does not exist. Prevents
password being reset to default + must_change_password flag
being set on every server restart.
Store trackId in multiIds at drag start. Each item computes
target from original track + crossOffset, immune to stale state
from previous drag events. Track 1 item drags n tracks -> track
1+n, track 2 item -> track 2+n, etc.
Each item computes its own target track as srcIdx + crossOffset.
Items from different source tracks land on different target tracks,
preserving the group's vertical layout shape.
Remove all cross-track logic in multiIds path. Each item only
updates its time position (delta) on its current track. No
merging or track reassignment.
Restore multiIds cross-track move for all selected items.
Clamp targetTrackId to first track. Auto-add new track via
addNewTrack() when dragging below the last track.
Cache PromptTemplateManager in ref to prevent new instance per
render. Filter: show only Rearrange/favorites when MIDI item
selected, all presets otherwise. Root cause of 'suggestion added
at top' was stale array reference from new instance every render.
Always show full preset list instead of filtering to rearrange/
favorites when item selected. Prevents suggestion list from
visually changing during selection/deselection.
Remove !st.isArmed guard in note-off handler. Stop note on ALL
tracks regardless of ARM state — FluidSynth stopNote on inactive
channel/pitch is a no-op, so this is safe.
- Master strip: add fader placeholder + VU meter bar
- MixerStrip: items-end -> items-stretch so fader + VU fill height
- VU meter: bar height maps volumeDb, color green/amber/red
- Track name uses track.color instead of fixed text-zinc-400
Add MixerStrip component for display-only track strips (no audio
routing). Mixer panel at bottom with drag resize handle (80-400px).
F7 keyboard shortcut, status bar toggle button, View menu item.
onUpdateTrack handles mute/solo/volume changes directly on tracks.
newId was defined inside updateActiveTracks callback but
referenced outside (line 15002 return). Moved declaration
before the callback as rearrangeNewId, accessible in both
the callback body and the outer return statement.
REARRANGE_TOOL_SPEC already has {type:'function', function:{...}}
wrapper. callLLM's tools.map(t => ({type:'function', function:t}))
added ANOTHER wrapper, creating nested:
{type:'function', function:{type:'function', function:{name}}}
which AI models couldn't parse -> function name became _unknown.
Fix: pass .function (inner spec) instead of the outer wrapper.
- showAIActionLog state defaults to false
- Action Log header clickable (cursor-pointer), shows '-' when
visible, '+' when hidden
- Body always rendered with CSS class 'hidden' toggled, avoids
deep ternary nesting that exceeded Babel 8 maxTargets limit
matchPreset was replacing systemInstruction with the preset's
template on keyword match. Typing 'epic orchestra' would
auto-apply 'Epic Orchestra Intro (8 Bars)' restrictive template.
Removed both override blocks (Piano Roll MIDI gen + DAW
rearrange). System instruction stays as generic default.
User can still fill prompt via suggestion click without
forced template override.
Backend sync effect (useEffect mount) was unconditionally
replacing mgr.presets with data.presets, destroying:
- Frontend-only default presets (12 vs backend's 7)
- User-defined presets in localStorage not yet synced to backend
Fix: merge backend presets by id — keep all local presets,
append any backend presets whose id doesn't exist locally.
User presets + frontend defaults are never lost.
Add 'Người dùng' category to filter dropdown. Filter logic
checks p.is_user_defined when this category is selected.
Shows only presets the user has created/added.
Use suggestions (filtered by getContextualSuggestions) instead
of promptMgr.presets (all). When MIDI item selected, only
Rearrange/Variation + favorites shown. When no MIDI item,
non-rearrange presets shown instead.