Commit fa416d32 authored by David Reid's avatar David Reid

Fix a bug when reading from a node with no attachments.

This would try reading from an uninitialized buffer thereby resulting
in a bad audio glitch. This does two things to fix the problem:

  1) When there are no input nodes attached to an input bus, nothing is
     read and 0 will be returned for the frames read variable.

  2) The buffer is silenced by default.

This fixes a bug with ma_engine where it would glitch in the moment
just after the engine is initialized and before a sound or group is
attached.
parent 14c5b35b
...@@ -1704,6 +1704,17 @@ MA_API size_t ma_get_accumulation_bytes_per_frame(ma_format format, ma_uint32 ch ...@@ -1704,6 +1704,17 @@ MA_API size_t ma_get_accumulation_bytes_per_frame(ma_format format, ma_uint32 ch
static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusIndex, float* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead, ma_uint64 globalTime); static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusIndex, float* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead, ma_uint64 globalTime);
static void ma_debug_fill_pcm_frames_with_sine_wave(float* pFramesOut, ma_uint32 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate)
{
ma_waveform_config waveformConfig;
ma_waveform waveform;
waveformConfig = ma_waveform_config_init(format, channels, sampleRate, ma_waveform_type_sine, 1.0, 400);
ma_waveform_init(&waveformConfig, &waveform);
ma_waveform_read_pcm_frames(&waveform, pFramesOut, frameCount);
}
static MA_INLINE ma_int16 ma_float_to_fixed_16(float x) static MA_INLINE ma_int16 ma_float_to_fixed_16(float x)
{ {
...@@ -2595,6 +2606,9 @@ static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_ ...@@ -2595,6 +2606,9 @@ static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_
after calling ma_node_input_bus_next(), which we won't be. after calling ma_node_input_bus_next(), which we won't be.
*/ */
pFirst = ma_node_input_bus_first(pInputBus); pFirst = ma_node_input_bus_first(pInputBus);
if (pFirst == NULL) {
return MA_SUCCESS; /* No attachments. Read nothing. */
}
for (pOutputBus = pFirst; pOutputBus != NULL; pOutputBus = ma_node_input_bus_next(pInputBus, pOutputBus)) { for (pOutputBus = pFirst; pOutputBus != NULL; pOutputBus = ma_node_input_bus_next(pInputBus, pOutputBus)) {
ma_uint32 framesProcessed = 0; ma_uint32 framesProcessed = 0;
...@@ -2775,7 +2789,7 @@ MA_API ma_result ma_node_init(ma_node_graph* pNodeGraph, const ma_node_config* p ...@@ -2775,7 +2789,7 @@ MA_API ma_result ma_node_init(ma_node_graph* pNodeGraph, const ma_node_config* p
pNodeBase->stateTimes[ma_node_state_started] = 0; pNodeBase->stateTimes[ma_node_state_started] = 0;
pNodeBase->stateTimes[ma_node_state_stopped] = (ma_uint64)(ma_int64)-1; /* Weird casting for VC6 compatibility. */ pNodeBase->stateTimes[ma_node_state_stopped] = (ma_uint64)(ma_int64)-1; /* Weird casting for VC6 compatibility. */
/* We need to run an initialization step for each input bus. This just sets up the dummy head and tail nodes. */ /* We need to run an initialization step for each input bus. */
for (iInputBus = 0; iInputBus < ma_node_get_input_bus_count(pNodeBase); iInputBus += 1) { for (iInputBus = 0; iInputBus < ma_node_get_input_bus_count(pNodeBase); iInputBus += 1) {
if (pConfig->inputChannels[iInputBus] < MA_MIN_CHANNELS || pConfig->inputChannels[iInputBus] > MA_MAX_CHANNELS) { if (pConfig->inputChannels[iInputBus] < MA_MIN_CHANNELS || pConfig->inputChannels[iInputBus] > MA_MAX_CHANNELS) {
return MA_INVALID_ARGS; /* Invalid channel count. */ return MA_INVALID_ARGS; /* Invalid channel count. */
...@@ -2834,6 +2848,24 @@ MA_API ma_result ma_node_init(ma_node_graph* pNodeGraph, const ma_node_config* p ...@@ -2834,6 +2848,24 @@ MA_API ma_result ma_node_init(ma_node_graph* pNodeGraph, const ma_node_config* p
if (pNodeBase->pCachedData == NULL) { if (pNodeBase->pCachedData == NULL) {
return MA_OUT_OF_MEMORY; return MA_OUT_OF_MEMORY;
} }
#if 1 /* Toggle this between 0 and 1 to turn debugging on or off. 1 = fill with a sine wave for debugging; 0 = fill with silence. */
/* For safety we'll go ahead and default the buffer to silence. */
for (iBus = 0; iBus < ma_node_get_input_bus_count(pNodeBase); iBus += 1) {
ma_silence_pcm_frames(ma_node_get_cached_input_ptr(pNode, iBus), pNodeBase->cachedDataCapInFramesPerBus, ma_format_f32, ma_node_input_bus_get_channels(&pNodeBase->inputBuses[iBus]));
}
for (iBus = 0; iBus < ma_node_get_output_bus_count(pNodeBase); iBus += 1) {
ma_silence_pcm_frames(ma_node_get_cached_output_ptr(pNode, iBus), pNodeBase->cachedDataCapInFramesPerBus, ma_format_f32, ma_node_output_bus_get_channels(&pNodeBase->outputBuses[iBus]));
}
#else
/* For debugging. Default to a sine wave. */
for (iBus = 0; iBus < ma_node_get_input_bus_count(pNodeBase); iBus += 1) {
ma_debug_fill_pcm_frames_with_sine_wave(ma_node_get_cached_input_ptr(pNode, iBus), pNodeBase->cachedDataCapInFramesPerBus, ma_format_f32, ma_node_input_bus_get_channels(&pNodeBase->inputBuses[iBus]), 48000);
}
for (iBus = 0; iBus < ma_node_get_output_bus_count(pNodeBase); iBus += 1) {
ma_debug_fill_pcm_frames_with_sine_wave(ma_node_get_cached_output_ptr(pNode, iBus), pNodeBase->cachedDataCapInFramesPerBus, ma_format_f32, ma_node_output_bus_get_channels(&pNodeBase->outputBuses[iBus]), 48000);
}
#endif
} }
......
...@@ -89,11 +89,11 @@ int main(int argc, char** argv) ...@@ -89,11 +89,11 @@ int main(int argc, char** argv)
return -1; return -1;
} }
ma_node_set_state_time(&g_dataSourceNode, ma_node_state_started, 48000*1); /*ma_node_set_state_time(&g_dataSourceNode, ma_node_state_started, 48000*1);
ma_node_set_state_time(&g_dataSourceNode, ma_node_state_stopped, 48000*5); ma_node_set_state_time(&g_dataSourceNode, ma_node_state_stopped, 48000*5);*/
#if 0
/* /*
Splitter node. Note that we've already attached the data source node to another, so this section Splitter node. Note that we've already attached the data source node to another, so this section
will test that changing of attachments works as expected. will test that changing of attachments works as expected.
...@@ -141,12 +141,12 @@ int main(int argc, char** argv) ...@@ -141,12 +141,12 @@ int main(int argc, char** argv)
ma_node_attach_output_bus(&g_splitterNode, 1, &g_loopNode, 1); ma_node_attach_output_bus(&g_splitterNode, 1, &g_loopNode, 1);
/* Now loop back to the splitter node to form a loop. */ /* Now loop back to the splitter node to form a loop. */
ma_node_attach_output_bus(&g_loopNode, 1, &g_splitterNode, 0); /*ma_node_attach_output_bus(&g_loopNode, 1, &g_splitterNode, 0);*/
#endif #endif
/* The data source needs to have it's connection changed from the endpoint to the splitter. */ /* The data source needs to have it's connection changed from the endpoint to the splitter. */
ma_node_attach_output_bus(&g_dataSourceNode, 0, &g_splitterNode, 0); ma_node_attach_output_bus(&g_dataSourceNode, 0, &g_splitterNode, 0);
#endif
......
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