dimanche, avril 29, 2007

Melodica

Petit instrument à vent, le mélodica ressemble plus à un jouet qu'à un véritable instrument de musique. Ayant la forme d'un petit piano de pas plus de trois octaves, le joueur souffle dans un embout en plastique tout en pianotant sur le clavier avec la main droite. Le son de cet instrument de musique se rapproche à mon avis beaucoup plus de l'accordéon que de l'harmonica.


Bien que peu connu en Europe, les premiers mélodicas furent commercialisés par l'entreprise allemande, Hohner. D'autres fabricants dont Yamaha et Suzuki lui ont donné des noms différents (Pianica et Melodion) et c'est en Asie que l'instrument a gagné en popularité chez les enfants apprenant la musique.

D'ailleurs, le mélodica que vous voyez sur la photo c'est le Melodion de Suzuki que j'ai acheté hier pour environ 55 euros en Inde. J'en avais jamais vu dans un magasin de musique avant de venir ici.

Le piano des moins doués

Pour l'instant je ne peux pratiquement rien jouer dessus, mais c'est un instrument simple que l'on peut découvrir seul avec un peu de feeling. Connaître les accords de piano aide, mais c'est gérer le souffle et synchroniser l'attaque sur les notes qui permettent de mieux exploiter l'expressivité du mélodica.

L'instrument se prête bien à certains styles de musique comme la valse, les anciennes chansons française ou le tango. Je me suis essayer sur quelques notes de Gotan Project et c'est amusant comme tout.
En soufflant faiblement et de manière plus ou moins continue, on peut jouer certaines mélodies en imitant le son mélancolique d'un harmonica, en moins criard.

Voilà un instrument bien sympathique et surtout facilement transportable avec lequel je pourrai m'amuser.

jeudi, avril 26, 2007

Je jouerais bien un peu de guitare

Qui est l'artiste?

Cet aprem en rentrant du bureau, j'me dis « tiens, je jouerais bien un peu de guitare». N'ayant pas d'instrument ici, je passe chez le seul gars du campus qui me prêterait bien sa guitare et je tombe sur un artiste.

Jugez par vous même de son talent.



samedi, avril 14, 2007

Synchronisation de threads

Les applications contenant plusieurs fils d'exécution indépendants doivent souvent synchroniser leurs opérations pour éviter les problèmes suivants:
  1. La mise à jour d'une variable partagée par au moins deux threads.
  2. L'attente de la disponibilité d'une ressource.
  3. L'exécution d'instructions suite à un événement.
Ces problèmes sont dûs au caractère non déterministe de l'ordonnancement de threads par le Système d'Exploitation.

Appliquer une solution

L'application oggreader (voir ancien post), devient gourmande en ressource processeur dès qu'on met le lecteur sur pause ou sur stop.
En fait ces deux fonctionnalités ont été mises en place en utilisant la technique du busy waiting qui consiste à boucler indéfiniment en attendant à ce qu'un événement quelconque se produise. Dans ce cas précis, le programme boucle jusqu'à ce que l'utilisateur se décide de cliquer sur play.

Ci-dessous les ressources utilisées lorsque l'application est lancée et que la lecture est en cours.


Lorsque l'on clic sur pause, on constate qu'il y a une utilisation anormalement forte du processeur.


Thread en attente

Il est possible de résoudre ce problème en mettant le thread Player en attente quand l'utilisateur clic sur pause ou stop. Lorsque la lecture est relancée par un clic sur play il suffit de réveiller le thread en attente. Bien que cette solution semble évidente à mettre en place, il faut prendre deux précautions, notamment:
  1. Ne pas perdre les messages de réveil du thread en l'envoyant alors que celui-ci n'est pas en encore en attente.
  2. Réveiller le thread si le programme est terminé alors que le lecteur est dans l'état pause ou stop.

Dans la classe Player on ajoute à la méthode play les lignes 9 à 11 qui permettent de réveiller inconditionnellement le thread mais qui met aussi à jour la variable is_waiting en une opération atomique. On aura pris soin d'initialiser cette variable au départ à 0 et d'avoir déclaré la variable condition de type QWaitCondition.

1 void Player::play() {
2 if (file == NULL) return;
3 if (is_playing || !is_ready) return;
4 thread_running = true;
5 is_playing = true;
6 if (!isRunning()) {
7 start();
8 } else {
9 QMutexLocker locker(&mutex);
10 condition.wakeOne();
11 is_waiting--;
12 }
13 return;
14 }

Toujours dans la même classe aux lignes 16-18, on incrémente is_playing et ensuite on teste si l'on peut mettre le thread en attente en vérifiant la valeur de la variable is_playing.

1 void Player::run() {
2 try {
3 while(thread_running) {
4 if (is_playing) {
5 // forward or rewind
6 if (offset_changed) {
7 decoder->seek(new_offset);
8 offset_changed = false;
9 pcm->drain();
10 }
11
12 if (!decoder->decode()) break;
13 pcm->write(decoder->get_buffer(), decoder->get_no_samples());
14 emit updated();
15 } else {
16 QMutexLocker locker(&mutex);
17 is_waiting++;
18 if (is_waiting != 0) condition.wait(&mutex);
19 }
20 }
21 } catch (GenericException &e) {
22 error_msg = e.what();
23 is_playing = false;
24 emit terminated();
25 }
26 pcm->drain();
27 decoder->seek(0);
28 is_playing = false;
29 }

Pour finir, il ne faut pas oublier de réveiller le thread avant que l'application ne termine.
1 void Player::stop_thread() {
2 thread_running = false;
3 condition.wakeOne();
4 }

Et le tour est joué. Le résultat est remarquable n'est-ce pas? Mais il y a toujours un petit chouia manquant, un genre de «faille» si vous voulez. A vous de découvrir ;o)