Building an MP3 Player with Qt5
published at 21.02.2013 15:54 by Jens Weller
Save to Instapaper Pocket
I've been playing around with Qt5 now for a few weeks, and my interest is especially in the new MultiMedia APIs. For 2 reasons, first, over 10 years ago I programmed my own simple MP3 Player with MFC and FMOD for the playback. Which I could recode now in Qt5, as its offering Media playback. Phonon did offer this in Qt4 already, but I never did take a closer look at Phonon. And secondly, because I'd like to use the Qt Multimedia APIs to build my own video recording application, as I couldn't find one for the last conference, and hence we screwed up that part last time.
As this is the first blog post about Qt5 and its Multimedia Framework I will focus on the MP3 Player code, and later in a 2nd post show how to use Qt5 for video recording. The UI of our MP3 player is quite simple, and I decided for now against using QML for the UI, as I think that the widget approach is currently the more stable/mature one on the desktop. Also I might should explain the why, I've been using my own MP3 player for years now, know its bugs but don't have the source anymore. (some where I still have to have it I think, but MFC and FMOD from 10 years ago...). So with the PlayList & Player classes for Multimedia in Qt5 I already have the most logic implemented and I'm multi platform from the start. I want the interface to be simple, just a few buttons, as this program does not have to be fancy, as there are already enough fancy MP3 players out there...
But lets have a look at the old and new MP3 Players
My old MP3 Player, build with MFC + FMOD | The new Version, build with Qt5 |
Some features are still lacking on the new MP3 Player, like showing the played time, but thats easily added.
C++11 and Qt5
A short paragraph about C++11 and Qt5. With Qt5 C++11 support comes to Qt, and it offers the opportunity to start new projects with Qt5 in C++11 mode. This is yet not the default in QtCreator, but for MinGW/GCC this does the trick:
QMAKE_CXXFLAGS += -std=c++0x
This enables the use of C++11 without running into compilation errors for the new syntax. Of course this isn't perfect yet, as the current build of Qt for MinGW/GCC mostly is done with Version 4.7.2, which already offers some C++11 support. But also this will make your code C++11 specific, and not all features are yet implemented for MSVC or clang, so your code might run for some time only correctly under MinGW/GCC without doing some refactoring. But this should be resolved within this year hopefully.
Implementation
As I said, I'd like to keep the UI simple, hence there is only a few buttons to fill with functionality. The Qt5 Multimedia APIs already offer classes for mediaplayback and for playlists. So, the most important part of an MP3 player is already implemented, we just have to write a UI that connects to this functionality and fills our playlist with titles. So first thing to do is create those classes in the constructor of MainWindow:
player = new QMediaPlayer(this); playlist = new QMediaPlaylist(player); player->setPlaylist(playlist);
connect(player,SIGNAL(positionChanged(qint64)),this,SLOT(onPositionChanged(qint64))); ui->progressBar->setRange(0,100);
So, with those 3 lines there is now everything ready for playing mediafiles. A QMediaPlayer is created to control the playback, and a QMediaPlaylist is created and given to the player in order to playback the items from the list. The connect is just to get position updates, in order to show a progressbar. So lets fill the playlist with something useful, the handler for Add Directory is a good example:
QString directory = QFileDialog::getExistingDirectory(this,tr("Select dir for files to import")); if(directory.isEmpty()) return; QDir dir(directory); QStringList files = dir.entryList(QStringList() << "*.mp3",QDir::Files); QList<QMediaContent> content; for(const QString& f:files) { content.push_back(QUrl::fromLocalFile(dir.path()+"/" + f)); QFileInfo fi(f); ui->listWidget->addItem(fi.fileName()); } playlist->addMedia(content); ui->listWidget->setCurrentRow(playlist->currentIndex() != -1? playlist->currentIndex():0);
First one needs to let the user select a directory to import. Then the entryList method von QDir is called to get all mp3 files (one could add other formats here too). The playlist expects a QList of QMediaContent items, so its necessary to convert the QStringList containing the path of the files to QMediaContent items, and add to them to the playlist. In the C++11 style for loop also the the QListWidget gets its content. The QMediaPlaylist does not expose its model, so the QListWidget has to manage its own data. "Add Song" is implemented almost the same way, only that it lets the user select files instead a directory. Actually the part of adding the QStringList to the playlist should be refactored into its own private method.
The Next- and Previousbuttons call the next/previous method of QMediaPlaylist and move the selection in the QListWidget up or down. The progressbar is getting its updates in the positionChanged slot, where the players property duration + position will be used to calculate the position for the progressbar. The Playbutton turns when clicked in the Stopbutton, beeing lazy I just test for the label to see which state there is:
if(ui->btn_play->text() == tr("Play")) { player->play(); ui->btn_play->setText(tr("Stop")); } else { player->stop(); ui->btn_play->setText(tr("Play")); }
There is still some work left, for example the import and export of playlists isn't yet implemented and the menu, but for now its already a functioning, simple MP3 Player build with Qt5!
Join the Meeting C++ patreon community!
This and other posts on Meeting C++ are enabled by my supporters on patreon!