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
+171
View File
@@ -8099,6 +8099,177 @@ const App = () => {
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);