// GDnD wiki example (2 of 2: AdaptiveMusicPlayer.cs, MusicStemLayers.cs) // Demonstrates: vertical layering (vertical remixing) in plain Unity, with no FMOD or Wwise. // Every stem of one piece (pad, percussion, bass, brass...) is exported at the same length // and tempo, given its own looping AudioSource, and started on the SAME dspTime with // AudioSource.PlayScheduled so the stems stay locked together. Intensity then just fades // stems in and out; nothing is ever stopped or restarted, so the layers never drift. // SetIntensity(0) = only stem 0 audible, SetIntensity(2) = stems 0, 1 and 2, and so on. // Related pages: [[unity-adaptive-music-crossfade]], [[interactive-music-techniques]], // [[unity-audiosource]] // Unity 6 (6000.x). Built-in audio only (UnityEngine.AudioModule). using UnityEngine; namespace GDnD.Audio { public class MusicStemLayers : MonoBehaviour { [Tooltip("One AudioSource per stem, quietest/most basic first. Loop on, Play On Awake off.")] [SerializeField] private AudioSource[] stems; [SerializeField, Range(0f, 1f)] private float stemVolume = 0.8f; [Tooltip("Seconds for a stem to fade fully in or out.")] [SerializeField] private float fadeSeconds = 1.5f; [SerializeField] private int startIntensity = 0; private float[] targets; private void Start() { targets = new float[stems.Length]; double startDsp = AudioSettings.dspTime + 0.2; // shared start time for every stem foreach (AudioSource stem in stems) { stem.loop = true; stem.volume = 0f; stem.PlayScheduled(startDsp); } SetIntensity(startIntensity); for (int i = 0; i < stems.Length; i++) stems[i].volume = targets[i]; // no fade at start } /// Call from game code, e.g. when enemies notice the player. public void SetIntensity(int level) { for (int i = 0; i < stems.Length; i++) targets[i] = i <= level ? stemVolume : 0f; } private void Update() { float step = stemVolume / Mathf.Max(fadeSeconds, 0.01f) * Time.unscaledDeltaTime; for (int i = 0; i < stems.Length; i++) stems[i].volume = Mathf.MoveTowards(stems[i].volume, targets[i], step); } } }