Commit 8a7a65c2 authored by David Reid's avatar David Reid

API CHANGE: Replace ma_sine_wave with ma_waveform.

The ma_waveform API is a more general API supporting different waveform
including sine, square, triangle and sawtooth.
parent 415ded56
...@@ -18,25 +18,25 @@ void main_loop__em() ...@@ -18,25 +18,25 @@ void main_loop__em()
void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
{ {
ma_sine_wave* pSineWave; ma_waveform* pSineWave;
MA_ASSERT(pDevice->playback.channels == DEVICE_CHANNELS); MA_ASSERT(pDevice->playback.channels == DEVICE_CHANNELS);
pSineWave = (ma_sine_wave*)pDevice->pUserData; pSineWave = (ma_waveform*)pDevice->pUserData;
MA_ASSERT(pSineWave != NULL); MA_ASSERT(pSineWave != NULL);
ma_sine_wave_read_pcm_frames(pSineWave, pOutput, frameCount, ma_format_f32, DEVICE_CHANNELS); ma_waveform_read_pcm_frames(pSineWave, pOutput, frameCount, ma_format_f32, DEVICE_CHANNELS);
(void)pInput; /* Unused. */ (void)pInput; /* Unused. */
} }
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
ma_sine_wave sineWave; ma_waveform sineWave;
ma_device_config deviceConfig; ma_device_config deviceConfig;
ma_device device; ma_device device;
ma_sine_wave_init(0.2, 400, DEVICE_SAMPLE_RATE, &sineWave); ma_waveform_init(ma_waveform_type_sine, 0.2, 220, DEVICE_SAMPLE_RATE, &sineWave);
deviceConfig = ma_device_config_init(ma_device_type_playback); deviceConfig = ma_device_config_init(ma_device_type_playback);
deviceConfig.playback.format = DEVICE_FORMAT; deviceConfig.playback.format = DEVICE_FORMAT;
......
...@@ -105,8 +105,10 @@ Other less major API changes have also been made in version 0.10. ...@@ -105,8 +105,10 @@ Other less major API changes have also been made in version 0.10.
`ma_device_set_stop_callback()` has been removed. You now must set the stop callback via the device config just like the data callback. `ma_device_set_stop_callback()` has been removed. You now must set the stop callback via the device config just like the data callback.
`ma_sine_wave_read_f32()` and `ma_sine_wave_read_f32_ex()` have been removed and replaced with `ma_sine_wave_process_pcm_frames()` which supports outputting The `ma_sine_wave` API has been replaced with a more general API called `ma_waveform`. This supports generation of different types of waveforms, including
PCM frames in any format (specified by a parameter). sine, square, triangle and sawtooth. Use `ma_waveform_init()` in place of `ma_sine_wave_init()` to initialize the waveform object. This takes the same
parameters, except an additional `ma_waveform_type` value which you would set to `ma_waveform_type_sine`. Use `ma_waveform_read_pcm_frames()` in place of
`ma_sine_wave_read_f32()` and `ma_sine_wave_read_f32_ex()`.
`ma_convert_frames()` and `ma_convert_frames_ex()` have been changed. Both of these functions now take a new parameter called `frameCountOut` which specifies `ma_convert_frames()` and `ma_convert_frames_ex()` have been changed. Both of these functions now take a new parameter called `frameCountOut` which specifies
the size of the output buffer in PCM frames. This has been added for safety. In addition to this, the parameters for `ma_convert_frames_ex()` have changed to the size of the output buffer in PCM frames. This has been added for safety. In addition to this, the parameters for `ma_convert_frames_ex()` have changed to
...@@ -127,6 +129,13 @@ filters together. Low-pass filtering is achieved via the `ma_lpf` API. Since the ...@@ -127,6 +129,13 @@ filters together. Low-pass filtering is achieved via the `ma_lpf` API. Since the
point and 16-bit signed integer formats. point and 16-bit signed integer formats.
Sine, Square, Triangle and Sawtooth Waveforms
---------------------------------------------
Previously miniaudio supported only sine wave generation. This has now been generalized to support sine, square, triangle and sawtooth waveforms. The old
`ma_sine_wave` API has been removed and replaced with the `ma_waveform` API. Use `ma_waveform_init()` to initialize the waveform. Here you specify tyhe type of
waveform you want to generated. You then read data using `ma_waveform_read_pcm_frames()`.
Miscellaneous Changes Miscellaneous Changes
--------------------- ---------------------
Internal functions have all been made static where possible. If you get warnings about unused functions, please submit a bug report. Internal functions have all been made static where possible. If you get warnings about unused functions, please submit a bug report.
...@@ -4714,16 +4723,25 @@ ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config ...@@ -4714,16 +4723,25 @@ ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config
Generation Generation
************************************************************************************************************************************************************/ ************************************************************************************************************************************************************/
typedef enum
{
ma_waveform_type_sine,
ma_waveform_type_square,
ma_waveform_type_triangle,
ma_waveform_type_sawtooth
} ma_waveform_type;
typedef struct typedef struct
{ {
ma_waveform_type type;
double amplitude; double amplitude;
double periodsPerSecond; double frequency;
double delta; double deltaTime;
double time; double time;
} ma_sine_wave; } ma_waveform;
ma_result ma_sine_wave_init(double amplitude, double period, ma_uint32 sampleRate, ma_sine_wave* pSineWave); ma_result ma_waveform_init(ma_waveform_type type, double amplitude, double frequency, ma_uint32 sampleRate, ma_waveform* pWaveform);
ma_uint64 ma_sine_wave_read_pcm_frames(ma_sine_wave* pSineWave, void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels); ma_uint64 ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels);
#ifdef __cplusplus #ifdef __cplusplus
} }
...@@ -5300,6 +5318,7 @@ Standard Library Stuff ...@@ -5300,6 +5318,7 @@ Standard Library Stuff
#define ma_countof(x) (sizeof(x) / sizeof(x[0])) #define ma_countof(x) (sizeof(x) / sizeof(x[0]))
#define ma_max(x, y) (((x) > (y)) ? (x) : (y)) #define ma_max(x, y) (((x) > (y)) ? (x) : (y))
#define ma_min(x, y) (((x) < (y)) ? (x) : (y)) #define ma_min(x, y) (((x) < (y)) ? (x) : (y))
#define ma_abs(x) (((x) > 0) ? (x) : -(x))
#define ma_clamp(x, lo, hi) (ma_max(lo, ma_min(x, hi))) #define ma_clamp(x, lo, hi) (ma_max(lo, ma_min(x, hi)))
#define ma_offset_ptr(p, offset) (((ma_uint8*)(p)) + (offset)) #define ma_offset_ptr(p, offset) (((ma_uint8*)(p)) + (offset))
...@@ -5344,8 +5363,6 @@ static MA_INLINE float ma_log10f(float x) ...@@ -5344,8 +5363,6 @@ static MA_INLINE float ma_log10f(float x)
} }
/* /*
Return Values: Return Values:
0: Success 0: Success
...@@ -37860,61 +37877,184 @@ ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config ...@@ -37860,61 +37877,184 @@ ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config
Generation Generation
**************************************************************************************************************************************************************/ **************************************************************************************************************************************************************/
ma_result ma_sine_wave_init(double amplitude, double periodsPerSecond, ma_uint32 sampleRate, ma_sine_wave* pSineWave) ma_result ma_waveform_init(ma_waveform_type type, double amplitude, double frequency, ma_uint32 sampleRate, ma_waveform* pWaveform)
{ {
if (pSineWave == NULL) { if (pWaveform == NULL) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
MA_ZERO_OBJECT(pSineWave);
if (amplitude == 0 || periodsPerSecond == 0) { MA_ZERO_OBJECT(pWaveform);
return MA_INVALID_ARGS;
pWaveform->type = type;
pWaveform->amplitude = amplitude;
pWaveform->frequency = frequency;
pWaveform->deltaTime = 1.0 / sampleRate;
pWaveform->time = 0;
return MA_SUCCESS;
}
static float ma_waveform_sine_f32(double time, double frequency, double amplitude)
{
return (float)(ma_sin(MA_TAU_D * time * frequency) * amplitude);
}
static float ma_waveform_square_f32(double time, double frequency, double amplitude)
{
double t = time * frequency;
double f = t - (ma_uint64)t;
double r;
if (f < 0.5) {
r = amplitude;
} else {
r = -amplitude;
} }
if (amplitude > 1) { return (float)r;
amplitude = 1; }
static float ma_waveform_triangle_f32(double time, double frequency, double amplitude)
{
double t = time * frequency;
double f = t - (ma_uint64)t;
double r;
r = 2 * ma_abs(2 * (f - 0.5)) - 1;
return (float)(r * amplitude);
}
static float ma_waveform_sawtooth_f32(double time, double frequency, double amplitude)
{
double t = time * frequency;
double f = t - (ma_uint64)t;
double r;
r = 2 * (f - 0.5);
return (float)(r * amplitude);
}
static void ma_waveform_read_pcm_frames__sine(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels)
{
ma_uint64 iFrame;
ma_uint64 iChannel;
ma_uint32 bpf = ma_get_bytes_per_frame(format, channels);
ma_uint32 bps = ma_get_bytes_per_sample(format);
MA_ASSERT(pWaveform != NULL);
MA_ASSERT(pFramesOut != NULL);
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
float s = ma_waveform_sine_f32(pWaveform->time, pWaveform->frequency, pWaveform->amplitude);
pWaveform->time += pWaveform->deltaTime;
for (iChannel = 0; iChannel < channels; iChannel += 1) {
ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), format, &s, ma_format_f32, 1, ma_dither_mode_none);
}
} }
if (amplitude < -1) { }
amplitude = -1;
static void ma_waveform_read_pcm_frames__square(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels)
{
ma_uint64 iFrame;
ma_uint64 iChannel;
ma_uint32 bpf = ma_get_bytes_per_frame(format, channels);
ma_uint32 bps = ma_get_bytes_per_sample(format);
MA_ASSERT(pWaveform != NULL);
MA_ASSERT(pFramesOut != NULL);
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
float s = ma_waveform_square_f32(pWaveform->time, pWaveform->frequency, pWaveform->amplitude);
pWaveform->time += pWaveform->deltaTime;
for (iChannel = 0; iChannel < channels; iChannel += 1) {
ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), format, &s, ma_format_f32, 1, ma_dither_mode_none);
}
} }
}
pSineWave->amplitude = amplitude; static void ma_waveform_read_pcm_frames__triangle(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels)
pSineWave->periodsPerSecond = periodsPerSecond; {
pSineWave->delta = MA_TAU_D / sampleRate; ma_uint64 iFrame;
pSineWave->time = 0; ma_uint64 iChannel;
ma_uint32 bpf = ma_get_bytes_per_frame(format, channels);
ma_uint32 bps = ma_get_bytes_per_sample(format);
return MA_SUCCESS; MA_ASSERT(pWaveform != NULL);
MA_ASSERT(pFramesOut != NULL);
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
float s = ma_waveform_triangle_f32(pWaveform->time, pWaveform->frequency, pWaveform->amplitude);
pWaveform->time += pWaveform->deltaTime;
for (iChannel = 0; iChannel < channels; iChannel += 1) {
ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), format, &s, ma_format_f32, 1, ma_dither_mode_none);
}
}
}
static void ma_waveform_read_pcm_frames__sawtooth(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels)
{
ma_uint64 iFrame;
ma_uint64 iChannel;
ma_uint32 bpf = ma_get_bytes_per_frame(format, channels);
ma_uint32 bps = ma_get_bytes_per_sample(format);
MA_ASSERT(pWaveform != NULL);
MA_ASSERT(pFramesOut != NULL);
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
float s = ma_waveform_sawtooth_f32(pWaveform->time, pWaveform->frequency, pWaveform->amplitude);
pWaveform->time += pWaveform->deltaTime;
for (iChannel = 0; iChannel < channels; iChannel += 1) {
ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), format, &s, ma_format_f32, 1, ma_dither_mode_none);
}
}
} }
ma_uint64 ma_sine_wave_read_pcm_frames(ma_sine_wave* pSineWave, void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels) ma_uint64 ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels)
{ {
if (pSineWave == NULL) { if (pWaveform == NULL) {
return 0; return 0;
} }
if (pFramesOut != NULL) { if (pFramesOut != NULL) {
ma_uint64 iFrame; switch (pWaveform->type)
for (iFrame = 0; iFrame < frameCount; iFrame += 1) { {
ma_uint64 iChannel; case ma_waveform_type_sine:
float s; {
ma_waveform_read_pcm_frames__sine(pWaveform, pFramesOut, frameCount, format, channels);
} break;
s = (float)(ma_sin(pSineWave->time * pSineWave->periodsPerSecond) * pSineWave->amplitude); case ma_waveform_type_square:
pSineWave->time += pSineWave->delta; {
ma_waveform_read_pcm_frames__square(pWaveform, pFramesOut, frameCount, format, channels);
} break;
for (iChannel = 0; iChannel < channels; iChannel += 1) { case ma_waveform_type_triangle:
ma_uint32 bpf = ma_get_bytes_per_frame(format, channels); {
ma_uint32 bps = ma_get_bytes_per_sample(format); ma_waveform_read_pcm_frames__triangle(pWaveform, pFramesOut, frameCount, format, channels);
} break;
ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), format, &s, ma_format_f32, 1, ma_dither_mode_none); case ma_waveform_type_sawtooth:
} {
ma_waveform_read_pcm_frames__sawtooth(pWaveform, pFramesOut, frameCount, format, channels);
} break;
default: return 0;
} }
} else { } else {
pSineWave->time += pSineWave->delta * (ma_int64)frameCount; /* Cast to int64 required for VC6. Won't affect anything in practice. */ pWaveform->time += pWaveform->deltaTime * (ma_int64)frameCount; /* Cast to int64 required for VC6. Won't affect anything in practice. */
} }
return frameCount; return frameCount;
} }
/* End globally disabled warnings. */ /* End globally disabled warnings. */
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma warning(pop) #pragma warning(pop)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment