As i mentioned before in some posts GSAP has a timeline that controls all animation. And probably Storyline uses that timeline for its animation too. As i didnot find a way to control Storyline's timeline i made a sample showing how perfectly and easily GSAP's timelines control the speed of animations.
I have read several posts about GSAP, I did the test with the example of speeding up audio and video, however I would like to know if you have any update about the timeline speeding up as well.
When you plan your project with GSAP, and ensure all is build with GSAP instead of using default Storyline transitions and animations.... you can use GSAPs timeline functions and global timescale functionality to speed up or slow down the complete setup. The newest version of GSAP 3.11.1 has a new function called gsap.context() that makes it even easier to maintain and control behaviour of all your gsap animations.
As now all this still isnot possible with the default Storyline timeline and animations...i suspect they use GSAP internally for it, but i tried controlling it and that doesnot work. Mentioned this to Articulate though and hope they implement it in the near future.
Another great new feature in the latest gsap version is gsap.matchMedia()
This feature gives you the option to adapt animations based on screensize and resizing. Whether and how this works in Storyline360 ( Storyline being not responsize ) i have to test.
var allAudios = document.getElementsByTagName("audio"); for (var i = 0; i < allAudios.length; i++) { allAudios[i].playbackRate = 1.25; }
slow down audio
var allAudios = document.getElementsByTagName("audio"); for (var i = 0; i < allAudios.length; i++) { allAudios[i].playbackRate = 0.5; }
Audio background
//load the scripts dynamically into the head of the document
function add_line() { var line = document.createElement("audio"); var head=document.getElementsByTagName('body')[0]; line.type = "audio/mp3"; line.src=""; line.id="bgSong" ; line.autoplay = true; line.loop = true; head.appendChild(line); }
//but we only want to add these once! if(document.getElementById('bgSong')==null){ add_line(); var audio = document.getElementById('bgSong'); audio.volume = 0.5; }
play audio background
var audio = document.getElementById('bgSong'); audio.src="story_content/external_files/MusicaDiversidad.mp3"; audio.load(); audio.play();
Hope you find the solution in the java so that it does not take the background audio speed, also I would like the speed respect in the other slides, because I keep continuing the slides I need to set up the velocity in each one.
I wish I had knowledge of java, but this time it's beyond my knowledge.
What you did wrong is looping all the audios in the Storyline and changing their playback speed.
A for loop basically acts on all elements it finds. To fix that you need to only act on your embedded audio. How to do that ? Well several solutions...for one you can check the name of the audio...if that is the one you want changed....act.
for (var i = 0; i < allAudios.length; i++) { allAudios[i].playbackRate = 0.25; }
Like this...it changes th playbackRate of all your audios...
for (var i = 0; i < allAudios.length; i++) { if(mp3Name !="MusicaDiversidad.mp3"){ allAudios[i].playbackRate = 0.25; } }
And like this it changes all audios except your background music. To get this working we still need to know the names of our mp3s. Especially because Storyline generates a custom name for embedded audio.
Like this when checking for allAudios[i].url: .../story_content/external_files/MusicaDiversidad.mp3 .../story_content/5UxkXXG1RPh_44100_48_0.mp3
Also you notice the folder structure for embedded and external audio is different.
So splitting the url in an array and getting the last value of that array gives us the proper names. Then this works.
for (var i = 0; i < allAudios.length; i++) { var mp3URL = allAudios[i].src; var tmpArr = mp3URL.split("/"); mp3Name = tmpArr[tmpArr.length-1]; audioNamesArray.push(mp3Name); console.log(mp3Name+" pushed into ["+audioNamesArray+"]"); if(mp3Name !="MusicaDiversidad.mp3"){ allAudios[i].playbackRate = 0.25; } }
Woooooow that's great news... Thank you very much Math, you don't know how grateful I am. It is that I was taking several post codes on the subject and so I did not know how to configure it correctly, what course I need to take to learn java.
One more question, is there any way to add in the code that respects the speed of playback from one slide to another, because every time I advance to the next slide the user would have to click on speed +/-, and we need it because this configuration is for people with disabilities and should be as few clicks as possible .
Create a custom variable. In this case 'audioSpeed', a numeric variable
Its default value will be 1. Then we go to the Javascript ( PS. it is Javascript, Java is something completely different ;-)
In this case we cannot add all of the script simply to the Maximo and Minimo buttons as you want the audio to be speed up or down on next pages when a user set it earlier. So we need 2 changes...one on the buttons that saves the chosen speed to the variable 'audioSpeed' and one on the start of every slide that sets the speed of the audio. Let us first change the buttons Maximo and Minimo.
This is the code needed on Minimo. // player is your StorylinePlayer and GetPlayer() is a command to connect to it. var player = GetPlayer();
// the audiospeed we want var audioSpeed = 0.25;
// Now we can set the Storyline variable player.SetVar("audioSpeed",audioSpeed);
And offcourse in your loop like this. allAudios[i].playbackRate = audioSpeed;
On Maximo its the same except for the different speed.
Change this, and test it :-)
If you have that working as planned, the next step is getting it working on start of every next slide. You could add it to a Masterslide and have it happen on every slide that uses that Masterslide, but for now im showing it just on start of the existing slides.
We start with adding a Javascript trigger that gets executed When the timeline starts.
The code we need now is this. var allAudios = document.getElementsByTagName("audio"); var audioNamesArray = []; var mp3Name;
// player is your StorylinePlayer and GetPlayer() is a command to connect to it. var player = GetPlayer();
// Now we can get the Storyline variable var audioSpeed = player.GetVar("audioSpeed");
for (var i = 0; i < allAudios.length; i++) { var mp3URL = allAudios[i].src; var tmpArr = mp3URL.split("/"); mp3Name = tmpArr[tmpArr.length-1]; audioNamesArray.push(mp3Name); console.log(mp3Name+" pushed into ["+audioNamesArray+"]"); if(mp3Name !="MusicaDiversidad.mp3"){ allAudios[i].playbackRate = audioSpeed; }
}
Notice GetVar to get a Storyline variable into Javascript.
Math, I saw the storyline project very quickly and my brain exploded at a surprising result. Let me interact with this, but again, verily thank you very much...
HI MATH; I'm having problems with the content, but it's weird because when I view the story.html on my computer the button speed works, but when I upload it on an lms it doesn't work. I leave you here my file and the link of it in the lms to know what I am doing wrong.
I know this happened before... Mark Ramsey figured out why i do believe.... something to do with selector in Storyline not correct when published on the LMS. In this post i believe... https://community.articulate.com/discussions/articulate-storyline/variable-playback-speed On page 4 it states why...getting to the audio file by using getElementsByTagName returns zero indexes on a LMS.
A direct selector to the proper folder the audio is in should work. As this always depends on the LMS you use...i see if i can find a solution.
PS. The invitation to Scorm Cloud is not valid anymore.
I do think that getting the 'getElementsByTagName' so the part where all audio used in the Storyline is gathered... out of the MasterSlide and into the main HTML of the published output might work.
I thought this might work...but on Review it still blocks access ( CORS-error...so thats to blame Articulate ) to the html. Allthough all should be on the same domain... well you can test this on your LMS... not sure it will work...can't test it myself at this point.
Thank you Math, hope you can found a solution, also I asked Mark if he knew something new.
I was so secure about the code, and now I need to do 13 materials accessible with these functions at the end of the week, I am going to cry if we don't found a solution. :P
i have tested a .story file with some audios - and there is an interesting result
if I start the published files with file:// protokoll, all audios are append at the end of the story.html
BUT, if I start the same files with https:// from my webserver (no lms server), no <audio> elements are appended - so the js query cannot find any audio
it seems articulate uses a pure javascript solution - without dom - to play audio from webserver
i will invest some more hours to learn the exact method how storyline playing audios from webserver
one idea - you would have to prevent storyline from switching to web audio
for this you have to patch "html5/lib/scripts/bootstrapper.min.js"
replace return window.AudioContext||window.webkitAudioContext||null with return /*window.AudioContext||window.webkitAudioContext||*/null
=> the player gets always the info "no web audio" available, use "normal audio"
important: save your patch js library - which is exacly for one storyline version - and copy the file after every publish
result on a https:// webserver
if you want the patched file for all your courses you could overwrite the library file in the programm folder - so a manual overwrite after every publish should no longer be necessary (just not tested !)
Wouldn't a Javascript based solution like this... https://codepen.io/Rumyra/pen/qyMzqN/ not be far more easier ( and with more possibilities ) for users ?
34 Replies
Hi Math,
I have read several posts about GSAP, I did the test with the example of speeding up audio and video, however I would like to know if you have any update about the timeline speeding up as well.
Greetings!
When you plan your project with GSAP, and ensure all is build with GSAP instead of using default Storyline transitions and animations.... you can use GSAPs timeline functions and global timescale functionality to speed up or slow down the complete setup. The newest version of GSAP 3.11.1 has a new function called gsap.context() that makes it even easier to maintain and control behaviour of all your gsap animations.
As now all this still isnot possible with the default Storyline timeline and animations...i suspect they use GSAP internally for it, but i tried controlling it and that doesnot work. Mentioned this to Articulate though and hope they implement it in the near future.
Another great new feature in the latest gsap version is gsap.matchMedia()
This feature gives you the option to adapt animations based on screensize and resizing. Whether and how this works in Storyline360 ( Storyline being not responsize ) i have to test.
Thank you very much Math,
I have a conflict with the background audio help, since also within my functionalities I added to be able to speed up the voiceover audio (https://community.articulate.com/discussions/articulate-storyline/can-you-speed-up-the-player-in-articulate-360?page=3), however, when I do this, it also speeds up my background audio.
Can you help me to find the solution in the java so that it does not take the background audio speed.
https://community.articulate.com/discussions/articulate-storyline/continuous-playing-background-music-over-all-slides-in-storyline360
My code:
speed up audio
var allAudios = document.getElementsByTagName("audio");
for (var i = 0; i < allAudios.length; i++) {
allAudios[i].playbackRate = 1.25;
}
slow down audio
var allAudios = document.getElementsByTagName("audio");
for (var i = 0; i < allAudios.length; i++) {
allAudios[i].playbackRate = 0.5;
}
Audio background
//load the scripts dynamically into the head of the document
function add_line() {
var line = document.createElement("audio");
var head=document.getElementsByTagName('body')[0];
line.type = "audio/mp3";
line.src="";
line.id="bgSong" ;
line.autoplay = true;
line.loop = true;
head.appendChild(line);
}
//but we only want to add these once!
if(document.getElementById('bgSong')==null){
add_line();
var audio = document.getElementById('bgSong');
audio.volume = 0.5;
}
play audio background
var audio = document.getElementById('bgSong');
audio.src="story_content/external_files/MusicaDiversidad.mp3";
audio.load();
audio.play();
I hope you can help me
Thanks
Please add a sample then i check it out.
Hi Math,
Hope you find the solution in the java so that it does not take the background audio speed, also I would like the speed respect in the other slides, because I keep continuing the slides I need to set up the velocity in each one.
I wish I had knowledge of java, but this time it's beyond my knowledge.
Thanks for the support!
What you did wrong is looping all the audios in the Storyline and changing their playback speed.
A for loop basically acts on all elements it finds. To fix that you need to only act on your embedded audio. How to do that ? Well several solutions...for one you can check the name of the audio...if that is the one you want changed....act.
for (var i = 0; i < allAudios.length; i++) {
allAudios[i].playbackRate = 0.25;
}
Like this...it changes th playbackRate of all your audios...
for (var i = 0; i < allAudios.length; i++) {
if(mp3Name !="MusicaDiversidad.mp3"){
allAudios[i].playbackRate = 0.25;
}
}
And like this it changes all audios except your background music.
To get this working we still need to know the names of our mp3s. Especially because Storyline generates a custom name for embedded audio.
Like this when checking for allAudios[i].url:
.../story_content/external_files/MusicaDiversidad.mp3
.../story_content/5UxkXXG1RPh_44100_48_0.mp3
Also you notice the folder structure for embedded and external audio is different.
So splitting the url in an array and getting the last value of that array gives us the proper names.
Then this works.
for (var i = 0; i < allAudios.length; i++) {
var mp3URL = allAudios[i].src;
var tmpArr = mp3URL.split("/");
mp3Name = tmpArr[tmpArr.length-1];
audioNamesArray.push(mp3Name);
console.log(mp3Name+" pushed into ["+audioNamesArray+"]");
if(mp3Name !="MusicaDiversidad.mp3"){
allAudios[i].playbackRate = 0.25;
}
}
Kind regards,Math
Woooooow that's great news...
Thank you very much Math, you don't know how grateful I am.
It is that I was taking several post codes on the subject and so I did not know how to configure it correctly, what course I need to take to learn java.
One more question, is there any way to add in the code that respects the speed of playback from one slide to another, because every time I advance to the next slide the user would have to click on speed +/-, and we need it because this configuration is for people with disabilities and should be as few clicks as possible .
Save the speed as a Storyline variable...and get that at next slides ;-)
But how, because the speed is on the java code, how can I add a variable to respect the speed?
In easy to follow steps...
Create a custom variable. In this case 'audioSpeed', a numeric variable
Its default value will be 1. Then we go to the Javascript ( PS. it is Javascript, Java is something completely different ;-)
In this case we cannot add all of the script simply to the Maximo and Minimo buttons as you want the audio to be speed up or down on next pages when a user set it earlier. So we need 2 changes...one on the buttons that saves the chosen speed to the variable 'audioSpeed' and one on the start of every slide that sets the speed of the audio. Let us first change the buttons Maximo and Minimo.
This is the code needed on Minimo.
// player is your StorylinePlayer and GetPlayer() is a command to connect to it.
var player = GetPlayer();
// the audiospeed we want
var audioSpeed = 0.25;
// Now we can set the Storyline variable
player.SetVar("audioSpeed",audioSpeed);
And offcourse in your loop like this.
allAudios[i].playbackRate = audioSpeed;
On Maximo its the same except for the different speed.
Change this, and test it :-)
If you have that working as planned, the next step is getting it working on start of every next slide. You could add it to a Masterslide and have it happen on every slide that uses that Masterslide, but for now im showing it just on start of the existing slides.
We start with adding a Javascript trigger that gets executed When the timeline starts.
The code we need now is this.
var allAudios = document.getElementsByTagName("audio");
var audioNamesArray = [];
var mp3Name;
// player is your StorylinePlayer and GetPlayer() is a command to connect to it.
var player = GetPlayer();
// Now we can get the Storyline variable
var audioSpeed = player.GetVar("audioSpeed");
for (var i = 0; i < allAudios.length; i++) {
var mp3URL = allAudios[i].src;
var tmpArr = mp3URL.split("/");
mp3Name = tmpArr[tmpArr.length-1];
audioNamesArray.push(mp3Name);
console.log(mp3Name+" pushed into ["+audioNamesArray+"]");
if(mp3Name !="MusicaDiversidad.mp3"){
allAudios[i].playbackRate = audioSpeed;
}
}
Notice GetVar to get a Storyline variable into Javascript.
Thats it.
Math, I saw the storyline project very quickly and my brain exploded at a surprising result.
Let me interact with this, but again, verily thank you very much...
HI MATH;
I'm having problems with the content, but it's weird because when I view the story.html on my computer the button speed works, but when I upload it on an lms it doesn't work.
I leave you here my file and the link of it in the lms to know what I am doing wrong.
Link:
https://app.cloud.scorm.com/sc/InvitationConfirmEmail?publicInvitationId=20ac6d0f-e01c-4187-bfe7-033242c98617
I know this happened before... Mark Ramsey figured out why i do believe.... something to do with selector in Storyline not correct when published on the LMS. In this post i believe...
https://community.articulate.com/discussions/articulate-storyline/variable-playback-speed On page 4 it states why...getting to the audio file by using getElementsByTagName returns zero indexes on a LMS.
A direct selector to the proper folder the audio is in should work. As this always depends on the LMS you use...i see if i can find a solution.
PS. The invitation to Scorm Cloud is not valid anymore.
I do think that getting the 'getElementsByTagName' so the part where all audio used in the Storyline is gathered... out of the MasterSlide and into the main HTML of the published output might work.
I thought this might work...but on Review it still blocks access ( CORS-error...so thats to blame Articulate ) to the html. Allthough all should be on the same domain... well you can test this on your LMS... not sure it will work...can't test it myself at this point.
Bad news, still not working :(
I will test it out myself on ScormCloud one of these days...
Thank you Math, hope you can found a solution, also I asked Mark if he knew something new.
I was so secure about the code, and now I need to do 13 materials accessible with these functions at the end of the week, I am going to cry if we don't found a solution. :P
i have tested a .story file with some audios - and there is an interesting result
if I start the published files with file:// protokoll, all audios are append at the end of the story.html
BUT, if I start the same files with https:// from my webserver (no lms server), no <audio> elements are appended - so the js query cannot find any audio
it seems articulate uses a pure javascript solution - without dom - to play audio from webserver
i will invest some more hours to learn the exact method how storyline playing audios from webserver
Interesting 😉 they keep surprising me
new results: if web audio is available, no <audio> elements are added to the DOM

to check: i have disabled "web audio" in firefox
result:
now enable "web audio"
https://caniuse.com/?search=web%20audio
https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API
Hi Jürgen,
¿Where do I need to change this code to function the speed audio?
one idea - you would have to prevent storyline from switching to web audio
for this you have to patch "html5/lib/scripts/bootstrapper.min.js"
replace
return window.AudioContext||window.webkitAudioContext||null
with
return /*window.AudioContext||window.webkitAudioContext||*/null
=> the player gets always the info "no web audio" available, use "normal audio"
important: save your patch js library - which is exacly for one storyline version - and copy the file after every publish
result on a https:// webserver
if you want the patched file for all your courses you could overwrite the library file in the programm folder - so a manual overwrite after every publish should no longer be necessary
(just not tested !)
Wouldn't a Javascript based solution like this...
https://codepen.io/Rumyra/pen/qyMzqN/
not be far more easier ( and with more possibilities ) for users ?
but how can you find in the memory the timeline "web audio" object?
new idea
copy
to
story.html + index_lms.html
or better at the end of the user.js
the two lines cannot be added to the internal storyline javascript - it's to late