Loading s4prg_rust_06_instrument...

enib_small.png S4-PRG_Rust 06_Instrument — Les instruments de musique

De manière extrêmement simplifiée ici, nous assimilerons un instrument de musique à :
Dans un nouveau module instrument, dédié aux instruments de musique, réalisez les structures suivantes.
La structure Envelope est publique ainsi que ses quatre membres attack_duration, decay_duration, sustain_level et release_duration qui sont de type f32.
La structure Overtone est publique ainsi que ses deux membres freq_factor et amplitude qui sont de type f32.
La structure Instrument est publique mais doit appliquer la démarche d'encapsulation des ressources afin que ses membres ne soient plus modifiés après leur initialisation :
À titre d'illustration, le fichier instruments.json décrit quelques instruments.
Nous adjoindrons à la structure Instrument un bloc d'implémentation afin de fournir les fonctionnalités permettant d'interagir avec des données de ce type.

Le jeu de la note par l'instrument n'est pas facile à réaliser car il nécessite la prise en compte de multiples notions.
Nous simplifierons cette fonctionnalité dans un premier temps en ignorant les informations liées à l'enveloppe sonore et nous procéderons alors ainsi :
Voici une aide en pseudo-code Python
En l'état, afin de tester, vous devriez être en mesure de produire un fichier sonore contenant des séquences de notes de votre choix jouées par des instruments de votre choix.

Maintenant, pour prendre en compte l'enveloppe sonore de l'instrument, il faut générer la séquence des amplitudes qui concernent chaque échantillon.
Pour cela, il faut étudier avec attention la signification des paramètres A, D, S et R de l'enveloppe pour réaliser une fonction à usage interne (non publique).
Remarquons en particulier que :
Voici une aide en pseudo-code Python
Une fois cette séquence d'amplitudes générée, il faut reprendre la génération précédente des échantillons correspondants aux fréquences partielles de l'instrument (la fonction play()) pour qu'elle prenne en compte cette séquence d'amplitudes.
Pour ceci, les itérations en consultation et en modification sur, respectivement, la séquence d'amplitudes et la slice exclusive (mutable) représentant la portion de la piste sonore à altérer, pourront être combinées par .zip().
Le test précédemment réalisé, doit pouvoir être réutilisé tel quel ; il permet maintenant de percevoir l'effet des enveloppes sonores des divers instruments.

Comme amélioration possible, mais pas obligatoire, il est envisageable de définir un type énuméré Wave qui permettrait de choisir une forme d'onde qui soit, au choix, sinusoïdale, carrée, triangulaire ou en dent de scie.
Chaque partiel d'un instrument devrait alors avoir un membre wave pour une telle information, ce qui permettrait de faciliter l'expression d'instruments produisant des sons élaborés (les percussions notamment).

Pour plus de confort, réalisez dans le module instrument une fonction capable de lire un fichier tel que instruments.json et de créer l'ensemble des instruments qu'il décrit.
Une utilisation minimale de cette fonction serait :
let my_instruments = load_instruments("instruments.json")?;

Il n'est pas question d'essayer d'analyser par nos propres moyens les éléments d'un tel fichier ; il s'agit au contraire de s'appuyer sur les fonctionnalités de sérialisation au format json communément utilisées.
Si vous n'avez pas réalisé l'amélioration qui permet de choisir la forme d'onde, il faudra au préalable retirer du fichier fourni l'instrument nommé “drum”.
Remarquez que les opérations de lecture d'un fichier et de désérialisation peuvent échouer ; la fonction doit envisager cet échec dans son type de retour.

Si au contraire vous considérez les diverses formes d'onde, il faudra faire en sorte que la désérialisation considère par défaut une sinusoïde lorsque la forme d'onde d'un partiel n'est pas précisée.

Les différents étapes des tests réalisés constitueront à nouveau, selon leur complexité, des tests unitaires pour compléter la documentation ou bien des tests d'intégration.