css Audio - Active file-generic CSS - Active Generic - Active HTML - Active JS - Active SVG - Active Text - Active file-generic Video - Active header Love html icon-new-collection icon-person icon-team numbered-list123 pop-out spinner split-screen star tv

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

            
                  <div id="drop-info">
        Drop your audio 
    or <a href="#play" id="play-local-audio">play</a> 
      to make it move
    </div>
            
          
!
            
                          @import url('https://fonts.googleapis.com/css?family=Raleway:900');
body,
html {
    margin: 0;
    padding: 0;
    height: 100%;
    width: 100%;
    overflow: hidden;
  }
  
  body {
      background-color: #3B4060;
      margin: 0px;
      overflow: hidden;
      background-image: -webkit-gradient(#3B4060, #DE7E6E);
      /* Safari 5.1, iOS 5.0-6.1, Chrome 10-25, Android 4.0-4.3 */
      background-image: -webkit-linear-gradient(#3B4060, #DE7E6E);
      /* Firefox 3.6 - 15 */
      background-image: -moz-linear-gradient(#3B4060, #DE7E6E);
      /* Opera 11.1 - 12 */
      background-image: -o-linear-gradient(#3B4060, #DE7E6E);
      /* Opera 15+, Chrome 25+, IE 10+, Firefox 16+, Safari 6.1+, iOS 7+, Android 4.4+ */
      background-image: linear-gradient(#3B4060, #DE7E6E);
    }
    
    #drop-info {
        font-family: 'Raleway', sans-serif;
        position: absolute;
        z-index: 10;
        bottom: 20px;
        left: 0;
        right: 0;
        /* margin: auto; */
        text-align: center;
        /* text-transform: uppercase; */
        color: #f2f5f0;
        font-size: 1.2em;
      }
      
      #drop-info > a {
          color: #FFF;
          cursor: pointer;
        }
        
        #drop-info > a:hover {
            color: #f2f5f0;
          }
          
          canvas {
              z-index: 1000;
            }
            
          
!
            
                  var soundReact,
    audioUrl = "https://bastiencornier.com/sources/monolithparty/PILOTPRIEST%20-%20TRANS%20-%2004%20I%20Am%20You.mp3",
    audioName = "PilotPriest - I AM YOU"
    dropInfo = document.getElementById("drop-info");
    // On recupère la largeur et la hauteur de la fenêtre
    var WIDTH = window.innerWidth,
    HEIGHT = window.innerHeight;

    window.onload = function() {
        soundReact = new SoundReact();
        soundReact.init();
        soundReact.createCylinders();
        soundReact.processAudio();
        soundReact.getLocalAudio(audioUrl);
        soundReact.dropAudio();
    };

// Classe globale
function SoundReact() {

    // Rendu
    this.scene;
    this.camera;
    this.renderer;
    this.controls;

    // Cylindres
    this.cylinders = new Array();
    this.numberOfCylinder = 60;

    // Audio
    this.audioCtx;
    this.sourceBuffer;
    this.analyser;
};


// Init de la scene three js
SoundReact.prototype.init = function() {
    var self = this;

    // Generation de la scene Three JS
    this.scene = new THREE.Scene();

    // On init le renderer
    this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true
    });
    this.renderer.setSize(WIDTH, HEIGHT);

    // Ajout du renderer au body
    document.body.appendChild(this.renderer.domElement);

    // Créer et ajouter camera
    this.camera = new THREE.PerspectiveCamera(50, WIDTH / HEIGHT, 0.1, 2000);
    this.camera.position.set(50, 10, 0);
    this.camera.lookAt(this.scene.position);
    this.scene.add(this.camera);

    // Mettre à jour la taille du renderer, le ratio et la projection au retaillage de la fenêtre
    window.addEventListener('resize', function() {
        var WIDTH = window.innerWidth,
        HEIGHT = window.innerHeight;
        self.renderer.setSize(WIDTH, HEIGHT);
        self.camera.aspect = WIDTH / HEIGHT;
        self.camera.updateProjectionMatrix();
    });

    // Crée lumière ambiance + ajout scene
    this.light = new THREE.PointLight(0xffffff);
    this.light.position.set(-200, 0, -200);
    this.scene.add(this.light);
    this.light.intensity = 0.2;

    // Crée lumière + ajout scene
    this.ambiantlight = new THREE.AmbientLight(0xffffff);
    this.ambiantlight.position.set(0, 100, 0);
    this.scene.add(this.ambiantlight);
    this.ambiantlight.intensity = 0.5;

    /* Sol de la scène : dunes du désert  */
    // on crée notre texture
    var texture = new THREE.Texture(generateTexture());
    texture.needsUpdate = true; // important!
    var planeGeometry = new THREE.PlaneGeometry(500, 500, 50, 50);
    // Hauteur aléatoire des sommets
    for (var i = 0, l = planeGeometry.vertices.length; i < l; i++) {
        planeGeometry.vertices[i].z = getRandomInt(0, -10);
    };

    // On défini la texture et la couleur du sol
    var materialBase = new THREE.MeshBasicMaterial({
        map: texture,
        transparent: true
    });

    // On crée le sol en lui assignant sa géométrie et son apparence
    var floor = new THREE.Mesh(planeGeometry, materialBase);
    floor.material.side = THREE.DoubleSide;
    floor.rotation.x = Math.radians(90);
    this.scene.add(floor);
};



// Créer les rectangles pour la visualisation
SoundReact.prototype.createCylinders = function() {
    // Boucle et crée les cylindres
    for (var i = 0; i < this.numberOfCylinder; i++) {
        // crée une barre
        var cylinderGeometry = new THREE.CylinderGeometry(1, 1, 3, 5);
        // Créer un materiel
        var material = new THREE.MeshPhongMaterial({
            color: 0x26283F,
            specular: 0x26283F
        });
        // Créer la géometrie et appliquer la position initiale
        this.cylinders[i] = new THREE.Mesh(cylinderGeometry, material);
        this.cylinders[i].position.set(i - this.numberOfCylinder / 2 * getRandomInt(1, 2), 1, getRandomInt(-22, 22));
        this.cylinders[i].rotation.x = Math.radians(getRandomInt(-40, 40));
        //ajout des cylidnres crées à la scène
        this.scene.add(this.cylinders[i]);
        this.cylinders[i].scale.y = 60;
    };
};
// Drag and drop d'un fichier audio
SoundReact.prototype.dropAudio = function() {


    //drag over
    // En prévention de la lecture directe par le navigateur
    document.body.addEventListener("dragover", function(e) {
        e.stopPropagation();
        e.preventDefault();
        e.dataTransfer.dropEffect = 'copy';
    }, false);
    //drop de l'audio
    document.body.addEventListener("drop", function(e) {
        // Empêche le comportement par défaut
        e.stopPropagation();
        e.preventDefault();
        // On récupère le fichier
        var file = e.dataTransfer.files[0];
        var fileName = file.name;
        // On ajoute le nom du fichier joué
        dropInfo.innerHTML = "Playing " + fileName;
        var fileReader = new FileReader();
        // On lie le fichier une fois chargé
        fileReader.onload = function(e) {
            var fileResult = e.target.result;
            soundReact.start(fileResult);
        };
        fileReader.onerror = function(e) {
            debugger
        };
        // Process du contenu du fichier audio, retourne un tampon de données binaires pour la lecture de l'audio
        fileReader.readAsArrayBuffer(file);
    }, false);
};
// Récupère le fichier audio par défaut pour le lire directement
SoundReact.prototype.getLocalAudio = function(audioUrl) {
    var playLocalAudio = document.getElementById("play-local-audio"),
    self = this;
    // Nouvelle requête de l'audio
    var request = new XMLHttpRequest();

    // On récupère le fichier et on l'envoi en tant que tableau de données
    request.open("GET", audioUrl, true);
    // On récupère un tampon de données binaires à partir du fichier audio pour les traiter à la suite
    request.responseType = "arraybuffer";
    // Envoi de la requête
    request.send();
    // On lance la lecture une fois le fichier chargé
    request.onload = playAudio();

    function playAudio() {
        // On joue le fichier au click sur le play
        playLocalAudio.addEventListener("click", function(e) {
            e.preventDefault();
            dropInfo.innerHTML = "loading...";
            request.addEventListener("load", transferComplete, false);

        });
    };

    function transferComplete(evt) {
      self.start(request.response);
      dropInfo.innerHTML = "Playing " + audioName;
  }
};




// Analyse de l'audio
SoundReact.prototype.processAudio = function() {

    // Nouveau contexte audio
    this.audioCtx = new(window.AudioContext || window.webkitAudioContext)();

    // On crée le tampon qui va accueillir les données audio
    this.sourceBuffer = this.audioCtx.createBufferSource();

    // On crée l'analyseur
    this.analyser = this.audioCtx.createAnalyser();

    // On définit la puissance max et min de l'intervalle pour l'analyse des données FFT
    this.analyser.minDecibels = -90;
    this.analyser.maxDecibels = -10;

    // On lisse la transition entre les valeurs
    this.analyser.smoothingTimeConstant = 0.97;

    // On détermine le domaine fréquentiel par transformation de Fourier rapide (fft)
    this.analyser.fftSize = 256;

    // Après avoir crées ses nœuds, on les connecte

    // On connecte les données tampon à l'analyseur
    this.sourceBuffer.connect(this.analyser);

    // On connecte les données tampon à la carte audio
    this.sourceBuffer.connect(this.audioCtx.destination);

    // On appelle la fonction de visualisation de l'audio
    soundReact.visualizeAudio();
};




// La ou la magie opère
// On connecte l'audio à la scène three.js puis on l'anime
SoundReact.prototype.visualizeAudio = function() {

    // On crée un tableau données sur 8 bits à partir de la taille de la mémoire tampon
    var audioData = new Uint8Array(soundReact.analyser.frequencyBinCount);

    function draw() {
        requestAnimationFrame(draw);

        // On copie les données de fréquence dans le Uint8Array passé en argument
        // Ces données vont nous permettre de modifier les éléments de la scène
        soundReact.analyser.getByteFrequencyData(audioData);

        // Calcul le pas entre la longueur du tableau des fréquences audio et le nombre de cylindres
        var step = Math.round(audioData.length / soundReact.numberOfCylinder);

        // Rendu de la scène et de la caméra
        soundReact.renderer.render(soundReact.scene, soundReact.camera);

        // On ajoute un léger zoom à la caméra en fonction du volume de la fréquence la plus basse
        var cameraX = audioData[0].map(200, 250, 50, 47);
        cameraX = cameraX < 47 ? 47 : cameraX;
        soundReact.camera.position.set(cameraX, 12, 0);

        // On modifie l'intensité de la lumière en fonction du volume de la fréquence la plus basse
        soundReact.light.intensity = audioData[0].map(190, 230, 0.1, 1);

        // On Boucle à traver les cylindres et on modifie l'axe des z en fonction du volume des fréquences
        for (var i = 0; i < soundReact.numberOfCylinder; i++) {

            // On récupère la valeur de la fréquence par rapport au numéro du cylindre 
            // On divise par 4 pour avoir une valeur d'échelle propice
            var value = audioData[i * step] / 4;
            var minVal = i < soundReact.numberOfCylinder / 10 ? 30 : 1;
            value = value < minVal ? minVal : value;
            soundReact.cylinders[i].scale.y = (value + 0.1) / 3;
        }
    };

    draw();

};




// Lecture de l'audio
SoundReact.prototype.start = function(buffer) {

    // On décode les données tampon avec la méthode decodeAudioData de manière asynchrone
    this.audioCtx.decodeAudioData(buffer, decodeAudioDataSuccess, decodeAudioDataFailed);
    var self = this;

    // En cas de succès
    function decodeAudioDataSuccess(decodedBuffer) {

        // On connecte les données audio au tampon sourceBuffer
        self.sourceBuffer.buffer = decodedBuffer;

        // On lance la lecture de l'audio
        self.sourceBuffer.start(0);
    }

    // Erreur
    function decodeAudioDataFailed() {
        debugger
    }
};



// Création de la texture en dégradé du sol
function generateTexture() {
    var size = 512;
    // create canvas
    canvas = document.createElement('canvas');
    canvas.width = size;
    canvas.height = size;
    // get context
    var context = canvas.getContext('2d');
    // draw gradient
    context.rect(0, 0, size, size);
    var gradient = context.createLinearGradient(0, 0, size, size);
    gradient.addColorStop(0, '#794750'); // light blue 
    gradient.addColorStop(1, 'rgb(17, 17, 22)'); // dark
    context.fillStyle = gradient;
    context.fill();
    return canvas;
}

/**
 * Returns a random integer between min (inclusive) and max (inclusive)
 * Using Math.round() will give you a non-uniform distribution!
 */
 function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Converts from degrees to radians.
Math.radians = function(degrees) {
    return degrees * Math.PI / 180;
};
// map a range of numbers to another range of numbers
Number.prototype.map = function(in_min, in_max, out_min, out_max) {
    return (this - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.
Loading ..................

Console