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

#include <CUAudioResampler.h>

Inheritance diagram for cugl::audio::AudioResampler:
cugl::audio::AudioNode

Public Member Functions

 AudioResampler ()
 
 ~AudioResampler ()
 
virtual bool init () override
 
virtual bool init (Uint8 channels, Uint32 rate) override
 
bool init (const std::shared_ptr< AudioNode > &input, Uint32 rate)
 
virtual void dispose () override
 
bool attach (const std::shared_ptr< AudioNode > &node)
 
std::shared_ptr< AudioNodedetach ()
 
std::shared_ptr< AudioNodegetInput () const
 
Uint32 getInputRate () const
 
void setInputRate (Uint32 value)
 
float getStopband () const
 
void setStopband (float value)
 
Uint32 getBitPrecision () const
 
void setBitPrecision (Uint32 value)
 
Uint32 getZeroCrossings () const
 
void setZeroCrossings (Uint32 value)
 
virtual bool completed () 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
 
virtual double getRemaining () const override
 
virtual double setRemaining (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 ()
 

Static Public Member Functions

static std::shared_ptr< AudioResampleralloc ()
 
static std::shared_ptr< AudioResampleralloc (Uint8 channels, Uint32 rate)
 
static std::shared_ptr< AudioResampleralloc (const std::shared_ptr< AudioNode > &input, 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 provides a graph node for converting from one sample rate to another.

The node uses a kaiser-windowed sinc filter to perform continuous resampling on a potentially infinite audio stream. This is is necessary for cross-platform reasons as iPhones are very stubborn about delivering any requested sampling rates other than 48000.

The filter is configurable. You can set the number of zero crossings, as well as the attentionuation factor in decibels. Details behind the filter design of this resampler can be found here

https://tomroelandts.com/articles/how-to-create-a-configurable-filter-using-a-kaiser-window

This is a dynamic resampler. While the output sampling rate is fixed, the input is not. It will readjust the conversion filter to match the sampling rate of the input node whenever the input node changes.

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 class does not support any actions for the AudioNode#setCallback.

Constructor & Destructor Documentation

◆ AudioResampler()

cugl::audio::AudioResampler::AudioResampler ( )

Creates a degenerate audio resampler.

The node has not been initialized, so it is not active. The node must be initialized to be used.

◆ ~AudioResampler()

cugl::audio::AudioResampler::~AudioResampler ( )
inline

Deletes the audio resampler, disposing of all resources

Member Function Documentation

◆ advance()

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

Advances the stream by the given number of frames.

DELEGATED METHOD: This method delegates its call to the input node. It returns -1 if there is no input node or if this method is unsupported in that node

This method only advances the read position, it does not actually read data into a buffer. This method is generally not supported for nodes with real-time input like AudioInput.

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

Reimplemented from cugl::audio::AudioNode.

◆ alloc() [1/3]

static std::shared_ptr<AudioResampler> cugl::audio::AudioResampler::alloc ( )
inlinestatic

Returns a newly allocated resampler with 2 channels at 48000 Hz.

This sample rate of the output of this node is 48000 Hz, but the input sample rate depends on the input node, which can change over time. However, the input node must agree with number of channels, which is fixed.

Returns
a newly allocated resampler with 2 channels at 48000 Hz.

◆ alloc() [2/3]

static std::shared_ptr<AudioResampler> cugl::audio::AudioResampler::alloc ( const std::shared_ptr< AudioNode > &  input,
Uint32  rate 
)
inlinestatic

Returns a newly allocated resampler with the given input node and sample rate.

This node acquires the channels of the input, but will use the given sample rate as its output rate. If input is nullptr, this method will fail.

Parameters
inputThe audio node to resample
rateThe output sample rate (frequency) in Hz
Returns
a newly allocated resampler with the given input node and sample rate.

◆ alloc() [3/3]

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

Returns a newly allocated resampler with the given channels and sample rate.

This sample rate is the output rate of this node. The input same rate depends on the input node, which can change over time. However, the input node must agree with number of channels, which is fixed.

Parameters
channelsThe number of audio channels
rateThe output sample rate (frequency) in HZ
Returns
a newly allocated resampler with the given channels and sample rate.

◆ attach()

bool cugl::audio::AudioResampler::attach ( const std::shared_ptr< AudioNode > &  node)

Attaches an audio node to this resampler.

This method will reset the resampler stream if the input has a different rate than the previous input value (and is not the same rate as the output). It will fail if the input does not have the same number of channels as this resampler.

Parameters
nodeThe audio node to resample
Returns
true if the attachment was successful

◆ completed()

virtual bool cugl::audio::AudioResampler::completed ( )
overridevirtual

Returns true if this resampler has no more data.

An audio node is typically completed if it return 0 (no frames read) on subsequent calls to read(). However, for infinite-running audio threads, it is possible for this method to return true even when data can still be read; in that case the node is notifying that it should be shut down.

Returns
true if this audio node has no more data.

Reimplemented from cugl::audio::AudioNode.

◆ detach()

std::shared_ptr<AudioNode> cugl::audio::AudioResampler::detach ( )

Detaches an audio node from this resampler.

If the method succeeds, it returns the audio node that was removed. This method will not automatically reset the sampling stream.

Returns
The audio node to detach (or null if failed)

◆ dispose()

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

Disposes any resources allocated for this resampler.

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.

◆ getBitPrecision()

Uint32 cugl::audio::AudioResampler::getBitPrecision ( ) const
inline

Returns the bit precision for audio sent to this filter.

Even though CUGL processes all audio data as floats, that does not mean that the audio on this platform is guaranteed to have 32 bit precision. Indeed, on Android, most audio is processed at 16 bit precision, and many audio files are recorded at this level of precision as well. Hence this filter assumes 16 bit precision by default.

This is relevant for the size of the filter to process the audio. Each additional bit doubles the size of the filter table used for the convolution. A 16 bit filter uses a very reasonable 512 entries per zero crossing. On the other hand, a 32 bit filter would require 131072 entries per zero crossing. Given the limitations of real-time resampling, it typically does not make much sense to assume more than 16 bits.

Returns
the bit precision for audio sent to this filter.

◆ getElapsed()

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

Returns the elapsed time in seconds.

DELEGATED METHOD: This method delegates its call to the input node. It returns -1 if there is no input node or if this method is unsupported in that node

In some nodes like AudioInput, this method is only supported if mark() is set. In that case, the times will be the number of seconds since the mark. Other nodes like AudioPlayer measure from the start of the stream.

Returns
the elapsed time in seconds.

Reimplemented from cugl::audio::AudioNode.

◆ getInput()

std::shared_ptr<AudioNode> cugl::audio::AudioResampler::getInput ( ) const
inline

Returns the input node of this resampler.

Returns
the input node of this resampler.

◆ getInputRate()

Uint32 cugl::audio::AudioResampler::getInputRate ( ) const
inline

Returns the input sample rate of this filter.

This value is distinct from AudioNode#getRate(), which is the output sample rate of this node. Instead, this value is the sample rate of any audio node connected to this one via the attach method.

Normally this value is assigned when a new audio node is attached. However, changing this value requires that the underlying read buffer be resized. Hence, by setting this value ahead of time (and making sure that all attached input nodes match this sample rate), you can improve the performance of this filter.

Assigning this value while there is still an attached audio node has undefined behavior.

Returns
the input sample rate of this filter.

◆ getPosition()

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

Returns the current frame position of this audio node

DELEGATED METHOD: This method delegates its call to the input node. It returns -1 if there is no input node or if this method is unsupported in that node

In some nodes like AudioInput, this method is only supported if mark() is set. In that case, the position will be the number of frames since the mark. Other nodes like AudioPlayer measure from the start of the stream.

Returns
the current frame position of this audio node.

Reimplemented from cugl::audio::AudioNode.

◆ getRemaining()

virtual double cugl::audio::AudioResampler::getRemaining ( ) const
overridevirtual

Returns the remaining time in seconds.

DELEGATED METHOD: This method delegates its call to the input node. It returns -1 if there is no input node or if this method is unsupported in that node

In some nodes like AudioInput, this method is only supported if setRemaining() has been called. In that case, the node will be marked as completed after the given number of seconds. This may or may not actually move the read head. For example, in AudioPlayer it will skip to the end of the sample. However, in AudioInput it will simply time out after the given time.

Returns
the remaining time in seconds.

Reimplemented from cugl::audio::AudioNode.

◆ getStopband()

float cugl::audio::AudioResampler::getStopband ( ) const
inline

Returns the stopband attentuation for this filter in dB

This value is described in more detail here:

https://tomroelandts.com/articles/how-to-create-a-configurable-filter-using-a-kaiser-window

By default, this value is 80.0.

Returns
the ripple factor for this filter in dB

◆ getZeroCrossings()

Uint32 cugl::audio::AudioResampler::getZeroCrossings ( ) const
inline

Returns the number of zero-crossings of this filter.

The zero-crossings of a sinc filter are relevant because the determine the number of coefficients in a single filter convolution. For X zero-crossings, a single output sample requires 2*(X-1) input computations. Increasing this value can give some increased value in filter. However, the droppoff for sinc filters is large enough that eventually that large enough values will have no discernable effect.

The default number of zero crossing is 5, meaning that this filter roughly causes an 8x-10x decrease in performance when processing audio (when taking all the relevant overhead into account). This value is that one recommended by this tutorial website:

https://www.dsprelated.com/freebooks/pasp/Windowed_Sinc_Interpolation.html
Returns
the number of zero-crossings of this filter.

◆ init() [1/3]

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

Initializes a resampler with 2 channels at 48000 Hz.

This sample rate of the output of this node is 48000 Hz, but the input sample rate depends on the input node, which can change over time. However, the input node must agree with number of channels, which is fixed.

Returns
true if initialization was successful

Reimplemented from cugl::audio::AudioNode.

◆ init() [2/3]

bool cugl::audio::AudioResampler::init ( const std::shared_ptr< AudioNode > &  input,
Uint32  rate 
)

Initializes a resampler with the given input node and sample rate.

This node acquires the channels of the input, but will use the given sample rate as its output rate. If input is nullptr, this method will fail.

Parameters
inputThe audio node to resample
rateThe output sample rate (frequency) in Hz
Returns
true if initialization was successful

◆ init() [3/3]

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

Initializes a resampler with the given channels and sample rate.

This sample rate is the output rate of this node. The input same rate depends on the input node, which can change over time. However, the input node must agree with number of channels, which is fixed.

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

Reimplemented from cugl::audio::AudioNode.

◆ mark()

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

Marks the current read position in the audio steam.

DELEGATED METHOD: This method delegates its call to the input node. It returns false if there is no input node or if this method is unsupported in that node

This method is typically used by reset() to determine where to restore the read position. For some nodes (like AudioInput), this method may start recording data to a buffer, which will continue until reset() is called.

It is possible for reset() to be supported even if this method is not.

Returns
true if the read position was marked.

Reimplemented from cugl::audio::AudioNode.

◆ read()

virtual Uint32 cugl::audio::AudioResampler::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 AudioOutput.

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.

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::AudioResampler::reset ( )
overridevirtual

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

DELEGATED METHOD: This method delegates its call to the input node. It returns false if there is no input node or if this method is unsupported in that node

When no mark() is set, the result of this method is node dependent. Some nodes (such as AudioPlayer) will reset to the beginning of the stream, while others (like AudioInput) only support a rest when a mark is set. Pay attention to the return value of this method to see if the call is successful.

Returns
true if the read position was moved.

Reimplemented from cugl::audio::AudioNode.

◆ setBitPrecision()

void cugl::audio::AudioResampler::setBitPrecision ( Uint32  value)

Sets the bit precision for audio sent to this filter.

Even though CUGL processes all audio data as floats, that does not mean that the audio on this platform is guaranteed to have 32 bit precision. Indeed, on Android, most audio is processed at 16 bit precision, and many audio files are recorded at this level of precision as well. Hence this filter assumes 16 bit precision by default.

This is relevant for the size of the filter to process the audio. Each additional bit doubles the size of the filter table used for the convolution. A 16 bit filter uses a very reasonable 512 entries per zero crossing. On the other hand, a 32 bit filter would require 131072 entries per zero crossing. Given the limitations of real-time resampling, it typically does not make much sense to assume more than 16 bits.

Parameters
valueThe bit precision for audio sent to this filter.

◆ setElapsed()

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

Sets the read position to the elapsed time in seconds.

DELEGATED METHOD: This method delegates its call to the input node. It returns -1 if there is no input node or if this method is unsupported in that node

In some nodes like AudioInput, this method is only supported if mark() is set. In that case, the new time will be meaured from the mark. Other nodes like AudioPlayer measure from the start of the stream.

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

Reimplemented from cugl::audio::AudioNode.

◆ setInputRate()

void cugl::audio::AudioResampler::setInputRate ( Uint32  value)

Sets the input sample rate of this filter.

This value is distinct from AudioNode#getRate(), which is the output sample rate of this node. Instead, this value is the sample rate of any audio node connected to this one via the attach method.

Normally this value is assigned when a new audio node is attached. However, changing this value requires that the underlying read buffer be resized. Hence, by setting this value ahead of time (and making sure that all attached input nodes match this sample rate), you can improve the performance of this filter.

Assigning this value while there is still an attached audio node has undefined behavior.

Parameters
valueThe input sample rate of this filter.

◆ setPosition()

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

Sets the current frame position of this audio node.

DELEGATED METHOD: This method delegates its call to the input node. It returns -1 if there is no input node or if this method is unsupported in that node

In some nodes like AudioInput, this method is only supported if mark() is set. In that case, the position will be the number of frames since the mark. Other nodes like AudioPlayer measure from the start of the stream.

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

Reimplemented from cugl::audio::AudioNode.

◆ setRemaining()

virtual double cugl::audio::AudioResampler::setRemaining ( double  time)
overridevirtual

Sets the remaining time in seconds.

DELEGATED METHOD: This method delegates its call to the input node. It returns -1 if there is no input node or if this method is unsupported in that node

If this method is supported, then the node will be marked as completed after the given number of seconds. This may or may not actually move the read head. For example, in AudioPlayer it will skip to the end of the sample. However, in AudioInput it will simply time out after the given time.

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

Reimplemented from cugl::audio::AudioNode.

◆ setStopband()

void cugl::audio::AudioResampler::setStopband ( float  value)

Sets the stopband attentuation for this filter in dB

This value is described in more detail here:

https://tomroelandts.com/articles/how-to-create-a-configurable-filter-using-a-kaiser-window

By default, this value is 80.0.

Parameters
valueThe ripple factor for this filter in dB

◆ setZeroCrossings()

void cugl::audio::AudioResampler::setZeroCrossings ( Uint32  value)

Sets the number of zero-crossings of this filter.

The zero-crossings of a sinc filter are relevant because the determine the number of coefficients in a single filter convolution. For X zero-crossings, a single output sample requires 2*(X-1) input computations. Increasing this value can give some increased value in filter. However, the droppoff for sinc filters is large enough that eventually that large enough values will have no discernable effect.

The default number of zero crossing is 5, meaning that this filter roughly causes an 8x-10x decrease in performance when processing audio (when taking all the relevant overhead into account). This value is that one recommended by this tutorial website:

https://www.dsprelated.com/freebooks/pasp/Windowed_Sinc_Interpolation.html
Parameters
valueThe number of zero-crossings of this filter.

◆ unmark()

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

Clears the current marked position.

DELEGATED METHOD: This method delegates its call to the input node. It returns false if there is no input node or if this method is unsupported in that node

If the method mark() started recording to a buffer (such as with AudioInput), this method will stop recording and release the buffer. When the mark is cleared, reset() may or may not work depending upon the specific node.

Returns
true if the read position was marked.

Reimplemented from cugl::audio::AudioNode.


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