From 479d36c2a1463960cf62bdd03676de0ae92a2a52 Mon Sep 17 00:00:00 2001 From: David Reid Date: Tue, 25 Feb 2020 19:07:50 +1000 Subject: [PATCH] Add support for Brownian noise. --- miniaudio.h | 101 +++++++++++++++++- .../ma_test_generation_noise.c | 25 +++++ 2 files changed, 124 insertions(+), 2 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 38ff9c94..288e100f 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -5190,7 +5190,8 @@ typedef struct typedef enum { ma_noise_type_white, - ma_noise_type_pink + ma_noise_type_pink, + ma_noise_type_brownian } ma_noise_type; typedef struct @@ -5217,6 +5218,10 @@ typedef struct double accumulation[MA_MAX_CHANNELS]; ma_uint32 counter[MA_MAX_CHANNELS]; } pink; + struct + { + double accumulation[MA_MAX_CHANNELS]; + } brownian; } state; } ma_noise; @@ -40699,6 +40704,13 @@ ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise) } } + if (pNoise->config.type == ma_noise_type_brownian) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) { + pNoise->state.brownian.accumulation[iChannel] = 0; + } + } + return MA_SUCCESS; } @@ -40811,7 +40823,8 @@ static MA_INLINE float ma_noise_f32_pink(ma_noise* pNoise, ma_uint32 iChannel) pNoise->state.pink.accumulation[iChannel] += (binNext - binPrev); pNoise->state.pink.counter[iChannel] += 1; - result = (ma_lcg_rand_f64(&pNoise->lcg) + pNoise->state.pink.accumulation[iChannel]) / 10; + result = (ma_lcg_rand_f64(&pNoise->lcg) + pNoise->state.pink.accumulation[iChannel]); + result /= 10; return (float)(result * pNoise->config.amplitude); } @@ -40882,6 +40895,86 @@ static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__pink(ma_noise* pNoise, void return frameCount; } + +static MA_INLINE float ma_noise_f32_brownian(ma_noise* pNoise, ma_uint32 iChannel) +{ + double result; + + result = (ma_lcg_rand_f64(&pNoise->lcg) + pNoise->state.brownian.accumulation[iChannel]); + result /= 1.005; /* Don't escape the -1..1 range on average. */ + + pNoise->state.brownian.accumulation[iChannel] = result; + result /= 20; + + return (float)(result * pNoise->config.amplitude); +} + +static MA_INLINE ma_int16 ma_noise_s16_brownian(ma_noise* pNoise, ma_uint32 iChannel) +{ + return ma_pcm_sample_f32_to_s16(ma_noise_f32_brownian(pNoise, iChannel)); +} + +static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__brownian(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount) +{ + ma_uint64 iFrame; + ma_uint32 iChannel; + + if (pNoise->config.format == ma_format_f32) { + float* pFramesOutF32 = (float*)pFramesOut; + if (pNoise->config.duplicateChannels) { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float s = ma_noise_f32_brownian(pNoise, 0); + for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = s; + } + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = ma_noise_f32_brownian(pNoise, iChannel); + } + } + } + } else if (pNoise->config.format == ma_format_s16) { + ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut; + if (pNoise->config.duplicateChannels) { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_int16 s = ma_noise_s16_brownian(pNoise, 0); + for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = s; + } + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = ma_noise_s16_brownian(pNoise, iChannel); + } + } + } + } else { + ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format); + ma_uint32 bpf = bps * pNoise->config.channels; + + if (pNoise->config.duplicateChannels) { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float s = ma_noise_f32_brownian(pNoise, 0); + for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); + } + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) { + float s = ma_noise_f32_brownian(pNoise, iChannel); + ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); + } + } + } + } + + return frameCount; +} + ma_uint64 ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount) { if (pNoise == NULL) { @@ -40896,6 +40989,10 @@ ma_uint64 ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 return ma_noise_read_pcm_frames__pink(pNoise, pFramesOut, frameCount); } + if (pNoise->config.type == ma_noise_type_brownian) { + return ma_noise_read_pcm_frames__brownian(pNoise, pFramesOut, frameCount); + } + /* Should never get here. */ MA_ASSERT(MA_FALSE); return 0; diff --git a/tests/test_generation/ma_test_generation_noise.c b/tests/test_generation/ma_test_generation_noise.c index 2b3b8a33..991fccc1 100644 --- a/tests/test_generation/ma_test_generation_noise.c +++ b/tests/test_generation/ma_test_generation_noise.c @@ -49,6 +49,11 @@ ma_result test_noise__f32() hasError = MA_TRUE; } + result = test_noise__by_format_and_type(ma_format_f32, ma_noise_type_brownian, "output/noise_f32_brownian.wav"); + if (result != MA_SUCCESS) { + hasError = MA_TRUE; + } + if (hasError) { return MA_ERROR; } else { @@ -66,6 +71,16 @@ ma_result test_noise__s16() hasError = MA_TRUE; } + result = test_noise__by_format_and_type(ma_format_s16, ma_noise_type_pink, "output/noise_s16_pink.wav"); + if (result != MA_SUCCESS) { + hasError = MA_TRUE; + } + + result = test_noise__by_format_and_type(ma_format_s16, ma_noise_type_brownian, "output/noise_s16_brownian.wav"); + if (result != MA_SUCCESS) { + hasError = MA_TRUE; + } + if (hasError) { return MA_ERROR; } else { @@ -83,6 +98,16 @@ ma_result test_noise__u8() hasError = MA_TRUE; } + result = test_noise__by_format_and_type(ma_format_u8, ma_noise_type_pink, "output/noise_u8_pink.wav"); + if (result != MA_SUCCESS) { + hasError = MA_TRUE; + } + + result = test_noise__by_format_and_type(ma_format_u8, ma_noise_type_brownian, "output/noise_u8_brownian.wav"); + if (result != MA_SUCCESS) { + hasError = MA_TRUE; + } + if (hasError) { return MA_ERROR; } else {