fix: copilot Multi-tool Calling)

This commit is contained in:
2026-07-22 17:20:41 +07:00
parent b4ec7981a6
commit 610c384bca
4 changed files with 287 additions and 1 deletions
+109
View File
@@ -7729,6 +7729,115 @@ const App = () => {
return { ...t, markers: [...(t.markers || []), { id: 'ai_marker_' + Date.now(), time, label: args.label || 'AI Marker' }] };
}));
return { success: true, trackId, time };
},
fadeIn: (args) => {
const trackIdRaw = args.track_id || selectedTrackId;
const track = tracks.find(t => t.id === String(trackIdRaw) || t.id === 'track_' + trackIdRaw);
if (!track) return { success: false, error: `Track ${trackIdRaw} not found` };
const clips = track.clips && track.clips.length > 0 ? track.clips : (track.buffer ? [{ id: 'default_' + track.id, buffer: track.buffer, startTime: track.startTime || 0, name: track.name }] : []);
if (clips.length === 0) return { success: false, error: 'No clips on track' };
let clip = null;
if (args.clip_id) {
clip = clips.find(c => c.id === args.clip_id);
} else if (args.clip_index !== undefined) {
const idx = parseInt(args.clip_index);
const realIdx = idx > 0 ? idx - 1 : 0;
clip = clips[realIdx] || clips[0];
} else {
clip = clips[0];
}
if (!clip || !clip.buffer) return { success: false, error: 'Clip has no audio buffer' };
const duration = parseFloat(args.duration_seconds || 3);
const buffer = clip.buffer;
const sr = buffer.sampleRate;
const numChannels = buffer.numberOfChannels;
const length = buffer.length;
const ctx = getAudioContext();
const newBuffer = ctx.createBuffer(numChannels, length, sr);
for (let c = 0; c < numChannels; c++) {
newBuffer.getChannelData(c).set(buffer.getChannelData(c));
}
const fadeSamples = Math.min(length, Math.floor(duration * sr));
for (let c = 0; c < numChannels; c++) {
const data = newBuffer.getChannelData(c);
for (let i = 0; i < fadeSamples; i++) {
const factor = (1 - Math.cos(Math.PI * i / fadeSamples)) / 2;
data[i] *= factor;
}
}
const beforeSnap = captureTrackSnapshot(track.id);
setTracks(prev => prev.map(t => {
if (t.id !== track.id) return t;
const existingClips = t.clips && t.clips.length > 0 ? t.clips : (t.buffer ? [{ id: 'default_' + t.id, buffer: t.buffer, startTime: t.startTime || 0, name: t.name }] : []);
const updatedClips = existingClips.map(c => {
if (c.id === clip.id || (clip.id.startsWith('default_') && c.id === 'default')) {
return { ...c, buffer: newBuffer };
}
return c;
});
const mainBuffer = updatedClips[0]?.buffer || t.buffer;
return { ...t, clips: updatedClips, buffer: mainBuffer };
}));
setTimeout(() => {
const afterSnap = captureTrackSnapshot(track.id);
pushAction('AI_FADE_IN', track.id, beforeSnap, afterSnap);
}, 50);
return { success: true, trackId: track.id, clipId: clip.id, duration_seconds: duration };
},
fadeOut: (args) => {
const trackIdRaw = args.track_id || selectedTrackId;
const track = tracks.find(t => t.id === String(trackIdRaw) || t.id === 'track_' + trackIdRaw);
if (!track) return { success: false, error: `Track ${trackIdRaw} not found` };
const clips = track.clips && track.clips.length > 0 ? track.clips : (track.buffer ? [{ id: 'default_' + track.id, buffer: track.buffer, startTime: track.startTime || 0, name: track.name }] : []);
if (clips.length === 0) return { success: false, error: 'No clips on track' };
let clip = null;
if (args.clip_id) {
clip = clips.find(c => c.id === args.clip_id);
} else if (args.clip_index !== undefined) {
const idx = parseInt(args.clip_index);
const realIdx = idx > 0 ? idx - 1 : 0;
clip = clips[realIdx] || clips[0];
} else {
clip = clips[0];
}
if (!clip || !clip.buffer) return { success: false, error: 'Clip has no audio buffer' };
const duration = parseFloat(args.duration_seconds || 3);
const buffer = clip.buffer;
const sr = buffer.sampleRate;
const numChannels = buffer.numberOfChannels;
const length = buffer.length;
const ctx = getAudioContext();
const newBuffer = ctx.createBuffer(numChannels, length, sr);
for (let c = 0; c < numChannels; c++) {
newBuffer.getChannelData(c).set(buffer.getChannelData(c));
}
const fadeSamples = Math.min(length, Math.floor(duration * sr));
for (let c = 0; c < numChannels; c++) {
const data = newBuffer.getChannelData(c);
for (let i = 0; i < fadeSamples; i++) {
const idx = length - fadeSamples + i;
const factor = (1 + Math.cos(Math.PI * i / fadeSamples)) / 2;
data[idx] *= factor;
}
}
const beforeSnap = captureTrackSnapshot(track.id);
setTracks(prev => prev.map(t => {
if (t.id !== track.id) return t;
const existingClips = t.clips && t.clips.length > 0 ? t.clips : (t.buffer ? [{ id: 'default_' + t.id, buffer: t.buffer, startTime: t.startTime || 0, name: t.name }] : []);
const updatedClips = existingClips.map(c => {
if (c.id === clip.id || (clip.id.startsWith('default_') && c.id === 'default')) {
return { ...c, buffer: newBuffer };
}
return c;
});
const mainBuffer = updatedClips[0]?.buffer || t.buffer;
return { ...t, clips: updatedClips, buffer: mainBuffer };
}));
setTimeout(() => {
const afterSnap = captureTrackSnapshot(track.id);
pushAction('AI_FADE_OUT', track.id, beforeSnap, afterSnap);
}, 50);
return { success: true, trackId: track.id, clipId: clip.id, duration_seconds: duration };
}
};
window.DAWCommandDispatcher.registerDAWCommands(api);