4

I apologize if my use of terminology is inaccurate. I'm a novice.

I have a long list of variables that are being shared/used by the function loop(). I am currently only calling loop() twice and only passing unique arguments for the sound file link. I am going to scale this code up so that I will have many calls to loop() but each with a unique set of arguments replacing my long shared list of variables. I think it will be a bit messy and confusing to have a long list of unique arguments for each call to loop(). Is there a way that I can keep things readable and organized by making different variable lists that can only be accessed by the parameters for a specific call to loop()? Something like this pseudocode:

argumentListA {
    var sound = 'audio/sample.mp3'
    var aStartMin = 2
    var aStartMax = 200
    var seekMin = .5
    var seekMax = 2
    }

argumentListB {
    var sound = 'audio/sampleB.mp3'        
    var aStartMin = 0
    var aStartMax = 100
    var seekMin = 0
    var seekMax = 1
    }  

loop(argumentListA);
loop(argumentListB);

I'd love to be able to define all of these variables/parameters in one place and then have them referenced in a simple way by the function call.

Updated working code below:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <script src="js/howler.core.js"></script>
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <script>
        var options = {
        soundFileName: 'audio/sample.mp3',
        aStartMin: 0,
        aStartMax: 100,
        probablilityAMin: 0,
        probablilityAMax: 10,
        probabilityThreshold: 3,
        seekMin: 0,
        seekMax: 1,
        aFadeIn: 9000,
        aFadeOut: 3000,
        aPlayDurationMin: 5000,
        aPlayDurationMax: 11000,
        maxVolume: 1,
        numberOfSounds: 0, // starting variable at 0 
        maxNumberOfSounds: 2
    };

    function logNumberOfSounds() { // passing options into this before is what broke code
        options.numberOfSounds++;
        console.log('Number of sounds is now: ' + options.numberOfSounds);
    }

    // calls the soundSorter function repeatedly so sounds will play

    (function masterClock(options) {
        setTimeout(function () {
            soundSorter();
            masterClock();
        }, 2000);
    }());

    function soundSorter() { // passing options into this before is what broke code
        var probabilityResult = Math.floor((Math.random() * options.probablilityAMax) + options.probablilityAMin);
        if (probabilityResult > options.probabilityThreshold) {
            loop(options);
        }
        else {
            loop(options);
        }
    }

    function loop(options) {

        setTimeout(function () {

            var playDuration = Math.floor((Math.random() * options.aPlayDurationMax) + options.aPlayDurationMin);

            setTimeout(function () {
                if (options.numberOfSounds < options.maxNumberOfSounds) { //Don't create more than the max number of sounds.

                    var sound = getSound(options.soundFileName);
                    var id2 = sound.play();

                    logNumberOfSounds();
                    console.log('probabilityThreshold is now: ' + options.probabilityThreshold);

                    //sound.volume(0); // don't think I need this since it's defined next as well as in getSound()
                    sound.fade(0, options.maxVolume, options.aFadeIn, id2); // FADE IN

                    setTimeout(function () {
                        sound.fade(options.maxVolume, 0, options.aFadeOut, id2); // FADE OUT
                        options.numberOfSounds--; //when it fades out subtract one

                        // Attempt to clean up the sound object
                        setTimeout(function () {
                            sound.stop();
                            sound.unload();
                        }, options.aFadeOut + 1000);
                    }, playDuration);
                }
            }, 0);
        }, 0);
    }

    // PLAYER FOR MAIN SOUND FUNCTION /////////////////////////////
    function getSound() {
        return new Howl({
            src: [options.soundFileName],
            autoplay: true,
            loop: true,
            volume: 0,
            fade: 0 // removes the blip
        });
    }

    </script>

    <script src="js/howler.core.js"></script>
    <script src="js/siriwave.js"></script>
    <script src="js/player.js"></script>

</body>

</html>
forestkelley
  • 341
  • 3
  • 14

2 Answers2

5

Yes, it's quite common for things like this to be passed in as an options object.

function loop(options) {
  // use options.sound, options.aStartMin, etc
}

You can then store the options object separately if you wanted:

var options1 = {
  sound: 'audio/sample.mp3',
  aStartMin: 2,
  aStartMax: 200,
  seekMin: .5,
  seekMax: 2
}

In fact, this is so common that (depending on the browsers you aim on supporting, or your level of babel transpilation) there is support now for something called 'object destructuring' that makes this even easier:

function loop({ sound, aStartMin, aStartMax, etc }) {
  // Can now use sound, aStartMin, aStartMax, etc as if they were plain arguments.
}
david
  • 17,925
  • 4
  • 43
  • 57
  • This is great and seems clear, but I can't get my code working. I suspect I'm missing something. I get a "ReferenceError" that my sound is not defined as well as "TypeError: optionsA is undefined." I'm not quie sure how/if I should pass the options list via the main function or the call, but I've tired both. I don't believe I can reply with full code here, so here is the abbreviated code: `var optionsA = {soundFileName: 'audio/sample.mp3',` `loop(optionsA);` ` function loop(optionsA) {var sound = getSound(optionsA.soundFileName);var id2 = sound.play();sound.fade(0, 1, 3000, id2);}` – forestkelley Feb 04 '19 at 17:03
  • @forestkelley Your abbreviated code works fine when I try it: https://jsfiddle.net/786hte5f/ There must be something else going on. Maybe update your question with the new code? – david Feb 04 '19 at 20:51
  • Thanks. I updated my post to show the current state of my code. I'm not sure why in your js Fiddle you used "optionsA" in the var/options list definition and in the function call, but inside the function you simply use "options" without the "A." I would think you'd use the same paramater/name throughout. But your Fiddle does break if I change them all to "optionsA." So I followed your lead in my code above, but I still get the errors "TypeError: track is null" and "ReferenceError: options is not defined." – forestkelley Feb 04 '19 at 23:37
  • @forestkelley You've mixed `optionsA` and `options` all the way through your code, you need to sort that out and then it will work. Inside the function you should use `options` because you don't know what options object will be passed in (at the moment you only have optionsA, but one day you might have optionsB as well, and you don't want to have to make a new loop function) – david Feb 05 '19 at 01:28
  • I managed to get the options list working in a limited way. But I'm still trying to figure out why my full code breaks when I use it. I stripped down the code a bit to try to isolate the problem and I am using the `getSounds(options.soundFileName);` code from your jsFiddle to verify that it works. It does pass the `soundFileName`, but it will only do it if I remove all of the code that I comment out. If I include any of those (variable definitions, etc.) that are now commented out, `soundFileName` won't pass. Do you have any idea what is causing the problem? Thanks! – forestkelley Feb 06 '19 at 19:53
2

Other benefits of a destructuring assignment using an object are:

  1. Values are passed by name and not order (object properties don't have an order anyway)
  2. Not all (or any) of the values need to be used
  3. If a property is missing, it's passed as undefined
  4. You can still set default values in the declaration

// Define 3 properties on options object
var opts = {
  opt1: 'opt1 value',
  opt2: 'opt2 value',
  opt3: 'opt3 value'
};

// Use some option properties, even not defined props
function myFunc({opt3, opt1, foo, bar = 'bar'}) {
  console.log(`opt1: ${opt1}\nopt3: ${opt3}\nfoo : ${foo}\nbar : ${bar}`);
}

myFunc(opts);
RobG
  • 142,382
  • 31
  • 172
  • 209