Commit c3a9ab9b authored by David Reid's avatar David Reid

Version 0.11.6

parent 13f1d31a
/* /*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.11.5 - 2022-01-16 miniaudio - v0.11.6 - 2022-01-22
David Reid - mackron@gmail.com David Reid - mackron@gmail.com
...@@ -4535,7 +4535,6 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority ...@@ -4535,7 +4535,6 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority
static void ma_thread_wait__posix(ma_thread* pThread) static void ma_thread_wait__posix(ma_thread* pThread)
{ {
pthread_join((pthread_t)*pThread, NULL); pthread_join((pthread_t)*pThread, NULL);
pthread_detach((pthread_t)*pThread);
} }
...@@ -9848,9 +9847,23 @@ static ma_result ma_device_uninit__wasapi(ma_device* pDevice) ...@@ -9848,9 +9847,23 @@ static ma_result ma_device_uninit__wasapi(ma_device* pDevice)
#endif #endif
if (pDevice->wasapi.pRenderClient) { if (pDevice->wasapi.pRenderClient) {
if (pDevice->wasapi.pMappedBufferPlayback != NULL) {
ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, pDevice->wasapi.mappedBufferPlaybackCap, 0);
pDevice->wasapi.pMappedBufferPlayback = NULL;
pDevice->wasapi.mappedBufferPlaybackCap = 0;
pDevice->wasapi.mappedBufferPlaybackLen = 0;
}
ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient); ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient);
} }
if (pDevice->wasapi.pCaptureClient) { if (pDevice->wasapi.pCaptureClient) {
if (pDevice->wasapi.pMappedBufferCapture != NULL) {
ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap);
pDevice->wasapi.pMappedBufferCapture = NULL;
pDevice->wasapi.mappedBufferCaptureCap = 0;
pDevice->wasapi.mappedBufferCaptureLen = 0;
}
ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient); ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
} }
...@@ -10971,7 +10984,7 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui ...@@ -10971,7 +10984,7 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui
continue; continue;
} else { } else {
if (hr == MA_AUDCLNT_S_BUFFER_EMPTY) { if (hr == MA_AUDCLNT_S_BUFFER_EMPTY || hr == MA_AUDCLNT_E_BUFFER_ERROR) {
/* /*
No data is available. We need to wait for more. There's two situations to consider No data is available. We need to wait for more. There's two situations to consider
here. The first is normal capture mode. If this times out it probably means the here. The first is normal capture mode. If this times out it probably means the
...@@ -10984,6 +10997,7 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui ...@@ -10984,6 +10997,7 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui
if (pDevice->type == ma_device_type_loopback) { if (pDevice->type == ma_device_type_loopback) {
continue; /* Keep waiting in loopback mode. */ continue; /* Keep waiting in loopback mode. */
} else { } else {
result = MA_ERROR;
break; /* Wait failed. */ break; /* Wait failed. */
} }
} }
...@@ -10991,6 +11005,7 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui ...@@ -10991,6 +11005,7 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui
/* At this point we should be able to loop back to the start of the loop and try retrieving a data buffer again. */ /* At this point we should be able to loop back to the start of the loop and try retrieving a data buffer again. */
} else { } else {
/* An error occured and we need to abort. */ /* An error occured and we need to abort. */
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for reading from the device. HRESULT = %d. Stopping device.\n", (int)hr);
result = ma_result_from_HRESULT(hr); result = ma_result_from_HRESULT(hr);
break; break;
} }
...@@ -11019,6 +11034,7 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui ...@@ -11019,6 +11034,7 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui
static ma_result ma_device_write__wasapi(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten) static ma_result ma_device_write__wasapi(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
{ {
ma_result result = MA_SUCCESS;
ma_uint32 totalFramesProcessed = 0; ma_uint32 totalFramesProcessed = 0;
/* Keep writing to the device until it's stopped or we've consumed all of our input. */ /* Keep writing to the device until it's stopped or we've consumed all of our input. */
...@@ -11063,6 +11079,7 @@ static ma_result ma_device_write__wasapi(ma_device* pDevice, const void* pFrames ...@@ -11063,6 +11079,7 @@ static ma_result ma_device_write__wasapi(ma_device* pDevice, const void* pFrames
*/ */
if (pDevice->playback.shareMode == ma_share_mode_exclusive) { if (pDevice->playback.shareMode == ma_share_mode_exclusive) {
if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
result = MA_ERROR;
break; /* Wait failed. Probably timed out. */ break; /* Wait failed. Probably timed out. */
} }
} }
...@@ -11085,14 +11102,16 @@ static ma_result ma_device_write__wasapi(ma_device* pDevice, const void* pFrames ...@@ -11085,14 +11102,16 @@ static ma_result ma_device_write__wasapi(ma_device* pDevice, const void* pFrames
pDevice->wasapi.mappedBufferPlaybackCap = bufferSizeInFrames; pDevice->wasapi.mappedBufferPlaybackCap = bufferSizeInFrames;
pDevice->wasapi.mappedBufferPlaybackLen = 0; pDevice->wasapi.mappedBufferPlaybackLen = 0;
} else { } else {
if (hr == MA_AUDCLNT_E_BUFFER_TOO_LARGE) { if (hr == MA_AUDCLNT_E_BUFFER_TOO_LARGE || hr == MA_AUDCLNT_E_BUFFER_ERROR) {
/* Not enough data available. We need to wait for more. */ /* Not enough data available. We need to wait for more. */
if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
result = MA_ERROR;
break; /* Wait failed. Probably timed out. */ break; /* Wait failed. Probably timed out. */
} }
} else { } else {
/* Some error occurred. We'll need to abort. */ /* Some error occurred. We'll need to abort. */
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device."); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device. HRESULT = %d. Stopping device.\n", (int)hr);
result = ma_result_from_HRESULT(hr);
break; break;
} }
} }
...@@ -11103,7 +11122,7 @@ static ma_result ma_device_write__wasapi(ma_device* pDevice, const void* pFrames ...@@ -11103,7 +11122,7 @@ static ma_result ma_device_write__wasapi(ma_device* pDevice, const void* pFrames
*pFramesWritten = totalFramesProcessed; *pFramesWritten = totalFramesProcessed;
} }
return MA_SUCCESS; return result;
} }
static ma_result ma_device_data_loop_wakeup__wasapi(ma_device* pDevice) static ma_result ma_device_data_loop_wakeup__wasapi(ma_device* pDevice)
...@@ -13546,7 +13565,7 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi ...@@ -13546,7 +13565,7 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi
MMRESULT resultMM; MMRESULT resultMM;
/* We use an event to know when a new fragment needs to be enqueued. */ /* We use an event to know when a new fragment needs to be enqueued. */
pDevice->winmm.hEventPlayback = (ma_handle)CreateEvent(NULL, TRUE, TRUE, NULL); pDevice->winmm.hEventPlayback = (ma_handle)CreateEventW(NULL, TRUE, TRUE, NULL);
if (pDevice->winmm.hEventPlayback == NULL) { if (pDevice->winmm.hEventPlayback == NULL) {
errorMsg = "[WinMM] Failed to create event for fragment enqueing for the playback device.", errorCode = ma_result_from_GetLastError(GetLastError()); errorMsg = "[WinMM] Failed to create event for fragment enqueing for the playback device.", errorCode = ma_result_from_GetLastError(GetLastError());
goto on_error; goto on_error;
...@@ -17905,16 +17924,26 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ...@@ -17905,16 +17924,26 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi
goto on_error2; goto on_error2;
} }
/* Internal format. */ /* Internal format. */
pActualSS = ((ma_pa_stream_get_sample_spec_proc)pDevice->pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamCapture); pActualSS = ((ma_pa_stream_get_sample_spec_proc)pDevice->pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
if (pActualSS != NULL) { if (pActualSS != NULL) {
ss = *pActualSS; ss = *pActualSS;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture sample spec: format=%s, channels=%d, rate=%d\n", ma_get_format_name(ma_format_from_pulse(ss.format)), ss.channels, ss.rate);
} else {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Failed to retrieve capture sample spec.\n");
} }
pDescriptorCapture->format = ma_format_from_pulse(ss.format); pDescriptorCapture->format = ma_format_from_pulse(ss.format);
pDescriptorCapture->channels = ss.channels; pDescriptorCapture->channels = ss.channels;
pDescriptorCapture->sampleRate = ss.rate; pDescriptorCapture->sampleRate = ss.rate;
if (pDescriptorCapture->format == ma_format_unknown || pDescriptorCapture->channels == 0 || pDescriptorCapture->sampleRate == 0) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Capture sample spec is invalid. Device unusable by miniaudio. format=%s, channels=%d, sampleRate=%d.\n", ma_get_format_name(pDescriptorCapture->format), pDescriptorCapture->channels, pDescriptorCapture->sampleRate);
result = MA_ERROR;
goto on_error4;
}
/* Internal channel map. */ /* Internal channel map. */
pActualCMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamCapture); pActualCMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
if (pActualCMap != NULL) { if (pActualCMap != NULL) {
...@@ -17932,9 +17961,13 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ...@@ -17932,9 +17961,13 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi
attr = *pActualAttr; attr = *pActualAttr;
} }
pDescriptorCapture->periodCount = attr.maxlength / attr.fragsize; if (attr.fragsize > 0) {
pDescriptorCapture->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) / pDescriptorCapture->periodCount; pDescriptorPlayback->periodCount = ma_max(attr.maxlength / attr.fragsize, 1);
} else {
pDescriptorPlayback->periodCount = 1;
}
pDescriptorCapture->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) / pDescriptorCapture->periodCount;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Capture actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames);
} }
...@@ -18016,12 +18049,21 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ...@@ -18016,12 +18049,21 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi
pActualSS = ((ma_pa_stream_get_sample_spec_proc)pDevice->pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); pActualSS = ((ma_pa_stream_get_sample_spec_proc)pDevice->pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
if (pActualSS != NULL) { if (pActualSS != NULL) {
ss = *pActualSS; ss = *pActualSS;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback sample spec: format=%s, channels=%d, rate=%d\n", ma_get_format_name(ma_format_from_pulse(ss.format)), ss.channels, ss.rate);
} else {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Failed to retrieve playback sample spec.\n");
} }
pDescriptorPlayback->format = ma_format_from_pulse(ss.format); pDescriptorPlayback->format = ma_format_from_pulse(ss.format);
pDescriptorPlayback->channels = ss.channels; pDescriptorPlayback->channels = ss.channels;
pDescriptorPlayback->sampleRate = ss.rate; pDescriptorPlayback->sampleRate = ss.rate;
if (pDescriptorPlayback->format == ma_format_unknown || pDescriptorPlayback->channels == 0 || pDescriptorPlayback->sampleRate == 0) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Playback sample spec is invalid. Device unusable by miniaudio. format=%s, channels=%d, sampleRate=%d.\n", ma_get_format_name(pDescriptorPlayback->format), pDescriptorPlayback->channels, pDescriptorPlayback->sampleRate);
result = MA_ERROR;
goto on_error4;
}
/* Internal channel map. */ /* Internal channel map. */
pActualCMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); pActualCMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
if (pActualCMap != NULL) { if (pActualCMap != NULL) {
...@@ -18039,7 +18081,12 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ...@@ -18039,7 +18081,12 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi
attr = *pActualAttr; attr = *pActualAttr;
} }
pDescriptorPlayback->periodCount = ma_max(attr.maxlength / attr.tlength, 1); if (attr.tlength > 0) {
pDescriptorPlayback->periodCount = ma_max(attr.maxlength / attr.tlength, 1);
} else {
pDescriptorPlayback->periodCount = 1;
}
pDescriptorPlayback->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels) / pDescriptorPlayback->periodCount; pDescriptorPlayback->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels) / pDescriptorPlayback->periodCount;
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorPlayback->periodSizeInFrames); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[PulseAudio] Playback actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorPlayback->periodSizeInFrames);
} }
...@@ -34004,7 +34051,7 @@ static ma_result ma_hpf_get_heap_layout(const ma_hpf_config* pConfig, ma_hpf_hea ...@@ -34004,7 +34051,7 @@ static ma_result ma_hpf_get_heap_layout(const ma_hpf_config* pConfig, ma_hpf_hea
pHeapLayout->sizeInBytes = 0; pHeapLayout->sizeInBytes = 0;
/* LPF 1 */ /* HPF 1 */
pHeapLayout->hpf1Offset = pHeapLayout->sizeInBytes; pHeapLayout->hpf1Offset = pHeapLayout->sizeInBytes;
for (ihpf1 = 0; ihpf1 < hpf1Count; ihpf1 += 1) { for (ihpf1 = 0; ihpf1 < hpf1Count; ihpf1 += 1) {
size_t hpf1HeapSizeInBytes; size_t hpf1HeapSizeInBytes;
...@@ -34018,7 +34065,7 @@ static ma_result ma_hpf_get_heap_layout(const ma_hpf_config* pConfig, ma_hpf_hea ...@@ -34018,7 +34065,7 @@ static ma_result ma_hpf_get_heap_layout(const ma_hpf_config* pConfig, ma_hpf_hea
pHeapLayout->sizeInBytes += sizeof(ma_hpf1) + hpf1HeapSizeInBytes; pHeapLayout->sizeInBytes += sizeof(ma_hpf1) + hpf1HeapSizeInBytes;
} }
/* LPF 2*/ /* HPF 2*/
pHeapLayout->hpf2Offset = pHeapLayout->sizeInBytes; pHeapLayout->hpf2Offset = pHeapLayout->sizeInBytes;
for (ihpf2 = 0; ihpf2 < hpf2Count; ihpf2 += 1) { for (ihpf2 = 0; ihpf2 < hpf2Count; ihpf2 += 1) {
size_t hpf2HeapSizeInBytes; size_t hpf2HeapSizeInBytes;
...@@ -34102,7 +34149,7 @@ static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, void* pHe ...@@ -34102,7 +34149,7 @@ static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, void* pHe
result = ma_hpf1_get_heap_size(&hpf1Config, &hpf1HeapSizeInBytes); result = ma_hpf1_get_heap_size(&hpf1Config, &hpf1HeapSizeInBytes);
if (result == MA_SUCCESS) { if (result == MA_SUCCESS) {
result = ma_hpf1_init_preallocated(&hpf1Config, ma_offset_ptr(pHeap, heapLayout.hpf1Offset + (ihpf1 * (sizeof(ma_hpf1) + hpf1HeapSizeInBytes)) + sizeof(ma_hpf1)), &pHPF->pHPF1[ihpf1]); result = ma_hpf1_init_preallocated(&hpf1Config, ma_offset_ptr(pHeap, heapLayout.hpf1Offset + (sizeof(ma_hpf1) * hpf1Count) + (ihpf1 * hpf1HeapSizeInBytes)), &pHPF->pHPF1[ihpf1]);
} }
} else { } else {
result = ma_hpf1_reinit(&hpf1Config, &pHPF->pHPF1[ihpf1]); result = ma_hpf1_reinit(&hpf1Config, &pHPF->pHPF1[ihpf1]);
...@@ -34139,7 +34186,7 @@ static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, void* pHe ...@@ -34139,7 +34186,7 @@ static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, void* pHe
result = ma_hpf2_get_heap_size(&hpf2Config, &hpf2HeapSizeInBytes); result = ma_hpf2_get_heap_size(&hpf2Config, &hpf2HeapSizeInBytes);
if (result == MA_SUCCESS) { if (result == MA_SUCCESS) {
result = ma_hpf2_init_preallocated(&hpf2Config, ma_offset_ptr(pHeap, heapLayout.hpf2Offset + (ihpf2 * (sizeof(ma_hpf2) + hpf2HeapSizeInBytes)) + sizeof(ma_hpf2)), &pHPF->pHPF2[ihpf2]); result = ma_hpf2_init_preallocated(&hpf2Config, ma_offset_ptr(pHeap, heapLayout.hpf2Offset + (sizeof(ma_hpf2) * hpf2Count) + (ihpf2 * hpf2HeapSizeInBytes)), &pHPF->pHPF2[ihpf2]);
} }
} else { } else {
result = ma_hpf2_reinit(&hpf2Config, &pHPF->pHPF2[ihpf2]); result = ma_hpf2_reinit(&hpf2Config, &pHPF->pHPF2[ihpf2]);
...@@ -34654,7 +34701,7 @@ static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, void* pHe ...@@ -34654,7 +34701,7 @@ static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, void* pHe
result = ma_bpf2_get_heap_size(&bpf2Config, &bpf2HeapSizeInBytes); result = ma_bpf2_get_heap_size(&bpf2Config, &bpf2HeapSizeInBytes);
if (result == MA_SUCCESS) { if (result == MA_SUCCESS) {
result = ma_bpf2_init_preallocated(&bpf2Config, ma_offset_ptr(pHeap, heapLayout.bpf2Offset + (ibpf2 * (sizeof(ma_bpf2) + bpf2HeapSizeInBytes)) + sizeof(ma_bpf2)), &pBPF->pBPF2[ibpf2]); result = ma_bpf2_init_preallocated(&bpf2Config, ma_offset_ptr(pHeap, heapLayout.bpf2Offset + (sizeof(ma_bpf2) * bpf2Count) + (ibpf2 * bpf2HeapSizeInBytes)), &pBPF->pBPF2[ibpf2]);
} }
} else { } else {
result = ma_bpf2_reinit(&bpf2Config, &pBPF->pBPF2[ibpf2]); result = ma_bpf2_reinit(&bpf2Config, &pBPF->pBPF2[ibpf2]);
...@@ -43763,6 +43810,60 @@ MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSo ...@@ -43763,6 +43810,60 @@ MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSo
return pDataSourceBase->vtable->onGetLength(pDataSource, pLength); return pDataSourceBase->vtable->onGetLength(pDataSource, pLength);
} }
MA_API ma_result ma_data_source_get_cursor_in_seconds(ma_data_source* pDataSource, float* pCursor)
{
ma_result result;
ma_uint64 cursorInPCMFrames;
ma_uint32 sampleRate;
if (pCursor == NULL) {
return MA_INVALID_ARGS;
}
*pCursor = 0;
result = ma_data_source_get_cursor_in_pcm_frames(pDataSource, &cursorInPCMFrames);
if (result != MA_SUCCESS) {
return result;
}
result = ma_data_source_get_data_format(pDataSource, NULL, NULL, &sampleRate, NULL, 0);
if (result != MA_SUCCESS) {
return result;
}
*pCursor = cursorInPCMFrames / (float)sampleRate;
return MA_SUCCESS;
}
MA_API ma_result ma_data_source_get_length_in_seconds(ma_data_source* pDataSource, float* pLength)
{
ma_result result;
ma_uint64 lengthInPCMFrames;
ma_uint32 sampleRate;
if (pLength == NULL) {
return MA_INVALID_ARGS;
}
*pLength = 0;
result = ma_data_source_get_length_in_pcm_frames(pDataSource, &lengthInPCMFrames);
if (result != MA_SUCCESS) {
return result;
}
result = ma_data_source_get_data_format(pDataSource, NULL, NULL, &sampleRate, NULL, 0);
if (result != MA_SUCCESS) {
return result;
}
*pLength = lengthInPCMFrames / (float)sampleRate;
return MA_SUCCESS;
}
MA_API ma_result ma_data_source_set_looping(ma_data_source* pDataSource, ma_bool32 isLooping) MA_API ma_result ma_data_source_set_looping(ma_data_source* pDataSource, ma_bool32 isLooping)
{ {
ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
...@@ -56740,6 +56841,28 @@ static ma_bool32 ma_node_graph_is_reading(ma_node_graph* pNodeGraph) ...@@ -56740,6 +56841,28 @@ static ma_bool32 ma_node_graph_is_reading(ma_node_graph* pNodeGraph)
#endif #endif
static void ma_node_graph_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
{
ma_node_graph* pNodeGraph = (ma_node_graph*)pNode;
ma_uint64 framesRead;
ma_node_graph_read_pcm_frames(pNodeGraph, ppFramesOut[0], *pFrameCountOut, &framesRead);
*pFrameCountOut = (ma_uint32)framesRead; /* Safe cast. */
(void)ppFramesIn;
(void)pFrameCountIn;
}
static ma_node_vtable g_node_graph_node_vtable =
{
ma_node_graph_node_process_pcm_frames,
NULL, /* onGetRequiredInputFrameCount */
0, /* 0 input buses. */
1, /* 1 output bus. */
0 /* Flags. */
};
static void ma_node_graph_endpoint_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) static void ma_node_graph_endpoint_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
{ {
MA_ASSERT(pNode != NULL); MA_ASSERT(pNode != NULL);
...@@ -56776,6 +56899,7 @@ static ma_node_vtable g_node_graph_endpoint_vtable = ...@@ -56776,6 +56899,7 @@ static ma_node_vtable g_node_graph_endpoint_vtable =
MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node_graph* pNodeGraph) MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node_graph* pNodeGraph)
{ {
ma_result result; ma_result result;
ma_node_config baseConfig;
ma_node_config endpointConfig; ma_node_config endpointConfig;
if (pNodeGraph == NULL) { if (pNodeGraph == NULL) {
...@@ -56788,6 +56912,19 @@ MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const m ...@@ -56788,6 +56912,19 @@ MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const m
pNodeGraph->nodeCacheCapInFrames = MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS; pNodeGraph->nodeCacheCapInFrames = MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS;
} }
/* Base node so we can use the node graph as a node into another graph. */
baseConfig = ma_node_config_init();
baseConfig.vtable = &g_node_graph_node_vtable;
baseConfig.pOutputChannels = &pConfig->channels;
result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pNodeGraph->base);
if (result != MA_SUCCESS) {
return result;
}
/* Endpoint. */
endpointConfig = ma_node_config_init(); endpointConfig = ma_node_config_init();
endpointConfig.vtable = &g_node_graph_endpoint_vtable; endpointConfig.vtable = &g_node_graph_endpoint_vtable;
endpointConfig.pInputChannels = &pConfig->channels; endpointConfig.pInputChannels = &pConfig->channels;
...@@ -56795,6 +56932,7 @@ MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const m ...@@ -56795,6 +56932,7 @@ MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const m
result = ma_node_init(pNodeGraph, &endpointConfig, pAllocationCallbacks, &pNodeGraph->endpoint); result = ma_node_init(pNodeGraph, &endpointConfig, pAllocationCallbacks, &pNodeGraph->endpoint);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
ma_node_uninit(&pNodeGraph->base, pAllocationCallbacks);
return result; return result;
} }
...@@ -59686,8 +59824,8 @@ static void ma_engine_node_process_pcm_frames__general(ma_engine_node* pEngineNo ...@@ -59686,8 +59824,8 @@ static void ma_engine_node_process_pcm_frames__general(ma_engine_node* pEngineNo
framesJustProcessedIn = (ma_uint32)resampleFrameCountIn; framesJustProcessedIn = (ma_uint32)resampleFrameCountIn;
framesJustProcessedOut = (ma_uint32)resampleFrameCountOut; framesJustProcessedOut = (ma_uint32)resampleFrameCountOut;
} else { } else {
framesJustProcessedIn = framesAvailableIn; framesJustProcessedIn = ma_min(framesAvailableIn, framesAvailableOut);
framesJustProcessedOut = framesAvailableOut; framesJustProcessedOut = framesJustProcessedIn; /* When no resampling is being performed, the number of output frames is the same as input frames. */
} }
/* Fading. */ /* Fading. */
...@@ -62024,6 +62162,34 @@ MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* ...@@ -62024,6 +62162,34 @@ MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64*
return ma_data_source_get_length_in_pcm_frames(pSound->pDataSource, pLength); return ma_data_source_get_length_in_pcm_frames(pSound->pDataSource, pLength);
} }
MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor)
{
if (pSound == NULL) {
return MA_INVALID_ARGS;
}
/* The notion of a cursor is only valid for sounds that are backed by a data source. */
if (pSound->pDataSource == NULL) {
return MA_INVALID_OPERATION;
}
return ma_data_source_get_cursor_in_seconds(pSound->pDataSource, pCursor);
}
MA_API ma_result ma_sound_get_length_in_seconds(ma_sound* pSound, float* pLength)
{
if (pSound == NULL) {
return MA_INVALID_ARGS;
}
/* The notion of a sound length is only valid for sounds that are backed by a data source. */
if (pSound->pDataSource == NULL) {
return MA_INVALID_OPERATION;
}
return ma_data_source_get_length_in_seconds(pSound->pDataSource, pLength);
}
MA_API ma_result ma_sound_group_init(ma_engine* pEngine, ma_uint32 flags, ma_sound_group* pParentGroup, ma_sound_group* pGroup) MA_API ma_result ma_sound_group_init(ma_engine* pEngine, ma_uint32 flags, ma_sound_group* pParentGroup, ma_sound_group* pGroup)
{ {
/* /*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.11.5 - 2022-01-16 miniaudio - v0.11.6 - 2022-01-22
David Reid - mackron@gmail.com David Reid - mackron@gmail.com
...@@ -20,7 +20,7 @@ extern "C" { ...@@ -20,7 +20,7 @@ extern "C" {
#define MA_VERSION_MAJOR 0 #define MA_VERSION_MAJOR 0
#define MA_VERSION_MINOR 11 #define MA_VERSION_MINOR 11
#define MA_VERSION_REVISION 5 #define MA_VERSION_REVISION 6
#define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION) #define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION)
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)
...@@ -5689,6 +5689,8 @@ MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, m ...@@ -5689,6 +5689,8 @@ MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, m
MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor); MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor);
MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength); /* Returns MA_NOT_IMPLEMENTED if the length is unknown or cannot be determined. Decoders can return this. */ MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength); /* Returns MA_NOT_IMPLEMENTED if the length is unknown or cannot be determined. Decoders can return this. */
MA_API ma_result ma_data_source_get_cursor_in_seconds(ma_data_source* pDataSource, float* pCursor);
MA_API ma_result ma_data_source_get_length_in_seconds(ma_data_source* pDataSource, float* pLength);
MA_API ma_result ma_data_source_set_looping(ma_data_source* pDataSource, ma_bool32 isLooping); MA_API ma_result ma_data_source_set_looping(ma_data_source* pDataSource, ma_bool32 isLooping);
MA_API ma_bool32 ma_data_source_is_looping(ma_data_source* pDataSource); MA_API ma_bool32 ma_data_source_is_looping(ma_data_source* pDataSource);
MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 rangeBegInFrames, ma_uint64 rangeEndInFrames); MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 rangeBegInFrames, ma_uint64 rangeEndInFrames);
...@@ -6748,6 +6750,7 @@ MA_API ma_node_graph_config ma_node_graph_config_init(ma_uint32 channels); ...@@ -6748,6 +6750,7 @@ MA_API ma_node_graph_config ma_node_graph_config_init(ma_uint32 channels);
struct ma_node_graph struct ma_node_graph
{ {
/* Immutable. */ /* Immutable. */
ma_node_base base; /* The node graph itself is a node so it can be connected as an input to different node graph. This has zero inputs and calls ma_node_graph_read_pcm_frames() to generate it's output. */
ma_node_base endpoint; /* Special node that all nodes eventually connect to. Data is read from this node in ma_node_graph_read_pcm_frames(). */ ma_node_base endpoint; /* Special node that all nodes eventually connect to. Data is read from this node in ma_node_graph_read_pcm_frames(). */
ma_uint16 nodeCacheCapInFrames; ma_uint16 nodeCacheCapInFrames;
...@@ -7308,6 +7311,8 @@ MA_API ma_result ma_sound_seek_to_pcm_frame(ma_sound* pSound, ma_uint64 frameInd ...@@ -7308,6 +7311,8 @@ MA_API ma_result ma_sound_seek_to_pcm_frame(ma_sound* pSound, ma_uint64 frameInd
MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor); MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor);
MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength); MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength);
MA_API ma_result ma_sound_get_cursor_in_seconds(ma_sound* pSound, float* pCursor);
MA_API ma_result ma_sound_get_length_in_seconds(ma_sound* pSound, float* pLength);
MA_API ma_result ma_sound_group_init(ma_engine* pEngine, ma_uint32 flags, ma_sound_group* pParentGroup, ma_sound_group* pGroup); MA_API ma_result ma_sound_group_init(ma_engine* pEngine, ma_uint32 flags, ma_sound_group* pParentGroup, ma_sound_group* pGroup);
MA_API ma_result ma_sound_group_init_ex(ma_engine* pEngine, const ma_sound_group_config* pConfig, ma_sound_group* pGroup); MA_API ma_result ma_sound_group_init_ex(ma_engine* pEngine, const ma_sound_group_config* pConfig, ma_sound_group* pGroup);
......
/* /*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.11.5 - 2022-01-16 miniaudio - v0.11.6 - 2022-01-22
David Reid - mackron@gmail.com David Reid - mackron@gmail.com
...@@ -3637,7 +3637,7 @@ extern "C" { ...@@ -3637,7 +3637,7 @@ extern "C" {
#define MA_VERSION_MAJOR 0 #define MA_VERSION_MAJOR 0
#define MA_VERSION_MINOR 11 #define MA_VERSION_MINOR 11
#define MA_VERSION_REVISION 5 #define MA_VERSION_REVISION 6
#define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION) #define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION)
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)
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