How to call javascript functions from other functions (multiple times in a row)?

Hello Hype forum friends!

I’m trying to trigger functions (scene changes in this case), from other functions.
More specifically, I’m trying to create a chain reaction of functions so that scenes are automatically triggered to switch from one to the next (thereby potentially creating an endless loop of switching scenes from one button click).

I’ve looked at hype forum posts like this one and this one.

Even after looking at these posts I am still not able to make this work.
Can someone help me understand how to make this happen?

Here is a super simple example of what I was hoping would work:
callMultipleFunctions.zip (33.0 KB)

In this example, when I look at the console.logs, it seems like I am successfully moving from function to function. But the scene changes that I’m trying to make happen are not being triggered (only the first scene change works!).

How would I change the code to make it work?

Thanks so much!

Hi Raleigh!

I would take another route - only requires code in one function & location - You won’t need to have every scene require its own special code…

In this demo I use the “setInterval” method inside the “switchToScene” function to do all the work (please see code below). The function is triggered by the “Start sequence” button.
sceneSwitch_setInterval.hype.zip (26.4 KB)

Also, I did not see any sort of timing mechanism in the code of your example project that controlled how long a scene remained on-screen before the next transition. With the “setInterval” method this is its “raison d’être”.

The timing is in milliseconds. In the demo I have it set to 2000 (2 seconds) - You can make the sequence timing run faster or slower as You wish, of course. Note that this sequence timing is distinct from the actual transition timing itself (1.1 seconds in this demo).


function switchToScene

var counter = 2; // first use of "counter" will be to show "scene2"
var totalScenes = 3; // only consider the # of scenes we want to view as part of the "sequence"
	
hypeDocument.showNextScene(hypeDocument.kSceneTransitionPushRightToLeft, 1.1);
// i.e. go to "scene1"
		
var sceneTransitions = setInterval(switchScenes, 2000);
// 2000 milliseconds (2 secs) is our interval before the next transition occurs
	
function switchScenes() {
	if (counter <= totalScenes) {
		hypeDocument.showSceneNamed('scene'+ counter, hypeDocument.kSceneTransitionPushRightToLeft, 1.1);
		counter++;
	} else if (counter > totalScenes) {
		counter = 1;
		hypeDocument.showSceneNamed('scene'+ counter, hypeDocument.kSceneTransitionPushRightToLeft, 1.1);
		counter++;
		}
	}
		
	//clearInterval(sceneTransitions);

Note: “clearInterval” will be needed if You wish to turn off this setInterval code; most likely using another event and/or function such as a button click, etc. I have included it here for future reference.

Alternatively, this can be achieved without the use of external javascript code. You can drop an action along the main timeline for each of the scenes you want this to occur.

Thanks so much for taking a look at this Jim!
I really like how you have done this with only one function.

In the full project, the timing of the switch will be determined by song length.
A song will play. And at end of the song will trigger a check to see whether the AutoPlay button is on or not. If it is on, then it will switch to the next scene and play the next song, etc., etc.

I think I’m still wondering how this can be done in Hype though as just a general question. If I really wanted to split these into different functions, then could it be done with the right syntax?

Thanks so much for the input Pete!

I would have loved to use native Hype actions, but in my actual project, the scene switching will be triggered by the end of an audio file. As a result, I think I’m stuck with having to make some custom javascript to make it work. Thankfully, I’m using howler.js, which provides an easy onend() function.

Thanks again!

I see, well what ever works to get the job done. :slight_smile: I just didn’t understand the complexities involved with your project seeing as though this could be a native thing boy was I wrong :wink:

OK - now I have a better idea of what You are after…

AudioSceneTrigger_JHSv1.hype.zip (262.3 KB)

Overview
Scene Loads > Song plays > Song ends > Transition to the next Scene…

Note: No need for “howler.js” for this particular situation.


Once again we are going for simplicity & compactness - only one function is needed (“sceneAudio” - please see bottom of this post). I am not trying to provide a complete solution here - only a concept. In the Demo everything gets rolling immediately with an “On Scene Load” handler but the initial trigger can instead be user initiated (button, etc.) - just haven’t bothered with that here.

You can easily write your own “auto-play” in Hype using a variable… a Scene plays the music but does not advance to the next Scene (e.g. autoplay = false) or runs all the Scenes (autoplay = true). This functionality is not included in the attached Demo.

The General Concept is we match the Scene Name with the Audio tag iD and take it from there.


Audio tags - in the Demo select the rect (Scene01) or ellipse (Scene02) and view the innerHTML:

Scene01

<audio id="audio_01" width="400" preload="auto">
    <source src="${resourcesFolderName}/audio_01.mp3" type="audio/mpeg">
 </audio>

Scene02

<audio id="audio_02" width="400" preload="auto">
     <source src="${resourcesFolderName}/audio_02.mp3" type="audio/mpeg">
</audio>


"sceneAudio" function - called by the “On Scene Load” handler

The “slice” method as used here extracts the last 2 characters of the Scene Name (e.g. "01 or “02”) to match the audio tag IDs (e.g. “audio_01” or “audio_02”).

var whatScene = hypeDocument.currentSceneName();
whatScene = whatScene.slice(-2);
whatScene = "audio_" + whatScene;
	
var myAudio = document.getElementById(whatScene); 
myAudio.play();

myAudio.onended = function() {
   hypeDocument.showNextScene(hypeDocument.kSceneTransitionPushRightToLeft, 1.1)
};
1 Like

Additional Notes:
An example of simplifying things more > put all your audio tags in a Persistent Symbol (“Add to All Scenes” option); that way You have just one location to edit and do not need to create an element for every Scene just to hold an Audio tag. This is a real time saver if You have many Scenes.

Note: In the attached Demo below this Persistent Symbol (rectangle) is placed just outside the Scenes’ boundary on the right hand side, vertically centered.

Now the only thing You need to do to create this sequence of Scenes & music is select the “On Scene Load” handler for each Scene and choose: Run JavaScript > sceneAudio().

AudioSceneTrigger_JHSv2.hype.zip (263.0 KB)

1 Like

Hi Jim,

Thanks so very much for your input here!

So, now I’m faced with a quandary:

I love how dry your code solution is.
But (unfortunately, or fortunately, can’t decide which, lol) I now have it working perfectly with my initial setup. So, I’m really happy that it’s working, but I’m quite certain that my solution is not nearly as elegant as yours. So, now I’ve got to think - do I want to keep my working code as-is and move on to building in my next functionality (ie displaying audio track time, displaying audio track length, and possibly audio scrubbing with a dragbar). Or, do I want to redo my mockup with your code in order to sleep soundly knowing that a nice dry solution is under the hood?

I’ve included my finished mockup so you can see exactly how all of this is supposed to work along with navigation and regular audio controls (play, pause, stop).

In general, I would have loved to have been able to just use Hype’s native audio controls (and thereby avoided howler.js), but I know at the very least I would need to be able to pause. And since Hype can’t do that (yet! I hope future Hype versions will have more robust audio control, :slight_smile: ), seemed like an audio library like howler.js was the only way to go.

Here is the working mockup with full functionality:

autoPlayTest6.zip (237.5 KB)

In your opinion, is the example above working well enough to keep my code as-is? Or if this was you, do you think there is enough benefit (with your cleaner code) to refactor mine with your solution?

Again, thanks so much for your time and input with this. Super helpful and learning a ton!

Hi Raleigh!

I won’t be able to respond tonight to your last post - but…

Here is a file for you inspection that has many of the basic features you have previously described and are in your example Hype project (in terms of operational function):

AudioSceneTrigger_JHSv4.hype.zip (274.5 KB)

“Auto Play” option, “Play~Pause” button, “Auto Scene” advance, “Manual Scene” change.

Have a go with it and see what You think. I will be in touch, here, tomorrow to go over this project file and your other questions

Hi Jim,

I can’t thank you enough for you help with all of this!
The way you used persistent symbols in your example is awesome.

The blessing and the curse for me at this point is that the code I was working on originally is now working absolutely perfectly (albeit less elegantly than I’d probably like).

Here is my most recent version :).

I now have all of the various audio and nav buttons working exactly the way they should. Tricky thing is, it took a sizable amount of tweaking to get the exact behavior I needed from all of the various controls, and I find myself taking a big gulp at the notion of getting a totally new setup up and running (despite how awesome of a setup it is).

The other huge factor is that I’m on a relatively tight time frame with this project and I’m afraid incorporating restructured code from the ground up is going to set me back time-wise farther than I can afford.
As a result, I’m inclined to keep my current code as-is and finish it off with the last functionality I need for the client. So, now I’m faced with the task of pressing on and building out the code in its current working state (for better or worse).

I hope you don’t feel like any time has been wasted with the code examples you helped me out with. Looking at your examples was hugely instructional and I had a number of important lightbulbs go off (so thank you again for that. I appreciate the help, and none is taken for granted).

All of that having been said, here is where I’m currently at:

Tonight I figured out how to display the duration of the currentSong in the innerHTML of an invisible box on each scene. I’m hoping I can use this knowledge to figure out how to display the currentTime (in another box) as the song plays using the howler.js’s seek() method, as well as how to add 2 buttons to skip the audio ahead or behind by 10 or 15 seconds.

Honestly, what I feel I am going to have a sizable challenge with is how to add an audio scrubber slider (and possibly a volume slider). In that regard, if you have the time and inclination, would you have any input on how I could construct an audio scrubber and incorporate it into my current working code?

In my research I came across your excellent post on building a volume slider. Could your volume slider setup be used to control the audio position like a scrubber?

Would so appreciate any input you might have.
It’s a huge help, thx again!

Hi Raleigh!

Well, You have anticipated my response. You have everything working so I would stick with it.

However, there was not anything in the howler.js code (as You have implemented its feature set) that could not be done with standard HTML & JavaScript - and You have my example project for future reference.


As regards the audio scrubber there are two (possibly three) approaches:

First approach: use the browser's "default" audio player - which You can control the functionality of (play, pause, etc.) with JavaScript using an audio tag as demo'd in the project below:

AudioSceneTrigger_JHSv5.hype.zip (119.7 KB)

However, each browser presents a different default look, size and positioning relative to the containing element (try the attached demo with different browsers to see what I mean). The height is fixed for a given browser's "default" browser audio player but You can control the width in the audio tag - example: style="width:500px;"; though when You shorten the "default" player too much it will lose functionality (e.g. volume control) due to the reduced real estate for the controls.

So You have limitations in how You present your page. If You go the browser "default" player route I would recommend placing it at the bottom of the page where the variation of different browser presentations is less noticeable. (As per my attached demo.)

Safari & Firefox have the most discrete default appearance. Chrome & Opera are way too much in-your-face.


Second approach: If You want a high level of control of your player's appearance, I'd say You are better off rolling your own, but of course have to write the functionality. The "volume slider" thread you sited in your last post would definitely be a good place to start for the concept of creating an audio scrubber~playhead. Try searching this forum for other player interfaces. (In this instance searching for "video" instead of "audio" player might yield better results... same concepts.)


A third approach... the Shadow DOM... to help You wrangle the default look of the "native" browser interface. Never have delved into this environment, but it looks interesting - one site discussing it is here. Google "Shadow DOM" to explore further. I have no experience to offer an informed opinion or give advice.


And now I will leave this discussion - with Best Wishes in your endeavor. :pray:

1 Like

Great, thanks again for your very helpful input Jim!

I think I will need to take the second approach you mentioned as I will need more control over the look and feel of the controls (and browser consistency). Looks like I will need to build it from scratch. I will indeed search for ‘video’ instead of ‘audio’ - I think I’ve scoured just about every one of the ‘audio’ ones already, lol.

Great to know what my options are though - have never heard of the Shadow DOM approach. Looks interesting - I will take a look when I have a moment.

Thanks again for sharing your expertise, all the best!

1 Like

Hi Raleigh!

I noticed an error in the “Volume Slider” example Hype project. Please use this one instead:
VolumeControlTimeline_JHSv2.hype.zip (274.6 KB)

Also - as long as I’m here - please see this link regarding getting & setting of audio time (HTML DOM).

You will want your audio scrubber to be set up as a percentage (as is the Volume slider), so the scrubber will self-adjust to the length of whatever audio track You are working with; which means of course You will need to know the duration of the audio track… (HTML DOM).

Thanks very much!
I will used the updated ‘Volume Slider’ for reference instead.

I think I’ve found a great tutorial to reference as well.
Going to try and implement it tomorrow.
It’s a really paired down example with only a play/pause button and progress bar slider.
Crossing my fingers!

1 Like

JimScott,

Thanks again for your great input a while back!
I had to switch gears to another feature and now I’m circling back around to this audio player/scrubber. The good news is, I was able to reverse engineer a video scrubber Hype example that works great!

Tricky thing is, it’s done with the standard web audio API and not howler.js. I tried to incorporate this audio player/scrubber into the main website and not surprisingly, it worked in an isolated way, but not in an integrated way with what I have already built. Unfortunately I am needing to stick with howler.js for the main website since I am using it for some other features and it’s pretty well intrenched now, otherwise, I’d consider retooling the site to work with standard HTML and JavaScript.

So, I’m now attempting to get the audio player/scrubber I built to get with howler.js.

Frustratingly, once I attempted to replace the web audio stuff with howler.js, some aspects work and some don’t. In particular, regular play() and pause() work great, but for the life of me I can’t get howler.js’s seek() method to work! Don’t know why. The seek() method (with no arguments) is, from what I understand, supposed to return the current time of the audio. Do you (or anyone else!) know what I can do to get this simple example to work with howler.js?

Here:
Audio Scrubber W Web Audio API.zip (1.8 MB)

is my working example that incorporates the web audio API, and

Here:
Audio Scrubber w Howler js.zip (2.2 MB)

is my (only partially working) example with howler.js. They are almost identical, but one difference worth mentioning is that the web audio example loads the audio with a rectangle shape’s innerHTML placed in the scene, whereas the howler.js example loads the audio from a function that creates a new Howl audio object (like it does in the main website).

Do you (or anyone) have any ideas at all with what I’m missing?
I feel like if I could figure out how to get that howler seek() function to work, than I’d be good to go! I’d so appreciate any help or input on how to get my audio/scrubber working with howler.js.

All the best and many thanks!!

Regarding the “Web Audio” & Howler" ZIP files: The downloads only contained PNG files.

Ah, many apologies!!
Here are the correct files that I intended to attach:

Update:

I have a friend across town that is great with code - although he is not a Hype user, I emailed him outlining the problem and he made a suggestion of how to configure things to get seek() to work (that was who the screen shots were for when I mistakenly attached the png’s - again, so sorry about accidentally uploading those instead of the intended Hype files).

Great news is, with his changes, I now have the timeDisplay working!
So, seek() is now working to an extent.

Unfortunately, the Scrubber is not only not moving when the audio is plays, but when the Scrubber button is moved, a console error is displayed that says:
Error in undefined: ReferenceError: Invalid left-hand side in assignment

Any thoughts at all what this might mean or how to get the Scrubber working?
It’s so puzzling considering the web audio API version and this howler.js version are basically identical. Seems the problem has to be in the changeAudioTimeBasedOnScrubber or the setupAudioToScrubberSync functions, but they are so alike. Seems like they should work the same way.

Here is the updated Hype file - do you have any thoughts at all? Thank you so much for any input you might have.

https://www.dropbox.com/s/kpvnu6vhan2w5vt/AudioScrubberHowler.hype.zip?dl=0

sunny day :slight_smile:

2 Likes