Programmer un lecteur Ogg Vorbis en C++
De retour au source
Ce qui rend un système GNU Linux encore plus intéressant, ceux sont les nombreuses bibliothèques et outils de développement libres qui viennent avec.
Comme j'ai dû abandonné le C++ pour me mettre plus sérieusement à Java et que maintenant je me retrouve à laisser de côté ce langage au profit de C#, je voulais pendant mon temps libre me remettre un peu au bon vieux langage à pointeurs.
Dans ce post, j'ai choisi de vous présenter une application simple avec une interface graphique que j'ai développée en C++ avec l'aide des bibliothèques Qt, Vorbisfile et ALSA. Il s'agit d'un lecteur décodant et jouant des fichiers de son compressés en Ogg Vorbis. Mais avant tout, quelques mots sur le langage C++ et les bibliothèques utilisées.
Du C++ à C#
Le nombre de langages de programmation évolués n'a cessé d'augmenter au fil des années pour répondre à la fois à de nouvelles problématiques, mais aussi pour introduire de nouveaux paradigmes, d'autres niveaux d'abstractions. Le langage C++, successeur du C, largement inspiré de Ada a été le vecteur du paradigme objet et reste aujourd'hui encore un langage de programmation de prédilection dans tous les domaines.
Les langages comme Java et C# se sont inspirés du C++ en laissant de côté certains aspects du langage qui n'ont cessé d'être diaboliser. Vous pourrez constater par le code source qui est présenté ici qu'il n'y a rien à craindre du C++ tant que le modèle de l'application est bien défini et que la programmation est menée proprement et avec rigueur.
Langage orienté framework
Aujourd'hui on voit de plus en plus disparaître la notion de langage de programmation comme entité indépendante. Le langage fait parti de tout un environnement de développement: la machine virtuelle, le compilateur juste à temps, les frameworks, le ramasse miettes... font tous partie des langages comme Java et C#. Leur forte intégration avec les technologies du Web, XML et ses applications, rendent ces langages encore plus appropriés pour la transition vers le Web 2.0.
Qt Toolkit
Qt est une bibliothèque de développement d'interface graphique portable sur plusieurs plate-formes. Créer par Trolltech et distribuée aussi sous licence Open Source, cette bibliothèque offre une boîte à outils qui rend la programmation en C++ moins laborieuse.
Dans le programme présenté, j'utilise la version Open Source 4.1.4 avec le designer pour créer l'interface et qmake pour générer le Makefile. La dernière version disponible à ce jour est la 4.2.3, alors pourquoi s'en priver.
Ogg Vorbis
Ogg Vorbis est un format libre de compression de données audio avec perte. Si vous voulez en savoir plus je vous recommande de lire la FAQ du site officiel. J'utilise ce format de compression pour deux raisons évidentes: la licence libre et la présence par défaut de la bibliothèque sur les distributions Linux. Le lecteur Ogg Vorbis programmé utilise libvorbis-1.1.2.
Advanced Linux Sound Architecture (ALSA)
ALSA est le standard de facto sous Linux pour la gestion de données audio. Il est possible de passer par l'interface PCM de la bibliothèque libasound pour communiquer avec les périphériques de son tout en restant dans l'espace utilisateur. Bien que cette bibliothèque offre une grande flexibilité au programmeur, le codage est un peu plus laborieux et malheureusement la documentation n'est à mon avis pas très claire. Le programme a été compilé avec la version 1.0.11 de alsa-lib.
Le résultat recherché
Oui je sais, l'interface n'est pas terrible. Mais avouez que c'est plus facile de comprendre l'exemple lorsqu'il est simple ;o)
Réaliser ce programme
Si vous avez lu jusqu'ici c'est que je vous dois bien ça. Les étapes pour créer ce lecteur Ogg Vorbis en utilisant tous les outils cités plus haut sont les suivantes:
Modèle UML
Bien définir le comportement des classes, leurs attributs, les comportements des méthodes et les relations entre les classes aide à améliorer la qualité du code que vous pourrez écrire. Par exemple en considérant les comportements des méthodes, vous pourrez savoir où définir les pointeurs et surtout déterminer où dans le code les instances créées sur le tas seront détruites. Un diagramme de séquence vous permettra d'éviter pas mal de Segmentation Fault. Pour ma part, je ne l'ai pas fait.
Voici le diagramme de classe simplifié de l'application:
La classe MainWindow représente l'interface graphique de l'application. Son rôle est d'afficher l'interface créée avec designer et d'intercepter les événements qui sont généralement délégués à la classe Player.
La classe Player est un thread qui utilise la classe Decoder et la classe PCM pour décoder le fichier Ogg Vorbis et le jouer sur l'interface PCM.
Decoder est une classe abstraite qui représente en fait plus un type de fichier qu'un décodeur. Cette modélisation permet d'étendre plus facilement l'application pour décoder d'autres formats de fichier.
Interface graphique: Héritage multiple
Lorsque vous lancez la compilation du programme avec make, le fichier XML à suffixe ui (ici main_window.ui), qui représente l'interface que vous avez créée avec le designer, est compilé par l'utilitaire uic pour générer un fichier header représentant votre interface utilisateur.
Pour pouvoir créer une instance de la fenêtre que vous avez construite dans votre code, vous pouvez utiliser le mécanisme d'héritage multiple comme présenté ci-dessous.
Cette approche permet à votre classe d'avoir une visibilité sur les composants que vous avez créés et ainsi vous permet de faire les liens entre les événements et les méthodes les gérant.
Synchronisation
Lorsque l'on utilise des threads il faut être vigilant sur leur synchronisation. Dans la classe MainWindow, lorsqu'on arrête le thread Player on attends que celui-ci s'arrête avant de détruire l'objet. Cette attente est réalisé par un player->wait().
Le reste du code est assez simple, il est généreusement commenté et il est naturellement sous licence GPL. Vous pouvez le télécharger ici.
Si ce post vous a été utile, qu'il manque des explications, que vous avez trouvé des bugs, que vous avez des questions... merci de le faire savoir par la voie des commentaires. Surtout, évitez de m'envoyer des mails à ce sujet, je n'ai pas suffisamment de temps pour gérer tout ça.
Ce qui rend un système GNU Linux encore plus intéressant, ceux sont les nombreuses bibliothèques et outils de développement libres qui viennent avec.
Comme j'ai dû abandonné le C++ pour me mettre plus sérieusement à Java et que maintenant je me retrouve à laisser de côté ce langage au profit de C#, je voulais pendant mon temps libre me remettre un peu au bon vieux langage à pointeurs.
Dans ce post, j'ai choisi de vous présenter une application simple avec une interface graphique que j'ai développée en C++ avec l'aide des bibliothèques Qt, Vorbisfile et ALSA. Il s'agit d'un lecteur décodant et jouant des fichiers de son compressés en Ogg Vorbis. Mais avant tout, quelques mots sur le langage C++ et les bibliothèques utilisées.
Du C++ à C#
Le nombre de langages de programmation évolués n'a cessé d'augmenter au fil des années pour répondre à la fois à de nouvelles problématiques, mais aussi pour introduire de nouveaux paradigmes, d'autres niveaux d'abstractions. Le langage C++, successeur du C, largement inspiré de Ada a été le vecteur du paradigme objet et reste aujourd'hui encore un langage de programmation de prédilection dans tous les domaines.
Les langages comme Java et C# se sont inspirés du C++ en laissant de côté certains aspects du langage qui n'ont cessé d'être diaboliser. Vous pourrez constater par le code source qui est présenté ici qu'il n'y a rien à craindre du C++ tant que le modèle de l'application est bien défini et que la programmation est menée proprement et avec rigueur.
Langage orienté framework
Aujourd'hui on voit de plus en plus disparaître la notion de langage de programmation comme entité indépendante. Le langage fait parti de tout un environnement de développement: la machine virtuelle, le compilateur juste à temps, les frameworks, le ramasse miettes... font tous partie des langages comme Java et C#. Leur forte intégration avec les technologies du Web, XML et ses applications, rendent ces langages encore plus appropriés pour la transition vers le Web 2.0.
Qt Toolkit
Qt est une bibliothèque de développement d'interface graphique portable sur plusieurs plate-formes. Créer par Trolltech et distribuée aussi sous licence Open Source, cette bibliothèque offre une boîte à outils qui rend la programmation en C++ moins laborieuse.
Dans le programme présenté, j'utilise la version Open Source 4.1.4 avec le designer pour créer l'interface et qmake pour générer le Makefile. La dernière version disponible à ce jour est la 4.2.3, alors pourquoi s'en priver.
Ogg Vorbis
Ogg Vorbis est un format libre de compression de données audio avec perte. Si vous voulez en savoir plus je vous recommande de lire la FAQ du site officiel. J'utilise ce format de compression pour deux raisons évidentes: la licence libre et la présence par défaut de la bibliothèque sur les distributions Linux. Le lecteur Ogg Vorbis programmé utilise libvorbis-1.1.2.
Advanced Linux Sound Architecture (ALSA)
ALSA est le standard de facto sous Linux pour la gestion de données audio. Il est possible de passer par l'interface PCM de la bibliothèque libasound pour communiquer avec les périphériques de son tout en restant dans l'espace utilisateur. Bien que cette bibliothèque offre une grande flexibilité au programmeur, le codage est un peu plus laborieux et malheureusement la documentation n'est à mon avis pas très claire. Le programme a été compilé avec la version 1.0.11 de alsa-lib.
Le résultat recherché
Oui je sais, l'interface n'est pas terrible. Mais avouez que c'est plus facile de comprendre l'exemple lorsqu'il est simple ;o)
Réaliser ce programme
Si vous avez lu jusqu'ici c'est que je vous dois bien ça. Les étapes pour créer ce lecteur Ogg Vorbis en utilisant tous les outils cités plus haut sont les suivantes:
- Assurez vous d'avoir les bonnes versions des bibliothèques sur votre système Linux.
- Vérifiez à ce que les variables d'environnement PATH et QTDIR indiquent le dossier où se trouve les exécutables de Qt et la racine où se trouve l'installation de Qt respectivement.
- Vous pouvez commencer par construire l'interface en lançant designer. Suivez le guide qui vient dans la documentation de Qt pour réaliser ceci.
- Coder les classes en respectant scrupuleusement votre modèle et en essayant de le faire le plus simplement que possible.
- Une fois l'interface construite, vous devrez créer le fichier project qui définit les fichiers sources à inclure pour la construction d'un Makefile. Référerez vous à la documentation et au fichier oggreader.pro pour comprendre la syntaxe.
- Le fichier Makefile se génère automatiquement en utilisant qmake.
- Vous pouvez maintenant compiler avec le traditionnel make et exécuter votre application.
Modèle UML
Bien définir le comportement des classes, leurs attributs, les comportements des méthodes et les relations entre les classes aide à améliorer la qualité du code que vous pourrez écrire. Par exemple en considérant les comportements des méthodes, vous pourrez savoir où définir les pointeurs et surtout déterminer où dans le code les instances créées sur le tas seront détruites. Un diagramme de séquence vous permettra d'éviter pas mal de Segmentation Fault. Pour ma part, je ne l'ai pas fait.
Voici le diagramme de classe simplifié de l'application:
La classe MainWindow représente l'interface graphique de l'application. Son rôle est d'afficher l'interface créée avec designer et d'intercepter les événements qui sont généralement délégués à la classe Player.
La classe Player est un thread qui utilise la classe Decoder et la classe PCM pour décoder le fichier Ogg Vorbis et le jouer sur l'interface PCM.
Decoder est une classe abstraite qui représente en fait plus un type de fichier qu'un décodeur. Cette modélisation permet d'étendre plus facilement l'application pour décoder d'autres formats de fichier.
Interface graphique: Héritage multiple
Lorsque vous lancez la compilation du programme avec make, le fichier XML à suffixe ui (ici main_window.ui), qui représente l'interface que vous avez créée avec le designer, est compilé par l'utilitaire uic pour générer un fichier header représentant votre interface utilisateur.
Pour pouvoir créer une instance de la fenêtre que vous avez construite dans votre code, vous pouvez utiliser le mécanisme d'héritage multiple comme présenté ci-dessous.
#ifndef MAIN_WINDOW_H
#define MAIN_WINDOW_H
#include <iostream>
#include <exception>
#include <QMainWindow>
#include <QMessageBox>
#include "ui_main_window.h"
#include "player.h"
#include "generic_exception.h"
using namespace std;
class Player;
class MainWindow: public QMainWindow, private Ui::MainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void reader_thread_update();
void reader_thread_ok();
void reader_thread_exception();
private:
Player *player;
private slots:
void on_btnPlay_clicked();
void on_btnStop_clicked();
void on_btnForward_clicked();
void on_btnRewind_clicked();
};
#endif
Cette approche permet à votre classe d'avoir une visibilité sur les composants que vous avez créés et ainsi vous permet de faire les liens entre les événements et les méthodes les gérant.
Synchronisation
Lorsque l'on utilise des threads il faut être vigilant sur leur synchronisation. Dans la classe MainWindow, lorsqu'on arrête le thread Player on attends que celui-ci s'arrête avant de détruire l'objet. Cette attente est réalisé par un player->wait().
Le reste du code est assez simple, il est généreusement commenté et il est naturellement sous licence GPL. Vous pouvez le télécharger ici.
Si ce post vous a été utile, qu'il manque des explications, que vous avez trouvé des bugs, que vous avez des questions... merci de le faire savoir par la voie des commentaires. Surtout, évitez de m'envoyer des mails à ce sujet, je n'ai pas suffisamment de temps pour gérer tout ça.
0 Comments:
Enregistrer un commentaire
<< Home