fix: draw clip rect/label always, skip only waveform when buffer null

- clip rect + label + markers drawn even without buffer
- shows '(audio chưa được tải)' for unloaded clips
- deserialize restores clip duration from duration_bars
This commit is contained in:
2026-07-30 21:05:33 +07:00
parent 7b8e10419f
commit 6c227fe6af
3 changed files with 28 additions and 13 deletions
+18 -9
View File
@@ -1373,15 +1373,10 @@ const WaveformLane = ({
if (clips.length > 0) { if (clips.length > 0) {
clips.forEach(clip => { clips.forEach(clip => {
if (!clip.buffer) return; const hasBuffer = !!clip.buffer;
const numChannels = clip.buffer.numberOfChannels || 1;
const dataL = clip.buffer.getChannelData(0);
const dataR = numChannels >= 2 ? clip.buffer.getChannelData(1) : dataL;
const sampleRate = clip.buffer.sampleRate;
const totalSamples = dataL.length;
const originalDuration = totalSamples / sampleRate;
const clipSpeed = clip.speed || 1.0; const clipSpeed = clip.speed || 1.0;
const duration = originalDuration / clipSpeed; const originalDuration = hasBuffer ? clip.buffer.duration / clipSpeed : 4.0;
const duration = originalDuration;
const clipStartTime = clip.startTime || 0; const clipStartTime = clip.startTime || 0;
const clipEndTime = clipStartTime + duration; const clipEndTime = clipStartTime + duration;
@@ -1392,7 +1387,7 @@ const WaveformLane = ({
const xStartLocal = xStartGlobal - scrollLeftVal; const xStartLocal = xStartGlobal - scrollLeftVal;
const xEndLocal = xStartLocal + wClip; const xEndLocal = xStartLocal + wClip;
// 1. Draw Clip Layer Background & Border // 1. Draw Clip Layer Background & Border (always draw even without buffer)
const clipIdentifier = clip.id === 'default' ? 'default_' + track.id : clip.id; const clipIdentifier = clip.id === 'default' ? 'default_' + track.id : clip.id;
const isClipSelected = (selectedClipId && selectedClipId.trackId === track.id && selectedClipId.clipId === clipIdentifier) || (selectedItemIds && selectedItemIds.has(clipIdentifier)); const isClipSelected = (selectedClipId && selectedClipId.trackId === track.id && selectedClipId.clipId === clipIdentifier) || (selectedItemIds && selectedItemIds.has(clipIdentifier));
ctx.fillStyle = clip.isTemp ? 'rgba(239, 68, 68, 0.25)' : isClipSelected ? track.color ? track.color + '44' : 'rgba(6, 182, 212, 0.30)' : track.color ? track.color + '22' : 'rgba(6, 182, 212, 0.12)'; ctx.fillStyle = clip.isTemp ? 'rgba(239, 68, 68, 0.25)' : isClipSelected ? track.color ? track.color + '44' : 'rgba(6, 182, 212, 0.30)' : track.color ? track.color + '22' : 'rgba(6, 182, 212, 0.12)';
@@ -1430,6 +1425,19 @@ const WaveformLane = ({
}); });
} }
if (!hasBuffer) {
ctx.fillStyle = 'rgba(255, 255, 255, 0.15)';
ctx.font = 'italic 8px sans-serif';
ctx.fillText('(audio chưa được tải)', Math.max(xStartLocal + 8, 8), clipTop + clipHeight - 6);
return;
}
const numChannels = clip.buffer.numberOfChannels || 1;
const dataL = clip.buffer.getChannelData(0);
const dataR = numChannels >= 2 ? clip.buffer.getChannelData(1) : dataL;
const sampleRate = clip.buffer.sampleRate;
const totalSamples = dataL.length;
// 3. Peak / Vector Waveform Drawing (Sound Forge Dual Stereo Channel Split Match) // 3. Peak / Vector Waveform Drawing (Sound Forge Dual Stereo Channel Split Match)
const drawXStartLocal = Math.max(0, Math.floor(xStartLocal)); const drawXStartLocal = Math.max(0, Math.floor(xStartLocal));
const drawXEndLocal = Math.min(drawWidth, Math.ceil(xEndLocal)); const drawXEndLocal = Math.min(drawWidth, Math.ceil(xEndLocal));
@@ -7637,6 +7645,7 @@ const deserializeTracksList = (schemaTracks, secondsPerBar, sectionStore) => {
name: item.name, name: item.name,
startTime: item.start_bar * secondsPerBar, startTime: item.start_bar * secondsPerBar,
speed: 1.0, speed: 1.0,
duration: item.duration_bars * secondsPerBar,
serverFileId: clipFileId serverFileId: clipFileId
}); });
} else if (item.type === "MIDI_ITEM") { } else if (item.type === "MIDI_ITEM") {
File diff suppressed because one or more lines are too long
+6
View File
@@ -849,6 +849,12 @@
- **Các file ảnh hưởng:** `app/templates/index.html`, `app/static/js/app.jsx` - **Các file ảnh hưởng:** `app/templates/index.html`, `app/static/js/app.jsx`
- **Ghi chú/Test (nếu có):** `npm run build` — build passes. - **Ghi chú/Test (nếu có):** `npm run build` — build passes.
### [2026-07-30 21:02] Task: Fix audio clips lost — draw clip rect even without buffer + store duration in deserialize
- **Tóm tắt thay đổi:** WaveformLane từng `if (!clip.buffer) return;` skip toàn bộ clip (kể cả rect/label). Fix: draw rect/label luôn, chỉ skip waveform khi null buffer. Thêm label "(audio chưa được tải)". Deserialize giờ restore `duration` trên clip từ `duration_bars`.
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/static/js/app.precompiled.js`
- **Ghi chú/Test (nếu có):** `npm run build` pass. Clip không có buffer vẫn hiện rect + label + duration đúng.
---
### [2026-07-30 20:58] Task: Fix snap default + Power button mastering bypass ### [2026-07-30 20:58] Task: Fix snap default + Power button mastering bypass
- **Tóm tắt thay đổi:** (1) snapValue mặc định `'1'` (thay `'free'`), snapVal PIANO_ROLL mặc định `'1'` (thay `'1/16'`); (2) Power button trong MasterStripConsole: bỏ `isFxActive` local state dùng chung sai với FX button, đọc `masteringSettings.masterConnected` trực tiếp → toggle `masterConnected` + set `isBypassed` tương ứng. - **Tóm tắt thay đổi:** (1) snapValue mặc định `'1'` (thay `'free'`), snapVal PIANO_ROLL mặc định `'1'` (thay `'1/16'`); (2) Power button trong MasterStripConsole: bỏ `isFxActive` local state dùng chung sai với FX button, đọc `masteringSettings.masterConnected` trực tiếp → toggle `masterConnected` + set `isBypassed` tương ứng.
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/static/js/app.precompiled.js` - **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/static/js/app.precompiled.js`