Message web de David Hitillambeau
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:
- 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.
Si
l'une des étapes vous échappe, il y toujours la voie des commentaires
pour poser des questions. Mais si c'est le cas, peut-être que la
lecture d'un tutoriel de Qt vous aidera plus.
Modèle UMLBien
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 multipleLorsque 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.
Billet original sur Blog trotteurBillet original sur