Spaces:
Sleeping
Sleeping
| # Immediate waveform and real progress visualization | |
| ## Goal | |
| The application should no longer feel like a blank control surface after a file is selected. Loading audio is now the first visible step: the browser decodes the uploaded file locally and draws its waveform before the backend extraction job starts. | |
| During extraction, the waveform doubles as the progress surface. The completed portion of the pipeline is rendered over the left side of the uploaded waveform in the accent color; the remaining portion stays neutral. | |
| ## Implementation | |
| ### Browser-side uploaded waveform | |
| `web/app.js` builds an overview directly from the selected `File` using Web Audio: | |
| 1. read the file with `File.arrayBuffer()`; | |
| 2. decode with `AudioContext.decodeAudioData()`; | |
| 3. scan all decoded channels into a fixed-size peak envelope; | |
| 4. render that envelope immediately on `#waveform`; | |
| 5. keep the uploaded file as the `Source` transport target. | |
| No backend round-trip is needed for this first waveform. | |
| ### Real progress contract | |
| Backend job payloads now include a top-level `progress` object: | |
| ```json | |
| { | |
| "fraction": 0.1875, | |
| "completed_steps": 1, | |
| "total_steps": 8, | |
| "completed_units": 12.0, | |
| "total_units": 64.0, | |
| "stage_key": "stem", | |
| "stage_label": "Stem extraction / source load", | |
| "stage_fraction": 0.5, | |
| "stage_work_done": 4, | |
| "stage_work_total": 8, | |
| "basis": "exact completed work units: Demucs chunks when available, otherwise stage boundary units; no time-based estimates" | |
| } | |
| ``` | |
| The UI uses this object as-is. It does not animate guessed progress and does not estimate ETA. | |
| ### Demucs/stem progress | |
| `sample_extractor.extract_stem()` now accepts `progress_cb`. For separated-stem Demucs runs, the code computes the exact number of split chunks from model segment length, overlap, input length, and shift count. A small progress pool reports each completed chunk. | |
| For `stem=all` or cache hits, stem progress is reported as a completed single unit because no chunked separation work is performed. | |
| ### Stage progress | |
| `pipeline_runner.StageTiming` now includes: | |
| - `progress` | |
| - `work_done` | |
| - `work_total` | |
| Stages without internal chunk progress only update at exact boundaries: started and done. This is intentional. The app must show real state, not simulated activity. | |
| ### Waveform progress rendering | |
| `drawWaveform()` renders the same waveform in two colors during active jobs: | |
| - neutral waveform: work not yet completed; | |
| - accent waveform clipped from the left: exact backend progress fraction; | |
| - vertical accent boundary: current progress point. | |
| After completion, the waveform returns to the normal extracted overview with onset markers. | |
| ## UX flow | |
| A new `Start here` panel in the left sidebar makes the flow explicit: | |
| 1. Load audio. | |
| 2. Set controls. | |
| 3. Extract. | |
| 4. Review/export. | |
| The active step is updated from actual UI/job state. | |
| ## Limitations | |
| - The global `fraction` is a deterministic work-unit fraction: Demucs chunks when available, otherwise one boundary unit per stage. It is not elapsed-time prediction. | |
| - Demucs progress is chunk-accurate for the internal split chunks used by the Python API path. | |
| - Non-Demucs stages currently expose exact boundary progress only; adding finer-grained progress to onset detection and clustering requires breaking those algorithms into explicit callback-reporting loops. | |