fix: sửa lỗi audio clip dán từ clipboard không đúng duration
This commit is contained in:
+125
@@ -0,0 +1,125 @@
|
||||
# Technical Specification: Minimum Zoom Constraint Specification
|
||||
|
||||
This document defines the algorithm and graphical rendering mechanics (Rendering Logic) to solve the following problem: When zooming out to the absolute minimum, the audio waveforms of all tracks must fit perfectly within the horizontal width of the Editor viewport, as realistically illustrated in `image_f0c1e0.png`.
|
||||
|
||||
---
|
||||
|
||||
## 1. Current State & Design Problem Analysis
|
||||
|
||||
Based on `image_f0c1e0.png`, when a user performs a zoom-out operation to the absolute minimum limit:
|
||||
|
||||
* **Visual Requirement:** The entire audio range from the starting point ($0.00\text{ s}$) to the termination point ($T_{\text{max}}$) must be captured completely within the "Display Width" ($W_{\text{viewport}}$) of the screen.
|
||||
* **Desired Outcomes:**
|
||||
* No redundant horizontal scrollbars appear underneath the timeline.
|
||||
* No massive black voids (dead space) exist on the right side if the track duration is shorter than the viewport bounding container.
|
||||
* All audio tracks are scaled down synchronously in physical size to fully display their respective waveforms from start to finish.
|
||||
|
||||
|
||||
|
||||
```text
|
||||
Editor Viewport Width (W_viewport)
|
||||
|<───────────────────────────────────────────────────────────────────────────────────>|
|
||||
+─────────────────────────────────────────────────────────────────────────────────────+
|
||||
| Ruler: 0:00 0:10 0:20 0:30 0:40 0:50 1:00 |
|
||||
+─────────────────────────────────────────────────────────────────────────────────────+
|
||||
| Track 1: [███████████████████████████████████████████████████████████████████████] |
|
||||
| |
|
||||
| Track 2: [███████████████████████████████████████████████████████████████████████] |
|
||||
+─────────────────────────────────────────────────────────────────────────────────────+
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Dynamic Min-Zoom Calculation Algorithm
|
||||
|
||||
To guarantee that the waveforms always fit perfectly even when the user resizes the browser window (or a Python application window), the minimum boundary zoom value ($Z_{\text{min}}$) must be evaluated dynamically.
|
||||
|
||||
Let:
|
||||
|
||||
* **$W_{\text{viewport}}$ (pixels):** The actual horizontal visible width of the timeline container viewport.
|
||||
* **$T_{\text{max}}$ (seconds):** The maximum duration among all active tracks residing on the timeline.
|
||||
* **$Z$ (pixels/second):** The current zoom scale factor (Zoom Level—the number of physical pixels representing $1$ second of audio).
|
||||
|
||||
The bounding minimum zoom level ($Z_{\text{min}}$) is determined by the formula:
|
||||
|
||||
$$Z_{\text{min}} = \frac{W_{\text{viewport}}}{T_{\text{max}}}$$
|
||||
|
||||
### 2.1. Zoom Level Constraints
|
||||
|
||||
Throughout mouse wheel interaction events triggered to adjust $Z$, the system must check bounds and strictly clamp the value within a safe operating spectrum:
|
||||
|
||||
$$Z_{\text{clipped}} = \text{clamp}(Z_{\text{min}}, Z_{\text{target}}, Z_{\text{max}})$$
|
||||
|
||||
*Where:*
|
||||
|
||||
* **$Z_{\text{max}}$:** The upper zoom-in boundary limit (e.g., fixed at $2000\text{ pixels/s}$ to eliminate canvas rendering memory overflow vulnerabilities).
|
||||
* **$Z_{\text{min}}$:** The dynamic lower zoom-out boundary limit (re-calculated based on fluctuations of $W_{\text{viewport}}$ and $T_{\text{max}}$).
|
||||
|
||||
---
|
||||
|
||||
## 3. Synchronized Implementation Manual (Frontend JS & Python Porting)
|
||||
|
||||
### 3.1. Client-side Integration (JavaScript / React)
|
||||
|
||||
Utilize a `ResizeObserver` to systematically recompute $Z_{\text{min}}$ as soon as the user scales the browser viewport:
|
||||
|
||||
```javascript
|
||||
// Initialize element targeting for the Timeline container frame
|
||||
const timelineWrapper = document.getElementById('timeline-wrapper');
|
||||
|
||||
const resizeObserver = new ResizeObserver(entries => {
|
||||
for (let entry of entries) {
|
||||
const viewportWidth = entry.contentRect.width;
|
||||
|
||||
// Compute dynamic Z_min boundary condition
|
||||
const computedMinZoom = viewportWidth / maxDuration;
|
||||
|
||||
// Update state and instantly clamp current zoom so it doesn't fall below Z_min
|
||||
setZoom(prevZoom => {
|
||||
const nextZoom = Math.max(computedMinZoom, prevZoom);
|
||||
return nextZoom;
|
||||
});
|
||||
}
|
||||
});
|
||||
resizeObserver.observe(timelineWrapper);
|
||||
|
||||
```
|
||||
|
||||
### 3.2. Server-side / Desktop App Integration (Python PyQt6 / PySide6)
|
||||
|
||||
When porting this layout system and mathematical constraint model to a Python desktop application context, hook into the `resizeEvent` method of the `QWidget` class to handle container adjustments:
|
||||
|
||||
```python
|
||||
from PyQt6.QtWidgets import QWidget
|
||||
from PyQt6.QtCore import QSize
|
||||
|
||||
class TimelineContainerWidget(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.max_duration_seconds = 60.0 # Track duration benchmark (seconds)
|
||||
self.current_zoom = 100.0 # Current scale metric (pixels/second)
|
||||
self.max_zoom = 2000.0 # Strict upper ceiling for zoom-in operations
|
||||
|
||||
def resizeEvent(self, event):
|
||||
"""
|
||||
Intercepts the window/widget resizing event to refresh the minimum zoom bounds.
|
||||
"""
|
||||
viewport_width = self.width()
|
||||
|
||||
# 1. Evaluate the dynamic Z_min constraint from the new physical container width
|
||||
min_zoom = float(viewport_width) / self.max_duration_seconds
|
||||
|
||||
# 2. Hard clamp the active zoom level to prevent dropping underneath min_zoom
|
||||
if self.current_zoom < min_zoom:
|
||||
self.current_zoom = min_zoom
|
||||
|
||||
# 3. Request a graphical redraw of the waveform lanes
|
||||
self.update_waveform_painter()
|
||||
super().resizeEvent(event)
|
||||
|
||||
def update_waveform_painter(self):
|
||||
# Triggers the QPainter paintEvent routine redraw execution block
|
||||
self.update()
|
||||
|
||||
```
|
||||
Reference in New Issue
Block a user