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:
+18
-9
@@ -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
@@ -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`
|
||||||
|
|||||||
Reference in New Issue
Block a user