<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Playback States on DAD 424 Sound Design for Games</title><link>https://dsu-digital-sound-design.github.io/f-25-dad-424-sound-design-for-games/tags/playback-states/</link><description>Recent content in Playback States on DAD 424 Sound Design for Games</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Wed, 12 Jun 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://dsu-digital-sound-design.github.io/f-25-dad-424-sound-design-for-games/tags/playback-states/index.xml" rel="self" type="application/rss+xml"/><item><title>How to Use Playback States to Control Audio Flow</title><link>https://dsu-digital-sound-design.github.io/f-25-dad-424-sound-design-for-games/lectures/week-14/playback-states/</link><pubDate>Wed, 12 Jun 2024 00:00:00 +0000</pubDate><guid>https://dsu-digital-sound-design.github.io/f-25-dad-424-sound-design-for-games/lectures/week-14/playback-states/</guid><description>When implementing dynamic audio in Unity using FMOD, you often need to know exactly what an audio event is doing at any given moment. Is it playing? Is it stopping? Has it already stopped?
This is where Playback States come in.
In this tutorial, we will explore what FMOD Playback States are, how to access them in your C# scripts, and how to use them to fix a common audio bug: the &amp;ldquo;stuttering&amp;rdquo; sound effect on UI sliders.</description><content>&lt;p>When implementing dynamic audio in Unity using FMOD, you often need to know exactly what an audio event is doing at any given moment. Is it playing? Is it stopping? Has it already stopped?&lt;/p>
&lt;p>This is where &lt;strong>Playback States&lt;/strong> come in.&lt;/p>
&lt;p>In this tutorial, we will explore what FMOD Playback States are, how to access them in your C# scripts, and how to use them to fix a common audio bug: the &amp;ldquo;stuttering&amp;rdquo; sound effect on UI sliders.&lt;/p>
&lt;h2 id="what-is-a-playback-state">What is a Playback State?&lt;/h2>
&lt;p>A Playback State is a tool from FMOD’s API that allows us to check the status of an Event Instance. It returns the current status of the audio as an &lt;strong>Enumerator (Enum)&lt;/strong>.&lt;/p>
&lt;p>The five main states returned by the API are:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>PLAYING&lt;/strong>&lt;/li>
&lt;li>&lt;strong>STARTING&lt;/strong>&lt;/li>
&lt;li>&lt;strong>STOPPING&lt;/strong>&lt;/li>
&lt;li>&lt;strong>STOPPED&lt;/strong>&lt;/li>
&lt;li>&lt;strong>SUSTAINING&lt;/strong>&lt;/li>
&lt;/ol>
&lt;p>By accessing these states, we can write logic that prevents sounds from overlapping or triggering incorrectly.&lt;/p>
&lt;h2 id="part-1-setting-up-the-variable">Part 1: Setting Up the Variable&lt;/h2>
&lt;p>To use Playback States, you first need to define a variable to store the state information. Open the &lt;code>MusicPlayer&lt;/code> script.&lt;/p>
&lt;p>Inside your class, declare a variable of type &lt;code>FMOD.Studio.PLAYBACK_STATE&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">private&lt;/span> FMOD.Studio.PLAYBACK_STATE musicPlayState;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>Note: You can omit &lt;code>FMOD.Studio&lt;/code> if you are already using that namespace at the top of your script.&lt;/em>&lt;/p>
&lt;h2 id="part-2-retrieving-the-state">Part 2: Retrieving the State&lt;/h2>
&lt;p>To see what your audio is doing, you need to use the &lt;code>.getPlaybackState()&lt;/code> command. This command queries the event instance and outputs the result into the variable we just created.&lt;/p>
&lt;p>If you want to track the state in real-time, place this logic in your &lt;code>Update()&lt;/code> function:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">void&lt;/span> Update()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Assuming &amp;#39;_musicInst&amp;#39; is your FMOD Event Instance&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> _musicInst.getPlaybackState(&lt;span style="color:#66d9ef">out&lt;/span> musicPlayState);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Debug to the console to see the state change&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Debug.Log(musicPlayState);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>How it works:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>While Playing:&lt;/strong> The console will log &lt;code>PLAYING&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Entering a Portal/Stopping:&lt;/strong> If you trigger a stop command, it switches to &lt;code>STOPPING&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Finished:&lt;/strong> Once the audio fades out completely, it switches to &lt;code>STOPPED&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>&lt;em>Important:&lt;/em> &lt;code>getPlaybackState&lt;/code> only checks the state on the specific frame it is called. If you only put this in &lt;code>Start()&lt;/code>, it will likely only ever say &lt;code>STARTING&lt;/code> because it never updates again.&lt;/p>
&lt;h2 id="part-3-a-practical-example-the-ui-slider-fix">Part 3: A Practical Example (The UI Slider Fix)&lt;/h2>
&lt;p>One of the most useful applications for Playback States is preventing audio spam.&lt;/p>
&lt;p>Imagine you have a volume slider in your Settings menu. You want a sound effect to play when the user moves the slider so they can hear the volume level. However, if you simply tell the sound to &lt;code>Start()&lt;/code> every time the slider value changes, the sound will restart every single frame the mouse moves. This creates a messy &amp;ldquo;machine gun&amp;rdquo; stuttering effect.&lt;/p>
&lt;p>We can use Playback States to ensure the sound only starts if it isn&amp;rsquo;t &lt;em>already&lt;/em> playing.&lt;/p>
&lt;h3 id="step-1-the-setup">Step 1: The Setup&lt;/h3>
&lt;ol>
&lt;li>&lt;strong>In FMOD:&lt;/strong> Create a 2D Event (e.g., &lt;code>LevelTest&lt;/code>) in a &amp;ldquo;UI&amp;rdquo; folder.
&lt;ol>
&lt;li>Add some test sounds into a Multi Instrument.&lt;/li>
&lt;li>Ensure the event is sent to the SFX bus.&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>&lt;strong>In Unity:&lt;/strong> Open your &lt;code>F_BusControl&lt;/code> script.&lt;/li>
&lt;/ol>
&lt;h3 id="step-2-modify-the-script">Step 2: Modify the Script&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// ... Your existing using statements ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">F_BusControl_class&lt;/span> : MonoBehaviour
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// .. . Your existing variables ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> EventInstance levelTestEvent;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Start is called once before the first execution of Update after the MonoBehaviour is created&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">void&lt;/span> Start()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// ... Your existing bus setup code ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// only assign the event if its actually an SFX&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span>(busPath == &lt;span style="color:#e6db74">&amp;#34;SFX&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> levelTestEvent = RuntimeManager.CreateInstance(&lt;span style="color:#e6db74">&amp;#34;event:/SFX/UI/LevelTest&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#66d9ef">else&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> levelTestEvent.release();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> VolumeLevel(&lt;span style="color:#66d9ef">float&lt;/span> newSliderValue)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> bus.setVolume(newSliderValue);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> levelTestEvent.start();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You can hear that the sound stutters when you drag the slider quickly. We need to fix it by telling it to only start if th sound is not already playing.&lt;/p>
&lt;p>We can use playback states to fix this issue:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// ... Your existing using statements ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">F_BusControl_class&lt;/span> : MonoBehaviour
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// .. . Your existing variables ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> EventInstance levelTestEvent;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> PLAYBACK_STATE pbState;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Start is called once before the first execution of Update after the MonoBehaviour is created&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">void&lt;/span> Start()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// ... Your existing bus setup code ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// only assign the event if its actually an SFX&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span>(busPath == &lt;span style="color:#e6db74">&amp;#34;SFX&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> levelTestEvent = RuntimeManager.CreateInstance(&lt;span style="color:#e6db74">&amp;#34;event:/SFX/UI/LevelTest&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#66d9ef">else&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> levelTestEvent.release();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> VolumeLevel(&lt;span style="color:#66d9ef">float&lt;/span> newSliderValue)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> bus.setVolume(newSliderValue);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span>(busPath == &lt;span style="color:#e6db74">&amp;#34;SFX&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Check the playback state before starting the event&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> levelTestEvent.getPlaybackState(&lt;span style="color:#66d9ef">out&lt;/span> pbState);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (pbState != PLAYBACK_STATE.PLAYING)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> levelTestEvent.start();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now, when you drag the slider, the sound will play once. It will only play again after the previous instance has finished, resulting in a smooth, non-stuttering audio experience.&lt;/p>
&lt;h2 id="summary">Summary&lt;/h2>
&lt;p>By using &lt;strong>Playback States&lt;/strong>, you gain precise control over when your audio triggers. You are no longer just telling FMOD to &amp;ldquo;Play&amp;rdquo;; you are asking FMOD &amp;ldquo;Are you busy?&amp;rdquo; and acting accordingly.&lt;/p>
&lt;p>This simple check is essential for creating polished UI sounds, managing dynamic music transitions, and ensuring your game&amp;rsquo;s audio sounds professional and clean.&lt;/p></content></item></channel></rss>