Skip to content

Commit

Permalink
Prefill ALLEGRO_AUDIO_STREAMs with data in docstrings/examples/acodec.
Browse files Browse the repository at this point in the history
The audio system will attempt to grab data from a stream *before* it has
sent any events that it needs fragments. This causes a bit of lag, and
also log spam as the system complains about having no data.

This change adjusts most places to prefill the streams with data to
avoid this issue. It should be safe, and in fact beneficial as we should
get a few less sample-worths of lag when using
`al_play/load_audio_stream`.
  • Loading branch information
SiegeLordEx authored and SiegeLord committed Feb 21, 2024
1 parent edcc50e commit 0e7c9bd
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 39 deletions.
7 changes: 5 additions & 2 deletions addons/audio/kcm_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,7 @@ void *_al_kcm_feed_stream(ALLEGRO_THREAD *self, void *vstream)
ALLEGRO_AUDIO_STREAM *stream = vstream;
ALLEGRO_EVENT_QUEUE *queue;
bool finished_event_sent = false;
bool prefill = true;
(void)self;

ALLEGRO_DEBUG("Stream feeder thread started.\n");
Expand All @@ -702,10 +703,12 @@ void *_al_kcm_feed_stream(ALLEGRO_THREAD *self, void *vstream)
char *fragment;
ALLEGRO_EVENT event;

al_wait_for_event(queue, &event);
if (!prefill)
al_wait_for_event(queue, &event);

if (event.type == ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT
if ((prefill || event.type == ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT)
&& !stream->is_draining) {
prefill = false;
unsigned long bytes;
unsigned long bytes_written;
ALLEGRO_MUTEX *stream_mutex;
Expand Down
15 changes: 15 additions & 0 deletions docs/src/refman/audio.txt
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,21 @@ If you're late with supplying new data, the stream will be silent until new data
is provided. You must call [al_drain_audio_stream] when you're finished with
supplying data to the stream.

It is often a good idea to prefill the audio stream with data before
[ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT] events arrive. Here is a snippet that will
fill the stream buffers with silence:

~~~~c
ALLEGRO_AUDIO_STREAM *stream = al_create_audio_stream(8, SAMPLES_PER_BUFFER, 22050,
ALLEGRO_AUDIO_DEPTH_UINT8, ALLEGRO_CHANNEL_CONF_1);
void *buf;
while ((buf = al_get_audio_stream_fragment(stream))) {
al_fill_silence(buf, SAMPLES_PER_BUFFER, ALLEGRO_AUDIO_DEPTH_UINT8,
ALLEGRO_CHANNEL_CONF_1);
al_set_audio_stream_fragment(stream, buf);
}
~~~~

If the stream is created by [al_load_audio_stream] or [al_play_audio_stream]
then it will also generate an [ALLEGRO_EVENT_AUDIO_STREAM_FINISHED] event if it
reaches the end of the file and is not set to loop.
Expand Down
7 changes: 7 additions & 0 deletions examples/ex_saw.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ static void saw(ALLEGRO_AUDIO_STREAM *stream)
int main(int argc, char **argv)
{
ALLEGRO_AUDIO_STREAM *stream;
void *buf;

(void)argc;
(void)argv;
Expand All @@ -98,6 +99,12 @@ int main(int argc, char **argv)

stream = al_create_audio_stream(8, SAMPLES_PER_BUFFER, 22050,
ALLEGRO_AUDIO_DEPTH_UINT8, ALLEGRO_CHANNEL_CONF_1);
while ((buf = al_get_audio_stream_fragment(stream))) {
al_fill_silence(buf, SAMPLES_PER_BUFFER, ALLEGRO_AUDIO_DEPTH_UINT8,
ALLEGRO_CHANNEL_CONF_1);
al_set_audio_stream_fragment(stream, buf);
}

if (!stream) {
abort_example("Could not create stream.\n");
}
Expand Down
62 changes: 25 additions & 37 deletions examples/ex_synth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,7 @@ static void sawtooth(float *buf, size_t samples, double t,

/* globals */
ALLEGRO_FONT *font_gui;
ALLEGRO_AUDIO_STREAM *stream1;
ALLEGRO_AUDIO_STREAM *stream2;
ALLEGRO_AUDIO_STREAM *stream3;
ALLEGRO_AUDIO_STREAM *stream4;
ALLEGRO_AUDIO_STREAM *stream5;
ALLEGRO_AUDIO_STREAM *streams[5];

bool saving = false;
ALLEGRO_FILE *save_fp = NULL;
Expand Down Expand Up @@ -358,11 +354,8 @@ void Prog::run()
{
d.prepare();

d.register_event_source(al_get_audio_stream_event_source(stream1));
d.register_event_source(al_get_audio_stream_event_source(stream2));
d.register_event_source(al_get_audio_stream_event_source(stream3));
d.register_event_source(al_get_audio_stream_event_source(stream4));
d.register_event_source(al_get_audio_stream_event_source(stream5));
for (int i = 0; i < 5; i++)
d.register_event_source(al_get_audio_stream_event_source(streams[i]));
d.set_event_handler(this);

while (!d.is_quit_requested()) {
Expand Down Expand Up @@ -399,15 +392,15 @@ void Prog::handle_event(const ALLEGRO_EVENT & event)
return;
}

if (stream == stream1)
if (stream == streams[0])
group = &group1;
else if (stream == stream2)
else if (stream == streams[1])
group = &group2;
else if (stream == stream3)
else if (stream == streams[2])
group = &group3;
else if (stream == stream4)
else if (stream == streams[3])
group = &group4;
else if (stream == stream5)
else if (stream == streams[4])
group = &group5;
else
group = NULL;
Expand Down Expand Up @@ -474,27 +467,24 @@ int main(int argc, char *argv[])
size_t buffers = 8;
unsigned samples = SAMPLES_PER_BUFFER;
unsigned freq = STREAM_FREQUENCY;
void *buf;
ALLEGRO_AUDIO_DEPTH depth = ALLEGRO_AUDIO_DEPTH_FLOAT32;
ALLEGRO_CHANNEL_CONF ch = ALLEGRO_CHANNEL_CONF_1;
ALLEGRO_MIXER *mixer = al_get_default_mixer();

stream1 = al_create_audio_stream(buffers, samples, freq, depth, ch);
stream2 = al_create_audio_stream(buffers, samples, freq, depth, ch);
stream3 = al_create_audio_stream(buffers, samples, freq, depth, ch);
stream4 = al_create_audio_stream(buffers, samples, freq, depth, ch);
stream5 = al_create_audio_stream(buffers, samples, freq, depth, ch);
if (!stream1 || !stream2 || !stream3 || !stream4 || !stream5) {
abort_example("Could not create stream.\n");
}
for (int i = 0; i < 5; i++) {
streams[i] = al_create_audio_stream(buffers, samples, freq, depth, ch);
if (!streams[i]) {
abort_example("Could not create stream.\n");
}
while ((buf = al_get_audio_stream_fragment(streams[i]))) {
al_fill_silence(buf, samples, depth, ch);
al_set_audio_stream_fragment(streams[i], buf);
}

ALLEGRO_MIXER *mixer = al_get_default_mixer();
if (
!al_attach_audio_stream_to_mixer(stream1, mixer) ||
!al_attach_audio_stream_to_mixer(stream2, mixer) ||
!al_attach_audio_stream_to_mixer(stream3, mixer) ||
!al_attach_audio_stream_to_mixer(stream4, mixer) ||
!al_attach_audio_stream_to_mixer(stream5, mixer)
) {
abort_example("Could not attach stream to mixer.\n");
if (!al_attach_audio_stream_to_mixer(streams[i], mixer)) {
abort_example("Could not attach stream to mixer.\n");
}
}

al_set_mixer_postprocess_callback(mixer, mixer_pp_callback, mixer);
Expand All @@ -506,11 +496,9 @@ int main(int argc, char *argv[])
prog.run();
}

al_destroy_audio_stream(stream1);
al_destroy_audio_stream(stream2);
al_destroy_audio_stream(stream3);
al_destroy_audio_stream(stream4);
al_destroy_audio_stream(stream5);
for (int i = 0; i < 5; i++) {
al_destroy_audio_stream(streams[i]);
}
al_uninstall_audio();

al_destroy_font(font_gui);
Expand Down

0 comments on commit 0e7c9bd

Please sign in to comment.