Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get audio to play when MediaElementAudioSource outputs zeroes, but CORS is no longer an issue?

I am attempting to implement <audio> into a THREE.js scene and I am having some trouble with the audio playback. In my array that I am logging out to the console, All of the output is "0". I have accounted for the CORS issue by placing this: audio.crossOrigin = "anonymous" after the audio.play(); initialization, but to no avail has this helped. Any ideas would be appreciated.

Oh, I have also tested this with a server, so that's not the issue.

Here is a link to the repo.

Here is the jsbin.

Below is the code.

HTML

<html lang="en">

<head>
  <meta charset="UTF-8" />
  <title>Threejs Experiment</title>
  <link rel="stylesheet" href="style.css" media="screen" title="no title" charset="utf-8">
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r73/three.min.js"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
  <script src="https://dl.dropboxusercontent.com/u/3587259/Code/Threejs/OrbitControls.js"></script>
</head>

<body>
<audio id="song" src="https://soundcloud.com/madeon/madeon-cut-the-kid"></audio>
<script type="text/javascript" src="main.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>

</body>

</html>

JavaScript

$(function(){

// Add Audio context and Audio
var ctx = new AudioContext();
var audio = document.getElementById('song');
var audioSrc = ctx.createMediaElementSource(audio);
var analyser = ctx.createAnalyser();

audioSrc.connect(analyser);
audioSrc.connect(ctx.destination);
var frequencyData = new Uint8Array(analyser.frequencyBinCount);

// Set scene and camera
var scene = new THREE.Scene();
var aspectRatio = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(75, aspectRatio, 0.1, 100);
camera.target = new THREE.Vector3( 10, 10, 10 );

// Set the DOM
var renderer = new THREE.WebGLRenderer({ antialias:true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor("#000000");
document.body.appendChild(renderer.domElement);

// Add controls
// controls = new THREE.OrbitControls(camera, renderer );
// controls.addEventListener( 'change', render );

// Move the camera
camera.position.z = 10;
camera.position.y = 0;

// Point Lights

var pointLightBlue = new THREE.PointLight( "#00ccff", 5, 100, 2 );
pointLightBlue.position.set( -10, -40, -10 );
scene.add(pointLightBlue);

// var pointLightBlue = new THREE.PointLight( "#ffffff", 1, 0, 1 );
// pointLightBlue.position.set( -10, 20, -10 );
// scene.add(pointLightBlue);

// var pointLightPink = new THREE.PointLight( "#EE567C", 5, 100, 10 );
// pointLightPink.position.set( 1, 0, -5 );
// scene.add(pointLightPink);

var pointLight = new THREE.PointLight( "#A805FA", 100, 1000, 40 );
pointLight.position.set( 40, 0, 40 );
scene.add(pointLight);

var sphereSize = 5;
var pointLightHelper = new THREE.PointLightHelper( pointLight, sphereSize );
scene.add( pointLightHelper );

var pointLight2 = new THREE.PointLight( "#07FAA0", 100, 1000, 30 );
pointLight2.position.set( -40, 0, -40 );
scene.add(pointLight2);

var sphereSize = 5;
var pointLightHelper = new THREE.PointLightHelper( pointLight2, sphereSize );
scene.add( pointLightHelper );

var quantity = 50;
var shapes = [];


for (var i = 0; i < quantity; i++) {

    if(Math.random() < 0.5){
      var geometry = new THREE.RingGeometry( 50, 50, 18);

      // var geometries = [
            //      new THREE.IcosahedronGeometry( 20, 0 ),
            //      new THREE.OctahedronGeometry( 20, 0 ),
            //      new THREE.TetrahedronGeometry( 20, 0 ),
            //  ];
      //
            // var geometry = geometries[ Math.floor( Math.random() * geometries.length ) ];
            // var material = new THREE.MeshLambertMaterial( {
            //  color: new THREE.Color( Math.random(), Math.random() * 0.5, Math.random() ),
            //  blending: THREE.AdditiveBlending,
            //  depthTest: false,
            //  shading: THREE.FlatShading,
            //  transparent: true
            // } );
            // var mesh = new THREE.Mesh( geometry, material );
            // var wireframe = mesh.clone();
            // wireframe.material = wireframe.material.clone();
            // wireframe.material.wireframe = true;
            // mesh.add( wireframe );
            // scene.add(mesh);

      // var geometry = new THREE.RingGeometry( 20, 150, 18);

        //var geometry = new THREE.TorusKnotGeometry( 10, 3, 100, 16 );
    }
    else {
      // var geometry = new THREE.RingGeometry( 4, 40, 3);


      // var geometry = new THREE.RingGeometry( 1, 5, 6 );
      // var material = new THREE.MeshBasicMaterial( { color: 0xffff00,
      //   side: THREE.DoubleSide } );
      // var mesh = new THREE.Mesh( geometry, material );
      // scene.add( mesh );

      // var points = [];
      // for ( var j = 0; j < 10; j++ ) {
      //    points.push( new THREE.Vector3( Math.sin( j * 0.2 ) * 15 + 50, 0, ( j - 5 ) * 2 ) );
      //
      // }
      // var geometry = new THREE.LatheGeometry( points );
      // var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
      // var lathe = new THREE.Mesh( geometry, material );
      // scene.add( lathe );
    }

    if(i % 7 === 0) {
        var material = new THREE.MeshPhongMaterial( { color: "#ffffff"} );
    }
    else if(i % 2 === 0){
        var material = new THREE.MeshPhongMaterial( { color: "#666666"} );
    }
    else {
        var material = new THREE.MeshPhongMaterial( { color: "#333333"} );
    }

    var mesh = new THREE.Mesh(geometry, material);
    mesh.position.z = -i * 2;
    mesh.rotation.z = i;
    shapes.push(mesh);
    scene.add(mesh);
}

// Variables
var u_time = 0;

// Render function
var render = function() {
    requestAnimationFrame(render);
    u_time++;

    for (var i = 0; i < quantity; i++) {

        // Set rotation change of shapes
        shapes[i].position.z += 0.2;
        shapes[i].rotation.z += 0;
        shapes[i].scale.x = 1 + Math.sin(i + u_time * 0.1) * 0.05;
        shapes[i].scale.y = 1 + Math.sin(i + u_time * 0.1) * 0.05;

        var change = 1.5 + Math.sin(u_time * 0.5) * 0.5;

        // Set wireframe & width
        if(Math.random() < change){
            shapes[i].material.wireframe = true;
            shapes[i].material.wireframeLinewidth = Math.random() * 2;
        }
        else {
            shapes[i].material.wireframe = false;
        }

        if(shapes[i].position.z > 10){
            shapes[i].position.z = -70;
            shapes[i].rotation.z = i;
        }
    }

    // Set Point light Intensity & Position
    pointLight.intensity = Math.abs(Math.sin(u_time * 0.2) * 2);
    pointLight2.intensity = Math.abs(Math.cos(u_time * 0.2) * 2);
    pointLight.position.z = Math.abs(Math.sin(u_time * 0.02) * 30);
    pointLight2.position.z = Math.abs(Math.cos(u_time * 0.02) * 30);

    // camera.rotation.y = 90 * Math.PI / 180;
    // camera.rotation.z = frequencyData[20] * Math.PI / 180;
    // camera.rotation.x = frequencyData[100] * Math.PI / 180;
    console.log(frequencyData);

    //composer.render();
    renderer.render(scene, camera);

}
audio.play();
// audio.crossOrigin = "anonymous";
render();
});
like image 586
jshuadvd Avatar asked Dec 25 '22 10:12

jshuadvd


1 Answers

What do you mean "CORS isn't an issue"?

  1. if the audio is coming from a different origin you need to set the crossOrigin property BEFORE setting the src property

    someAudioElement.crossOrigin = "anonymous";
    

    In other words either put the crossOrigin property in the tag itself

    <audio crossOrigin="anonymous" src="http://somedomain/someaudio">...
    

    Or in JavaScript

    someAudioElement.crossOrigin = "anonymous";
    someAudioElement.src = "http://somedomain/someaudio";
    

    The reason you have to do this before is because the moment you set the src property the browser will try to get the audio. If you haven't already set the crossOrigin property the browser won't know to ask for permission to use the audio.

    Note that all that does is ask the server for permission. The server itself still has to give permission to the browser to use the audio. Most servers do not give this permission. Soundcloud does but not for all songs.

  2. Safari on iOS and Chrome on Android don't support analysing streaming audio data.

    You can track the Chrome issue to fix this here. Star it if you want to track the progress. I don't know if there is a webkit bug to track the issue on iOS

  3. AFAIK you can't play soundcloud URLs directly

    You have code like this

    <audio id="song" src="https://soundcloud.com/madeon/madeon-cut-the-kid"></audio>
    

    That is not a valid URL for soundcloud audio. You have to pass that URL to the soundcloud API along with an API key and it will give you back a correct URL.

    Here's an SO question about it

    Other things to note:

    • The soundcloud SDK 3.0 SDK doesn't work on Safari for analysing audio. Use the soundcloud SDK 2.0 or better, use a direct XMLHttpRequest because the soundcloud SDK 2.0 initializes flash even if you don't use it.

    • Example using the soundcloud sdk 2.0

      in HTML

      <script src="https://connect.soundcloud.com/sdk-2.0.0.js"></script> 
      

      in Javascript

      // see https://auth0.com/docs/connections/social/soundcloud
      var yourSoundCloudClientId = "???????";
      SC.initialize({
        client_id: yoursCoundCloudClientId,
      });
      
      var soundCloudURL = "https://soundcloud.com/madeon/madeon-cut-the-kid";
      SC.get("/resolve", { url: soundCloudUrl }, function(result, err) {
        if (err) {
          console.error("bad url:", url, err);
          return;
        }
        if (result.streamable && result.stream_url) {
          var src = result.stream_url + '?client_id=' + yourSoundCloudClientId;
          someAudioElement.crossOrigin = "anonymous";
          someAudioElement.src = src;
      
          // other things you might be interested in because
          // if you use soundcloud music you're required to give
          // and display attribution and links
      
          console.log("link to music:", result.permalink_url);
          console.log("link to band:", result.user.permalink_url);
          console.log("name of song:", result.title);
          console.log("name to band:", result.user.username);
        } else {
           console.error("not streamable:", url);
        }
      });
      

      This example does it without the soundcloud SDK.

like image 154
gman Avatar answered Dec 28 '22 08:12

gman