Loading prj_rust_03_wave...

enib_small.png PRJ-Rust 03_Wave — Un fichier sonore

Quel que sera l'avancement futur dans la réalisation, le seul résultat perceptible tiendra dans la production d'un fichier contenant du son.
Un premier objectif utile sera donc la réalisation d'une fonction dédiée à la génération d'un tel fichier, afin de pouvoir en écouter le contenu.
Cette étape est longue mais très importante puisqu'elle fait intervenir plusieurs notions qui seront utilisées tout au long du mini-projet.
Il est indispensable de la réaliser et la tester avec soin, sans quoi quasiment rien de ce qui suivra ne sera perceptible.

Cette fonction fera partie de notre crate et prendra place dans un module qui sera, à terme, dédié aux pistes sonores.
Complétez alors le fichier src/lib.rs afin qu'il annonce la présence d'un module track et ajoutez le fichier src/track.rs qui lui correspond.
Créez dans ce module une fonction save_track() qui recevra comme paramètres
Afin qu'elle soit utilisable de partout (le fichier main.rs, les tests, une réalisation externe...), elle doit être qualifiée de pub.

Comme illustré sur les exemples qui manipulent les fichiers, cette fonction devra utiliser le moyen conventionnel pour signaler une éventuelle erreur (due notamment aux opérations sur les fichiers).
En temps normal, sans erreur, notre fonction save_track() ne devrait renvoyer aucun résultat ; en Rust, c'est équivalent à renvoyer le résultat ().
Pour envisager les erreurs potentielles, le résultat de notre fonction sera alors de type
Result<(), Box<dyn std::error::Error>>
.

Nous utiliserons le format de fichier wav ; des documentations le décrivent notamment sur ce site et celui-ci.
Il s'agira dans un premier temps de préparer un tableau de 44 octets qui représente l'entête d'un tel fichier.
Voici une aide pour le constituer
Ensuite, il faudra inscrire cet entête dans le fichier choisi ; inspirez-vous pour cela du dernier exemple (données binaires) concernant les fichiers.

La suite du fichier devra contenir tous les échantillons fournis.
Seulement, par confort pour les calculs qui servent à les produire, nous les manipulons comme des réels, mais le fichier attend des échantillons de type i16.
Chaque échantillon réel devra alors être :
Conformément aux exemples, la dernière instruction de la fonction produira la valeur de retour en cas de succès.
Ici, ce sera Ok(()) puisque, au delà des éventuelles erreurs, aucun résultat utile n'est attendu.

Pour envisager de tester le bon fonctionnement de la fonction save_track(), il sera nécessaire de produire au préalable une séquence d'échantillons décrivant des signaux reconnaissables.
Pour faciliter cette démarche, il faudra ajouter au module track quatre fonctions très semblables :
Elles ne renvoient pas de résultat, mais attendent toutes ces paramètres :
Dans chacune de ces quatre fonctions, il suffit de :

Pour enfin obtenir un programme qui mette en œuvre ce qui vient d'être réalisé, nous interviendrons directement dans la fonction main().
La démarche sera la suivante :

Dans un environnement graphique, il suffit probablement de cliquer sur le fichier généré pour en entendre le contenu.
En ligne de commande sous Linux, on peut lancer l'écoute du fichier avec aplay output_sound1.wav.
Un outil graphique tel que audacity permet de visualiser le signal décrit par le fichier sonore afin d'en contrôler la forme.
En l'état, vous devriez constater l'enchaînement de quatre sons, d'une seconde chacun, correspondant aux signaux distinctifs que nous avons choisis.

Puisque l'inscription des signaux se fait par accumulation, il est possible d'en jouer plusieurs simultanément.
Complétez alors la séquence de quatre signaux de cette façon :
Une nouvelle écoute du fichier output_sound1.wav devrait laisser entendre à la fois des sons enchaînés et joués simultanément.
Remarquez que les amplitudes des divers signaux ont été choisies de façon à ce que leur accumulation ne dépasse jamais 1.0 ; en effet, la sauvegarde dans le fichier impose l'écrêtage à l'amplitude 1.0.

Après avoir vérifié que notre réalisation produit un effet conforme à nos attentes, nous devons finaliser ce qui vient d'être accompli, dans l'esprit d'une bibliothèque de fonctionnalités réutilisables.
Le fichier tests/integration.rs doit être complété en adaptant (par copier/coller) la fonction main() pour en faire une fonction de test d'intégration.
Les cinq fonctions réalisées dans le module track doivent être documentées.