Sound

If just playing a file at a given volume or pitch isn't enough, you should use the Sound class. This allows you to set loop points, fade in/out length, sound panning (playing on the left or right speaker), custom sample rates, pausing and resuming and prematurely ending playback. It also allows you to add event handlers, which are triggered under certain conditions during playback.

circle-exclamation

To slowly fade the sound in and out, you can specify the fade in length and the fade out length. If these are 0, they are ignored. Rather than just waiting some X number of seconds before we exit the program, here we're waiting until the sound has stopped playing.

using System;
using odl;

namespace TestNamespace
{
    class Program
    {
        public static void Main(string[] args)
        {
            Audio.Start();

            Sound s = new Sound("victory.ogg");
            s.FadeInLength = s.SampleRate * 6;
            s.FadeOutLength = s.SampleRate * 6;
            s.Play();

            while (s.Playing)
            {

            }

            Audio.Stop();
        }
    }
}

The fade in/out length properties are in samples. The sample rate is how many samples are in one second - in other words, the sampling frequency.

circle-info

Calling Play() on a Sound object just calls Audio.Play(the_sound). They're synonymous.

This is an example of basic playback looping.

If no loop start/end points are set, the sound will play to the end of the file, and then go back to the beginning. This can be changed by setting the LoopStart and LoopEnd properties to the position in samples where the sound should loop around.

This example will fade the sound in and out for the first and last 6 seconds, respectively (SampleRate is the number of samples in one second, so SampleRate*x means every x seconds). The sound will loop around after 14 seconds, back to 10 seconds.

The length in samples of the sound can be retrieved through the Length property.

You can choose which speaker is dominant by setting the Pan property. A value of -1 means 100% on the left speaker, a value of 0 means both speakers are equal, and a value of 1 means 100% on the right speaker. You can do some pretty cool things with that, such as phasing from the left speaker to the right speaker.

As there are no update methods, everything should be done via methods and callbacks. One way to facilitate this functionality is through the SlideXXX methods, which will linearly interpolate the property from one value to another over a given timespan.

For instance, you can manually create your own fade in by calling SlideVolume(int NewValue, long Time), and it will gradually go from its old value to the given NewValue, taking exactly Time samples. You can also use the utility method for this, however: FadeIn(long Time). This method also exists for fading out: FadeOut(long Time).

Both of these FadeIn and FadeOut also take an optional SlideCallbackdelegate. This callback is called whenever the sound has finished sliding a property, such as volume. As such, this delegate can be used to detect when the sound is done fading in or out, when the argument to the delegate is equal to 2 (2 is the Volume attribute).

There are three more Slide methods, specifically SlidePan(double Pan, long Time), SlidePitch(int Pitch, long Time), and SlideSampleRate(int SampleRate, long Time).

A Sound object can be paused with the Pause() method and resumed with the Resume() method. The Play() method will call Start() if the sound was not called before yet, and otherwise call Resume().

The Stop() method will immediately stop playback and free all the sound's resources. This is called automatically when a sound stops playback.

To get or set the position of playback, you can reference the Position property. The value is also in samples.

Next are callbacks. Using the AddPositionCallback(long Sample, SoundCallback Callback) method, you can set a "break point" in the audio playback. Once the playback position reaches the specified sample, the provided callback will be called. Please note that, since audio is playing synchronously with your callback code/main thread, you cannot specify this sample position too close to the current playback position. By the time the callback has been registered, the given position may already have been passed. In that trend, calling the Position property on your sound object in the callback will also produce a greater value than your specified sample. This is because in the time it took for the callback to get recognised and triggered, the audio has continued on playing.

Another callback you may use is AddEndCallback(SoundCallback Callback). The delegate is of the same type as the position callback, but is called whenever the sound reaches the end of playback.

Furthermore, there is AddSlideCallback, which is called whenever a Slide method has finished sliding its value (i.e. it's now equal to your specified value to slide to). Its delegate takes a SlideType argument, which holds information regarding which property has finished sliding.

Last, there is AddLoopCallback, which is called whenever the sound loops - either from the end of the sound to the start, or between your specified loop points.

All these AddXXXCallback methods return an integer, which is the handle of the callback. This handle can be used to de-register the callback using RemoveCallback(int Handle), to ensure it only runs whenever you want it to.

Last updated