feat: Merge pane (3rd Audio QToolBox page) — list + crossfade + buttons
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4538,6 +4538,43 @@ class MainWindow(QMainWindow):
|
||||
"Audition the current audio area (with the edits applied)")
|
||||
self._btn_audio_play.toggled.connect(self._on_audio_audition)
|
||||
self._audition_proc = None # QProcess while auditioning, else None
|
||||
|
||||
# ── Merge (crossfade) pane widgets ───────────────────────────
|
||||
self._merge_list = QListWidget()
|
||||
self._merge_list.setSelectionMode(
|
||||
QAbstractItemView.SelectionMode.SingleSelection)
|
||||
self._merge_list.setToolTip("Clips to merge, top to bottom")
|
||||
self._spn_crossfade = QDoubleSpinBox()
|
||||
self._spn_crossfade.setRange(0.0, 10.0)
|
||||
self._spn_crossfade.setDecimals(2)
|
||||
self._spn_crossfade.setSingleStep(0.1)
|
||||
self._spn_crossfade.setSuffix(" s")
|
||||
self._spn_crossfade.setToolTip("Crossfade applied at every join (0 = butt-join)")
|
||||
self._spn_crossfade.setValue(float(self._settings.value("audio_crossfade", 0.5)))
|
||||
self._spn_crossfade.valueChanged.connect(
|
||||
lambda v: self._settings.setValue("audio_crossfade", v))
|
||||
self._btn_merge_add_sel = QPushButton("+ Selection")
|
||||
self._btn_merge_add_sel.setToolTip(
|
||||
"Add the current audio area (with edits) as a clip")
|
||||
self._btn_merge_add_sel.clicked.connect(self._on_merge_add_selection)
|
||||
self._btn_merge_add_file = QPushButton("+ File…")
|
||||
self._btn_merge_add_file.setToolTip("Add audio file(s) as clips")
|
||||
self._btn_merge_add_file.clicked.connect(self._on_merge_add_file)
|
||||
self._btn_merge_up = QPushButton("▲")
|
||||
self._btn_merge_up.setToolTip("Move selected clip up")
|
||||
self._btn_merge_up.clicked.connect(lambda: self._merge_move(-1))
|
||||
self._btn_merge_down = QPushButton("▼")
|
||||
self._btn_merge_down.setToolTip("Move selected clip down")
|
||||
self._btn_merge_down.clicked.connect(lambda: self._merge_move(1))
|
||||
self._btn_merge_remove = QPushButton("✕")
|
||||
self._btn_merge_remove.setToolTip("Remove selected clip")
|
||||
self._btn_merge_remove.clicked.connect(self._merge_remove_selected)
|
||||
self._btn_merge_preview = QPushButton("▶ Preview")
|
||||
self._btn_merge_preview.setToolTip("Merge to a temp file and audition")
|
||||
self._btn_merge_preview.clicked.connect(self._on_merge_preview)
|
||||
self._btn_merge_save = QPushButton("Merge && Save…")
|
||||
self._btn_merge_save.setToolTip("Merge the clips and save the result")
|
||||
self._btn_merge_save.clicked.connect(self._on_merge_save)
|
||||
self._transport_row = transport_row
|
||||
|
||||
# Row 1b — subcategory (subprofile) export buttons live on their own
|
||||
@@ -4864,6 +4901,27 @@ class MainWindow(QMainWindow):
|
||||
sg.setColumnStretch(3, 1)
|
||||
tb.addItem(scan_page, "Scan / Classify")
|
||||
|
||||
# ── Page 3: Merge (crossfade) ────────────────────────────
|
||||
merge_page = QWidget()
|
||||
mv = QVBoxLayout(merge_page)
|
||||
mv.setContentsMargins(8, 6, 8, 6); mv.setSpacing(6)
|
||||
mv.addWidget(self._merge_list)
|
||||
xrow = QHBoxLayout()
|
||||
xrow.addWidget(QLabel("Crossfade:"))
|
||||
xrow.addWidget(self._spn_crossfade)
|
||||
xrow.addStretch()
|
||||
mv.addLayout(xrow)
|
||||
brow = QHBoxLayout()
|
||||
for b in (self._btn_merge_add_sel, self._btn_merge_add_file,
|
||||
self._btn_merge_up, self._btn_merge_down, self._btn_merge_remove):
|
||||
brow.addWidget(b)
|
||||
mv.addLayout(brow)
|
||||
arow = QHBoxLayout()
|
||||
arow.addWidget(self._btn_merge_preview)
|
||||
arow.addWidget(self._btn_merge_save)
|
||||
mv.addLayout(arow)
|
||||
tb.addItem(merge_page, "Merge")
|
||||
|
||||
outer.addWidget(tb)
|
||||
|
||||
# ── Menu bar ─────────────────────────────────────────────
|
||||
@@ -6521,6 +6579,24 @@ class MainWindow(QMainWindow):
|
||||
start = self._cursor
|
||||
self._timeline.set_audio_region(start, start + self._spn_audio_len.value())
|
||||
|
||||
def _on_merge_add_selection(self) -> None:
|
||||
pass # implemented in M3
|
||||
|
||||
def _on_merge_add_file(self) -> None:
|
||||
pass # implemented in M3
|
||||
|
||||
def _merge_move(self, delta: int) -> None:
|
||||
pass # implemented in M3
|
||||
|
||||
def _merge_remove_selected(self) -> None:
|
||||
pass # implemented in M3
|
||||
|
||||
def _on_merge_preview(self) -> None:
|
||||
pass # implemented in M4
|
||||
|
||||
def _on_merge_save(self) -> None:
|
||||
pass # implemented in M4
|
||||
|
||||
def _on_wave_refresh(self) -> None:
|
||||
"""Decode the current audio area and repaint the waveform strip."""
|
||||
if not self._file_path:
|
||||
|
||||
Reference in New Issue
Block a user