Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Popping with audio streams when doing stop, seek, play #1310

Closed
SiegeLord opened this issue Feb 24, 2022 · 9 comments
Closed

Popping with audio streams when doing stop, seek, play #1310

SiegeLord opened this issue Feb 24, 2022 · 9 comments
Milestone

Comments

@SiegeLord
Copy link
Member

Something like:

al_set_audio_stream_playing(s, false);
al_seek_audio_stream_secs(s, 5.);
al_set_audio_stream_playing(s, true);

but this does not pop:

al_seek_audio_stream_secs(s, 5.);
@WickedSmoke
Copy link
Contributor

WickedSmoke commented Feb 24, 2022

static void playSegment(ALLEGRO_AUDIO_STREAM* stream, const float* segment) {
    float start = segment[1];
    dialogEnd = start + segment[0];
    if (al_seek_audio_stream_secs(stream, start))
        al_set_audio_stream_playing(stream, 1);
}

// Duration, Start
static const float dialogParts[] = {
     2.856054,  0.0,
     2.995374,  2.856054,
     5.01551,   5.851428
};

// No pop if stream is playing.
playSegment(dialogStream, dialogParts);

// Pop if we stop stream first.
al_set_audio_stream_playing(dialogStream, 0);
playSegment(dialogStream, dialogParts);

The pop does sound like part of the previously played segment (it changes sound after different segments are played).

@WickedSmoke
Copy link
Contributor

The stream is created like this:

    ALLEGRO_FILE* slice;
    al_fseek(fh, ent->offset, ALLEGRO_SEEK_SET);
    slice = al_fopen_slice(fh, ent->bytes, "r");
    return al_load_audio_stream_f(slice, ".ogg", 4, 2048);

@SiegeLord
Copy link
Member Author

I found some time to look into it. I couldn't reproduce the pops with my audio files, but I did notice something odd. Calling al_set_audio_stream_playing(stream, false); actually does a short seek into the future, so stopping and starting a stream (without seek in between), will slowly advance the stream forward. This is due to the shenanigans performed by reset_stopped_stream function in kcm_stream.c. That function invalidates all existing buffers and resets the interpolation parameters. I think that function shouldn't be called there, and possibly when seeking instead.

al_get_audio_stream_position_secs seems bogus too, as it reports (at least for ogg) where the file reader is located (typically some number of segments in the future) rather where the actual played sample is.

These things I can probably fix, and maybe adding the reset_stopped_stream to seeking might fix it. On the other hand, it could be that the pops are actually the correct output, and the seeking behavior right now (which I currently don't believe resets anything) was actually smoothing the pops out. Something to think about.

@WickedSmoke
Copy link
Contributor

Thanks for looking into this. I'll try and setup a minimal test for you to reproduce it.

Because of this issue and other annoyances of Allegro audio, I have been writing my own high-level sound API. With that code this sort of segmented playback is working without any artifacts on Ogg streams. I'll leave a comment here when I publish my code.

@WickedSmoke
Copy link
Contributor

There's a stand alone test in an archive at http://xu4.sourceforge.net/download/segment_test.tar.gz
This contains a 7MB data file.

The segment is stopped in musicUpdate() based on what al_get_audio_stream_position_secs returns. The pop happens when streaming is started however, so that doesn't seem related to potentially stopping the segment early.

@SiegeLord
Copy link
Member Author

Thanks, this was extremely useful. The issue turned out to be that we were calling ov_time_seek_lap instead of ov_time_seek when seeking vorbis streams. This means that when decoding the vorbis streams we would cross-fade between the latest read chunk and the destination chunk. Since Allegro pre-loads a bunch of chunks in the future (4 buffers with 2048 samples each), it would cross fade the sound 4 * 2048 samples after the point where you called seek. In your file, this future point was at the beginning of the next voiceover. You wouldn't have had this issue if the gaps were even wider, funnily enough.

I'll switch the code to use ov_time_seek.

@WickedSmoke
Copy link
Contributor

The problem on my side is that the segment duration values include the one second of padding. So having more silence wouldn't have eliminated the bad audio.

With my audio API I just noticed this problem because the unwanted audio is heard at the end of a segment (as would be expected). Perhaps this is not happening with Allegro because of the incorrect (future) al_get_audio_stream_position_secs value?

@SiegeLord SiegeLord added this to the 5.2.8 milestone Mar 27, 2022
@WickedSmoke
Copy link
Contributor

The initial version of my audio library, Faun, is now at https://github.com/WickedSmoke/faun and may be of interest to Allegro users looking for a simpler API for playing sounds.

The faun_playStreamPart() function implements what I was trying accomplish when I ran across this Allegro issue.

SiegeLord pushed a commit to SiegeLord/allegro5 that referenced this issue Apr 2, 2022
The old one did cross-fades, causing unexpected behavior in certain
cases.

Fixes liballeg#1310
@SiegeLord
Copy link
Member Author

That looks nice, I like the name. I made a pull request for Allegro to fix this and the other issue, and with them, the playSegment from the test you sent me now looks like this (and there's no more logic to stop the stream, since it now stops at the loop end):

static void playSegment(ALLEGRO_AUDIO_STREAM* stream, const float* segment) {
    float start = segment[1];
    float end = start + segment[0];

    al_set_audio_stream_loop_secs(stream, start, end);
    if (al_seek_audio_stream_secs(stream, start)) {
        al_set_audio_stream_playing(stream, 1);
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants