Bogdan Valentin
Bogdan Valentin

Reputation: 31

(gtkmm, sfml) My music stream is experiencing stuttering

I want to build a music player using gtkmm and sfml but i am encountering stuttering with my music stream.

I tried using a separate thread for the music but i couldn't understand how to use Glib::Dispatcher to update my time bar. https://developer-old.gnome.org/gtkmm-tutorial/stable/sec-multithread-example.html.en

Is it necessary to use a second thread? If so, how should i implement the function that updates the time bar?


#include <iostream>
#include <thread>

// Audio library
#include <SFML/Audio.hpp>

// GUI library
#include <gtkmm.h>

class MainWindow : public Gtk::Window {
protected:
    Gtk::Box mainBox;
    Gtk::Box buttonsBox;
    Gtk::Box volumeAndTimeBox;
    Gtk::Box timeBarBox;
    Gtk::Box volumeBarBox;

    Gtk::Button prevButton;
    Gtk::Button pauseButton;
    Gtk::Button nextButton;

    Gtk::Scale timeBar;
    Gtk::Scale volumeBar;
    
    sf::Music musicStream;
    
    void pauseButtonClicked();
    void prevButtonClicked();
    void nextButtonClicked();
    void volumeSliderChanged();
    void timeSliderChanged();
    bool updateTimeBar();
    void openAndPlayMusic();
public:
    MainWindow();
    virtual ~MainWindow();
};
#include "MainWindow.hpp"
#include <gtkmm/application.h>

int main(int argc, char *argv[])
{
    auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example");

    MainWindow mainWindow;

    return app->run(mainWindow);
}
#include "MainWindow.hpp"

MainWindow::MainWindow() : prevButton("Previous"), pauseButton("Pause"), nextButton("Next"),
    volumeBar(Gtk::Adjustment::create(50, 0, 100, 1, 1, 0), Gtk::ORIENTATION_VERTICAL) {
    volumeBar.set_draw_value(false);
    volumeBar.set_digits(0);
    volumeBar.set_inverted(true);

    set_default_size(600, 300);
    set_border_width(10);

    openAndPlayMusic();

    // mainBox properties
    mainBox.set_orientation(Gtk::ORIENTATION_VERTICAL);
    mainBox.pack_start(buttonsBox);
    mainBox.pack_start(volumeAndTimeBox);

    // buttonsBox properties
    buttonsBox.set_orientation(Gtk::ORIENTATION_HORIZONTAL);
    buttonsBox.pack_start(prevButton);
    buttonsBox.pack_start(pauseButton);
    buttonsBox.pack_start(nextButton);

    // volumeAndTimeBox properties
    volumeAndTimeBox.set_orientation(Gtk::ORIENTATION_HORIZONTAL);
    volumeAndTimeBox.pack_start(timeBarBox);
    volumeAndTimeBox.pack_start(volumeBarBox);

    // timeBarBox properties
    timeBarBox.set_orientation(Gtk::ORIENTATION_HORIZONTAL);
    timeBarBox.pack_start(timeBar);

    // volumeBarBox properties
    volumeBarBox.pack_start(volumeBar);

    // Connect signals
    pauseButton.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::pauseButtonClicked));
    prevButton.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::prevButtonClicked));
    nextButton.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::nextButtonClicked));
    volumeBar.signal_value_changed().connect(sigc::mem_fun(*this, &MainWindow::volumeSliderChanged));
    timeBar.signal_value_changed().connect(sigc::mem_fun(*this, &MainWindow::timeSliderChanged));

    // timeBar properties
    timeBar.set_range(0, musicStream.getDuration().asSeconds() / 60);
    timeBar.set_digits(2);
    Glib::signal_timeout().connect(sigc::mem_fun(*this, &MainWindow::updateTimeBar), 1000);

    // volumeBar properties
    volumeBar.set_range(0, 100);
    
    // Show all the elements
    add(mainBox);
    show_all_children();
}

MainWindow::~MainWindow() {}

void MainWindow::openAndPlayMusic() {
    musicStream.openFromFile("Bad.flac");
    musicStream.play();
}

void MainWindow::pauseButtonClicked() {
    std::cout << "Pause button pressed." << std::endl;
    if(musicStream.getStatus() == sf::Music::Paused  ||
       musicStream.getStatus() == sf::Music::Stopped ) {
        musicStream.play();
    }
    else if(musicStream.getStatus() == sf::Music::Playing) {
        musicStream.pause();
    }
}

void MainWindow::prevButtonClicked() {
    std::cout << "Prev button pressed." << std::endl;
}

void MainWindow::nextButtonClicked() {
    std::cout << "Next button pressed." << std::endl;
}

void MainWindow::volumeSliderChanged() {
    musicStream.setVolume(volumeBar.get_value());
}

void MainWindow::timeSliderChanged() {
    musicStream.setPlayingOffset(sf::seconds(timeBar.get_value() * 60));
}

bool MainWindow::updateTimeBar() {
    if (musicStream.getStatus() == sf::Music::Playing) {
        // Update the time bar based on the current playing position
        float currentTime = musicStream.getPlayingOffset().asSeconds();
        timeBar.set_value(currentTime / 60);
    }
    return true;
}

Upvotes: 3

Views: 50

Answers (0)

Related Questions