CUGL 2.0
Cornell University Game Library
Public Member Functions | Static Public Member Functions | List of all members
cugl::audio::AudioScheduler Class Reference

#include <CUAudioScheduler.h>

Inheritance diagram for cugl::audio::AudioScheduler:
cugl::audio::AudioNode

Public Member Functions

 AudioScheduler ()
 
 ~AudioScheduler ()
 
virtual bool init () override
 
virtual bool init (Uint8 channels, Uint32 rate) override
 
virtual void dispose () override
 
void play (const std::shared_ptr< AudioNode > &node, Sint32 loop=0)
 
void append (const std::shared_ptr< AudioNode > &node, Sint32 loop=0)
 
std::shared_ptr< AudioNodegetCurrent () const
 
std::deque< std::shared_ptr< AudioNode > > getTail () const
 
Uint32 getTailSize () const
 
void clear (bool force=false)
 
void trim (Sint32 size=-1)
 
void skip (Uint32 n=0)
 
bool isPlaying ()
 
double getOverlap () const
 
void setOverlap (double time)
 
Sint32 getLoops () const
 
void setLoops (Sint32 loop)
 
virtual Uint32 read (float *buffer, Uint32 frames) override
 
virtual bool mark () override
 
virtual bool unmark () override
 
virtual bool reset () override
 
virtual Sint64 advance (Uint32 frames) override
 
virtual Sint64 getPosition () const override
 
virtual Sint64 setPosition (Uint32 position) override
 
virtual double getElapsed () const override
 
virtual double setElapsed (double time) override
 
- Public Member Functions inherited from cugl::audio::AudioNode
 AudioNode ()
 
virtual ~AudioNode ()
 
Uint8 getChannels () const
 
Uint32 getRate () const
 
float getGain ()
 
virtual void setGain (float gain)
 
const std::string & getClassName () const
 
const std::string & getName () const
 
void setName (const std::string name)
 
Sint32 getTag () const
 
void setTag (Sint32 tag)
 
virtual std::string toString (bool verbose=false) const
 
 operator std::string () const
 
Callback getCallback ()
 
void setCallback (Callback callback)
 
virtual bool isPaused ()
 
virtual bool pause ()
 
virtual bool resume ()
 
virtual bool completed ()
 
virtual double getRemaining () const
 
virtual double setRemaining (double time)
 

Static Public Member Functions

static std::shared_ptr< AudioScheduleralloc (Uint8 channels, Uint32 rate)
 

Additional Inherited Members

- Public Types inherited from cugl::audio::AudioNode
enum  Action : int {
  COMPLETE = 0, INTERRUPT = 1, FADE_OUT = 2, FADE_IN = 3,
  FADE_DIP = 4, LOOPBACK = 5
}
 
typedef std::function< void(const std::shared_ptr< AudioNode > &node, Action type)> Callback
 
- Static Public Attributes inherited from cugl::audio::AudioNode
const static Uint32 DEFAULT_CHANNELS
 
const static Uint32 DEFAULT_SAMPLING
 
- Protected Member Functions inherited from cugl::audio::AudioNode
void notify (const std::shared_ptr< AudioNode > &node, Action action)
 
- Protected Attributes inherited from cugl::audio::AudioNode
Uint8 _channels
 
Uint32 _sampling
 
bool _booted
 
std::atomic< float > _ndgain
 
std::atomic< bool > _paused
 
std::atomic< bool > _polling
 
Callback _callback
 
std::atomic< bool > _calling
 
Sint32 _tag
 
std::string _localname
 
std::string _classname
 
size_t _hashOfName
 

Detailed Description

This class is capable of scheduling audio nodes in sequence.

This node is important for supporting dynamic playback. While we can safely rearrange nodes in the audio graph when it is not active, this allows us to schedule nodes while playback is ongoing. When combined with AudioPlayer, this provides a classic player node such as you might find in AVFoundation. However, by generalizing this concept, we are able to schedule arbitrary audio patches as well.

To support seamless audio, a scheduler is fed by a queue. That way the user can queue up a new source while the current one is playing. However, to simplify the data structures and ensure thread safety, we do not allow the user to look at the contents of the queue. The user can only look at the currently playing node.

The audio graph should only be accessed in the main thread. In addition, no methods marked as AUDIO THREAD ONLY should ever be accessed by the user.

This audio node supports the callback functions in AudioNode#setCallback. This function function is called whenever a node is removed from the scheduler. This may be because the node played to completion (defined as a AudioScheduler#read() result that returns 0) or it was interrupted.

Constructor & Destructor Documentation

◆ AudioScheduler()

cugl::audio::AudioScheduler::AudioScheduler ( )

Creates an inactive scheduler node.

NEVER USE A CONSTRUCTOR WITH NEW. If you want to allocate a graph node on the heap, use one of the static constructors instead.

◆ ~AudioScheduler()

cugl::audio::AudioScheduler::~AudioScheduler ( )

Deletes the scheduler node, disposing of all resources

Member Function Documentation

◆ advance()

virtual Sint64 cugl::audio::AudioScheduler::advance ( Uint32  frames)
overridevirtual

Sets the current frame position of this audio node.

DELEGATED METHOD: This method delegates its call to the current audio node. It returns -1 if there is no active node or if this method is unsupported.

If the number of frames is set beyond the bounds of the current node, the outcome will depend on the state of the audio queue. A looped node will simply loop the given number of frames. Otherwise, if this position causes the audio node to complete, it will continue to advance through the queue so long as this method (and completed()) is supported.

This method is thread safe, and may be called outside the audio thread. However, the accuracy of the result on a non-paused audio source is subject to minor race conditions (e.g. you may set the time, but have it forwarded by the next window size without reading). In addition, some streaming formats are less accurate than others.

This method will work even if AudioNode#mark() is not set.

Parameters
framesThe number of frames to advance
Returns
the actual number of frames advanced; -1 if not supported

Reimplemented from cugl::audio::AudioNode.

◆ alloc()

static std::shared_ptr<AudioScheduler> cugl::audio::AudioScheduler::alloc ( Uint8  channels,
Uint32  rate 
)
inlinestatic

Returns an allocated player with the given number of channels and sample rate

These values determine the buffer the structure for all read operations. In addition, they also detemine what types of sources that the player can support. A player can only play assets with the right sampling rate and number of channels.

The node starts off inactive. It will become active when a source is added to the queue.

Parameters
channelsThe number of audio channels
rateThe sample rate (frequency) in HZ
Returns
an allocated player with the given number of channels and sample rate

◆ append()

void cugl::audio::AudioScheduler::append ( const std::shared_ptr< AudioNode > &  node,
Sint32  loop = 0 
)

Appends a new audio node for playback.

This method appends to the node to the playback queue. It will be played as soon as the nodes that are earlier in the queue have completed playing.

This audio node may be any satisfying class, though it is typically an instance of AudioPlayer. Gain control is handled in the node itself (though the scheduler can add extra gain). The only new feature added is looping.

The loop value is an integer. If it is 0, the audio node will not be looped. If it is positive, it will loop the audio that many (additional) times. If it is negative, the audio node will be looped indefinitely until it is stopped.

If the user has provided an optional callback function, this will be called when the node is removed, either because it completed (defined by AudioNode#completed()) or is interrupted.

Parameters
nodeThe audio node for playback
loopThe number of times to loop the audio

◆ clear()

void cugl::audio::AudioScheduler::clear ( bool  force = false)

Stops the current playback and empties the queue.

To ensure consistency, this method only flags the nodes for deletion. Clean-up will occur in the audio thread. This ensures that the callback function (if provided) is called from the audio thread for all of the nodes removed from the queue (as well as the current node). The complete flag will be false, indicating that they were interrupted.

The optional force argument allows for sounds to be purged immediately (such as during clean-up). However, doing so will not invoke the callback function, even if it is provided.

Parameters
forcewhether to delete the queue immediately, in the current thread

◆ dispose()

virtual void cugl::audio::AudioScheduler::dispose ( )
overridevirtual

Disposes any resources allocated for this node

The state of the node is reset to that of an uninitialized constructor. Unlike the destructor, this method allows the node to be reinitialized.

Reimplemented from cugl::audio::AudioNode.

◆ getCurrent()

std::shared_ptr<AudioNode> cugl::audio::AudioScheduler::getCurrent ( ) const

Returns the audio node currently being played.

If the user has provided an optional callback function, this will be called when this node is no longer active

Returns
the audio node currently being played.

◆ getElapsed()

virtual double cugl::audio::AudioScheduler::getElapsed ( ) const
overridevirtual

Returns the elapsed time in seconds.

DELEGATED METHOD: This method delegates its call to the current audio node. It returns -1 if there is no active node or if this method is unsupported.

This method has no effect unless mark() is called. All time is relative from the marked position.

This method is thread safe, and may be called outside the audio thread. However, the accuracy of the result on a non-paused audio source is subject to minor race conditions (e.g. you may set the time, but have it forwarded by the next window size without reading). In addition, some streaming formats are less accurate than others.

Returns
the elapsed time in seconds.

Reimplemented from cugl::audio::AudioNode.

◆ getLoops()

Sint32 cugl::audio::AudioScheduler::getLoops ( ) const

Returns number of loops remaining for the active audio node.

If the value is 0, then the audio node will be removed from the queue when it completes (as defined by AudioNode#completed(). A value greater than 0 will repeat that many times, assuming that the method AudioNode#reset() is implemented (a node that cannot be reset cannot be looped). Finally, a negative value will be played indefinitely, unless it is stopped or or the loop count is changed.

This method returns 0 if there is no active audio node

return true if the active audio node is looped.

◆ getOverlap()

double cugl::audio::AudioScheduler::getOverlap ( ) const

Returns the overlap time in seconds.

The overlap time is the amount of time to cross-fade between a node on the queue and the next. It does not apply to looped nodes; nodes can never cross-fade with themselves.

The cross-fade is triggered when a node implements the method AudioNode#getRemaining(), and this value is less than or equal to the overlap. It does not trigger if that method is not supported. In addition, if a node is forced to complete before the normal time remaining, the overlap will not apply.

The overlap should be chosen with care. If the play length of an audio node is less than the overlap, the results are undefined.

Returns
the overlap time in seconds.

◆ getPosition()

virtual Sint64 cugl::audio::AudioScheduler::getPosition ( ) const
overridevirtual

Returns the current frame position of this audio node.

DELEGATED METHOD: This method delegates its call to the current audio node. It returns -1 if there is no active node or if this method is unsupported.

This method is thread safe, and may be called outside the audio thread. However, the accuracy of the result on a non-paused audio source is subject to minor race conditions (e.g. you may set the time, but have it forwarded by the next window size without reading). In addition, some streaming formats are less accurate than others.

Returns
the current frame position of this audio node.

Reimplemented from cugl::audio::AudioNode.

◆ getTail()

std::deque<std::shared_ptr<AudioNode> > cugl::audio::AudioScheduler::getTail ( ) const

Returns all audio nodes waiting to be played.

This method only returns the nodes. It does not return any loop information.

Returns
all audio nodes waiting to be played.

◆ getTailSize()

Uint32 cugl::audio::AudioScheduler::getTailSize ( ) const

Returns the number audio nodes waiting to be played.

The currently playing audio is not included.

Returns
the number audio nodes waiting to be played.

◆ init() [1/2]

virtual bool cugl::audio::AudioScheduler::init ( )
overridevirtual

Initializes the scheduler with default stereo settings

The number of channels is two, for stereo output. The sample rate is the modern standard of 48000 HZ.

These values determine the buffer the structure for all read operations. In addition, they also detemine whether this node can serve as an input to other nodes in the audio graph.

Returns
true if initialization was successful

Reimplemented from cugl::audio::AudioNode.

◆ init() [2/2]

virtual bool cugl::audio::AudioScheduler::init ( Uint8  channels,
Uint32  rate 
)
overridevirtual

Initializes the scheduler with the given number of channels and sample rate

These values determine the buffer the structure for all read operations. In addition, they also detemine whether this node can serve as an input to other nodes in the audio graph.

Parameters
channelsThe number of audio channels
rateThe sample rate (frequency) in HZ
Returns
true if initialization was successful

Reimplemented from cugl::audio::AudioNode.

◆ isPlaying()

bool cugl::audio::AudioScheduler::isPlaying ( )

Returns true if the scheduler has an active audio node

This method only checks if there is a current active node. This method may return true even if the node is paused.

return true if the scheduler has an active audio node

◆ mark()

virtual bool cugl::audio::AudioScheduler::mark ( )
overridevirtual

Marks the current read position in the audio steam.

DELEGATED METHOD: This method delegates its call to the current audio node. It returns false if there is no active node or if this method is unsupported.

Once this method is called, the scheduler will mark the current audio node and buffer all subsequent audio nodes. It will create a secondary queue to prevent these nodes from being released. A call to the method reset() will return to the marked position of the current audio node and replay all subsequent audio nodes before returning to the audio queue.

This secondary queue will continue accumulating audio nodes until unmark() is called. It is not recommended for a marks to remain indefinitely.

Returns
true if the read position was marked.

Reimplemented from cugl::audio::AudioNode.

◆ play()

void cugl::audio::AudioScheduler::play ( const std::shared_ptr< AudioNode > &  node,
Sint32  loop = 0 
)

Immediately schedules a new audio node for playback.

This method clears the queue and immediately schedules the node for the next audio render frame.

This audio node may be any satisfying class, though it is typically an instance of AudioPlayer. Gain control is handled in the node itself (though the scheduler can add extra gain). The only new feature added is looping.

The loop value is an integer. If it is 0, the audio node will not be looped. If it is positive, it will loop the audio that many (additional) times. If it is negative, the audio node will be looped indefinitely until it is stopped.

If the user has provided an optional callback function, this will be called when the node is removed, either because it completed (defined by AudioNode#completed()) or is interrupted.

Parameters
nodeThe audio node for playback
loopThe number of times to loop the audio

◆ read()

virtual Uint32 cugl::audio::AudioScheduler::read ( float *  buffer,
Uint32  frames 
)
overridevirtual

Reads up to the specified number of frames into the given buffer

AUDIO THREAD ONLY: Users should never access this method directly. The only exception is when the user needs to create a custom subclass of this AudioNode.

The buffer should have enough room to store frames * channels elements. The channels are interleaved into the output buffer.

This method will always forward the read position after reading. Reading again may return different data.

Parameters
bufferThe read buffer to store the results
framesThe maximum number of frames to read
Returns
the actual number of frames read

Reimplemented from cugl::audio::AudioNode.

◆ reset()

virtual bool cugl::audio::AudioScheduler::reset ( )
overridevirtual

Resets the read position to the marked position of the audio stream.

DELEGATED METHOD: This method delegates its call to the current audio node. It returns false if there is no active node or if this method is unsupported.

This method returns the playback to the audio node and position set by a call to mark(). If mark has not been called, this method has no effect.

Returns
true if the read position was moved.

Reimplemented from cugl::audio::AudioNode.

◆ setElapsed()

virtual double cugl::audio::AudioScheduler::setElapsed ( double  time)
overridevirtual

Sets the read position to the elapsed time in seconds.

DELEGATED METHOD: This method delegates its call to the current audio node. It returns -1 if there is no active node or if this method is unsupported.

This method has no effect unless mark() is called. All time is relative from the marked position.

If the time is set beyond the bounds of the current node, the outcome will depend on the state of the audio queue. A looped node will simply loop the elapsed time. Otherwise, if this position causes the audio node to complete, it will continue to advance through the queue so long as this method (and completed()) is supported.

This method is thread safe, and may be called outside the audio thread. However, the accuracy of the result on a non-paused audio source is subject to minor race conditions (e.g. you may set the time, but have it forwarded by the next window size without reading). In addition, some streaming formats are less accurate than others.

Parameters
timeThe elapsed time in seconds.
Returns
the new elapsed time in seconds.

Reimplemented from cugl::audio::AudioNode.

◆ setLoops()

void cugl::audio::AudioScheduler::setLoops ( Sint32  loop)

Sets number of loops remaining for the active audio node.

If the value is 0, then the audio node will be removed from the queue when it completes (as defined by AudioNode#completed(). A value greater than 0 will repeat that many times, assuming that the method AudioNode#reset() is implemented (a node that cannot be reset cannot be looped). Finally, a negative value will be played indefinitely, unless it is stopped or or the loop count is changed.

This method does nothing if there is no active audio node.

Parameters
loopThe number of times to loop the audio

◆ setOverlap()

void cugl::audio::AudioScheduler::setOverlap ( double  time)

Sets the overlap time in seconds.

The overlap time is the amount of time to cross-fade between a node on the queue and the next. It does not apply to looped nodes; nodes can never cross-fade with themselves.

The cross-fade is triggered when a node implements the method AudioNode#getRemaining(), and this value is less than or equal to the overlap. It does not trigger if that method is not supported. In addition, if a node is forced to complete before the normal time remaining, the overlap will not apply.

The overlap should be chosen with care. If the play length of an audio node is less than the overlap, the results are undefined.

Parameters
timeThe overlap time in seconds.

◆ setPosition()

virtual Sint64 cugl::audio::AudioScheduler::setPosition ( Uint32  position)
overridevirtual

Sets the current frame position of this audio node.

DELEGATED METHOD: This method delegates its call to the current audio node. It returns -1 if there is no active node or if this method is unsupported.

This method has no effect unless mark() is called. All frame positions are relative from the marked position.

If the number of frames is set beyond the bounds of the current node, the outcome will depend on the state of the audio queue. A looped node will simply loop the given number of frames. Otherwise, if this position causes the audio node to complete, it will continue to advance through the queue so long as this method (and completed()) is supported.

This method is thread safe, and may be called outside the audio thread. However, the accuracy of the result on a non-paused audio source is subject to minor race conditions (e.g. you may set the time, but have it forwarded by the next window size without reading). In addition, some streaming formats are less accurate than others.

Parameters
positionthe current frame position of this audio node.
Returns
the new frame position of this audio node.

Reimplemented from cugl::audio::AudioNode.

◆ skip()

void cugl::audio::AudioScheduler::skip ( Uint32  n = 0)

Skips forward to a future nodes in the queue.

The optional parameter n specifies the number of additional nodes to skip. If n is 0, it will just go the front element of the queue. Otherwise, it will skip to the n element after the head of the queue. If n is larger than the size of the queue, this is the same as clear().

If the user has provided an optional callback function, this will be called for all of the nodes removed from the queue (as well as the current sound). The complete flag will be false, indicating that they were interrupted.

◆ trim()

void cugl::audio::AudioScheduler::trim ( Sint32  size = -1)

Empties the queue without stopping the current playback.

This method is useful when we want to clear the queue, but to smoothly fade-out the current playback.

◆ unmark()

virtual bool cugl::audio::AudioScheduler::unmark ( )
overridevirtual

Clears the current marked position.

The method mark() creates a second queue for buffering audio. This queue will continue accumulating audio nodes until this method is called.

This method has no effect if there is no current mark.

Returns
true if the read position was cleared.

Reimplemented from cugl::audio::AudioNode.


The documentation for this class was generated from the following file: