Skip to content

Audio Streaming

John Baglio edited this page Oct 5, 2024 · 6 revisions

It is highly recommended to check the Basic Setup page if you haven't already.
The features mentioned in this page will not work if MonoSound has not been initialized.

Table of Contents
Preface
How to Stream Audio
XACT Support
StreamPackage
SegmentedOggStream
Other Methods
Stream Sources

Preface

Audio files are large, especially XACT Wave Banks.
Hence, loading the entire file at once may take a while, and that could be undesirable for things like background music.

To remedy this predicament, MonoSound provides an API via the MonoSound.StreamLoader class which allows you to create audio streams from a file.

How to Stream Audio

Audio streams are represented by the StreamPackage class, which is loaded by StreamLoader.

To load an audio stream, call StreamLoader.GetStreamedSound():

StreamPackage stream = StreamLoader.GetStreamedSound("Content/chill.ogg", looping: true);
stream.Play();

By default, MonoSound supports streaming audio files from the following formats:

  • WAVE (.wav)
  • OGG Vorbis (.ogg)
  • MPEG Audio Layer III (.mp3)
  • Compiled SoundEffect (.xnb)
  • XACT Banks
  • Raw PCM Audio (.pcm) via class PcmFormat : CustomAudioFormat

Custom audio formats outside of these can also be supported, although they have to be registered if they want to be detected by this method.
See the Custom Audio Formats page for more information.

XACT Support

The legacy Cross-platform Audio Creation Tool (XACT) format is also supported by MonoSound, except it uses special methods.

To load an audio stream from XACT audio files, you first need the Wave Bank (.xwb) and corresponding Sound Bank (.xsb) files.
The Sound Engine (.xgs) file generated by XACT is not used by MonoSound and can be ignored.

Then, to load the stream from the banks, call StreamLoader.GetStreamedXACTSound():

StreamPackage stream = StreamLoader.GetStreamedXACTSound("Content/Sound Bank.xsb", "Content/Wave Bank.xwb", "music", looped: true);
stream.Play();

StreamPackage

The StreamPackage class manages everything related to the audio stream, such as the sound instance used to play it, the current time of the stream in the audio, and more.

Listed below is every important API that you should be aware of:

  • SoundMetrics Metrics { get; }
    • The metrics for the sound
    • Contains volume, pan, pitch, sound state and whether the sound has been disposed
  • AudioType type
    • The classification of the audio stream
  • bool IsLooping { get; set; }
    • Whether the stream will attempt to loop once it has reached the end of the audio data
    • Deriving classes can override the looping behavior
    • Default behavior when a loop is attempted due to the stream reaching the end of the audio data:
      • true makes the audio loop
      • false disposes the sound instance and frees the stream
  • TimeSpan CurrentDuration { get; }
    • The current location of the audio stream in the audio data
    • Does not work with Mp3Stream
  • TimeSpan MaxDuration { get; }
    • The length of the audio data
    • Does not work with Mp3Stream
  • void Play()
    • Plays or resumes the audio stream
  • void Pause()
    • Pauses the audio stream
  • void Resume()
    • Resumes the audio stream if it is paused
  • view Stop()
    • Stops the audio stream
    • Resets the audio stream to the start
    • Automatically calls void Reset()
  • void Reset()
    • virtual method
    • Called whenever the audio stream is stopped or attempts a loop
    • Check if (Metrics.State == SoundState.Stopped) for if the reset was caused by stopping the stream
  • void ApplyImmediateJump(double)
    • protected method
    • Intended to be used whenever the audio stream jumps to somewhere in the audio stream
    • Automatically called by void SetStreamPosition(double)
    • Necessary to make CurrentDuration recognize the position jump
  • void ReadSamples(double, out byte[], out int, out bool)
    • abstract method
    • Reads samples from the audio stream
  • void SetStreamPosition(double)
    • virtual method
    • Sets the location of the next batch of samples to read
    • Automatically calls void ApplyImmediateJump(double)
  • void ApplyFilters(params int[])
    • Applies the specified filter IDs to all audio data that will be read, or removes any active filters if null is passed
    • Can be called while the stream is playing
    • Audio streaming currently only supports the Low Pass, High Pass and Band Pass filter types

SegmentedOggStream

This type in the MonoSound.Default namespace represents an .ogg stream that can have multiple (optionally) looping sections.
Example uses can be found within the MonoSound.Tests project in this repository.

Loading the Segmented Stream

To load a stream of this type, the MonoSound.Default.SegmentedOggFormat type is used. Since .ogg is already covered, this format cannot be registered.

Shown below is a snippet from MonoSound.Tests that loads the stream:

streamedSegmentedSound = (SegmentedOggStream)StreamLoader.GetStreamedSound("Content/bonetrousle.ogg", new SegmentedOggFormat(), true, new IAudioSegment[] {
	// Intro
	new Segment(TimeSpan.Zero, TimeSpan.FromSeconds(31.95)),
	// Main loop
	new Segment(TimeSpan.FromSeconds(31.95), TimeSpan.FromSeconds(89.55)),
	// Ending
	new EndSegment(TimeSpan.FromSeconds(89.55))
});

StartSegment (not shown), Segment and EndSegment are predefined types that use the MonoSound.Default.IAudioSegment interface.

Jumping to a Segment

Jumping to another segment can be performed immediately, or after the current segment ends.
The following methods can be used to jump to a segment:

  • void JumpTo(int, bool)
    • Jumps to the provided segment number
  • void JumpToStart(bool)
    • Jumps to the start of the first segment
  • void JumpToNextLoopSection(bool)
    • Jumps to the next segment
    • Does nothing if the stream is in the final segment
  • void JumpToDelayedSection()
    • Immediately performs a jump if one is currently being delayed

Remaining API

There are a few additional variables and types not covered in the previous subsections.
They are listed below:

  • event OnDelayedSectionStart
    • This event fires whenever a delayed segment jump happens, and is then set to null
  • SegmentedOggStream.SegmentTracker tracker
    • Helper class for managing which segment the stream is currently playing
    • int TargetSegment { get; set; }
      • Which segment to loop through, should it loop
      • Stream can be located between segments, in which case it will be updated to the first segment whose end point is after the stream's read location
    • int Count { get; }
      • How many segments are present in the stream
    • IAudioSegment CurrentSegment { get; }
      • The current segment that the stream is using
    • void GetLoopBounds(out TimeSpan, out TimeSpan)
      • Gets the start and loop points for the current segment
    • void GetLoopBounds(int, out TimeSpan, out TimeSpan)
      • Gets the start and loop points for a given segment

Other Methods

StreamLoader also contains other methods not related to loading streams:

  • bool IsStreaming(StreamPackage)
    • Returns false if the stream is null, was disposed, or wasn't created via GetStreamedSound/GetStreamedXACTSound
    • Returns true otherwise
  • void FreeStreamedSound(ref StreamPackage)
    • Stops the streamed sound, disposes it, removes it from the tracked streams collection and then sets the stream to null
  • void FreeStreamedSound<T>(ref T) where T : StreamPackage
    • Generic variant for the previous method

Stream Sources

MonoSound also supports loading audio from System.IO.Stream objects, although the API is slightly different.
For non-XACT audio, an additional MonoSound.AudioType constant has to be provided to indicate what format the stream is in.

The aforementioned methods have the following definitions when loading from Stream objects:

  • GetStreamedSound
StreamPackage GetStreamedSound(Stream sampleSource, AudioType fileIdentifier, bool looping)
  • GetStreamedXACTSound
StreamPackage GetStreamedXACTSound(Stream soundBankSource, string soundBankIdentifier, Stream waveBankSource, string waveBankIdentifier, string cueName, bool looping)