Show / Hide Table of Contents

AmbienceSource

Ambience Source

AmbienceSource is a MonoBehaviour component to play an Ambience.

How it works

How it works

When it plays an Ambience connected to the slot, each AmbienceLayer listed inside that asset gets a corresponding GameObject which runs the layer. The parent is the object with AmbienceSource.

You can clearly see them in Play Mode. (If "Layers Debugging" is still checked.)

On each child, you can inspect to see how each layer works :

  • Looping Clip (LC) : An AudioSource with Loop checked, playing a single AudioClip. It potentially has Animation attached if you use automations.
  • One Shot Program (OSP) : An AudioSource with no AudioClip assigned, stationed to be a target of PlayOneShot.
  • Timeline (TL) : A PlayableDirector with AmbienceLayer assigned, looping just that layer.

Where to attach AmbienceSource

As explained, the parent of corresponding child GameObject of each layer is the object with AmbienceSource.

Ambiences are usually positional on your scene, so it is a good idea to attach this to an object that would make the sound. Though, what determines positional or global nature of an ambience is the connected AudioSource, not AmbienceSource

Or you can create an empty object floating around the area that make sounds. e.g. an ambience representing groups of tree, you don't have any specific tree to attach.

Sometimes ambience can be global, such as constantly running wind ambience. In that case you can create an empty object at 0,0,0 and set the source to 2D.

Ambience

Ambience Source

Attach an Ambience you want to play here. The component has Play method that use an asset connected to this slot, parallels to AudioSource and AudioClip.

Additionally, the component also has a Play overload that accepts any Ambience via scripting, ignoring this slot.

Play On Awake always use Ambience connected here. It is also the most popular use case, because usually you don't manually want to tell the trees and rivers to start playing audio. Ambience is a part of scene design and you want to do as many things as possible without scripting.

Audio Source

The AudioSource field will become an output for all AmbienceLayer.

Where to attach AudioSource

The AudioSource component is usually attached right next to this AmbienceSource component, though this component does not force you to do so. Just don't forget to connect the AudioSource or it won't work.

How it works

Exact implementation differs between layer modes :

  • Looping Clip : The AudioSource acts as a template. Each layer gets a personal copy of AudioSource with inherited values from the template on play.

    The personal copy of AudioSource can have Volume, Pitch, and Stereo Pan animated live via additional Animation component, due to automations.

  • One Shot Program : Again, the AudioSource acts as a template. Each layer gets a personal copy of AudioSource with inherited values from the template on play.

    The personal copy is the target of PlayOneShot. The reason why we cannot PlayOneShot directly on the template is that pitch adjustment is shared for all shots played on that source. Each our AmbienceLayer can have different Speed (Pitch) Adjustment.

  • Timeline : The AudioSource is a binding target for every AudioTrack that PlayableDirector is directing. Timeline layers do not get a personal copy of AudioSource but directly output audio stream to it.

Useful settings

AudioSource settings (1) AudioSource settings (2)

You need not to worry about ticking Loop, it will be ticked for you when the recipient layer is on Looping Clip. AudioClip can always be left empty. Play On Awake does not matter, as we have our own Play On Awake on the AmbienceSource.

While you can set any other settings you want, there are some settings that ambience author likely wants to do :

  • Output : It is very useful to have an AudioMixerGroup exclusively for ambiences in your project. After directing all ambiences in the game to one mixer, you can then fade everything out smoothly, for example.
  • Priority : Unity has a maximum limit of concurrent audio for mixing, which at that point it will begin cutting out sounds. Priority of ambiences likely needs to be 0 (the same as BGM). Otherwise, it is possible for the player to perform attacks so rapidly that it permanently removes forest ambience...
  • Volume, Pitch, Stereo Pan : These are inherited on top of what the layer wants to do. Normally you will adjust these on Ambience adjustments, or adjust on the AmbienceLayer directly and leave these at 1, 1, and 0 respectively.
  • Spatial Blend : This starts at 2D. But ambiences are often positional (3D) so set it accordingly, unless it is an ambience that affects an entire scene.
  • Reverb Zone Mix : Unity Audio Effects is quite useful for ambiences! It can blends together your field recordings to be more cohesive. Something that maybe annoying to get reverbs like wind ambience can get different mix by this settings.
  • 3D Sound Settings : When ambience is positional, you will want to tune how close the player (AudioListener) has to be to hear the audio. Very important settings if Spatial Blend is 3D. This deserves its own page here : Advanced/3D Sound Settings.

Time Source

Choose from :

  • Unscaled : Nothing happens to the ambience when you change Time.timeScale. This is how AudioSource works by default.
  • Scaled : Ambience speed up and slow down together with Time.timeScale. (Which is weird, but I learned from both Introloop and Native Audio customers that someone will eventually ask for it...)

Implementation details is described in Advanced/Time Source.

Adjusting "master volume"

You may occasionally want to fade out the ambience instead of just stopping them. (If you fade them out a bit slower than BGM, that feels good too!)

The solution is on the Output field on your AudioSource that is connected with AmbienceSource. It let you specify AudioMixerGroup. All 3 kinds of layers can output to this mixer. After routing everything, you can then fade out on the mixer's fader, completely unrelated to Tiny Ambience now.

Scripting API

Methods you can call on AmbienceSource are as you typically expected from an audio player :

// Use the `Ambience` connected on the slot.
public void Play() { /** impl **/ }
public void Play(PlayOptions playOptions) { /** impl **/ }

// Ignores `Ambience` connected on the slot.
public void Play(Ambience a) { /** impl **/ }
public void Play(IAmbienceLayerProvider a) { /** impl **/ }
public void Play(Ambience a, PlayOptions playOptions) { /** impl **/ }
public void Play(IAmbienceLayerProvider a, PlayOptions playOptions) { /** impl **/ }

// Playback controls.
public void Stop() { /** impl **/ }
public void Pause() { /** impl **/ }
public void Resume() { /** impl **/ }

PlayOptions currently can't do anything, but they are there so I could add some special features without breaking your code in the future, like fast-forwarding to the virtual future time on start playing.

Also, IAmbienceLayerProvider is the same as Ambience right now. There is currently no other thing that could provide layers in the package.

UnityEvent targeting Play

This Play overload in particular is extra cool because if you connect UnityEvent to it, editor will draw a nice asset picker to pick your Ambience!

public void Play(Ambience a) { /** impl **/ }

It maybe useful in niche use case where one source may need to play many kinds of ambience, commanded by some other things on the scene.

[SerializeField] private UnityEvent eventTargetingPlay;

UnityEvent picker

Bonus dynamic UnityEvent variations

UnityEvent is a cool class which the invoke target is serializable. UnityEvent<T> is even cooler as the invoker can specify arguments, making it dynamic instead of static. But a caveat is that Unity can't serialize generic classes, you must declare a new subclass that is solid.

The package provide some subclassed types which pairs with those Play overloads :

public class UnityEventAmbience 
	: UnityEvent<Ambience> { /** impl **/ }

public class UnityEventAmbienceWithOption 
	: UnityEvent<Ambience, PlayOptions> { /** impl **/ }

public class UnityEventAmbienceOnlyOption 
	: UnityEvent<PlayOptions> { /** impl **/ }
In This Article
Back to top
A Unity plugin by 5argon from Exceed7 Experiments. Problems/suggestions/contact : 5argon@exceed7.com Discord Unity Forum