Reputation: 31
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