Go.animate sound gain of sound loaded through collection proxy (SOLVED)

Hello Everyone!

I am trying to implement fade in/out effect for sound while changing to a new background sound, and sounds are loaded using collection proxy.

for fade in/out I am using go.animate

– Code block started
local base_url = “music:/music_go#music_intro”
go.animate(base_url, “gain”, go.PLAYBACK_ONCE_FORWARD, 1, go.EASING_LINEAR, 5, 0, function ()
print(“Fade in completed”)
end)
– Code block end

However, I am getting an error “go.animate can only animate instances within the same collection.”
am I missing something or any other ways for sound fade in/out I can try with the proxy collection?

Thanks

The only solution is to call go.animate() from a script in the same collection as the sound.

Thanks, @britzl for the quick reply
as suggested, I have moved the script to the collection,

However, with the code below, the sound is played directly with full gain without any fade In.

– Code block started
local base_url = “music:/music_go#music_intro”
go.animate(base_url, “gain”, go.PLAYBACK_ONCE_FORWARD, 1, go.EASING_LINEAR, 5, 0, function ()
print(“Fade in completed”)
end)
msg.post(base_url, “play_sound”, {delay = 0, gain = 0})
– Code block end

Surround your code with three back ticks instead!

You should start by playing the sound and then animate it. Not the other way around!

I also recommend that you use sound.play() instead of using a message.

Note: sound.play() will still generate a message “under the hood”

Hello,

I tried suggested changes, but with those changes also, sound start directly with full gain without any fade-in.

local base_url = “music:/music_go#music_intro”
sound.play(base_url, { gain = 0 }) 
go.animate(base_url, "gain", go.PLAYBACK_ONCE_FORWARD, 1, go.EASING_LINEAR, 5, 0)

as sound is already loud I tried fade-out by giving animate gain value to 0, and fade out is working as expected.

go.animate(base_url, "gain", go.PLAYBACK_ONCE_FORWARD, 0, go.EASING_LINEAR, 5, 0)

only facing issue with fade-in. is that something to do with default gain value? but again with sound.play function I am providing { gain = 0 }

Hmm, ok, I think the problem is that you are basically doing two things at the same time. You start the sound and you animate it on the same frame. I think it should work if you add a tiny delay to go.animate:

local base_url = “music:/music_go#music_intro”
sound.play(base_url, { gain = 0 }) 
-- animate gain to 1 over 5 seconds after an initial delay of 0.01 seconds
go.animate(base_url, "gain", go.PLAYBACK_ONCE_FORWARD, 1, go.EASING_LINEAR, 5, 0.01)

Hello,
I tried applying some delay to function go.animation() but it didn’t help,

also to be sure I have executed go.animation() function 5 seconds after sound.play() but that is also not working as expected, on go.animation sound is played with full gain without any fade-in,

local base_url = “music:/music_go#music_intro”
sound.play(base_url, { gain = 0}) 
-- add delay with timer for go.animate this should start gain animation 5 second after sound.play
self.loop_timer_id = TIMER.add(self.timer_context, 5, function ()
	self.loop_timer_id = -1
	go.animate(base_url, "gain", go.PLAYBACK_LOOP_FORWARD, 1, go.EASING_LINEAR, 5, 0.01)
end)

what else I can look into, or debug to confirm the issue?

Ok, I figured it out…

sound.play(base_url, { gain = 0})

This will set the gain to 0 for that specific instance/voice of the sound. When you use go.animate() you animate the gain of the all playing voices, and the value animated is the one on the sound component, not on the individual voices.

What you should do is this:

local sound_url = "#sound"
-- play one instance/voice of the sound
sound.play(sound_url)
-- set the gain of all active playing voices of the sound
sound.set_gain(sound_url, 0)
-- animate the gain of all active playing voices of the sound
go.animate(sound_url, "gain", go.PLAYBACK_LOOP_FORWARD, 1, go.EASING_LINEAR, 5, 0)

is the one on the sound component, not on the individual voices.

Incorrect.
We do update the values of the individual voices, as seen here.

The main problem here is that sound.play() is asynchronous. So the sound will actually play “a little later”, when the messages are dispatched.

Some further explanations: go.animate() is based on the go.get() mechanics, and together with the fact that the sound component may have many voices playing, we decided to return the component’s current gain value (as opposed to any of the voice’s gain). In your example, that gain value is still 1, since the sound didn’t actually start yet. And then you’ll animate from 1 to 1.

The workaround from @britzl will work though.

Thank you @britzl and @Mathias_Westerdahl
Suggested change of sound.play(sound_url) and then sound.set_gain(sound_url, 0)
is working as expected for fade-in.