0

I have a bunch of sounds on a page, similar to the sound grid example. Some of these tracks are music tracks and I'd like to treat them differently. Most of the sounds can play over each other and that is the intent, however, no music track should be able to play over another music track. Think radio buttons.

I've got some very woolly code that detects if the other track is playing when clicked and stops the track, and switches that track's css (play icons and such). But now, adding a 3rd or 4th track to the mix becomes unruly.

sounds are loaded and stored in a hash of reusable sound instances that look like:

  mySounds["sound1"]= createjs.Sound.createInstance("sound1");
  ...

when the button in the html is clicked on (I'm not currently using the data-type attribute, that was from an earlier attempt but I thought it might be useful):

    <button type="button" class="btn btn-vol btn-sm" data-type="music" data-track="music1" onclick="play(this)">
    <span class="glyphicon glyphicon-play bplay"></span></button>

I currently do:

function play(target) {

    //define some stuff from html
    musicTrack = $(target).attr('data-track');
    music1 = $('button[data-track="music1"]');
    music2 = $('button[data-track="music2"]');
    myInstance = mySounds[id] //id is defined elsewhere

    toggle = $(target).find('span.bplay'); //this is where I have the play/pause icons

    //For all cases, not just music I find the play icon and swap it.
    if(toggle.hasClass('glyphicon-play')){ //the sound is ready to play. if it had a stop icon it would mean it was already playing

    toggle.removeClass('glyphicon-play');
    toggle.addClass('glyphicon-stop')

    //special case for music Tracks
    if(musicTrack == "music1") { //If I clicked on music track 1
        if(mySounds[musicTrack2].position !=0){ //if it isn't 0, it's playing!
            music2.find('span.bplay).removeClass('glyphicon-stop');
            music2.find('span.bplay').addClass('glyphicon-play');
            mySounds[musicTrack2].stop();
        }
        else {
            //do nothing because track 2 isn't playing
        }

    } else if (musicTrack=="music2"){ //If I clicked on music track 2
        if(mySounds[musicTrack2].position !=0){
            music1.find('span.bplay').removeClass('glyphicon-stop');
            music1.find('span.bplay').addClass('glyphicon-play');
            mySounds[musicTrack1].stop();
        }
        else {
            //do nothing because track 1 isn't playing
        }

        myInstance.play(); // play the clicked on instance 

    }
    else {
        //if the glyphicon does not say play (says stop) then we stop the sound etc..
        toggle.removeClass('glyphicon-stop');
        toggle.addClass('glyphicon-play');
        myInstance.stop();
    }
}

I haven't checked the above for syntax as I copied it by hand from my code, keeping only the relevant bits, but all this works. I click on music1, if music 2 isn't playing - it plays. If music 2 is playing, it stops music 2, switches it's stop icon to play and plays music 1. My actual code does some tweening of the sounds before it stops so they crossfade nicely.

I'm not a programmer but I'd love to be able to do this in a more efficient/elegant manner. Surely there is a way!

Ejaz
  • 8,719
  • 3
  • 34
  • 49
dijon
  • 359
  • 1
  • 9
  • 21
  • just to clarify, is the question "Is there a more efficient/elegant solution for this problem?" – OJay May 12 '15 at 15:48
  • Basically if I only wanted 2 sounds to toggle each other, like shown here I'd be fine with this inelegant code - But I would like to have 4 or 5 sounds, each one toggling both graphics (buttons) and playback and the way I have it set up it would get very ugly and confusing. So, yes. – dijon May 12 '15 at 15:52

1 Answers1

0

A better way to do this would be give the music buttons a different click handling function, and using a app / global variable to track the currently playing music. Then use the icon to determine behavior. You'd need to add a way to get the currently playing music, possible another variable. Something like this:

var currentMusic;

function playMusic(target) {

//define some stuff from html
musicTrack = $(target).attr('data-track');
myInstance = mySounds[id]; //id is defined elsewhere

toggle = $(target).find('span.bplay'); //this is where I have the play/pause icons

//For all cases, not just music I find the play icon and swap it.
if(toggle.hasClass('glyphicon-stop')){ 
    toggle.removeClass('glyphicon-stop');
    toggle.addClass('glyphicon-play');
    currentMusic = null;
    myInstance.stop();
}
else {
    if(currentMusic) {
      // get current instance and call stop
      currentMusic.addClass('glyphicon-play');
      currentMusic.removeClass('glyphicon-stop');
    }
    toggle.removeClass('glyphicon-play');
    toggle.addClass('glyphicon-stop');
    currentMusic = toggle;
    myInstance.play();
    }
}
OJay
  • 1,249
  • 7
  • 14
  • Thanks Ojay, I think you're right about using a different click handler function, makes it easier to read.I think the thing I'm having trouble with is tracking the currently playing music. The toggle buttons are all the same, either play or stop, but the music could be any number of tracks/id's. I'm trying to wrap my head around the logic of it: Press Play -> are any of the other music tracks playing? ->no?->just play the selected track ->yes?->stop the currently playing one and then play the selected track. - It's the "are any other music tracks playing" part that I can't get programatically. – dijon May 14 '15 at 00:13
  • that's what currentMusic represents, if there is a currently playing music track. Because you can only have one at a time, this should work. You'll likely want to add an event listener to tracks for when they play to completion and change the button state and stop the music. It was not clear from your code how you were storing sound instances, so I didn't implement that aspect but that is something you would need to account for. Hope that helps. – OJay May 14 '15 at 15:40