mackron / miniaudio

Audio playback and capture library written in C, in a single source file.
https://miniaud.io
Other
4.07k stars 361 forks source link

Cannot get length of a Vorbis file #665

Closed fuelsoft closed 1 year ago

fuelsoft commented 1 year ago

Hi,

I'm not sure if I'm doing something wrong but I can't seem to get the length of a .ogg file - ma_sound_get_length_in_seconds (and the corresponding pcm_frame version) both set the length return parameter to 0. This is not an issue with .mp3 or .wav files.

Playback works correctly for all file types and the function returns MA_SUCCESS.

I have tried the current miniaudio.h on master as well as the dev branch, to be safe, and both exhibit this behaviour. I was testing on Windows under MSYS Clang with clang test.c -o test. The smallest working example is below, most of it is copied from the SDL example.

#define STB_VORBIS_HEADER_ONLY
#include "stb_vorbis.c"

#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"

#undef STB_VORBIS_HEADER_ONLY
#include "stb_vorbis.c"

#define CHANNELS 2
#define SAMPLE_RATE 48000

static ma_engine g_engine;
static ma_sound g_sound;

int main(int argc, char** argv)
{
    ma_result result;
    ma_engine_config engineConfig;

    if (argc < 2) {
        printf("No input file.");
        return -1;
    }

    engineConfig = ma_engine_config_init();
    engineConfig.noDevice   = MA_TRUE;
    engineConfig.channels   = CHANNELS;
    engineConfig.sampleRate = SAMPLE_RATE;

    result = ma_engine_init(&engineConfig, &g_engine);
    if (result != MA_SUCCESS) {
        printf("Failed to initialize audio engine.");
        return -1;
    }

    result = ma_sound_init_from_file(&g_engine, argv[1], 0, NULL, NULL, &g_sound);
    if (result != MA_SUCCESS) {
        printf("Failed to initialize sound.");
        return -1;
    }

    float length = 0;
    result = ma_sound_get_length_in_seconds(&g_sound, &length);

    if (result != MA_SUCCESS) {
        printf("Failed to get audio file length.");
        return -1;
    }

    printf("Audio file length: %f", length);

    ma_sound_uninit(&g_sound);
    ma_engine_uninit(&g_engine);

    return 0;
}
mackron commented 1 year ago

This is a known limitation with the Vorbis decoder. I haven't been able to find a good way to retrieve the length via stb_vorbis so it needs to return 0. If you want to determine the length, you'll need to read-and-discard until you reach the end, accumulating the number of frames read as you go, then seek back to the start. Obviously this will be time consuming so you'd need to do it during an initialization routine and cache it.

Returning 0 is a valid situation which you should be handling if you want complete robustness. Should probably do another pass on the documentation and make that clearer.

fuelsoft commented 1 year ago

Ah, that's unfortunate. I think I'll go with my plan B then, thanks for the reply.