mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
Remove loop detection code for now.
This needs a rethink. My test is no longer looping. Needs further investigation.
This commit is contained in:
@@ -65,20 +65,18 @@ int main(int argc, char** argv)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
result = ma_sound_group_init(&engine, 0, NULL, &group);
|
result = ma_sound_group_init(&engine, 0, NULL, &group);
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
printf("Failed to initialize sound group.");
|
printf("Failed to initialize sound group.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
loadNotification.cb.onSignal = on_sound_loaded;
|
loadNotification.cb.onSignal = on_sound_loaded;
|
||||||
loadNotification.pSound = &sound;
|
loadNotification.pSound = &sound;
|
||||||
|
|
||||||
result = ma_sound_init_from_file(&engine, argv[1], MA_DATA_SOURCE_FLAG_DECODE /*| MA_DATA_SOURCE_FLAG_ASYNC | MA_DATA_SOURCE_FLAG_STREAM*/, &loadNotification, NULL, &sound);
|
result = ma_sound_init_from_file(&engine, argv[1], MA_DATA_SOURCE_FLAG_DECODE /*| MA_DATA_SOURCE_FLAG_ASYNC | MA_DATA_SOURCE_FLAG_STREAM*/, &loadNotification, &group, &sound);
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
printf("Failed to load sound: %s\n", argv[1]);
|
printf("Failed to load sound: %s\n", argv[1]);
|
||||||
ma_engine_uninit(&engine);
|
ma_engine_uninit(&engine);
|
||||||
@@ -98,14 +96,14 @@ int main(int argc, char** argv)
|
|||||||
/*ma_data_source_seek_to_pcm_frame(sound.pDataSource, 5000000);*/
|
/*ma_data_source_seek_to_pcm_frame(sound.pDataSource, 5000000);*/
|
||||||
|
|
||||||
//ma_sound_group_set_pan(ma_engine_get_master_sound_group(&engine), -1);
|
//ma_sound_group_set_pan(ma_engine_get_master_sound_group(&engine), -1);
|
||||||
//ma_sound_group_set_pitch(ma_engine_get_master_sound_group(&engine), 1.0f);
|
ma_sound_group_set_pitch(&group, 1.1f);
|
||||||
//ma_sound_group_set_start_time(ma_engine_get_master_sound_group(&engine), 2000);
|
//ma_sound_group_set_start_time(ma_engine_get_master_sound_group(&engine), 2000);
|
||||||
//ma_sound_group_set_fade_in_milliseconds(&group, 0, 1, 5000);
|
//ma_sound_group_set_fade_in_milliseconds(&group, 0, 1, 5000);
|
||||||
|
//ma_sound_group_stop(&group);
|
||||||
|
|
||||||
//ma_sound_set_fade_in_milliseconds(&sound, 0, 1, 5000);
|
//ma_sound_set_fade_in_milliseconds(&sound, 0, 1, 5000);
|
||||||
/*ma_sound_set_volume(&sound, 0.25f);*/
|
/*ma_sound_set_volume(&sound, 0.25f);*/
|
||||||
/*ma_sound_set_pitch(&sound, 1.2f);*/
|
/*ma_sound_set_pitch(&sound, 1.1f);*/
|
||||||
/*ma_sound_set_pan(&sound, 0.0f);*/
|
/*ma_sound_set_pan(&sound, 0.0f);*/
|
||||||
/*ma_sound_set_looping(&sound, MA_TRUE);*/
|
/*ma_sound_set_looping(&sound, MA_TRUE);*/
|
||||||
//ma_sound_seek_to_pcm_frame(&sound, 6000000);
|
//ma_sound_seek_to_pcm_frame(&sound, 6000000);
|
||||||
|
|||||||
@@ -824,7 +824,6 @@ struct ma_node_output_bus
|
|||||||
{
|
{
|
||||||
/* Immutable. */
|
/* Immutable. */
|
||||||
ma_node* pNode; /* The node that owns this output bus. The input node. Will be null for dummy head and tail nodes. */
|
ma_node* pNode; /* The node that owns this output bus. The input node. Will be null for dummy head and tail nodes. */
|
||||||
ma_uint32 readCounter; /* For loop prevention. Compared with the current read count of the node graph. If larger, means a loop was encountered and reading is aborted and no samples read. */
|
|
||||||
ma_uint8 outputBusIndex; /* The index of the output bus on pNode that this output bus represents. */
|
ma_uint8 outputBusIndex; /* The index of the output bus on pNode that this output bus represents. */
|
||||||
ma_uint8 channels; /* The number of channels in the audio stream for this bus. */
|
ma_uint8 channels; /* The number of channels in the audio stream for this bus. */
|
||||||
|
|
||||||
@@ -849,8 +848,8 @@ struct ma_node_input_bus
|
|||||||
{
|
{
|
||||||
/* Mutable via multiple threads. */
|
/* Mutable via multiple threads. */
|
||||||
ma_node_output_bus head; /* Dummy head node for simplifying some lock-free thread-safety stuff. */
|
ma_node_output_bus head; /* Dummy head node for simplifying some lock-free thread-safety stuff. */
|
||||||
MA_ATOMIC ma_spinlock lock; /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */
|
|
||||||
MA_ATOMIC ma_uint16 nextCounter; /* This is used to determine whether or not the input bus is finding the next node in the list. Used for thread safety when detaching output buses. */
|
MA_ATOMIC ma_uint16 nextCounter; /* This is used to determine whether or not the input bus is finding the next node in the list. Used for thread safety when detaching output buses. */
|
||||||
|
MA_ATOMIC ma_spinlock lock; /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */
|
||||||
|
|
||||||
/* Set once at startup. */
|
/* Set once at startup. */
|
||||||
ma_uint8 channels; /* The number of channels in the audio stream for this bus. */
|
ma_uint8 channels; /* The number of channels in the audio stream for this bus. */
|
||||||
@@ -870,7 +869,6 @@ struct ma_node_base
|
|||||||
ma_uint16 cachedFrameCountOut;
|
ma_uint16 cachedFrameCountOut;
|
||||||
ma_uint16 cachedFrameCountIn;
|
ma_uint16 cachedFrameCountIn;
|
||||||
ma_uint16 consumedFrameCountIn;
|
ma_uint16 consumedFrameCountIn;
|
||||||
ma_uint32 readCounter; /* For loop prevention. Compared with the current read count of the node graph. If larger, means a loop was encountered and reading is aborted and no samples read. */
|
|
||||||
|
|
||||||
/* These variables are read and written between different threads. */
|
/* These variables are read and written between different threads. */
|
||||||
MA_ATOMIC ma_node_state state; /* When set to stopped, nothing will be read, regardless of the times in stateTimes. */
|
MA_ATOMIC ma_node_state state; /* When set to stopped, nothing will be read, regardless of the times in stateTimes. */
|
||||||
@@ -915,7 +913,6 @@ struct ma_node_graph
|
|||||||
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(). */
|
||||||
|
|
||||||
/* Read and written by multiple threads. */
|
/* Read and written by multiple threads. */
|
||||||
MA_ATOMIC ma_uint32 readCounter; /* Nodes spin on this while they wait for reading for finish before returning from ma_node_uninit(). */
|
|
||||||
MA_ATOMIC ma_bool8 isReading;
|
MA_ATOMIC ma_bool8 isReading;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2108,18 +2105,6 @@ static ma_bool8 ma_node_graph_is_reading(ma_node_graph* pNodeGraph)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void ma_node_graph_increment_read_counter(ma_node_graph* pNodeGraph)
|
|
||||||
{
|
|
||||||
MA_ASSERT(pNodeGraph != NULL);
|
|
||||||
c89atomic_fetch_add_32(&pNodeGraph->readCounter, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ma_uint32 ma_node_graph_get_read_counter(ma_node_graph* pNodeGraph)
|
|
||||||
{
|
|
||||||
MA_ASSERT(pNodeGraph != NULL);
|
|
||||||
return c89atomic_load_32(&pNodeGraph->readCounter);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
@@ -2226,7 +2211,6 @@ MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void*
|
|||||||
result = ma_node_read_pcm_frames(&pNodeGraph->endpoint, 0, (float*)ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, ma_format_f32, channels), framesToRead, &framesJustRead, ma_node_get_time(&pNodeGraph->endpoint));
|
result = ma_node_read_pcm_frames(&pNodeGraph->endpoint, 0, (float*)ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, ma_format_f32, channels), framesToRead, &framesJustRead, ma_node_get_time(&pNodeGraph->endpoint));
|
||||||
}
|
}
|
||||||
ma_node_graph_set_is_reading(pNodeGraph, MA_FALSE);
|
ma_node_graph_set_is_reading(pNodeGraph, MA_FALSE);
|
||||||
ma_node_graph_increment_read_counter(pNodeGraph);
|
|
||||||
|
|
||||||
totalFramesRead += framesJustRead;
|
totalFramesRead += framesJustRead;
|
||||||
|
|
||||||
@@ -2355,23 +2339,6 @@ static float ma_node_output_bus_get_volume(const ma_node_output_bus* pOutputBus)
|
|||||||
return c89atomic_load_f32((float*)&pOutputBus->volume);
|
return c89atomic_load_f32((float*)&pOutputBus->volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ma_uint32 ma_node_output_bus_set_read_counter(ma_node_output_bus* pOutputBus, ma_uint32 newReadCounter)
|
|
||||||
{
|
|
||||||
ma_uint32 oldReadCounter;
|
|
||||||
|
|
||||||
MA_ASSERT(pOutputBus != NULL);
|
|
||||||
|
|
||||||
/*
|
|
||||||
This function will only ever be called in a controlled environment (only on the audio thread,
|
|
||||||
and never concurrently).
|
|
||||||
*/
|
|
||||||
oldReadCounter = pOutputBus->readCounter;
|
|
||||||
pOutputBus->readCounter = newReadCounter;
|
|
||||||
|
|
||||||
return oldReadCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static ma_result ma_node_input_bus_init(ma_uint32 channels, ma_node_input_bus* pInputBus)
|
static ma_result ma_node_input_bus_init(ma_uint32 channels, ma_node_input_bus* pInputBus)
|
||||||
{
|
{
|
||||||
@@ -2659,28 +2626,9 @@ static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_
|
|||||||
|
|
||||||
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;
|
||||||
ma_uint32 readCounter;
|
|
||||||
|
|
||||||
MA_ASSERT(pOutputBus->pNode != NULL);
|
MA_ASSERT(pOutputBus->pNode != NULL);
|
||||||
|
|
||||||
/*
|
|
||||||
We need to grab the read counter at the start so we can set a new read counter first up. We
|
|
||||||
need to do this first so that recursive reads can have access to the new counter. Note that
|
|
||||||
we need to do this here and *not* in ma_node_read_pcm_frames() which would be the more
|
|
||||||
intuitive option because we need to loop here in order to fill up as many frames as we can
|
|
||||||
which would cause all iterations after the first to return 0 frames because of the loop
|
|
||||||
detection logic getting triggered.
|
|
||||||
*/
|
|
||||||
readCounter = ma_node_output_bus_set_read_counter(pOutputBus, ma_node_graph_get_read_counter(ma_node_get_node_graph(pOutputBus->pNode)) + 1);
|
|
||||||
|
|
||||||
/*
|
|
||||||
If the node's read counter is larger than that of the graph it means we've hit a loop and
|
|
||||||
we need to skip this attachment.
|
|
||||||
*/
|
|
||||||
if (readCounter > ma_node_graph_get_read_counter(ma_node_get_node_graph(pOutputBus->pNode))) {
|
|
||||||
continue; /* This output bus has already been processed by the current iteration. */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pFramesOut != NULL) {
|
if (pFramesOut != NULL) {
|
||||||
/* Read. */
|
/* Read. */
|
||||||
float temp[MA_DATA_CONVERTER_STACK_BUFFER_SIZE / sizeof(float)];
|
float temp[MA_DATA_CONVERTER_STACK_BUFFER_SIZE / sizeof(float)];
|
||||||
@@ -3407,9 +3355,10 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde
|
|||||||
requested, however we still need to clamp it to whatever can fit in the cache.
|
requested, however we still need to clamp it to whatever can fit in the cache.
|
||||||
|
|
||||||
This will also be used as the basis for determining how many input frames to read. This is
|
This will also be used as the basis for determining how many input frames to read. This is
|
||||||
not ideal because it can result in too many input frames being read which introduces latency,
|
not ideal because it can result in too many input frames being read which introduces latency.
|
||||||
however the alternative requires us to implement another callback in the node's vtable for
|
To solve this, nodes can implement an optional callback called onGetRequiredInputFrameCount
|
||||||
calculating the required input frame count which I'm not willing to do.
|
which is used as hint to miniaudio as to how many input frames it needs to read at a time. This
|
||||||
|
callback is completely optional, and if it's not set, miniaudio will assume `frameCount`.
|
||||||
|
|
||||||
This function will be called multiple times for each period of time, once for each output node.
|
This function will be called multiple times for each period of time, once for each output node.
|
||||||
We cannot read from each input node each time this function is called. Instead we need to check
|
We cannot read from each input node each time this function is called. Instead we need to check
|
||||||
|
|||||||
@@ -83,17 +83,17 @@ int main(int argc, char** argv)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = ma_node_attach_output_bus(&g_dataSourceNode, 0, ma_node_graph_get_endpoint(&g_nodeGraph), 0);
|
/*result = ma_node_attach_output_bus(&g_dataSourceNode, 0, ma_node_graph_get_endpoint(&g_nodeGraph), 0);
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
printf("Failed to attach node.");
|
printf("Failed to attach node.");
|
||||||
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
|
#if 1
|
||||||
/*
|
/*
|
||||||
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.
|
||||||
@@ -109,13 +109,9 @@ int main(int argc, char** argv)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Connect both outputs of the splitter to the endpoint for now. Later on we'll test effects and whatnot. */
|
|
||||||
ma_node_attach_output_bus(&g_loopNode, 0, ma_node_graph_get_endpoint(&g_nodeGraph), 0);
|
|
||||||
ma_node_attach_output_bus(&g_loopNode, 1, ma_node_graph_get_endpoint(&g_nodeGraph), 0);
|
|
||||||
|
|
||||||
/* Adjust the volume of the splitter node's endpoints. We'll just do it 50/50 so that both of them combine to reproduce the original signal at the endpoint. */
|
/* Adjust the volume of the splitter node's endpoints. We'll just do it 50/50 so that both of them combine to reproduce the original signal at the endpoint. */
|
||||||
ma_node_set_output_bus_volume(&g_loopNode, 0, 0.5f);
|
ma_node_set_output_bus_volume(&g_loopNode, 0, 1.0f);
|
||||||
ma_node_set_output_bus_volume(&g_loopNode, 1, 0.5f);
|
ma_node_set_output_bus_volume(&g_loopNode, 1, 1.0f);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -135,17 +131,26 @@ int main(int argc, char** argv)
|
|||||||
/* Adjust the volume of the splitter node's endpoints. We'll just do it 50/50 so that both of them combine to reproduce the original signal at the endpoint. */
|
/* Adjust the volume of the splitter node's endpoints. We'll just do it 50/50 so that both of them combine to reproduce the original signal at the endpoint. */
|
||||||
ma_node_set_output_bus_volume(&g_splitterNode, 0, 0.5f);
|
ma_node_set_output_bus_volume(&g_splitterNode, 0, 0.5f);
|
||||||
ma_node_set_output_bus_volume(&g_splitterNode, 1, 0.5f);
|
ma_node_set_output_bus_volume(&g_splitterNode, 1, 0.5f);
|
||||||
#else
|
|
||||||
/* Connect both outputs of the splitter to the endpoint for now. Later on we'll test effects and whatnot. */
|
|
||||||
ma_node_attach_output_bus(&g_splitterNode, 0, &g_loopNode, 0);
|
|
||||||
ma_node_attach_output_bus(&g_splitterNode, 1, &g_loopNode, 1);
|
|
||||||
|
|
||||||
/* Now loop back to the splitter node to form a loop. */
|
|
||||||
/*ma_node_attach_output_bus(&g_loopNode, 1, &g_splitterNode, 0);*/
|
|
||||||
#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);
|
||||||
|
#else
|
||||||
|
/* Connect the loop node directly to the output. */
|
||||||
|
ma_node_attach_output_bus(&g_loopNode, 0, ma_node_graph_get_endpoint(&g_nodeGraph), 0);
|
||||||
|
ma_node_attach_output_bus(&g_loopNode, 1, ma_node_graph_get_endpoint(&g_nodeGraph), 0);
|
||||||
|
|
||||||
|
/* Connect the splitter node directly to the loop node. */
|
||||||
|
ma_node_attach_output_bus(&g_splitterNode, 0, &g_loopNode, 0);
|
||||||
|
ma_node_attach_output_bus(&g_splitterNode, 1, &g_loopNode, 1);
|
||||||
|
|
||||||
|
/* Connect the data source node to the splitter node. */
|
||||||
|
ma_node_attach_output_bus(&g_dataSourceNode, 0, &g_splitterNode, 0);
|
||||||
|
|
||||||
|
/* Now loop back to the splitter node to form a loop. */
|
||||||
|
ma_node_attach_output_bus(&g_loopNode, 1, &g_splitterNode, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user