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

Decoding a particular OGG file appends a bit of silence at the end #92

Open
ivan-mogilko opened this issue Dec 1, 2023 · 4 comments · May be fixed by #97
Open

Decoding a particular OGG file appends a bit of silence at the end #92

ivan-mogilko opened this issue Dec 1, 2023 · 4 comments · May be fixed by #97

Comments

@ivan-mogilko
Copy link

ivan-mogilko commented Dec 1, 2023

There's a problem with decoding a particular 48 kHz OGG file: SDL_Sound appears to append a small bit of silence at the end (around 5-6 ms). This would not be a concern if a sound would play once, but when looping this extra bit causes an audible crackling noise.

Decoding is done without any requested conversion, passing null as desired format parameter.

If I convert the file itself to 44100 Hz, then it is loaded fine, without extra appends.

The original file:
VacuumNoise.zip

I used a small program to write SDL_Decode results to a file "raw". This "raw" file may be imported in a software like "Audacity", and a trailing silence observed:
test.raw.zip
Properties: 32-bit float, 48 kHz, 2 Channels, Little-endian.

The code used to decode and write this file is under the spoiler.
#include <stdio.h>
#include <SDL.h>
#include <SDL_sound.h>

const size_t SampleDefaultBufferSize = 64 * 1024;

int main(int argc, char *argv[])
{
    Sound_Init();

    Sound_Sample * sample = Sound_NewSampleFromFile("VacuumNoise.ogg", NULL, SampleDefaultBufferSize);
    if (!sample)
        return -1;

    FILE *f = fopen("test.raw", "wb");
    if (!f)
    {
        Sound_FreeSample(sample);
        return -2;
    }

    do
    {
        size_t sz = Sound_Decode(sample);
        if (sz > 0)
        {
            fwrite(sample->buffer, 1, sz, f);
        }
    } while ((sample->flags & SOUND_SAMPLEFLAG_EOF) == 0);

    fclose(f);
    Sound_FreeSample(sample);

    return 0;
}
@ericoporto
Copy link
Contributor

ericoporto commented Jan 18, 2024

Here's pair AGS issue: adventuregamestudio/ags#2244

Made a little repository to ease to reproduce this

https://github.com/ericoporto/sdl_sound_issue_92

image

In this image, above track is the original file and on the bottom is the track from the decoded raw from SDL_sound.

Uhm, I wonder if this right here should be an end of file flag, tested and it seems changing this to EOF flag doesn't make a difference.

https://github.com/icculus/SDL_sound/blob/c5639414c1bb24fb4eef5861c13adb42a4aab950/src/SDL_sound_vorbis.c#L176-177

Sound_GetDuration also gives just internal->total_time; which doesn't appear to use anything like length in ms reading of this from the sound file header and some way to know where in this length the sound is. So it just gives a value that is wrong and not of use...

I think then it's in stb_vorbis itself in stb_vorbis_get_samples_float_interleaved function.

@ericoporto
Copy link
Contributor

ericoporto commented Jan 19, 2024

Not sure yet what is the issue, but I noticed this truncation while debugging

SDL_sound/src/stb_vorbis.h

Lines 3603 to 3604 in fdcecaf

// truncate a short frame
if (len < right) right = len;

The last time we get here in the debugger, len is 0 and right is 128, and left is 0. Not sure yet what this means... But it feels like something wrong somewhere in stb_vorbis. Looking at the raw file in an hexeditor I don't see an obvious sequence of zeroes there, so I don't know exactly how that is appearing when seeing in audacity.

Stb vorbis has a special treatment when it opens the first part of the vorbis sample that contain it's header parts, I wonder if it could get it's length there and maintain it, at least as a sanity check.

Also I start to think it would be better to have an option to use Xiph vorbis library instead of stb. :/

Way too many revised PRs lingering in stb without being merged.

@ericoporto
Copy link
Contributor

ericoporto commented Jan 19, 2024

OK, I tried throwing a stb_vorbis_stream_length_in_seconds and the results match correctly the original file and not the raw. I think SDL_sound should use stb_vorbis_stream_length_in_samples (edit: it does but doesn't use the value see below) somewhere inside to keep track of things and make it not write more than it really exists in samples.

I noticed this is used in SDL_mixer, so I think this may have been noticed in the past there, but probably a long time ago.

Here in the repo there's a similar call for sanity check for the function similar to SDL_mixer, but the difference here is the returned total length in samples is not stored anywhere where it could be used to check later.

If the length that is used is instead in seconds it's better to use a double instead of the current milliseconds as int, or it will lose samples and loop poorly.

@ericoporto
Copy link
Contributor

ericoporto commented Feb 17, 2024

Also I start to think it would be better to have an option to use Xiph vorbis library instead of stb

I noticed SDL_mixer has this as an option, to use xiph libraries instead for ogg, would it be feasible to add this to SDL_sound?

Probably by building on top of the old v1.0 https://github.com/icculus/SDL_sound/blob/stable-1.0/decoders/ogg.c

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