fix: MIDI Rearrange — selected item triggers dedicated tool flow
- midiExtractor.js: extractSelectedMIDIContext with note name conversion - aiGateway.js: REARRANGE_TOOL_SPEC + buildRearrangeMessage - dawCommandDispatcher.js: register REARRANGE_MIDI_MELODY command - app.jsx: handleAISend detects selected MIDI item → rearrange flow - rearrangeMidiMelody handler places A/B track below source track
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
const SonicMidiExtractor = (function() {
|
||||
const NOTE_NAMES = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B'];
|
||||
|
||||
function midiPitchToNoteName(pitch) {
|
||||
const note = NOTE_NAMES[pitch % 12];
|
||||
const octave = Math.floor(pitch / 12) - 1;
|
||||
return note + octave;
|
||||
}
|
||||
|
||||
function extractSelectedMIDIContext(tracks, selectedItemId, bpm) {
|
||||
let targetItem = null;
|
||||
let targetTrack = null;
|
||||
|
||||
for (const track of tracks) {
|
||||
const items = track.midiItems || [];
|
||||
const item = items.find(i => i.id === selectedItemId);
|
||||
if (item) { targetItem = item; targetTrack = track; break; }
|
||||
}
|
||||
|
||||
if (!targetItem) {
|
||||
throw new Error('Please select a MIDI Item on the Timeline before requesting a Rearrangement!');
|
||||
}
|
||||
|
||||
const notes = targetItem.notes || [];
|
||||
if (notes.length === 0) {
|
||||
throw new Error('Selected MIDI item has no notes to rearrange.');
|
||||
}
|
||||
|
||||
const compactNotes = notes.map(n => ({
|
||||
pitch: n.pitch,
|
||||
note_name: midiPitchToNoteName(n.pitch),
|
||||
start_beat: parseFloat((n.start_beat || 0).toFixed(2)),
|
||||
duration_beats: parseFloat((n.duration_beats || 1).toFixed(2)),
|
||||
velocity: parseFloat((n.velocity || 0.8).toFixed(2))
|
||||
}));
|
||||
|
||||
const totalDurationBeats = compactNotes.reduce((max, n) => Math.max(max, n.start_beat + n.duration_beats), 0);
|
||||
|
||||
return {
|
||||
track_name: targetTrack.name,
|
||||
track_id: targetTrack.id,
|
||||
item_id: targetItem.id,
|
||||
item_name: targetItem.name,
|
||||
duration_bars: targetItem.length_bars || Math.ceil(totalDurationBeats / 4),
|
||||
total_beats: Math.ceil(totalDurationBeats),
|
||||
bpm: parseInt(bpm || '120'),
|
||||
total_notes: compactNotes.length,
|
||||
notes: compactNotes,
|
||||
instrument: targetTrack.synth_engine ? {
|
||||
soundfont_id: targetTrack.synth_engine.soundfont_id || '',
|
||||
soundfont_bank: targetTrack.synth_engine.soundfont_bank ?? 0,
|
||||
soundfont_program: targetTrack.synth_engine.soundfont_program ?? 0
|
||||
} : null
|
||||
};
|
||||
}
|
||||
|
||||
return { extractSelectedMIDIContext, midiPitchToNoteName };
|
||||
})();
|
||||
|
||||
window.SonicMidiExtractor = SonicMidiExtractor;
|
||||
Reference in New Issue
Block a user