fix(audio): robust async buffer loading with state merging + API fallback
- Rewrite loadAudioBuffersForTracks to use functional setTracks preventing loss of intermediate state updates - Add API download endpoint as fallback when static fetch fails - Also update sessionTabs tracks with loaded buffers - return decodeAudioFile result (audioBuffer+channelInfo) instead of just audioBuffer
This commit is contained in:
+56
-40
@@ -9860,65 +9860,81 @@ const App = () => {
|
||||
|
||||
const loadAudioBuffersForTracks = async (tracksList) => {
|
||||
let hasLoadedAny = false;
|
||||
const loadBuffer = async (url) => {
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) return null;
|
||||
const blob = await res.blob();
|
||||
return await window.SonicAudio.decodeAudioFile(blob);
|
||||
};
|
||||
const tryLoad = async (fileId) => {
|
||||
if (!fileId) return null;
|
||||
try {
|
||||
const result = await loadBuffer('/static/audio/uploads/' + fileId);
|
||||
if (result) return result;
|
||||
} catch (_) {}
|
||||
try {
|
||||
const result = await loadBuffer(`${API_AUDIO}/download/${fileId}`);
|
||||
if (result) return result;
|
||||
} catch (_) {}
|
||||
return null;
|
||||
};
|
||||
const updatedTracks = await Promise.all(tracksList.map(async t => {
|
||||
let trackBuffer = t.buffer;
|
||||
let trackChannelInfo = t.channelInfo;
|
||||
if (t.serverFileId && !trackBuffer) {
|
||||
try {
|
||||
const res = await fetch('/static/audio/uploads/' + t.serverFileId);
|
||||
if (res.ok) {
|
||||
const blob = await res.blob();
|
||||
const { audioBuffer, channelInfo } = await window.SonicAudio.decodeAudioFile(blob);
|
||||
trackBuffer = audioBuffer;
|
||||
trackChannelInfo = channelInfo;
|
||||
hasLoadedAny = true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Failed to autoload track buffer for " + t.serverFileId, e);
|
||||
const result = await tryLoad(t.serverFileId);
|
||||
if (result) {
|
||||
trackBuffer = result.audioBuffer;
|
||||
trackChannelInfo = result.channelInfo;
|
||||
hasLoadedAny = true;
|
||||
}
|
||||
}
|
||||
|
||||
let clipsUpdated = false;
|
||||
const updatedClips = await Promise.all((t.clips || []).map(async c => {
|
||||
let clipBuffer = c.buffer;
|
||||
const targetFileId = c.serverFileId || t.serverFileId;
|
||||
if (targetFileId && !clipBuffer) {
|
||||
try {
|
||||
const res = await fetch('/static/audio/uploads/' + targetFileId);
|
||||
if (res.ok) {
|
||||
const blob = await res.blob();
|
||||
const { audioBuffer } = await window.SonicAudio.decodeAudioFile(blob);
|
||||
clipBuffer = audioBuffer;
|
||||
clipsUpdated = true;
|
||||
hasLoadedAny = true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Failed to autoload clip buffer for " + targetFileId, e);
|
||||
const result = await tryLoad(targetFileId);
|
||||
if (result) {
|
||||
clipBuffer = result.audioBuffer;
|
||||
hasLoadedAny = true;
|
||||
}
|
||||
}
|
||||
return { ...c, buffer: clipBuffer };
|
||||
}));
|
||||
|
||||
if (trackBuffer && updatedClips.length === 0) {
|
||||
const clipId = `default_${t.id}`;
|
||||
return {
|
||||
...t,
|
||||
buffer: trackBuffer,
|
||||
channelInfo: trackChannelInfo,
|
||||
clips: [{ id: clipId, buffer: trackBuffer, startTime: t.startTime || 0, name: t.name, speed: 1.0 }]
|
||||
};
|
||||
return { ...t, buffer: trackBuffer, channelInfo: trackChannelInfo,
|
||||
clips: [{ id: clipId, buffer: trackBuffer, startTime: t.startTime || 0, name: t.name, speed: 1.0 }] };
|
||||
}
|
||||
|
||||
return {
|
||||
...t,
|
||||
buffer: trackBuffer,
|
||||
channelInfo: trackChannelInfo,
|
||||
clips: updatedClips
|
||||
};
|
||||
return { ...t, buffer: trackBuffer, channelInfo: trackChannelInfo, clips: updatedClips };
|
||||
}));
|
||||
|
||||
if (hasLoadedAny) {
|
||||
setTracks(updatedTracks);
|
||||
setTracks(prev => {
|
||||
const merged = [...updatedTracks];
|
||||
(prev || []).forEach((pt, i) => {
|
||||
if (!merged[i]) merged[i] = pt;
|
||||
else {
|
||||
merged[i] = { ...merged[i] };
|
||||
merged[i].clips = (pt.clips || []).map((pc, j) => {
|
||||
if (merged[i].clips && merged[i].clips[j] && (merged[i].clips[j].buffer || pc.buffer)) {
|
||||
return { ...pc, buffer: pc.buffer || merged[i].clips[j].buffer };
|
||||
}
|
||||
if ((pc.buffer || (merged[i].clips && merged[i].clips[j] && merged[i].clips[j].buffer))) {
|
||||
return pc;
|
||||
}
|
||||
return merged[i].clips && merged[i].clips[j] ? merged[i].clips[j] : pc;
|
||||
});
|
||||
}
|
||||
});
|
||||
return merged;
|
||||
});
|
||||
setSessionTabs(prev => prev.map(st => ({
|
||||
...st,
|
||||
tracks: (st.tracks || []).map(t => {
|
||||
const found = updatedTracks.find(u => u.id === t.id);
|
||||
return found || t;
|
||||
})
|
||||
})));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user