Script doesn't load Web Audio Buffers properly on "/:_id" routes

https://github.com/futureRobin/meteorAudioIssues

Trying to load audio buffers into memory. When I hit localhost:3000/tides or localhost:3000 it loads my buffers into memory with no problems. When I then click through onto a session e.g. localhost:3000/tides/SOMESESSIONID. the buffers have already loaded from the previous state.

However, when I then refresh the page on “localhost:3000/tides/SOMESESSIONID” the buffers don’t load properly and the console just logs an array of file path names.

I need to be able to dynamically load the buffers based on the database entries samples array and for these samples to load when the page is refreshed.

It works find when on homepage, doesn't load on ID paths.

Crucial to app functionality. Any help would be great as going in circles now.

audio.js

             //new context for loadKit
             var context = new AudioContext();
             var audioContext = null;
             var scheduleAheadTime = 0;
             var current16thNote = 0;
             var bpm = 140;

             //array of samples to load first. 
             var samplesToLoad = [
                 "ghost_kick.wav", "ghost_snare.wav", "zap.wav", "ghost_knock.wav"
             ];


             //create a class called loadKit for loading the sounds. 
             function loadKit(inputArg) {
                 //get the array of 6 file paths from input. 
                 this.drumPath = inputArg;
             }

             //load prototype runs loadsample function. 
             loadKit.prototype.load = function() {
                 //when we call load, call loadsample 6 times
                 //feed it the id and drumPath index value 
                 for (var i = 0; i < 6; i++) {
                     this.loadSample(i, this.drumPath[i]);
                 }

             };

             //array to hold the samples in. 
             //now loadKitInstance.kickBuffer will hold the buffer.  
             var buffers = [
                 function(buffer) {
                     this.buffer1 = buffer;
                 },
                 function(buffer) {
                     this.buffer2 = buffer;
                 },
                 function(buffer) {
                     this.buffer3 = buffer;
                 },
                 function(buffer) {
                     this.buffer4 = buffer;
                 },
                 function(buffer) {
                     this.buffer5 = buffer;
                 },
                 function(buffer) {
                     this.buffer6 = buffer;
                 }
             ];


             //load in the samples. 
             loadKit.prototype.loadSample = function(id, url) {
                 //new XML request.
                 var request = new XMLHttpRequest();
                 //load the url & set response to arraybuffer
                 request.open("GET", url, true);
                 request.responseType = "arraybuffer";

                 //save the result to sample
                 var sample = this;



                 //once loaded decode the output & bind to the buffers array
                 request.onload = function() {
                         buffers[id].bind("");
                         context.decodeAudioData(request.response, buffers[id].bind(sample));
                     }
                     //send the request. 
                 request.send();
             };

             //get the list of drums from the beat.json
             //load them into a the var 'loadedkit'.
             loadDrums = function(listOfSamples) {
                 var drums = samplesToLoad;
                 loadedKit = new loadKit(listOfSamples);
                 loadedKit.load();
                 console.log(loadedKit);
             }

             //create a new audio context.
             initContext = function() {
                 try {
                     //create new Audio Context, global.
                     sampleContext = new AudioContext();
                     //create new Tuna instance, global
                     console.log("web audio context loaded");
                 } catch (e) {
                     //if not then alert
                     alert('Sorry, your browser does not support the Web Audio API.');
                 }
             }


   
             }

client/main.js

Meteor.startup(function() {
    Meteor.startup(function() {
        init();
        initContext();
    });

router.js

Router.route('/', {
        template: 'myTemplate',

        subscriptions: function() {
        this.subscribe('sessions').wait();
      },
       // Subscriptions or other things we want to "wait" on. This also
      // automatically uses the loading hook. That's the only difference between
      // this option and the subscriptions option above.
      waitOn: function () {
        return Meteor.subscribe('sessions');
      },

       // A data function that can be used to automatically set the data context for
      // our layout. This function can also be used by hooks and plugins. For
      // example, the "dataNotFound" plugin calls this function to see if it
      // returns a null value, and if so, renders the not found template.
      data: function () {
        return Sessions.findOne({});
      },

        action: function () {
        loadDrums(["ghost_kick.wav", "ghost_snare.wav", "zap.wav", "ghost_knock.wav"]);
        // render all templates and regions for this route
        this.render();
      }
    });



    Router.route('/tides/:_id',{
        template: 'idTemplate', 
     // a place to put your subscriptions
      subscriptions: function() {
        this.subscribe('sessions', this.params._id).wait();
      },
       // Subscriptions or other things we want to "wait" on. This also
      // automatically uses the loading hook. That's the only difference between
      // this option and the subscriptions option above.
      waitOn: function () {
        return Meteor.subscribe('sessions');
      },

       // A data function that can be used to automatically set the data context for
      // our layout. This function can also be used by hooks and plugins. For
      // example, the "dataNotFound" plugin calls this function to see if it
      // returns a null value, and if so, renders the not found template.
      data: function (params) {
        return Sessions.findOne(this.params._id);
      },

        action: function () {
          console.log("IN ACTION")
          console.log(Sessions.findOne(this.params._id));
          var samples = Sessions.findOne(this.params._id)["sampleList"];
          console.log(samples);
        loadDrums(samples);
        // render all templates and regions for this route
        this.render();
      }
    })

it looks like your problem is relative paths, it’s trying to load your files from localhost:3000/tides/ghost_*.wav if you change line 58 of your router to go up a directory for each file it should work

loadDrums(["../ghost_kick.wav", "../ghost_snare.wav", "../zap.wav", "../ghost_knock.wav"]);

1 Like

That’s done the trick - thanks very much indeed.

Do you know any more about the problem as i’m keen to know how it can work without ‘…/’ in one route and not in another…

you could always use an absolute path, regardless of route. you can get the current base url with window.location.origin which in development should return http://localhost:3000 or on this site https://forums.meteor.com and then construct the url to your resource from there

you could change the loadSample(id, file) to do something like
request.open("GET", window.location.origin + '/' + file, true);

1 Like