|<- [[3.10 Multiple sounds]]|[[3.14 Visual step display]] ->|
[code](https://live.codecircle.com/d/PGr4xwdqbzmwqqhZs)
https://live.codecircle.com/d/9k8raocXrwGw7mP9J
html
javascript
function Samples_set ( contexte ) {
/* Set de samples permettant de charger simplement des samples et de les jouer */
this.contexte = contexte;
this.samples_set = {};
}
Samples_set.prototype.charger = function ( nom, url ) {
/* Charge le sample et l'ajoute au set
String, String -> Void */
// on créé une référence à this (notre occurence de Sample_set)
var self = this;
// on créé l'objet requête
var requete = new XMLHttpRequest();
// que l'on paramètre :
// 1 : requête GET, url de la requête, requête asynchrone : true
requete.open('GET', url, true);
// 2 : type de réponse
requete.responseType = 'arraybuffer';
// 3 : écouteur onload et fonction à exécuter alors
requete.onload = function () {
// les données audio
var donnees_audio = requete.response;
// sont passées pour décodage au contexte audio
contexte.decodeAudioData( donnees_audio, function( buffer ) {
// on ajoute le buffer à notre objet instruments
self.samples_set[nom] = buffer;
});
};
// on envoie la requête
requete.send();
};
Samples_set.prototype.jouer = function ( nom, instant ) {
/* Joue le sample à un instant t s'il est trouvé
String, Number -> Void */
// si le sample existe, a été chargé
if ( this.samples_set[nom] ) {
try {
//on créé un BufferSource
var player = contexte.createBufferSource();
// on y charge notre sample
player.buffer = this.samples_set[nom];
// on spécifie qu'on ne le joue pas en boucle
player.loop = false;
// on le connecte au contexte
player.connect(this.contexte.destination);
// on le lancera à l'instant t
player.start( instant );
// en cas d'erreur
} catch (e) {
console.error('erreur : Samples_set.jouer :', e);
}
}
};
var contexte_audio = window.AudioContext || window.webkitAudioContext;
var contexte = new contexte_audio();
var batterie = new Samples_set( contexte );
batterie.charger( 'charleston', 'cl_hat_3001.wav');
batterie.charger( 'caisse claire', 'brp_snrim1.wav');
// la séquence que l'on souhaite jouer
var sequenceur = [
[0,0,0,0],
[0,0,0,0],
];
// référence à l'étape où l'on en est dans la séquence
var etape = 0;
// base_rythmique : temps entre deux étapes de la séquence *en secondes*
// car on va se baser sur le temps tel que donné par l'API audio en secondes
var base_rythmique = 0.125;
// intervalle entre deux appel à setInterval
// on continue à travailler en secondes et on multipliera pour setInterval qui prends de millisecondes en paramètre
var intervalle = 0.5;
// référence à l'instant t max déjà traité
var t_max_traite;
// toutes les 0.5 secondes (intervalle)
setInterval( function(){
// on va travailler à partir de l'instant t qui est égal à maintenant
var t = contexte.currentTime;
// on va déclarer tous les événement entre t et t_max qui est égal à 1.5 fois le temps entre deux base_rythmique
// cela nous donne une marge de jusqu'à 0.5 fois notre base_rythmique
// pour absorber les cas où setInterval serait en retard
// si on change quelque chose on aura aussi une latence allant jusqu'à intervalle * 1.5
var t_max = t + (intervalle * 1.5);
// si on a déjà traité au-delà de t
if ( t_max_traite > t ) {
// on passe déjà à l'instant t où l'on avait précédemment déjà été
t = t_max_traite;
}
// de l'instant t à notre limite t_max
while ( t <= t_max ){
// on passe à l'étape suivant dans notre séquenceur
etape ++;
// si on doit jouer le sample à cette étape
if ( sequenceur[0] [ etape % sequenceur[0].length ] ) {
// on programme cela pour l'instant t correspondant
batterie.jouer('charleston', t);
}
// si on doit jouer le sample à cette étape
if ( sequenceur[1] [ etape % sequenceur[1].length ] ) {
// on programme cela pour l'instant t correspondant
batterie.jouer('caisse claire', t);
}
// on incrémente t pour passer à l'étape suivant
t += base_rythmique;
}
// quant on a fini, on garde en mémoire le dernier instant t traité
t_max_traite = t;
/// tous les intervalle * 1000 car setInterval prend en paramètre des millisecondes et intervalle est en secondes
}, intervalle * 1000);
var matrix, son_mobile;
nx.onload = function () {
matrix.row = sequenceur.length;
matrix.col = sequenceur[0].length;
matrix.init();
matrix.on('*', function ( data ) {
sequenceur[data.row][data.col] = data.level;
});
// sur mobile, on doit déclencher un son avec une action utilisateur avant de pouvoir utiliser le son
son_mobile.on('*', function(){
batterie.jouer('charleston', contexte.currentTime);
});
};