CUGL 2.3
Cornell University Game Library
|
#include <CUAudioWaveform.h>
Public Types | |
enum class | Type : int { NOISE = 0 , SINE = 1 , NAIVE_TRIANG = 2 , NAIVE_SQUARE = 3 , NAIVE_TOOTH = 4 , NAIVE_TRAIN = 5 , POLY_TRIANG = 6 , POLY_SQUARE = 7 , POLY_TOOTH = 8 , BLIT_TRAIN = 9 , UNKNOWN = 10 } |
Public Member Functions | |
AudioWaveform () | |
~AudioWaveform () | |
bool | init () |
bool | init (Uint8 channels, Uint32 rate) |
bool | init (Uint8 channels, Uint32 rate, Type type, float frequency) |
virtual void | dispose () override |
Type | getType () const |
void | setType (Type type) |
bool | isUpper () const |
void | setUpper (bool upper) |
float | getFrequency () const |
void | setFrequency (float frequency) |
virtual Sint64 | getLength () const override |
virtual double | getDuration () const override |
void | setDuration (double time) |
Uint32 | generate (float *buffer, Uint32 frames, Uint64 offset, float last) |
virtual std::shared_ptr< audio::AudioNode > | createNode () override |
Public Member Functions inherited from cugl::Sound | |
Sound () | |
~Sound () | |
virtual void | dispose () |
Uint32 | getRate () const |
Uint32 | getChannels () const |
virtual Sint64 | getLength () const |
virtual double | getDuration () const |
const std::string | getFile () const |
const std::string | getSuffix () const |
float | getVolume () const |
void | setVolume (float volume) |
virtual std::shared_ptr< audio::AudioNode > | createNode () |
Static Public Member Functions | |
static std::shared_ptr< AudioWaveform > | alloc () |
static std::shared_ptr< AudioWaveform > | alloc (Uint8 channels, Uint32 rate) |
static std::shared_ptr< AudioWaveform > | alloc (Uint8 channels, Uint32 rate, Type type, float frequency) |
static std::shared_ptr< AudioWaveform > | allocWithData (const std::shared_ptr< JsonValue > &data) |
Static Public Attributes | |
static const float | DEFAULT_FREQUENCY |
Protected Attributes | |
std::atomic< int > | _type |
std::atomic< bool > | _upper |
std::atomic< float > | _frequency |
std::atomic< bool > | _newfreq |
std::atomic< double > | _duration |
std::minstd_rand0 | _random |
Protected Attributes inherited from cugl::Sound | |
Uint8 | _channels |
Uint32 | _rate |
std::string | _file |
float | _volume |
This class represents a single-frequency waveform.
Intuitively, this class is used to represent a pure sine wave, which can be read and included in an audio graph. However, this class also supports more traditional computer-music waveforms, like square waves and sawtooth waves. The type of waveform is specified by the getType()
attribute.
We support both naive waveforms and bandwidth-limited forms. Bandwidth-limited forms are design to reduce the aliasing that can occur at the discontinuites:
https://ccrma.stanford.edu/~stilti/papers/blit.pdf
For simplicity, we do not use the BLIT integration techniques of Stilson and Smith. Those techniques are subject to error creep over time unless a a backing table is used. Instead, we use the PolyBLEP technique:
https://ieeexplore.ieee.org/document/4117934
This technique is not "music quality." It is known to have audible aliasing near the Nyquist frequency and overly attenuate higher frequencies. However, it is compact and ideal for real-time sound generation. It is also good enough for procedural sound generation in most games.
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 audio::AudioNode#setCallback
.
|
strong |
The wave generator type.
These types are inspired by STK, the Synthesis Toolkit (even though we chose not to adopt BLIT integration). They are not necessarily complete and additional wave form types may be added at any time. For that reason, you should never refer to a type by its raw number.
Enumerator | |
---|---|
NOISE | Creates random noise using the C rand() function. The quality of the rand() function varies from one OS to another. |
SINE | Creates a sine wave with the given frequency. |
NAIVE_TRIANG | Creates a naive square triangular with the given frequency. The waveform will have first-order discontinuities at PI and 2PI. This will create a more smoother sound than a square or sawtooth wave of the same frequency. |
NAIVE_SQUARE | Creates a naive square wave with the given frequency. The waveform will have discontinuities at PI and 2PI. This will create a harsh sound reminiscent of old-school games. |
NAIVE_TOOTH | Creates a naive sawtooth wave with the given frequency. The waveform will have a discontinuity at 2PI. This will create a harsh sound reminiscent of old-school games. |
NAIVE_TRAIN | Creates an alternating sign impulse train with the given frequency. The frequence given is the twice the period of the impulse because the signs will alternate when |
POLY_TRIANG | Creates a bandwidth-limited triangle wave with the given frequency. The algorithm uses a PolyBLEP curve to create a bandwidth-limited square wave, as reported in "Antialiasing Oscillators in Subtractive Synthesis" by Valimaki and Huovilainen (2007). This wave is then integrated to produce a triangle wave, using the leaky integration in "Alias-Free Digital Synthesis of Classic Analog Waveforms" by Stilson and Smith (1996). This particular version is adapted from http://www.martin-finke.de/blog/articles/audio-plugins-018-polyblep-oscillator/ |
POLY_SQUARE | Creates a bandwidth-limited square wave with the given frequency. The algorithm uses a PolyBLEP curve as reported in "Antialiasing Oscillators in Subtractive Synthesis" by Valimaki and Huovilainen (2007). This particular version is adapted from http://www.martin-finke.de/blog/articles/audio-plugins-018-polyblep-oscillator/ |
POLY_TOOTH | Creates a bandwidth-limited sawtooth wave with the given frequency. The algorithm uses a PolyBLEP curve as reported in "Antialiasing Oscillators in Subtractive Synthesis" by Valimaki and Huovilainen (2007). This particular version is adapted from http://www.martin-finke.de/blog/articles/audio-plugins-018-polyblep-oscillator/ |
BLIT_TRAIN | Creates a band-limited impulse train. This algorithm uses the closed-form algorithm "Alias-Free Digital Synthesis of Classic Analog Waveforms" by Stilson and Smith (1996). This implementation assumes the maximum number of harmonics. Based on code by Robin Davies, Gary Scavone, 2005 - 2006. |
UNKNOWN | An unknown type |
cugl::AudioWaveform::AudioWaveform | ( | ) |
Creates a degenerate waveform with no frequency.
The waveform has no channels or frequency, so read options will do nothing. The waveform must be initialized to be used.
|
inline |
Deletes this waveform, disposing of all resources.
|
inlinestatic |
Returns a newly allocated sine wave of 480 Hz.
When included in an audio graph, the node will support 2 channels at a sampling rate of 48000 Hz.
|
inlinestatic |
Returns a newly allocated sine wave of 480 Hz.
When included in an audio graph, the node will support the given number of channels at the given sampling rate.
channels | The number of audio channels |
rate | The sample rate (frequency) in Hz |
|
inlinestatic |
Returns a newly allocated wave form of the given type and frequency.
The frequency is specified is the fundamental frequency of the wave form. However, for the Type#NOISE
type, it is the seed of the random number generator.
The frequency specified is independent of the sampling rate. The wave form algorithms will create the correct date for both the sampling rate and frequency.
channels | The number of audio channels |
rate | The sample rate (frequency) in Hz |
type | The waveform type |
frequency | The waveform fundamental frequency |
|
static |
Returns a newly allocated waveform with the given JSON specificaton.
This initializer is designed to receive the "data" object from the JSON passed to Scene2Loader
. This JSON format supports the following attribute values:
"shape": The wave shape as a string (e.g. "sine", "triangle") "tone": A float, representing the frequency "channels": An int, representing the number of channels "rate": An int, representing the sample rate "volume": A float, representing the volume "duration" A float, representing the duration in seconds
All attributes are optional. There are no required attributes. The recognized shapes are as follows: noise, sine, native triangle, naive square, naive sawtooth, naive impulse, triangle, square, sawtooth, and impulse. The non-naive names are all bandwidth limited.
data | The JSON object specifying the waveform |
|
overridevirtual |
Returns a playble audio node for this asset.
This audio node may be attached to an audio::AudioOutput
for immediate playback. Nodes are distinct. Each call to this method allocates a new audio node.
Reimplemented from cugl::Sound.
|
overridevirtual |
Disposes any resources allocated for this waveform
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::Sound.
Uint32 cugl::AudioWaveform::generate | ( | float * | buffer, |
Uint32 | frames, | ||
Uint64 | offset, | ||
float | last | ||
) |
Generates the given number of frames for the waveform fom the given offset.
This function is used by audio::AudioNode
to generate the correct data for each type. For reasons of precision, the offset is given in frames and not the phase (which is real-valued).
Some waveforms require discrete integration. This is the purpose of last, which was the last sample generated. It is up to the user to remember this value. The method returns the frame position of the last sample generated.
buffer | The read buffer to store the results |
frames | The maximum number of frames to read |
offset | The phase offset measured in frames |
last | The last value generated (for integration purposes) |
|
overridevirtual |
Returns the length of this waveform in seconds.
The accuracy of this method depends on the specific implementation. If the asset is infinite (e.g. AudioWaveform
), then this method returns a negative value.
Reimplemented from cugl::Sound.
float cugl::AudioWaveform::getFrequency | ( | ) | const |
Returns the fundamental frequency of this waveform.
|
overridevirtual |
Returns the frame length of this waveform.
The frame length is the number of audio samples in the asset. If the asset is infinite (e.g. AudioWaveform
), then this method returns a negative value.
Reimplemented from cugl::Sound.
Type cugl::AudioWaveform::getType | ( | ) | const |
Returns the waveform type.
bool cugl::AudioWaveform::init | ( | ) |
Initializes a stereo sine wave of 480 Hz.
When included in an audio graph, the node will support 2 channels at a sampling rate of 48000 Hz.
bool cugl::AudioWaveform::init | ( | Uint8 | channels, |
Uint32 | rate | ||
) |
Initializes a sine wave of 480 Hz.
When included in an audio graph, the node will support the given number of channels at the given sampling rate.
channels | The number of audio channels |
rate | The sample rate (frequency) in Hz |
bool cugl::AudioWaveform::init | ( | Uint8 | channels, |
Uint32 | rate, | ||
Type | type, | ||
float | frequency | ||
) |
Initializes a wave form of the given type and frequency.
The frequency is specified is the fundamental frequency of the wave form. However, for the Type#NOISE
type, it is the seed of the random number generator.
The frequency specified is independent of the sampling rate. The wave form algorithms will create the correct date for both the sampling rate and frequency.
channels | The number of audio channels |
rate | The sample rate (frequency) in Hz |
type | The waveform type |
frequency | The waveform fundamental frequency |
bool cugl::AudioWaveform::isUpper | ( | ) | const |
Returns true if the waveform has only nonnegative samples.
Mathematically, we sometimes want a waveform to have only non-negative values. For an impulse train, this means a train with only positive poles (as opposed to a bipolar train). For triangle, square, and sawtooth waves, the result is a waveform of the same shape but from 0 to 1 instead of -1 to 1. For a sine wave, the result is the absolute value (or a rectified sine wave). For noise, this has no effect.
void cugl::AudioWaveform::setDuration | ( | double | time | ) |
Sets the length of this waveform in seconds.
The accuracy of this method depends on the specific implementation. If the asset is infinite (e.g. AudioWaveform
), then this value is negative.
time | the length of this waveform in seconds. |
void cugl::AudioWaveform::setFrequency | ( | float | frequency | ) |
Sets the fundamental frequency of this waveform.
frequency | the fundamental frequency of this waveform. |
void cugl::AudioWaveform::setType | ( | Type | type | ) |
Sets the waveform type.
type | the waveform type. |
void cugl::AudioWaveform::setUpper | ( | bool | upper | ) |
Sets whether the waveform has only nonnegative samples.
Mathematically, we sometimes want a waveform to have only non-negative values. For an impulse train, this means a train with only positive poles (as opposed to a bipolar train). For triangle, square, and sawtooth waves, the result is a waveform of the same shape but from 0 to 1 instead of -1 to 1. For a sine wave, the result is the absolute value (or a rectified sine wave). For noise, this has no effect.
upper | Whether the waveform has only nonnegative samples. |
|
protected |
The duration in seconds; -1 if infinite
|
protected |
The (normalized) fundamental frequency
|
protected |
Whether the frequency has changed recently
|
protected |
The random generator for noise
|
protected |
Atomic proxy for the signal type
|
protected |
Whether to limit the waveform to the positive y-axis.
|
static |
The default fundamental frequency