From 56660fe0b56586299bd0281001a555237dc4ee21 Mon Sep 17 00:00:00 2001 From: Carl Philipp Klemm Date: Wed, 4 Mar 2026 19:53:04 +0100 Subject: [PATCH] Ui improvements --- AudioPlayer.cpp | 42 ++++++++++++++++++++++++++-- AudioPlayer.h | 7 +++++ MainWindow.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++++---- MainWindow.h | 7 +++++ 4 files changed, 122 insertions(+), 7 deletions(-) diff --git a/AudioPlayer.cpp b/AudioPlayer.cpp index 423de7d..a9b77ca 100644 --- a/AudioPlayer.cpp +++ b/AudioPlayer.cpp @@ -4,7 +4,8 @@ AudioPlayer::AudioPlayer(QObject *parent) : QObject(parent), mediaPlayer(new QMediaPlayer(this)), - audioOutput(new QAudioOutput(this)) + audioOutput(new QAudioOutput(this)), + positionTimer(new QTimer(this)) { // Set up audio output with default device mediaPlayer->setAudioOutput(audioOutput); @@ -13,6 +14,14 @@ AudioPlayer::AudioPlayer(QObject *parent) this, &AudioPlayer::handlePlaybackStateChanged); connect(mediaPlayer, &QMediaPlayer::mediaStatusChanged, this, &AudioPlayer::handleMediaStatusChanged); + + // Set up position timer for updating playback position + positionTimer->setInterval(500); // Update every 500ms + connect(positionTimer, &QTimer::timeout, [this]() { + if (isPlaying()) { + emit positionChanged(mediaPlayer->position()); + } + }); } AudioPlayer::~AudioPlayer() @@ -28,11 +37,36 @@ void AudioPlayer::play(const QString &filePath) mediaPlayer->setSource(QUrl::fromLocalFile(filePath)); mediaPlayer->play(); + + // Start position timer + positionTimer->start(); +} + +void AudioPlayer::play() +{ + if (!isPlaying()) { + mediaPlayer->play(); + positionTimer->start(); + } +} + +void AudioPlayer::pause() +{ + if (isPlaying()) { + mediaPlayer->pause(); + positionTimer->stop(); + } +} + +void AudioPlayer::setPosition(int position) +{ + mediaPlayer->setPosition(position); } void AudioPlayer::stop() { mediaPlayer->stop(); + positionTimer->stop(); } bool AudioPlayer::isPlaying() const @@ -69,7 +103,11 @@ void AudioPlayer::handleMediaStatusChanged(QMediaPlayer::MediaStatus status) emit playbackFinished(); } else if (status == QMediaPlayer::LoadedMedia || status == QMediaPlayer::BufferedMedia) { - // Media loaded successfully + // Media loaded successfully, emit duration + int duration = mediaPlayer->duration(); + if (duration > 0) { + emit durationChanged(duration); + } } else if (status == QMediaPlayer::InvalidMedia) { emit playbackError(mediaPlayer->errorString()); } diff --git a/AudioPlayer.h b/AudioPlayer.h index 8b12f97..496670b 100644 --- a/AudioPlayer.h +++ b/AudioPlayer.h @@ -8,6 +8,7 @@ #include #include #include +#include class AudioPlayer : public QObject { @@ -17,7 +18,10 @@ public: ~AudioPlayer(); void play(const QString &filePath); + void play(); void stop(); + void pause(); + void setPosition(int position); bool isPlaying() const; int duration() const; int position() const; @@ -26,6 +30,8 @@ signals: void playbackStarted(); void playbackFinished(); void playbackError(const QString &error); + void positionChanged(int position); + void durationChanged(int duration); private slots: void handlePlaybackStateChanged(QMediaPlayer::PlaybackState state); @@ -34,6 +40,7 @@ private slots: private: QMediaPlayer *mediaPlayer; QAudioOutput *audioOutput; + QTimer *positionTimer; }; #endif // AUDIOPLAYER_H diff --git a/MainWindow.cpp b/MainWindow.cpp index df71d7b..8d3b694 100644 --- a/MainWindow.cpp +++ b/MainWindow.cpp @@ -22,6 +22,7 @@ MainWindow::MainWindow(QWidget *parent) playbackTimer(new QTimer(this)), currentSongIndex(-1), isPlaying(false), + isPaused(false), shuffleMode(false) { ui->setupUi(this); @@ -111,11 +112,42 @@ void MainWindow::saveSettings() settings.setValue("vaeModelPath", vaeModelPath); } +QString MainWindow::formatTime(int milliseconds) +{ + if (milliseconds < 0) return "0:00"; + + int seconds = milliseconds / 1000; + int minutes = seconds / 60; + seconds = seconds % 60; + + return QString("%1:%2").arg(minutes).arg(seconds, 2, 10, QChar('0')); +} + +void MainWindow::updatePosition(int position) +{ + if (position < 0) return; + + // Update slider and time labels + ui->positionSlider->setValue(position); + ui->elapsedTimeLabel->setText(formatTime(position)); +} + +void MainWindow::updateDuration(int duration) +{ + if (duration <= 0) return; + + // Set slider range and update duration label + ui->positionSlider->setRange(0, duration); + ui->durationLabel->setText(formatTime(duration)); +} + void MainWindow::updateControls() { bool hasSongs = songModel->rowCount() > 0; - ui->playButton->setEnabled(hasSongs && !isPlaying); + // Play button is enabled when not playing, or can be used to resume when paused + ui->playButton->setEnabled(hasSongs && (!isPlaying || isPaused)); + ui->pauseButton->setEnabled(isPlaying && !isPaused); ui->skipButton->setEnabled(isPlaying); ui->stopButton->setEnabled(isPlaying); ui->addSongButton->setEnabled(true); @@ -125,9 +157,18 @@ void MainWindow::updateControls() void MainWindow::on_playButton_clicked() { + if (isPaused) { + // Resume playback + audioPlayer->play(); + isPaused = false; + updateControls(); + return; + } + if (isPlaying) { audioPlayer->stop(); isPlaying = false; + isPaused = false; updateControls(); return; } @@ -141,11 +182,22 @@ void MainWindow::on_playButton_clicked() generateAndPlayNext(); } +void MainWindow::on_pauseButton_clicked() +{ + if (isPlaying && !isPaused) { + // Pause playback + audioPlayer->pause(); + isPaused = true; + updateControls(); + } +} + void MainWindow::on_skipButton_clicked() { if (isPlaying) { // Stop current playback and move to next song audioPlayer->stop(); + isPaused = false; playNextSong(); } } @@ -156,11 +208,20 @@ void MainWindow::on_stopButton_clicked() // Stop current playback completely audioPlayer->stop(); isPlaying = false; + isPaused = false; ui->statusLabel->setText("Stopped"); updateControls(); } } +void MainWindow::on_positionSlider_sliderMoved(int position) +{ + if (isPlaying && audioPlayer->isPlaying()) { + // Seek to the new position when slider is moved + audioPlayer->setPosition(position); + } +} + void MainWindow::on_shuffleButton_clicked() { shuffleMode = ui->shuffleButton->isChecked(); @@ -258,10 +319,6 @@ void MainWindow::on_advancedSettingsButton_clicked() jsonTemplateEdit->setMinimumHeight(200); jsonLayout->addWidget(jsonTemplateEdit); - QLabel *fieldsLabel = new QLabel("Available fields: caption, lyrics, instrumental, bpm, duration, keyscale, timesignature,\nvocal_language, seed, lm_temperature, lm_cfg_scale, lm_top_p, lm_top_k, lm_negative_prompt,\naudio_codes, inference_steps, guidance_scale, shift"); - fieldsLabel->setWordWrap(true); - jsonLayout->addWidget(fieldsLabel); - tabWidget->addTab(jsonTab, "JSON Template"); // Path Settings tab @@ -405,6 +462,10 @@ void MainWindow::songGenerated(const QString &filePath) // Play the generated song audioPlayer->play(filePath); + + // Connect position and duration updates for the slider + connect(audioPlayer, &AudioPlayer::positionChanged, this, &MainWindow::updatePosition); + connect(audioPlayer, &AudioPlayer::durationChanged, this, &MainWindow::updateDuration); } void MainWindow::playNextSong() @@ -420,6 +481,7 @@ void MainWindow::playNextSong() } else { // No more songs isPlaying = false; + isPaused = false; ui->statusLabel->setText("Finished playback"); updateControls(); } @@ -453,6 +515,7 @@ void MainWindow::generationError(const QString &error) dialog.exec(); isPlaying = false; + isPaused = false; updateControls(); } diff --git a/MainWindow.h b/MainWindow.h index a4380bc..f91fcd8 100644 --- a/MainWindow.h +++ b/MainWindow.h @@ -23,9 +23,13 @@ public: private slots: void on_playButton_clicked(); + void on_pauseButton_clicked(); void on_skipButton_clicked(); void on_stopButton_clicked(); void on_shuffleButton_clicked(); + void on_positionSlider_sliderMoved(int position); + void updatePosition(int position); + void updateDuration(int duration); void on_addSongButton_clicked(); void on_editSongButton_clicked(); void on_removeSongButton_clicked(); @@ -44,8 +48,11 @@ private: AceStepWorker *aceStepWorker; QTimer *playbackTimer; + QString formatTime(int milliseconds); + int currentSongIndex; bool isPlaying; + bool isPaused; bool shuffleMode; QString jsonTemplate;