Skip to main content
Known Participant
October 17, 2022
Question

Stop audio on slide revisit – an alternative with javascript and a hidden button

  • October 17, 2022
  • 1 reply
  • 187 views

So I was trying to do this with a few key ideas in mind:

 

  1. I need the audio to be slide audio, since I'm using closed captions on some slides
  2. I did not want to create custom variables for each slide, to record if it is visited or not. I am making a framework with templates that will be used for many courses, so I need it to be generic and just ... work without having to create a new variable, each time i copy and re-use a slide.
  3. I did not want to pause the timeline. Some slides may need to use the timeline regardless of the sound playing.

 

The first thing I needed was a way to make a way to store what slides are visited and not. I wanted it more generic than a custom made variable for each slide, so I opted for a js Map(). This stores two items [key, value] and you can easily .get and .set values. So in the On enter-advanced action I create a tab that executes a javascript. I create the map, if it does not already exist. I then loop through with a for-lop, using cpInfoSlideCount and set the keys to "i" and the value to "notVisited". I set the initial value of i to 1 instead of 0, so that it corresponds with how CP count the slides, starting with 1 and not 0.

 

I then need a way to stop slide audio, preferably without pausing the project. Now, all buttons has this as an option. So, I created a shape-button with No action on success and ticked "Stop slide audio" under its Options. I called the button btn_stopAudio, hide it, set not to pause and to show for the entire project. So I have an invisible tool that when "clicked" will stop the slide audio. Now all you have to do, is to "click" the button using javascript.

 

//Store the button in a variable. Otherwise, the script can't reach the button, although it is set to show for the rest of the project
// querySelectorAll used this way, captures all elements in the scene whose name starts with btn_stopAudio. It stores them in an “array” starting with the canvas element (stopAudio[0].id == object_namec). The second is the object in the scene (stopAudio[1].id == object_name)

var stopAudio = document.querySelectorAll("[id^='btn_stopAudio']");
//Create the map, if it is not already created

if(!mapSlideVisited){
var mapSlideVisited = new Map();
   for(i = 1; i < cpInfoSlideCount+1; i++){
   mapSlideVisited.set(i, "notVisited");
   }
}

 

Unfortunately, the javascript executes so quickly, that it is finished running, once the slide audio begins. I therefore had to add some silence to the beginning of my sound files. I added 0,5 sek. This is non the less useful, otherwise the sound doesn't begin playing too abruptly, in my opinion. I therefore had to set a timeout for the following functions.

 

//wait 100 ms
setTimeout(function() { funcStopAudio(); }, 100);
function funcStopAudio(){
//stop sound if slide status = "visited"
if("visited" == mapSlideVisited.get(cpInfoCurrentSlide)){
   cp.clickHandler(stopAudio[1]);  //The clickHandler takes the object, not the ID of the object.
   }
}

//wait 200 ms
setTimeout(function() { funcSetSlideVisited(); }, 200);
function funcSetSlideVisited(){
//Set the slide status to "visited"
mapSlideVisited.set(cpInfoCurrentSlide, "visited");
}

 

I do hate to have to add an invisible button as a workaround to a project. But I already have one, to load an external js using cpextra. It just seems that all these workarounds should be unnecessary, and that CP should give us the tools, variables and access to make stuff like this happen. I'm hoping Project Charm will make something like this a lot easier.

 

I've tested the solution on our LMS (Moodle), and it seems to work fine. Happy to hear any thoughts you might have on the solution.

 

Here's the complete js in the advanced action. I add this to a tab in the on enter advanced action on all slides (except for the first line) that should only play slide audio on the first slide visit:

 

//This first line only goes on the first slide of the project. The rest goes on all you need the sound to stop on, for the second visit.
var stopAudio = document.querySelectorAll("[id^='btn_stopAudio']");

if(!mapSlideVisited){
   var mapSlideVisited = new Map();
   for(i = 1; i < cpInfoSlideCount+1; i++){
   mapSlideVisited.set(i, "notVisited");
   }
}

setTimeout(function() { funcStopAudio(); }, 100);
function funcStopAudio(){
    //stop sound if slide status = "visited"
    if("visited" == mapSlideVisited.get(cpInfoCurrentSlide)){
    cp.clickHandler(stopAudio[1]);
    }
}

setTimeout(function() { funcSetSlideVisited(); }, 200);
function funcSetSlideVisited(){
//Set the current slides status to "visited"
mapSlideVisited.set(cpInfoCurrentSlide, "visited");
}

 

This topic has been closed for replies.

1 reply

Inspiring
October 18, 2022

How about use mute instead?

Known Participant
October 18, 2022

Hmmm.... yes. I guess it would. And that will remove the need for the hidden button.

I'm already checking if the slide is visited or not, so I could just go (psudocode):

if(not visited){cpCmndMute = 0;}

if(visited){cpCmndMute = 1;}

 

The only drawback is that some slides may have buttons that trigger audio. I'll then have to unmute before playing the sound. These buttons can have Stop slide audio ticked off, though.

 

Thanks! I'll give it a try.

 

PS.

No harm in learning to click buttons with JS, thoug. Never know when it mught come in handy 🙂