Atel:er

Lecteur Audio avec son oscilloscope

Qu'est qu'un osciloscope ?

Un oscilloscope1 est un instrument de mesure destiné à visualiser un signal électrique, le plus souvent variable au cours du temps.
Il est utilisé par de nombreux scientifiques afin de visualiser soit des tensions électriques, soit diverses autres grandeurs physiques préalablement transformées en tension au moyen d'un convertisseur adapté ou de capteurs. La courbe de rendu d'un oscilloscope est appelée oscillogramme.

Il existe deux sorte d'oscilloscope: Analogique et celle que nous verrons Numérique.

  • L'analogique : utilise directement un multiple de la tension d'entrée pour produire la déviation du spot.
  • Le Numérique: quand à lui transforme préalablement pour un traitement futur, la tension d'entrée en nombre. L'affichage est reconstruit après coup. Ici nous récupérons le spectre du signal pour générer l'oscillogramme.

API AUDIO

L'API est paru en 2010, son principe est assez simple : il prends des objets audioNode de façon arbitraire. Chaque noeud possède une entrée et/ou une sortie. Le noeud d'entrée ne possède qu'une sortie alors qu'un noeud de sortie ne possède qu'une entrée (== destination). On peut placer différents noeuds entre le noeud Source et le noeud de Destination. Ce principe est appelé 'routage' et cela se produit dans un 'audioContext'.

le son

Un son est constitué d'une série d'ondes, vibrations d'air très fines, qui oscillent selon des fréquences généralement irrégulières, variables dans le temps. L'oreille humaine détecte des variations de fréquences sonores entre 20Hz et 20Khz.

Le spectre correspond la longueur > [intervalle] à analyser (temps d'une piste par exemple).

L'analyseur de spectre sonore va donc re-découper la composition spectrale du signal audio produit en tranches de fréquences, de 20Hz à 20KHz, mais au lieu de modifier le volume sur ces tranches, il va finement restituer une courbe graphique tracée à partir du volume effectivement détecté sur chacune des plages analysées.

Les résultats se cantonnent toujours à la plage dynamique de l'audition humaine de 20Hz à 20KHz. Cela peut être utile dans l'analyse du caractère de la musique et en notant si certaines fréquences sont dominante ou manquantes au sein d'un mix. spectre == styles de spectrogrammes proposés sont variables

                
    SHEMAS
        ENTRÉE                   NOEUDS                         SORTIE/RENDER
    ---------------         ----------------            --------------------------------
    | MP3 / MIC  | × ===> × | ANALYSER/GAIN |  × ===> × | HAUT-PARLEUR / OSCILLO RENDU |
    ---------------         ----------------            --------------------------------
                
              

Outillage et CORS

La doc du W3C a subit plusieurs moutures depuis ça publication du 15 Décembre 2011, 5 précisément.

Le temps a pousser à sécurser le web. Les éléments audios étaient une failles à gérer. Les HTMLMediaElement permettent d'accéder à des sources d'origine différentes en les analysant. Parfois cela crée une perte d'information si un script d'une origine inspect celle d'une autre origine. C'est pour ces conditions que nous utilisons un server (local ici:lite-server) afin de ne pas lever les panneaux d'alertes de Chrome par exemple avec les autorisations CORs-ross-origine qui ne permettent pas de lire un fichier contenant des audioELements.

Outillage

Pour créer l'oscilloscope et pour son bon fonctionnement il est nécesaire de préparer plusieur outils:

  • de source mp3/ogg/mp4 etc...(lien de téléchargement)
  • un serveur (local ou non), on prendra lite-server que l'on lance via le Terminal avec la cmd $ lite-server
  • de la prise de connaissance de la web API Audio

je vous épargne ça: téléchargez le script Shell suivant ("enregistrer-sous"): telecharger le script

une fois téléchargé lancez le terminal et aller dans le répertoire dans lequel vous avez enregistré le fichier.sh et lancz la commande suivante : $ ./screatoscillo.sh il vous créera dans votre répertoire ./Documents un dossier /createOscillo/

Structure HTML

en premier lieu on construit la structure du html: ouvrez le fichier $atom index.html, il se présentera comme le suivant :

              
          

Prototype

  1. pour commencer on doit va créer un nouvel objet AUDIO().
  2. on paramètre l'attribut SOURCE avec le lien de l'audio que vous avez dans votre dossier ./mp3/
  3. on mettra le controls a true pour pouvoir le récupérer
  4. l'attribut 'loop' est sur false mais vous pouvez très bien le mettre sur 'true' si vous voulez devenir fou avec une seule chanson
                
      var audio = new Audio();
      audio.src = PlayList[0].src; // './mp3/jpetelesplombs.mp3'
      audio.controls = true;
      audio.loop = false;
                
              
  5. On appel la fonction que nous allons créer dans la partie deux au chargement de la page.
            
    window.addEventListener("load", initMP3, true);
            
          
  • on cré toutes les variables dont on aura besoin
              
      var canvas,
      ctx,
      source,
      context,
      analyser,
      fbc_array,
      bars,
      bar_x,
      bar_width,
      bar_height;
                
              
  • initialiser et contextualisation Audio

    1. on cré une fonction qui va initialiser le mp3 dans laquelle on va tout d'abord récupérer l'élément Html qui recevra en tant que parent l'élément audio que nous avons créé précédement. On paramètre l'attribut id de ce nouvel enfant pour pouvoir l'exploiter.
    2. récédement. On paramètre l'attribut id de ce nouvel enfant pour pouvoir l'exploiter.
                      
          function initMp3(){
          document.getElementById('audio_box').appendChild(audio).setAttribute('id', 'audioOscilo');
                      
                    
    3. c'est ici qu'il faut créer le contexte audio afin qu'il créer l'interface et pouvoir connecter des nouveau noeuds. On fait un appel à l'objet 'window.' pour dire que c'est de cette que le context va agir.
                      
          window.AudioContext = window.AudioContext ||
                                window.webkitAudioContext;
          context = new AudioContext();
                      
                    
    4. maintenant le contextes est insatallé il faut lui envoyer un noeud, ici on lui cré un Analyser, on aurit très pien pu créer un oscillatorNode mais cela ne créera pas réllement ce que l'on voudra.
                    
          analyser = context.createAnalyser()
                    
                  
    5. Nous avons créer au paravant un élement canvas dans le html, celui-ci contiendria le rendu générée par l'oscilloscope.
                    
          canvas = document.getElementById('analyser_render');
          ctx = canvas.getContext('2d');
                    
                  
    6. Vous vous souvenez du schémas cd SOURCE > NODE > DESTINATION le voici : le contexte audio prend en source l'objet audio() qui est envoyé à l'analyser et pour être encuite envoyé et interprété par la sortie.
                    
          source = context.createMediaElementSource(audio);
          source.connect(analyser);
          analyser.connect(context.destination);
                    
                  

    Générer le rendu graphique

    1. window.requestAnimationFrame()

      La méthode window.requestAnimationFrame() notifie le navigateur que l'on souhaite exécuter une animation et demande que celui-ci exécute une fonction spécifique de mise à jour de l'animation, avant le prochain rafraîchissement du navigateur. Cette méthode prend comme argument un callback qui sera appelé avant le rafraîchissement du navigateur.

      Note pour appeler l'animation suivant: Si l'on veut animer une nouvelle animation lors du prochain rafraichissement on rappele la méthode requestAnimFrame(). IL faut paramétrer le callback à 60/s, cela est dû au paramètre de rafraîssement de l'écran LCD de référence qui est en général égal à 60Hz

                    
        window.requestAnimFrame = (function(){
        return  window.requestAnimationFrame       ||
                window.webkitRequestAnimationFrame ||
                window.mozRequestAnimationFrame    ||
                function( callback ){
                  window.setTimeout(callback, 1000 / 60); // rappel
                };
        })();
      
        window.requestAnimationFrame(frameLooper);
                    
                  
    2. frequencyBinCount

      La propriété frequencyBinCount de l'objet AnalyserNode est un nombre entier non signé équivalent à la moitié la taille de la FFT. Il correspond en général au nombre de valeurs que l'on aurat à manipuler pour la visualisation.

                    
        fbc_array = new Uint8Array(analyser.frequencyBinCount);
                    
                  
    3. bejetNode.getByteFrequencyData()

      La méthode getByteFrequencyData() de l'objet AnalyserNode copie les données de fréquence dans le Uint8Array (tableau d'entiers non-signés) passé en argument. Si le tableau a moins d'éléments que AnalyserNode.frequencyBinCount, les excédants sont supprimés; s'il en a davantage, les excédants sont ignorés.

                    
        analyser.getByteFrequencyData(fbc_array);
                    
                  
              
                  // tableau des données piste
                  var PlayList = [
                  {track: 1, artist: "Rihanna", album: "Anti", title:"Needed Me", src: "./mp3/neededme.mp3", imgsrc: "./img/neededme.jpg" }, // 0
                  {track: 2, artist: "Young Money", album: "Rise Of An Empire", title:"Senile", src: "./mp3/senile.mp3", imgsrc: "./img/senile.jpg" } , // 1
                  {track: 3, artist: "Disiz la peste", album: "Le Poisson Rouge", title:"J'pète Les Plombs", src: "./mp3/jpetelesplombs.mp3", imgsrc: "./img/jpetelesplombs.jpg" }, // 2
                  {track: 4, artist: "Bjork", album: "Homogenic", title:"Joga", src: "./mp3/joga.mp3", imgsrc: "./img/joga.jpg" }, // 4
                  {track: 5, artist: "Yemi Alade", album: "King of Queens", title:"Johnny", src: "./mp3/johnny.mp3", imgsrc: "./img/johnny.jpg" },// 5
                  //{track: 6, artist: "Midnite", album: "Unpolished", title:"Don't Move", src: "./mp3/dontmove.mp3", imgsrc: "./img/dontmove.jpg" }, // 6 NE PAS DECOMMENTER
                  {track: 7, artist: "Le Peuple De L'Herbe", album: "P.H Test/Two", title:"No Escape", src: "./mp3/noescape.mp3", imgsrc: "./img/noescape.jpg" },// 7
                  {track: 8, artist: "Vanessa Da Mata", album: "Good Luck ft Ben Harper", title:"Boa Sorte", src: "./mp3/boasorte.mp3", imgsrc: "./img/boasorte.jpg" }, // 8
                  {track: 9, artist: "Rihanna", album: "Good Girl Gone Bad", title:"Rehab", src: "./mp3/rehab.mp3", imgsrc: "./img/rehab.jpg" },// 9
                  {track: 10, artist: "Oscar Chavez", album: "Desde Mexico Para Siempre Che", title:"Hasta Siempre Comandante Che Guevara", src: "./mp3/hastasiemprecomandantecheguevara.mp3", imgsrc: "./img/hastasiemprecomandantecheguevara.jpg" }, // 10
                  ];
    
                  console.log(PlayList);
    
                  /*---------------- AUDIO API----------------*/
                  //Access-Control-Allow-Credentials: true; TOFIXED
                  var audio = new Audio();
                  audio.src = PlayList[0].src; //  on cré la source en récupérant la proprité 'src' >> source.mp3 dans le tableau de propriété.
                  audio.controls = true; // on paramètre le controls du médias pour pouvoir le récupérer et le designer sois-même
                  audio.loop = false; // DÉSACTIVER LE LOOP car c'est par défaut
                  //audio.crossorigin = "anonymous";
    
                  // DECLARATION DES VARIABLES QUI VONT ETRE UTILISÉS
                  var canvas, ctx, source, context, analyser, fbc_array, bars, bar_x, bar_width, bar_height;
    
                  // APPELLE DE LA FONCTION INIALISATRICE DU MP3
                  window.addEventListener("load", initMP3, true);
    
    
                  function initMP3(){
                  // on récupère de l'id de l'audio_box
                  document.getElementById('audio_box').appendChild(audio).setAttribute('id', 'audioOscilo');
    
                  // CREATION DE L'AUDIOCONTEXT
                  window.AudioContext = window.AudioContext ||
                              window.webkitAudioContext;
                  context = new AudioContext();
    
                  analyser = context.createAnalyser();
                  canvas = document.getElementById('analyser_render');
                  ctx = canvas.getContext('2d');
    
                  // CONNEXION DE DE LA SOURCE VERS L'ANALYSEUR
                  source = context.createMediaElementSource(audio);
                  source.connect(analyser);
                  // on connect l'analyseur à la destination
                  analyser.connect(context.destination);
                  playRandom(); // intègre les options de lecture
                  frameLooper();
                  };
    
                  // APPELER FRAME
                  function frameLooper(){
    
                  // ON REQUETE SUR LE CADRE DE L'ANIMATION.
                  // webkit pour l'adaption des diff browsers
                  //
                  window.requestAnimFrame = (function(){
                  return  window.requestAnimationFrame       ||
                  window.webkitRequestAnimationFrame ||
                  window.mozRequestAnimationFrame    ||
                  function( callback ){
                    window.setTimeout(callback, 1000 / 60); // rappel
                  };
                  })();
    
    
                  window.requestAnimationFrame(frameLooper);
                  fbc_array = new Uint8Array(analyser.frequencyBinCount);
                  analyser.getByteFrequencyData(fbc_array);
    
    
                  ctx.clearRect(0, 0, canvas.width, canvas.height);
                  // création du style
                  ctx.fillStyle = "#ff6666";
                  // création du diagramme en bars.
                  bars = 50; // nombre de bars sur l'abscisse
                  for (var i = 0; i < bars; i++){
                  bar_x = i * 10;
                  bar_width = 8; // largeur des bars
                  bar_height = -(fbc_array[i]/2);
                  ctx.fillRect(bar_x, canvas.height, bar_width, bar_height);
                  };
                  };
                  /*---------------- PLAYRANDOM---------- */
                        
                      

    Haut de page