CUGL 2.3
Cornell University Game Library
|
#include <CUAudioScheduler.h>
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< AudioNode > | getCurrent () 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 void | setReadSize (Uint32 size) override |
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 () |
virtual bool | init () |
virtual bool | init (Uint8 channels, Uint32 rate) |
virtual void | dispose () |
Uint8 | getChannels () const |
Uint32 | getRate () const |
float | getGain () |
virtual void | setGain (float gain) |
Uint32 | getReadSize () const |
virtual void | setReadSize (Uint32 size) |
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 Uint32 | read (float *buffer, Uint32 frames) |
virtual bool | mark () |
virtual bool | unmark () |
virtual bool | reset () |
virtual Sint64 | advance (Uint32 frames) |
virtual Sint64 | getPosition () const |
virtual Sint64 | setPosition (Uint32 position) |
virtual double | getElapsed () const |
virtual double | setElapsed (double time) |
virtual double | getRemaining () const |
virtual double | setRemaining (double time) |
Static Public Member Functions | |
static std::shared_ptr< AudioScheduler > | alloc (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 | |
static const Uint32 | DEFAULT_CHANNELS |
static const 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 |
Uint32 | _readsize |
std::string | _localname |
std::string | _classname |
size_t | _hashOfName |
bool | _locked |
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.
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.
cugl::audio::AudioScheduler::~AudioScheduler | ( | ) |
Deletes the scheduler node, disposing of all resources
|
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.
frames | The number of frames to advance |
Reimplemented from cugl::audio::AudioNode.
|
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.
channels | The number of audio channels |
rate | The sample rate (frequency) in HZ |
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.
node | The audio node for playback |
loop | The number of times to loop the audio |
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.
force | whether to delete the queue immediately, in the current thread |
|
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.
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
|
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.
Reimplemented from cugl::audio::AudioNode.
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.
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.
|
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.
Reimplemented from cugl::audio::AudioNode.
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.
Uint32 cugl::audio::AudioScheduler::getTailSize | ( | ) | const |
Returns the number audio nodes waiting to be played.
The currently playing audio is not included.
|
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.
Reimplemented from cugl::audio::AudioNode.
|
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.
channels | The number of audio channels |
rate | The sample rate (frequency) in HZ |
Reimplemented from cugl::audio::AudioNode.
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
|
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.
Reimplemented from cugl::audio::AudioNode.
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.
node | The audio node for playback |
loop | The number of times to loop the audio |
|
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.
buffer | The read buffer to store the results |
frames | The maximum number of frames to read |
Reimplemented from cugl::audio::AudioNode.
|
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.
Reimplemented from cugl::audio::AudioNode.
|
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.
time | The elapsed time in seconds. |
Reimplemented from cugl::audio::AudioNode.
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.
loop | The number of times to loop the audio |
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.
time | The overlap time in seconds. |
|
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.
position | the current frame position of this audio node. |
Reimplemented from cugl::audio::AudioNode.
|
overridevirtual |
Sets the typical read size of this node.
Some audio nodes need an internal buffer for operations like mixing or resampling. In that case, it helps to know the requested read
size ahead of time. The capacity is the minimal required read amount of the AudioEngine
and corresponds to AudioEngine#getReadSize
.
It is not actually necessary to set this size. However for nodes with internal buffer, setting this value can optimize performance.
This method is not synchronized because it is assumed that this value will never change while the audio engine in running. The average user should never call this method explicitly. You should always call AudioEngine#setReadSize
instead.
size | The typical read size of this node. |
Reimplemented from cugl::audio::AudioNode.
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.
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.
|
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.
Reimplemented from cugl::audio::AudioNode.