4.10 Algorave machine4.14 FX

https://live.codecircle.com/d/BgYubrZxQxgoyDhCr

html

<textarea id="charleston"></textarea>
<textarea id="caisse-claire"></textarea>

<script>
var contexte = (function(){
  var contexte_audio = window.AudioContext || window.webkitAudioContext;

  var contexte = new contexte_audio();

  return contexte;
})();

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 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 sequence_charleston = [0.25, 1, 1, 1, 0, 0.1, 0];
var sequence_caisse_claire = [0, 0.25, 0.25, 0.1, 1, 0.1, 1];

// 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 ( determiner_si_on_doit_jouer ( sequence_charleston [ etape % sequence_charleston.length ] ) ) {

      // on programme cela pour l'instant t correspondant
      batterie.jouer('charleston', t);
    }

    // si on doit jouer le sample à cette étape
    if ( determiner_si_on_doit_jouer ( sequence_caisse_claire [ etape % sequence_caisse_claire.length ] ) ) {

      // on programme cela pour l'instant t correspondant
      batterie.jouer('caisse claire', t);
    }

    melodie_algorithmique.changer_note( t );

    // on incrémente t pour passer à l'étape suivant
    t += base_rythmique;
  }

  function determiner_si_on_doit_jouer ( probabilite ) {
    if ( Math.random() > 1 - probabilite ) {
      return true;
    } else {
      return false;
    }
  }

  // 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 melodie_algorithmique = (function () {
  var composant = {};

  var oscillateur = contexte.createOscillator();
  oscillateur.type = 'triangle';

  var amplificateur = contexte.createGain();
  amplificateur.gain.value = 0.2;

  oscillateur.connect( amplificateur );
  amplificateur.connect( contexte.destination );

  oscillateur.start();

  var frequence = 200;

  var intervalle;

  oscillateur.frequency.value = frequence;

  composant.changer_note = function ( t ) {
    frequence = frequence * 1.5;

    frequence = frequence > 2000 ? 200 + Math.random() * 100 : frequence;

    // la ligne suivante fait que la fréquence va changer de manière progressive
    // oscillateur.frequency.value = frequence;

    // si l'on souhaite un changement immédiat :
    oscillateur.frequency.setValueAtTime(frequence, t);
  };

  return composant;
})();


document.getElementById('charleston').addEventListener('keyup', maj_charleston, false);
document.getElementById('caisse-claire').addEventListener('keyup', maj_caisse_claire, false);

function maj_charleston () {
    console.log('maj_charlestion');
  var valeurs = document.getElementById('charleston').value;
  sequence_charleston = valeurs.split(',');
}

function maj_caisse_claire () {
    console.log('caisse claire');
  var valeurs = document.getElementById('caisse-claire').value;
  sequence_caisse_claire = valeurs.split(',');
}
</script>