fix: canvas audioclip hiển thị theo tỉ lệ tempo, không giãn khung
This commit is contained in:
+11
-6
@@ -9759,8 +9759,11 @@ const MediaExplorerPanel = ({ height }) => {
|
|||||||
} else {
|
} else {
|
||||||
const pk = curPeaks && curPeaks.length > 0 ? curPeaks : null;
|
const pk = curPeaks && curPeaks.length > 0 ? curPeaks : null;
|
||||||
if (pk) {
|
if (pk) {
|
||||||
const pxPerSec = 50;
|
// Audio hiển thị theo tỉ lệ tempo (pxPerSec), không giãn đầy khung preview
|
||||||
const contentW = Math.max(w, dur * pxPerSec);
|
const audioBpm = curTempo || 120;
|
||||||
|
const pxPerBeat = 42;
|
||||||
|
const pxPerSec = pxPerBeat * audioBpm / 60;
|
||||||
|
const contentW = Math.max(1, dur * pxPerSec);
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
if (playing && contentW > w && dur > 0) {
|
if (playing && contentW > w && dur > 0) {
|
||||||
offset = Math.max(0, Math.min(contentW - w, t * pxPerSec - w / 2));
|
offset = Math.max(0, Math.min(contentW - w, t * pxPerSec - w / 2));
|
||||||
@@ -9774,7 +9777,8 @@ const MediaExplorerPanel = ({ height }) => {
|
|||||||
const ph = Math.max(2, pk[i] * (h / 2 - 4));
|
const ph = Math.max(2, pk[i] * (h / 2 - 4));
|
||||||
ctx.fillRect(x, mid - ph, barW, ph * 2);
|
ctx.fillRect(x, mid - ph, barW, ph * 2);
|
||||||
}
|
}
|
||||||
const audioPlayheadX = contentW > w ? Math.min(w / 2, t * pxPerSec) : Math.min(w, t * pxPerSec);
|
// Playhead theo tỉ lệ tempo; khi content rộng hơn frame thì khóa giữa + scroll
|
||||||
|
const audioPlayheadX = contentW > w ? Math.min(w / 2, t * pxPerSec) : (t * pxPerSec);
|
||||||
if (playing && dur > 0) {
|
if (playing && dur > 0) {
|
||||||
ctx.fillStyle = '#ef4444';
|
ctx.fillStyle = '#ef4444';
|
||||||
ctx.fillRect(audioPlayheadX - 1, 0, 2, h - 14);
|
ctx.fillRect(audioPlayheadX - 1, 0, 2, h - 14);
|
||||||
@@ -9788,10 +9792,11 @@ const MediaExplorerPanel = ({ height }) => {
|
|||||||
ctx.fillStyle = '#111'; ctx.fillRect(0, h - 14, w, 14);
|
ctx.fillStyle = '#111'; ctx.fillRect(0, h - 14, w, 14);
|
||||||
ctx.fillStyle = '#888'; ctx.font = '9px JetBrains Mono, monospace';
|
ctx.fillStyle = '#888'; ctx.font = '9px JetBrains Mono, monospace';
|
||||||
const rulerBpm = curTempo || 120;
|
const rulerBpm = curTempo || 120;
|
||||||
const rulerPxPerBeat = isMidiFile(f) ? 42 : (50 * 60 / rulerBpm);
|
const rulerPxPerBeat = 42;
|
||||||
const isRealMidi = isMidiFile(f) && curMidiNotes && curMidiNotes.length && curMidiTotalBeats > 0;
|
const isRealMidi = isMidiFile(f) && curMidiNotes && curMidiNotes.length && curMidiTotalBeats > 0;
|
||||||
const rulerTotalBeats = isRealMidi ? Math.max(curMidiTotalBeats, 4) : Math.max(4, Math.ceil(dur * rulerBpm / 60) || 16);
|
const rulerTotalBeats = isRealMidi ? Math.max(curMidiTotalBeats, 4) : Math.max(4, Math.ceil(dur * rulerBpm / 60) || 16);
|
||||||
const rulerContentW = isRealMidi ? Math.max(w, rulerTotalBeats * rulerPxPerBeat) : Math.max(w, dur * rulerPxPerBeat * rulerBpm / 60);
|
// Tỉ lệ theo tempo (không giãn đầy khung)
|
||||||
|
const rulerContentW = Math.max(1, rulerTotalBeats * rulerPxPerBeat);
|
||||||
const rulerPxPerSec = rulerPxPerBeat * rulerBpm / 60;
|
const rulerPxPerSec = rulerPxPerBeat * rulerBpm / 60;
|
||||||
const rulerOffset = (playing && rulerContentW > w && dur > 0) ? Math.max(0, Math.min(rulerContentW - w, t * rulerPxPerSec - w / 2)) : 0;
|
const rulerOffset = (playing && rulerContentW > w && dur > 0) ? Math.max(0, Math.min(rulerContentW - w, t * rulerPxPerSec - w / 2)) : 0;
|
||||||
for (let b = 0; b <= rulerTotalBeats; b += 4) {
|
for (let b = 0; b <= rulerTotalBeats; b += 4) {
|
||||||
@@ -9801,7 +9806,7 @@ const MediaExplorerPanel = ({ height }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
React.useEffect(() => { drawCanvas(currentTime); }, [peaks, audioBuffer, midiNotes, selected, folder, isPlaying]);
|
React.useEffect(() => { drawCanvas(currentTime); }, [peaks, audioBuffer, audioDuration, midiNotes, selected, folder, isPlaying]);
|
||||||
React.useEffect(() => () => { if (rafRef.current) cancelAnimationFrame(rafRef.current); }, []);
|
React.useEffect(() => () => { if (rafRef.current) cancelAnimationFrame(rafRef.current); }, []);
|
||||||
|
|
||||||
const handleSelect = (f) => {
|
const handleSelect = (f) => {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -24,7 +24,7 @@
|
|||||||
<script src="/static/js/services/midiExtractor.js?v=202607281052"></script>
|
<script src="/static/js/services/midiExtractor.js?v=202607281052"></script>
|
||||||
<script src="/static/js/services/promptTemplateManager.js?v=202607281039"></script>
|
<script src="/static/js/services/promptTemplateManager.js?v=202607281039"></script>
|
||||||
<script src="/static/js/services/undoRedoEngine.js?v=202607290941"></script>
|
<script src="/static/js/services/undoRedoEngine.js?v=202607290941"></script>
|
||||||
<script src="/static/js/app.precompiled.js?v=202608021930" defer></script>
|
<script src="/static/js/app.precompiled.js?v=202608021936" defer></script>
|
||||||
<link rel="stylesheet" href="/static/css/styles.css?v=202607271016">
|
<link rel="stylesheet" href="/static/css/styles.css?v=202607271016">
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
|
|||||||
@@ -1139,3 +1139,8 @@
|
|||||||
- **Tóm tắt thay đổi:** (1) Fix canvas audio hiển thị sai: waveform server trả `duration` nhưng không lưu → `dur=0` nên ruler/playhead/time sai. Thêm state `audioDuration` (set ở loadWaveform local/server + playSelected, clear ở handleSelect), `fileDuration` ưu tiên dùng; bar width waveform sửa theo `contentW` thay vì `w` để scroll đúng. (2) Drag & drop file từ Media Explorer vào timeline MAIN SESSION + SECTION-TAB: file row `draggable` + `onDragStart` set `window.__mediaExplorerDragFile`; App thêm `resolveMediaExplorerDropFile()` chuyển entry → real File (client handle `getFile()`, server `file_id` fetch download, local `path` fetch `/media/file`); drop handlers trên track lane + wrapper timeline xử lý cả drag ME lẫn drag OS file (MIDI → new track / audio → load vào track).
|
- **Tóm tắt thay đổi:** (1) Fix canvas audio hiển thị sai: waveform server trả `duration` nhưng không lưu → `dur=0` nên ruler/playhead/time sai. Thêm state `audioDuration` (set ở loadWaveform local/server + playSelected, clear ở handleSelect), `fileDuration` ưu tiên dùng; bar width waveform sửa theo `contentW` thay vì `w` để scroll đúng. (2) Drag & drop file từ Media Explorer vào timeline MAIN SESSION + SECTION-TAB: file row `draggable` + `onDragStart` set `window.__mediaExplorerDragFile`; App thêm `resolveMediaExplorerDropFile()` chuyển entry → real File (client handle `getFile()`, server `file_id` fetch download, local `path` fetch `/media/file`); drop handlers trên track lane + wrapper timeline xử lý cả drag ME lẫn drag OS file (MIDI → new track / audio → load vào track).
|
||||||
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/static/js/app.precompiled.js`, `app/templates/index.html`
|
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/static/js/app.precompiled.js`, `app/templates/index.html`
|
||||||
- **Ghi chú/Test (nếu có):** Smoke jsdom: wav client → metadata Duration 3.00s (trước là 0); drag file row → payload text/plain=name + `__mediaExplorerDragFile` set → drop vào track lane → resolve thành File + load (uploadToServer gọi). Hard reload.
|
- **Ghi chú/Test (nếu có):** Smoke jsdom: wav client → metadata Duration 3.00s (trước là 0); drag file row → payload text/plain=name + `__mediaExplorerDragFile` set → drop vào track lane → resolve thành File + load (uploadToServer gọi). Hard reload.
|
||||||
|
|
||||||
|
### [2026-08-02 19:36] Task: Fix canvas audioclip giãn đầy khung preview
|
||||||
|
- **Tóm tắt thay đổi:** `drawCanvas` branch audio: bỏ `contentW = Math.max(w, dur*pxPerSec)` (giãn đầy frame) → `contentW = max(1, dur*pxPerSec)` với `pxPerBeat=42`, `pxPerSec = 42*bpm/60` (cùng tỉ lệ tempo với MIDI). Clip ngắn hiển thị đúng chiều rộng theo tempo (2s@120 → 168px), clip dài scroll; playhead theo tỉ lệ tempo (`t*pxPerSec`, khóa giữa khi scroll). Ruler cùng scale (bỏ stretch `Math.max(w, ...)`). Thêm `audioDuration` vào deps effect redraw.
|
||||||
|
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/static/js/app.precompiled.js`, `app/templates/index.html`
|
||||||
|
- **Ghi chú/Test (nếu có):** Probe drawCanvas: 2s@120 → contentW=168, waveform maxX 167.8 < 300 (không giãn); 10s → 840 scroll; 2s@240 → 336 (rộng hơn theo tempo). Hard reload.
|
||||||
|
|||||||
Reference in New Issue
Block a user