Skip to content

Commit 889cddc

Browse files
committed
Enhance audio clip editing features and UI components
- Added Audio Clip Editor functionality, allowing users to edit audio clips within the application. - Integrated audio clip selection and double-click actions to open the Audio Clip Editor. - Updated MainWindow to include a toggle for the Audio Clip Editor dock, improving accessibility. - Enhanced the EditManager with new signals for audio clip interactions, facilitating better communication between components. - Improved UI responsiveness and layout adjustments for better user experience in audio editing tasks.
1 parent d6e287f commit 889cddc

24 files changed

Lines changed: 3075 additions & 28 deletions

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ set(FREEDAW_SOURCES
8181
src/ui/effects/EffectSelectorDialog.h src/ui/effects/EffectSelectorDialog.cpp
8282
src/ui/effects/VstSelectorDialog.h src/ui/effects/VstSelectorDialog.cpp
8383
src/ui/effects/PluginEditorWindow.h src/ui/effects/PluginEditorWindow.cpp
84+
src/ui/audioclip/WaveformSelection.h
85+
src/ui/audioclip/AudioFileUndoManager.h src/ui/audioclip/AudioFileUndoManager.cpp
86+
src/ui/audioclip/AudioFileOperations.h src/ui/audioclip/AudioFileOperations.cpp
87+
src/ui/audioclip/AudioClipEditor.h src/ui/audioclip/AudioClipEditor.cpp
88+
src/ui/audioclip/AudioWaveformView.h src/ui/audioclip/AudioWaveformView.cpp
8489
src/ui/pianoroll/PianoRollEditor.h src/ui/pianoroll/PianoRollEditor.cpp
8590
src/ui/pianoroll/PianoKeyboard.h src/ui/pianoroll/PianoKeyboard.cpp
8691
src/ui/pianoroll/NoteGrid.h src/ui/pianoroll/NoteGrid.cpp

src/ai/AiChatWidget.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "engine/AudioEngine.h"
44
#include "engine/PluginScanner.h"
55
#include "utils/ThemeManager.h"
6+
#include "utils/IconFont.h"
67
#include <QHBoxLayout>
78
#include <QDialog>
89
#include <QDialogButtonBox>
@@ -80,13 +81,19 @@ void AiChatWidget::setupUi()
8081
showToolOutput_ = s.value("ai/showToolOutput", false).toBool();
8182
}
8283

83-
toolToggleBtn_ = new QPushButton(showToolOutput_ ? "Tools: ON" : "Tools: OFF", headerBar_);
84+
const auto miFont = icons::materialIcons(14);
85+
toolToggleBtn_ = new QPushButton(headerBar_);
8486
toolToggleBtn_->setAccessibleName("Toggle Tool Output Display");
85-
toolToggleBtn_->setFixedSize(68, 24);
87+
toolToggleBtn_->setFont(miFont);
88+
toolToggleBtn_->setText(showToolOutput_ ? QString(icons::mi::Visibility)
89+
: QString(icons::mi::VisibilityOff));
90+
toolToggleBtn_->setToolTip(showToolOutput_ ? "Tool calls visible – click to hide"
91+
: "Tool calls hidden – click to show");
92+
toolToggleBtn_->setFixedSize(28, 24);
8693
toolToggleBtn_->setCheckable(true);
8794
toolToggleBtn_->setChecked(showToolOutput_);
8895
toolToggleBtn_->setStyleSheet(
89-
QString("QPushButton { font-size: 10px; background: %1; color: %2; "
96+
QString("QPushButton { font-size: 14px; background: %1; color: %2; "
9097
"border: 1px solid %3; border-radius: 3px; }"
9198
"QPushButton:hover { background: %4; }"
9299
"QPushButton:checked { background: %5; color: #fff; }")
@@ -95,7 +102,10 @@ void AiChatWidget::setupUi()
95102
theme.accent.darker(130).name()));
96103
connect(toolToggleBtn_, &QPushButton::toggled, this, [this](bool on) {
97104
showToolOutput_ = on;
98-
toolToggleBtn_->setText(on ? "Tools: ON" : "Tools: OFF");
105+
toolToggleBtn_->setText(on ? QString(icons::mi::Visibility)
106+
: QString(icons::mi::VisibilityOff));
107+
toolToggleBtn_->setToolTip(on ? "Tool calls visible – click to hide"
108+
: "Tool calls hidden – click to show");
99109
QSettings s;
100110
s.setValue("ai/showToolOutput", on);
101111
updateToolBubbleVisibility();

src/engine/EditManager.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ class EditManager : public QObject {
130130
void midiClipDoubleClicked(te::MidiClip* clip);
131131
void midiClipSelected(te::MidiClip* clip);
132132
void midiClipModified(te::MidiClip* clip);
133+
void audioClipDoubleClicked(te::WaveAudioClip* clip);
134+
void audioClipSelected(te::WaveAudioClip* clip);
135+
void audioClipModified(te::WaveAudioClip* clip);
133136

134137
private:
135138
void teardownCurrentEdit();

src/ui/MainWindow.cpp

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "ui/effects/VstSelectorDialog.h"
33
#include "ui/effects/PluginEditorWindow.h"
44
#include "ui/pianoroll/PianoRollEditor.h"
5+
#include "ui/audioclip/AudioClipEditor.h"
56
#include "ui/dialogs/ExportDialog.h"
67
#include "ui/SplashScreen.h"
78
#include "utils/ThemeManager.h"
@@ -21,6 +22,7 @@
2122
#include <QPlainTextEdit>
2223
#include <QComboBox>
2324
#include <QShortcutEvent>
25+
#include <QTimer>
2426
#include <QtConcurrent/QtConcurrent>
2527

2628
namespace freedaw {
@@ -92,6 +94,8 @@ MainWindow::MainWindow(FreeDawApplication& app, QWidget* parent)
9294
this, [this]() {
9395
if (pianoRoll_)
9496
pianoRoll_->setClip(nullptr);
97+
if (audioClipEditor_)
98+
audioClipEditor_->setClip(nullptr, nullptr);
9599
});
96100

97101
setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
@@ -102,6 +106,8 @@ MainWindow::MainWindow(FreeDawApplication& app, QWidget* parent)
102106
createToolBar();
103107
createStatusBar();
104108

109+
resizeDocks({mixerDock_}, {350}, Qt::Vertical);
110+
105111
aiQuickPrompt_ = new AiQuickPrompt(this);
106112
connect(aiQuickPrompt_, &AiQuickPrompt::promptSubmitted,
107113
this, [this](const QString& text) {
@@ -252,6 +258,10 @@ void MainWindow::createMenus()
252258
viewMenu->addAction("Toggle &Effects", this, [this]() {
253259
effectsDock_->setVisible(!effectsDock_->isVisible());
254260
});
261+
viewMenu->addAction("Toggle Audio &Clip Editor", this, [this]() {
262+
audioClipDock_->setVisible(!audioClipDock_->isVisible());
263+
if (audioClipDock_->isVisible()) audioClipDock_->raise();
264+
});
255265
viewMenu->addAction("Toggle &Routing", this, [this]() {
256266
routingDock_->setVisible(!routingDock_->isVisible());
257267
if (routingDock_->isVisible()) routingDock_->raise();
@@ -438,6 +448,12 @@ void MainWindow::createToolBar()
438448
effectsToggle->setToolTip("Toggle Effects");
439449
mainToolBar_->addAction(effectsToggle);
440450
}
451+
if (audioClipDock_) {
452+
auto* audioClipToggle = audioClipDock_->toggleViewAction();
453+
audioClipToggle->setIcon(faIcon(icons::fa::Waveform));
454+
audioClipToggle->setToolTip("Toggle Audio Clip Editor");
455+
mainToolBar_->addAction(audioClipToggle);
456+
}
441457
if (routingDock_) {
442458
auto* routingToggle = routingDock_->toggleViewAction();
443459
routingToggle->setIcon(miIcon(icons::mi::Settings));
@@ -511,6 +527,42 @@ void MainWindow::createDocks()
511527
pianoRoll_->setClip(clip);
512528
});
513529

530+
// Audio Clip Editor dock (bottom, tabbed with mixer and piano roll)
531+
audioClipDock_ = new QDockWidget("Audio Clip", this);
532+
audioClipDock_->setAccessibleName("Audio Clip Editor Dock");
533+
audioClipEditor_ = new AudioClipEditor(audioClipDock_);
534+
audioClipDock_->setWidget(audioClipEditor_);
535+
addDockWidget(Qt::BottomDockWidgetArea, audioClipDock_);
536+
537+
connect(audioClipEditor_, &AudioClipEditor::clipModified,
538+
timelineView_, &TimelineView::rebuildClips);
539+
540+
connect(&editMgr_, &EditManager::aboutToChangeEdit, this, [this]() {
541+
if (audioClipEditor_)
542+
audioClipEditor_->setClip(nullptr, nullptr);
543+
});
544+
545+
connect(&editMgr_, &EditManager::editChanged, this, [this]() {
546+
if (audioClipEditor_ && audioClipEditor_->clip()) {
547+
if (editMgr_.isClipValid(audioClipEditor_->clip()))
548+
audioClipEditor_->refresh();
549+
else
550+
audioClipEditor_->setClip(nullptr, nullptr);
551+
}
552+
});
553+
554+
connect(&editMgr_, &EditManager::audioClipModified,
555+
this, [this](te::WaveAudioClip* clip) {
556+
if (audioClipEditor_ && audioClipEditor_->clip() == clip)
557+
audioClipEditor_->refresh();
558+
});
559+
560+
connect(&editMgr_, &EditManager::audioClipSelected,
561+
this, [this](te::WaveAudioClip* clip) {
562+
if (audioClipDock_ && audioClipDock_->isVisible() && audioClipEditor_ && clip)
563+
audioClipEditor_->setClip(clip, &editMgr_);
564+
});
565+
514566
// Routing view dock (bottom, tabbed with mixer and piano roll)
515567
routingDock_ = new QDockWidget("Routing", this);
516568
routingDock_->setAccessibleName("Routing Dock");
@@ -533,12 +585,16 @@ void MainWindow::createDocks()
533585
});
534586

535587
tabifyDockWidget(mixerDock_, pianoRollDock_);
536-
tabifyDockWidget(pianoRollDock_, routingDock_);
588+
tabifyDockWidget(pianoRollDock_, audioClipDock_);
589+
tabifyDockWidget(audioClipDock_, routingDock_);
537590
mixerDock_->raise();
538591

539592
connect(&editMgr_, &EditManager::midiClipDoubleClicked,
540593
this, &MainWindow::onMidiClipDoubleClicked);
541594

595+
connect(&editMgr_, &EditManager::audioClipDoubleClicked,
596+
this, &MainWindow::onAudioClipDoubleClicked);
597+
542598
// File browser dock (right, collapsible)
543599
browserDock_ = new QDockWidget("Browser", this);
544600
browserDock_->setAccessibleName("File Browser Dock");
@@ -777,4 +833,14 @@ void MainWindow::onMidiClipDoubleClicked(te::MidiClip* clip)
777833
pianoRoll_->setClip(clip);
778834
}
779835

836+
void MainWindow::onAudioClipDoubleClicked(te::WaveAudioClip* clip)
837+
{
838+
if (!clip) return;
839+
audioClipDock_->setVisible(true);
840+
audioClipDock_->raise();
841+
842+
if (audioClipEditor_)
843+
audioClipEditor_->setClip(clip, &editMgr_);
844+
}
845+
780846
} // namespace freedaw

src/ui/MainWindow.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
namespace freedaw {
2020

2121
class PianoRollEditor;
22+
class AudioClipEditor;
2223

2324
class ShortcutFilter : public QObject {
2425
Q_OBJECT
@@ -55,6 +56,7 @@ class MainWindow : public QMainWindow {
5556
void onEffectInsertRequested(te::AudioTrack* track, int slotIndex);
5657
void onInstrumentSelectRequested(te::AudioTrack* track);
5758
void onMidiClipDoubleClicked(te::MidiClip* clip);
59+
void onAudioClipDoubleClicked(te::WaveAudioClip* clip);
5860

5961
FreeDawApplication& app_;
6062
EditManager& editMgr_;
@@ -65,6 +67,7 @@ class MainWindow : public QMainWindow {
6567
EffectChainWidget* effectChain_ = nullptr;
6668
FileBrowserPanel* fileBrowser_ = nullptr;
6769
PianoRollEditor* pianoRoll_ = nullptr;
70+
AudioClipEditor* audioClipEditor_ = nullptr;
6871
RoutingView* routingView_ = nullptr;
6972
AiChatWidget* aiChatWidget_ = nullptr;
7073
AiQuickPrompt* aiQuickPrompt_ = nullptr;
@@ -73,6 +76,7 @@ class MainWindow : public QMainWindow {
7376
QDockWidget* effectsDock_ = nullptr;
7477
QDockWidget* browserDock_ = nullptr;
7578
QDockWidget* pianoRollDock_ = nullptr;
79+
QDockWidget* audioClipDock_ = nullptr;
7680
QDockWidget* routingDock_ = nullptr;
7781
QDockWidget* aiDock_ = nullptr;
7882

0 commit comments

Comments
 (0)