Drag control timeline with volume crossfade

Hello again! I’m back with another problem that I haven’t been able to solve via cutting and pasting JS from similar solutions in the forum. You guys have been super helpful in the past and I really appreciate any way you can help my slow brain with this one too…

The attached doc can hopefully help explain what I’m after as visually as possible Drag_Volume_Crossfade.hype.zip (544.8 KB)

I have an animated timeline that is controlled by horizontal drag plus two sound files that I want to crossfade (currently they are both playing at the same time so apologies for the mix). I want the scene to start with Sound 1 at full volume, Sound 2 no volume, then as the user drags the timeline, Sound 1 volume should fade out and Sound 2 volume should fade in like a crossfade. This should also work in reverse when dragging in the opposite direction.

To help visualise what I mean, I’ve used text in the scene, but this won’t be on the final animation. I’ve also changed the colour of the ellipse at the start and end point of the crossfade as an extra visual aid.

So thanks in advance and apologies for still being useless at JS but I’m pretty excited about what I’m going to build with this and would just love to find a solution if possible.

Cheers!


First free tip.

The you are wanting to control a timeline of animation on it. Life is easier if you create a new timeline and work on that. Putting everything on the Main Timeline will constrain your flexibility.
Use the timelines to break things down


Possibly your best bet is to look at WebAudio API

It looks like most people use the gain property to control volume and fade.
I initially looked here

And hacked an example together.

This is not 100% how you should construct it and I suggest you have a proper look through the docs/examples out there ( unlike what I have done )

There are a lot of examples about, like this one. ( found it later on )


In this very rough example, I created the audio tags inside a rect (the Click to start innerHTML Audio Sounds rect ).

Now since you are going to read through all that stuff I suggested I will not get into that to HTML Audi / Web Audio.

But the part that will likely help is how we fade in and out at once via a drag in a single direction at any time.

Lots of problems with that if we go down the wrong path.

The gain property starts at 0 through 1.
0 = 0%, 0.5 = 50% , 1 = 100% volume.

So that is fine if we want to the current time going from left to right, we can math down so we get 0 thru 1 but your drag starts on the right and the timeline starts at 0.

We need the equivalent of two ships passing in the night.

As we drag from right to left we need one sound going down and one sound coming up at the same time and vice versa
0 < 1
0 > 1

So when we drag the timeline we use the timeline duration and current time line to calculate both gain/volume settings going in both directions.

      var cTime = hypeDocument.currentTimeInTimelineNamed('drag')  
	  var  durationTimeSecs =  Math.floor(hypeDocument.durationForTimelineNamed('drag'))
	  
	 
	 var settingOne = Math.floor(durationTimeSecs - cTime) /10
	  var settingTwo =  Math.floor(cTime)/10
	  
	    
	  gainNode.gain.linearRampToValueAtTime(  settingOne, audioCtx.currentTime + 0.3);
	 	gainNode2.gain.linearRampToValueAtTime( settingTwo, audioCtx2.currentTime + 0.3);

Any way here it is… Hope it helps and I am sure others will chip in.

Drag_Volume_Crossfade.hype 2.zip (556.7 KB)

2 Likes

Legend, thank you Mark! I’ll have a read and get my teeth into what you’ve done to see how it works.

On initial testing, I’m only hearing Sound 1 which fades out nicely but Sound 2 doesn’t fade in - this is on Firefox. Chrome and Safari don’t seem to like the audio at all but I was experiencing that before anyway.

My goal is to feature this in an iOS app which is a whole other can of worms but I’m guessing if it works well in a browser then it should convert over ok via one of your Xcode templates with ‘Allows Media Auto Play’ activated? I’m clearly over-simplifying this though so feel free to shoot me down :slight_smile:

Thanks again!

Just some feedback: by removing the ‘myAudio2.volume = 0’ line, both sounds now work and fade correctly in Firefox. I’m not getting a short burst of Sound 2 either. Chrome no sound still and Safari just a short snippet of Sound 1 then nothing. Will keep tweaking…

Ok

On My Safari it works no problem and that where I tested it, It works on my firefox.

Screenshot 2020-05-15 at 18.19.14 Screenshot 2020-05-15 at 18.19.41

But on Chrome nope.
I have the sound to start on button click. But when I look in the Chrome console I see that the Audio Context is not allowed without user interaction.

I.e in the example the audioini() function which sets up the context runs on scene load therefore not with any user interaction.

So we can take that function off scene load and have it on the first function that fires on which ever element also runs the playStart()

2 Likes

Yep, with that change it’s working for me in all browsers too now Mark, nice one!

I just need to figure out how to start the crossfade later in the animation now but will have a play and see where I get to…

Appreciate it, thanks!

1 Like

This has been very helpful to me as I am trying do something similar.

However in my case I need to trigger 4 sounds as I drag a controller around within a circle and depending on which quadrant of the circle the controller is in the sounds fade from what ever track(s) was playing to the track assigned to that quadrant.

I probably am being confusing, but any help would be appreciated.

That would be pretty neat, and I don't think too difficult to adjust @MarkHunte's solution to use 4 audio sources. The basic way I would do it is:

  1. In the audioIni() function, repeat everything done with the "2" variants of the audio code for a 3 and 4. Basically just copy every line with a 2 in it and make those versions so now you have 4 different audio setups.

  2. I'd probably remove the Scene's On Drag handler and instead use an On Drag even on an element to Control Element Position, and then run the rampdownup() javascript. In this code you would look at the position of the element like:

    var top = hypeDocument.getElementProperty(element, "top");
    var left = hypeDocument.getElementProperty(element, "left");
    

    After this, you would then need to make calculations of volume, basing on a percentage of a known width/height that is being occupied. I'll say 600x400 as an example... this will replace the "setting" variables:

    var settingOne = (top / 400);
    var settingTwo = 1.0 - (top / 400);
    var settingThree = (left / 600);
    var settingFour = 1.0 - (left / 600);
    

    Then you'd need to call the linearRampToValueAtTime() with the additional gainNode3 and gainNode4 made in step 1.

At least that would be a very simple approach to get started. Some items to consider would be restricting element bounds and perhaps making the width/height dynamically discovered instead of hard-coded.

2 Likes