diff --git a/miniaudio.h b/miniaudio.h index 5f8392ae..65e0f100 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -7614,6 +7614,7 @@ typedef enum ma_noise_type_brownian } ma_noise_type; + typedef struct { ma_format format; @@ -7635,19 +7636,25 @@ typedef struct { struct { - double bin[MA_MAX_CHANNELS][16]; - double accumulation[MA_MAX_CHANNELS]; - ma_uint32 counter[MA_MAX_CHANNELS]; + double** bin; + double* accumulation; + ma_uint32* counter; } pink; struct { - double accumulation[MA_MAX_CHANNELS]; + double* accumulation; } brownian; } state; + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; } ma_noise; -MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise); -MA_API void ma_noise_uninit(ma_noise* pNoise); +MA_API ma_result ma_noise_get_heap_size(const ma_noise_config* pConfig, size_t* pHeapSizeInBytes); +MA_API ma_result ma_noise_init_preallocated(const ma_noise_config* pConfig, void* pHeap, ma_noise* pNoise); +MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_noise* pNoise); +MA_API void ma_noise_uninit(ma_noise* pNoise, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); MA_API ma_result ma_noise_set_amplitude(ma_noise* pNoise, double amplitude); MA_API ma_result ma_noise_set_seed(ma_noise* pNoise, ma_int32 seed); @@ -57432,16 +57439,31 @@ static ma_data_source_vtable g_ma_noise_data_source_vtable = NULL /* onGetLength. No notion of a length for noise. */ }; -MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise) + +#ifndef MA_PINK_NOISE_BIN_SIZE +#define MA_PINK_NOISE_BIN_SIZE 16 +#endif + +typedef struct { - ma_result result; - ma_data_source_config dataSourceConfig; + size_t sizeInBytes; + struct + { + size_t binOffset; + size_t accumulationOffset; + size_t counterOffset; + } pink; + struct + { + size_t accumulationOffset; + } brownian; +} ma_noise_heap_layout; - if (pNoise == NULL) { - return MA_INVALID_ARGS; - } +static ma_result ma_noise_get_heap_layout(const ma_noise_config* pConfig, ma_noise_heap_layout* pHeapLayout) +{ + MA_ASSERT(pHeapLayout != NULL); - MA_ZERO_OBJECT(pNoise); + MA_ZERO_OBJECT(pHeapLayout); if (pConfig == NULL) { return MA_INVALID_ARGS; @@ -57451,6 +57473,76 @@ MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise) return MA_INVALID_ARGS; } + pHeapLayout->sizeInBytes = 0; + + /* Pink. */ + if (pConfig->type == ma_noise_type_pink) { + /* bin */ + pHeapLayout->pink.binOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += sizeof(double*) * pConfig->channels; + pHeapLayout->sizeInBytes += sizeof(double ) * pConfig->channels * MA_PINK_NOISE_BIN_SIZE; + + /* accumulation */ + pHeapLayout->pink.accumulationOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += sizeof(double) * pConfig->channels; + + /* counter */ + pHeapLayout->pink.counterOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += sizeof(ma_uint32) * pConfig->channels; + } + + /* Brownian. */ + if (pConfig->type == ma_noise_type_brownian) { + /* accumulation */ + pHeapLayout->brownian.accumulationOffset = pHeapLayout->sizeInBytes; + pHeapLayout->sizeInBytes += sizeof(double) * pConfig->channels; + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_noise_get_heap_size(const ma_noise_config* pConfig, size_t* pHeapSizeInBytes) +{ + ma_result result; + ma_noise_heap_layout heapLayout; + + if (pHeapSizeInBytes == NULL) { + return MA_INVALID_ARGS; + } + + *pHeapSizeInBytes = 0; + + result = ma_noise_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + *pHeapSizeInBytes = heapLayout.sizeInBytes; + + return MA_SUCCESS; +} + +MA_API ma_result ma_noise_init_preallocated(const ma_noise_config* pConfig, void* pHeap, ma_noise* pNoise) +{ + ma_result result; + ma_noise_heap_layout heapLayout; + ma_data_source_config dataSourceConfig; + ma_uint32 iChannel; + + if (pNoise == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pNoise); + + result = ma_noise_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + pNoise->_pHeap = pHeap; + MA_ZERO_MEMORY(pNoise->_pHeap, heapLayout.sizeInBytes); + dataSourceConfig = ma_data_source_config_init(); dataSourceConfig.vtable = &g_ma_noise_data_source_vtable; @@ -57463,15 +57555,20 @@ MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise) ma_lcg_seed(&pNoise->lcg, pConfig->seed); if (pNoise->config.type == ma_noise_type_pink) { - ma_uint32 iChannel; + pNoise->state.pink.bin = (double** )ma_offset_ptr(pHeap, heapLayout.pink.binOffset); + pNoise->state.pink.accumulation = (double* )ma_offset_ptr(pHeap, heapLayout.pink.accumulationOffset); + pNoise->state.pink.counter = (ma_uint32*)ma_offset_ptr(pHeap, heapLayout.pink.counterOffset); + for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) { + pNoise->state.pink.bin[iChannel] = (double*)ma_offset_ptr(pHeap, heapLayout.pink.binOffset + (sizeof(double*) * pConfig->channels) + (sizeof(double) * MA_PINK_NOISE_BIN_SIZE * iChannel)); pNoise->state.pink.accumulation[iChannel] = 0; pNoise->state.pink.counter[iChannel] = 1; } } if (pNoise->config.type == ma_noise_type_brownian) { - ma_uint32 iChannel; + pNoise->state.brownian.accumulation = (double*)ma_offset_ptr(pHeap, heapLayout.brownian.accumulationOffset); + for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) { pNoise->state.brownian.accumulation[iChannel] = 0; } @@ -57480,13 +57577,47 @@ MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise) return MA_SUCCESS; } -MA_API void ma_noise_uninit(ma_noise* pNoise) +MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_noise* pNoise) +{ + ma_result result; + size_t heapSizeInBytes; + void* pHeap; + + result = ma_noise_get_heap_size(pConfig, &heapSizeInBytes); + if (result != MA_SUCCESS) { + return result; + } + + if (heapSizeInBytes > 0) { + pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks); + if (pHeap == NULL) { + return MA_OUT_OF_MEMORY; + } + } else { + pHeap = NULL; + } + + result = ma_noise_init_preallocated(pConfig, pHeap, pNoise); + if (result != MA_SUCCESS) { + ma_free(pHeap, pAllocationCallbacks); + return result; + } + + pNoise->_ownsHeap = MA_TRUE; + return MA_SUCCESS; +} + +MA_API void ma_noise_uninit(ma_noise* pNoise, const ma_allocation_callbacks* pAllocationCallbacks) { if (pNoise == NULL) { return; } ma_data_source_uninit(&pNoise->ds); + + if (pNoise->_ownsHeap) { + ma_free(pNoise->_pHeap, pAllocationCallbacks); + } } MA_API ma_result ma_noise_set_amplitude(ma_noise* pNoise, double amplitude) @@ -57629,7 +57760,7 @@ static MA_INLINE float ma_noise_f32_pink(ma_noise* pNoise, ma_uint32 iChannel) double binNext; unsigned int ibin; - ibin = ma_tzcnt32(pNoise->state.pink.counter[iChannel]) & (ma_countof(pNoise->state.pink.bin[0]) - 1); + ibin = ma_tzcnt32(pNoise->state.pink.counter[iChannel]) & (MA_PINK_NOISE_BIN_SIZE - 1); binPrev = pNoise->state.pink.bin[iChannel][ibin]; binNext = ma_lcg_rand_f64(&pNoise->lcg); diff --git a/tests/test_common/ma_test_common.c b/tests/test_common/ma_test_common.c index 735e1cb6..74e7e43e 100644 --- a/tests/test_common/ma_test_common.c +++ b/tests/test_common/ma_test_common.c @@ -1,7 +1,3 @@ -/* Make sure we include the Speex resampler so we can test it. */ -#define MINIAUDIO_SPEEX_RESAMPLER_IMPLEMENTATION -#include "../../extras/speex_resampler/ma_speex_resampler.h" - #define MINIAUDIO_IMPLEMENTATION #include "../../miniaudio.h" diff --git a/tests/test_deviceio/ma_test_deviceio.c b/tests/test_deviceio/ma_test_deviceio.c index 4a49c460..f3b59ffb 100644 --- a/tests/test_deviceio/ma_test_deviceio.c +++ b/tests/test_deviceio/ma_test_deviceio.c @@ -235,13 +235,12 @@ ma_bool32 try_parse_noise(const char* arg, ma_noise_type* pNoiseType) ma_result print_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pDeviceInfo) { ma_result result; - ma_uint32 iFormat; ma_device_info detailedDeviceInfo; MA_ASSERT(pDeviceInfo != NULL); #if 1 - result = ma_context_get_device_info(pContext, deviceType, &pDeviceInfo->id, ma_share_mode_shared, &detailedDeviceInfo); + result = ma_context_get_device_info(pContext, deviceType, &pDeviceInfo->id, &detailedDeviceInfo); if (result != MA_SUCCESS) { return result; } @@ -249,17 +248,24 @@ ma_result print_device_info(ma_context* pContext, ma_device_type deviceType, con detailedDeviceInfo = *pDeviceInfo; #endif - printf("%s\n", pDeviceInfo->name); - printf(" Default: %s\n", (detailedDeviceInfo.isDefault) ? "Yes" : "No"); - printf(" Min Channels: %d\n", detailedDeviceInfo.minChannels); - printf(" Max Channels: %d\n", detailedDeviceInfo.maxChannels); - printf(" Min Sample Rate: %d\n", detailedDeviceInfo.minSampleRate); - printf(" Max Sample Rate: %d\n", detailedDeviceInfo.maxSampleRate); - printf(" Format Count: %d\n", detailedDeviceInfo.formatCount); - for (iFormat = 0; iFormat < detailedDeviceInfo.formatCount; ++iFormat) { - printf(" %s\n", ma_get_format_name(detailedDeviceInfo.formats[iFormat])); + /* TODO: Update this to print the new device info structure. */ + #if 0 + { + ma_uint32 iFormat; + + printf("%s\n", pDeviceInfo->name); + printf(" Default: %s\n", (detailedDeviceInfo.isDefault) ? "Yes" : "No"); + printf(" Min Channels: %d\n", detailedDeviceInfo.minChannels); + printf(" Max Channels: %d\n", detailedDeviceInfo.maxChannels); + printf(" Min Sample Rate: %d\n", detailedDeviceInfo.minSampleRate); + printf(" Max Sample Rate: %d\n", detailedDeviceInfo.maxSampleRate); + printf(" Format Count: %d\n", detailedDeviceInfo.formatCount); + for (iFormat = 0; iFormat < detailedDeviceInfo.formatCount; ++iFormat) { + printf(" %s\n", ma_get_format_name(detailedDeviceInfo.formats[iFormat])); + } + printf("\n"); } - printf("\n"); + #endif return MA_SUCCESS; } @@ -299,10 +305,9 @@ ma_result enumerate_devices(ma_context* pContext) return MA_SUCCESS; } -void on_log(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message) +void on_log(void* pUserData, ma_uint32 logLevel, const char* message) { - (void)pContext; - (void)pDevice; + (void)pUserData; printf("%s: %s\n", ma_log_level_to_string(logLevel), message); } @@ -321,11 +326,11 @@ void on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uin { /* In the playback case we just read from our input source. */ if (g_State.sourceType == source_type_decoder) { - ma_decoder_read_pcm_frames(&g_State.decoder, pFramesOut, frameCount); + ma_decoder_read_pcm_frames(&g_State.decoder, pFramesOut, frameCount, NULL); } else if (g_State.sourceType == source_type_waveform) { - ma_waveform_read_pcm_frames(&g_State.waveform, pFramesOut, frameCount); + ma_waveform_read_pcm_frames(&g_State.waveform, pFramesOut, frameCount, NULL); } else if (g_State.sourceType == source_type_noise) { - ma_noise_read_pcm_frames(&g_State.noise, pFramesOut, frameCount); + ma_noise_read_pcm_frames(&g_State.noise, pFramesOut, frameCount, NULL); } } break; @@ -333,7 +338,7 @@ void on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uin case ma_device_type_loopback: { /* In the capture and loopback cases we just output straight to a file. */ - ma_encoder_write_pcm_frames(&g_State.encoder, pFramesIn, frameCount); + ma_encoder_write_pcm_frames(&g_State.encoder, pFramesIn, frameCount, NULL); } break; case ma_device_type_duplex: @@ -345,7 +350,7 @@ void on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uin /* Also output to the encoder if necessary. */ if (g_State.hasEncoder) { - ma_encoder_write_pcm_frames(&g_State.encoder, pFramesIn, frameCount); + ma_encoder_write_pcm_frames(&g_State.encoder, pFramesIn, frameCount, NULL); } } break; @@ -426,13 +431,14 @@ int main(int argc, char** argv) /* Initialize the context first. If no backends were passed into the command line we just use defaults. */ contextConfig = ma_context_config_init(); - contextConfig.logCallback = on_log; result = ma_context_init((backendCount == 0) ? NULL : backends, backendCount, &contextConfig, &g_State.context); if (result != MA_SUCCESS) { printf("Failed to initialize context.\n"); return -1; } + ma_log_register_callback(ma_context_get_log(&g_State.context), ma_log_callback_init(on_log, NULL)); + /* Here we'll print some info about what we're doing. */ printf("Backend: %s\n", ma_get_backend_name(g_State.context.backend)); printf("Mode: %s\n", get_mode_description(deviceType)); @@ -503,7 +509,7 @@ int main(int argc, char** argv) if (g_State.sourceType == source_type_noise) { ma_noise_config noiseConfig; noiseConfig = ma_noise_config_init(g_State.device.playback.format, g_State.device.playback.channels, noiseType, 0, 0.1); - result = ma_noise_init(&noiseConfig, &g_State.noise); + result = ma_noise_init(&noiseConfig, NULL, &g_State.noise); if (result != MA_SUCCESS) { printf("Failed to initialize noise.\n"); ma_device_uninit(&g_State.device); @@ -515,7 +521,7 @@ int main(int argc, char** argv) if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback || (deviceType == ma_device_type_duplex && pFilePath != NULL && pFilePath[0] != '\0')) { ma_encoder_config encoderConfig; - encoderConfig = ma_encoder_config_init(ma_resource_format_wav, g_State.device.capture.format, g_State.device.capture.channels, g_State.device.sampleRate); + encoderConfig = ma_encoder_config_init(ma_encoding_format_wav, g_State.device.capture.format, g_State.device.capture.channels, g_State.device.sampleRate); result = ma_encoder_init_file(pFilePath, &encoderConfig, &g_State.encoder); if (result != MA_SUCCESS) { printf("Failed to initialize output file for capture \"%s\".\n", pFilePath); @@ -579,6 +585,12 @@ done: if (g_State.sourceType == source_type_decoder) { ma_decoder_uninit(&g_State.decoder); } + if (g_State.sourceType == source_type_waveform) { + ma_waveform_uninit(&g_State.waveform); + } + if (g_State.sourceType == source_type_noise) { + ma_noise_uninit(&g_State.noise, NULL); + } if (g_State.hasEncoder) { ma_encoder_uninit(&g_State.encoder); }