fix: audio clip items lost after reload — missing serverFileId on clip/track

- set serverFileId on clip + track when upload succeeds
- serialize/deserialize server_file_id in source_data
- guard clip.buffer null in WaveformLane canvas draw
This commit is contained in:
2026-07-30 20:54:23 +07:00
parent 9c487614f1
commit 4005088e89
3 changed files with 22 additions and 9 deletions
+13 -6
View File
@@ -1376,6 +1376,7 @@ const WaveformLane = ({
if (clips.length > 0) {
clips.forEach(clip => {
if (!clip.buffer) return;
const numChannels = clip.buffer.numberOfChannels || 1;
const dataL = clip.buffer.getChannelData(0);
const dataR = numChannels >= 2 ? clip.buffer.getChannelData(1) : dataL;
@@ -7548,6 +7549,7 @@ const serializeTracksList = (tracksList, secondsPerBar) => {
if (trackType === "AUDIO" && t.clips) {
t.clips.forEach(c => {
const durationSec = c.buffer ? c.buffer.duration : 4.0;
const clipFileId = c.serverFileId || t.serverFileId;
items.push({
id: c.id,
name: c.name || "Audio Clip",
@@ -7556,10 +7558,11 @@ const serializeTracksList = (tracksList, secondsPerBar) => {
duration_bars: (durationSec / (c.speed || 1.0)) / secondsPerBar,
clip_start_offset_bars: 0.0,
source_data: {
audio_file_url: t.serverFileId ? `/static/audio/uploads/${t.serverFileId}` : "",
audio_file_url: clipFileId ? `/static/audio/uploads/${clipFileId}` : "",
sample_rate: c.buffer ? c.buffer.sampleRate : 44100,
channels: c.buffer ? c.buffer.numberOfChannels : 2,
gain: 1.0
gain: 1.0,
server_file_id: clipFileId
}
});
});
@@ -7631,11 +7634,13 @@ const deserializeTracksList = (schemaTracks, secondsPerBar, sectionStore) => {
(t.items || []).forEach(item => {
if (item.type === "AUDIO_ITEM") {
const src = item.source_data || {};
const clipFileId = src.server_file_id || null;
clips.push({
id: item.id,
name: item.name,
startTime: item.start_bar * secondsPerBar,
speed: 1.0
speed: 1.0,
serverFileId: clipFileId
});
} else if (item.type === "MIDI_ITEM") {
const src = item.source_data || {};
@@ -7683,7 +7688,7 @@ const deserializeTracksList = (schemaTracks, secondsPerBar, sectionStore) => {
startTime: t.start_time || 0,
height: t.height || 140,
markers: t.markers || [],
serverFileId: t.server_file_id || (t.items && t.items.find(function(i) { return i.type === 'AUDIO_ITEM'; })?.source_data?.audio_file_url?.split('/').pop()) || null,
serverFileId: t.server_file_id || (t.items && t.items.find(function(i) { return i.type === 'AUDIO_ITEM'; })?.source_data?.server_file_id) || (t.items && t.items.find(function(i) { return i.type === 'AUDIO_ITEM'; })?.source_data?.audio_file_url?.split('/').pop()) || null,
channelInfo: t.channel_info || null,
isArmed: t.is_armed || false,
monitoringEnabled: t.monitoring_enabled !== false,
@@ -15775,13 +15780,15 @@ const App = () => {
let count = 0;
for (const file of files) {
try {
uploadToServer(file, track.id);
const uploadResult = await uploadToServer(file, track.id);
const fileId = uploadResult?.file_id || null;
const { audioBuffer: decodedBuffer, channelInfo } = await window.SonicAudio.decodeAudioFile(file);
const clipId = `clip_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
const newClip = { id: clipId, buffer: decodedBuffer, startTime: offset, name: file.name, speed: 1.0 };
const newClip = { id: clipId, buffer: decodedBuffer, startTime: offset, name: file.name, speed: 1.0, serverFileId: fileId };
createClipWithUndo(selectedTrackId, newClip);
updateActiveTracks(prev => prev.map(t => t.id === selectedTrackId ? {
...t,
serverFileId: t.serverFileId || fileId,
clips: [...(t.clips || []), newClip]
} : t));
offset += decodedBuffer.duration;
File diff suppressed because one or more lines are too long