feat: editor playback + temp cleanup on close + docs (v1.6)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 18:31:13 +02:00
co-authored by Claude Opus 4.8
parent 4d54f29514
commit 4a34a87d37
3 changed files with 90 additions and 2 deletions
+64 -2
View File
@@ -4112,6 +4112,7 @@ class AudioEditorDialog(QDialog):
self._versions: list[str] = [path]
self._ver_idx = 0
self._temps: set[str] = set() # rendered version temps to clean up
self._play_proc = None # ffplay audition process
self._clip_dur = 0.0 # true duration of the current version
self._wave = AudioWaveform()
@@ -4250,7 +4251,61 @@ class AudioEditorDialog(QDialog):
self._ver_idx += 1
self._reload()
def _on_play(self): pass
def _on_play(self, checked: bool) -> None:
if not checked:
self._stop_play()
return
from PyQt6.QtCore import QProcess
self._stop_play()
self._play_proc = QProcess(self)
self._play_proc.finished.connect(self._on_play_finished)
self._play_proc.errorOccurred.connect(self._on_play_error)
self._play_proc.start(
_bin("ffplay"),
["-autoexit", "-nodisp", "-loglevel", "error", self._current()])
self._btn_play.setText("■ Stop")
def _on_play_error(self, _err) -> None:
self._set_status("Playback unavailable (ffplay not found)")
self._teardown_play()
def _on_play_finished(self, *_a) -> None:
self._teardown_play()
def _teardown_play(self) -> None:
proc = self._play_proc
self._play_proc = None
if proc is not None:
proc.deleteLater()
self._btn_play.setText("▶ Play")
if self._btn_play.isChecked():
self._btn_play.blockSignals(True)
self._btn_play.setChecked(False)
self._btn_play.blockSignals(False)
def _stop_play(self) -> None:
proc = self._play_proc
self._play_proc = None
if proc is not None:
try:
proc.finished.disconnect()
proc.errorOccurred.disconnect()
except Exception:
pass
proc.kill()
proc.waitForFinished(100)
proc.deleteLater()
self._btn_play.setText("▶ Play")
def closeEvent(self, ev) -> None:
self._stop_play()
for _t in list(self._temps):
try:
os.remove(_t)
except OSError:
pass
self._temps.clear()
super().closeEvent(ev)
def _on_save_as(self):
path, _sel = QFileDialog.getSaveFileName(
@@ -5364,13 +5419,20 @@ class MainWindow(QMainWindow):
# ── Changelog ────────────────────────────────────────────
APP_VERSION = "1.5"
APP_VERSION = "1.6"
_SPLIT_HEADER_H = 22 # deck split-column header height (keep both deck spots in sync)
_WAVE_MIN_VIEW = 3.0 # minimum waveform view window (seconds)
_MERGE_CURVES = (("Triangular", "tri"), ("Exponential", "exp"),
("Logarithmic", "log"), ("Quarter sine", "qsin"),
("Half sine", "hsin"))
CHANGELOG: list[tuple[str, list[str]]] = [
("1.6", [
"<b>Destructive clip editor</b> — <b>✎ Edit clip…</b> in the Audio "
"tab opens the current area in an editor: drag to select a region "
"and <b>Delete</b>, <b>Silence</b>, <b>Reverse</b>, or <b>Trim to "
"selection</b>, with <b>undo/redo</b> and audition, then <b>Save "
"as…</b>. Non-destructive — the original is never touched.",
]),
("1.5", [
"<b>Interactive waveform</b> — the Audio tab's waveform is now a "
"selection surface: <b>drag the in/out handles</b> (or drag a new "