Wav Streaming: some technical helps needed

Discussion in '3DS - Homebrew Development and Emulators' started by Rinnegatamante, Dec 17, 2014.

  1. Rinnegatamante
    OP

    Rinnegatamante GBAtemp Psycho!

    Member
    3,127
    3,260
    Nov 24, 2014
    Italy
    Bologna
    Hi, i'm writing a function to stream a wav file (so i can reduce RAM usage for Wav reproduction) but i'm not very expert about samplerate and bps.

    If i know:
    - Current time passed from wav starts in millisecond
    - Wav samplerate
    - Wav bytepersample (BlockAlign voice in header)
    - Audiobuffer size

    How can i find how much bytes have been read from audio buffer?

    For example, if i heard 20 seconds of an audiobuffer at 44100HZ Samplerate for a Wav with 16 Bitpersample Stereo (so Bytepersample = 4) with PCM16 Codec, how many bytes from my audiobuffer have been processed by CSND_playsound?
     
  2. titegtnodI

    titegtnodI Advanced Member

    Newcomer
    82
    67
    Nov 25, 2014
    Canada
  3. Rinnegatamante
    OP

    Rinnegatamante GBAtemp Psycho!

    Member
    3,127
    3,260
    Nov 24, 2014
    Italy
    Bologna
    Thanks for the link, i wrote the correct condition check i think but now i'm having some issues with buffer updating. Is it possible tu update only a part of a buffer when playsound is processing it?

    I wrote a thing like this, but it seems the function jumps directly from first loaded block to the final block of the wav file (without processing the middle part of the file):

    Code:
    static int lua_streamWav(lua_State *L)
    {
        int argc = lua_gettop(L);
        if (argc != 1) return luaL_error(L, "wrong number of arguments");
        wav* src = (wav*)luaL_checkint(L, 1);
        if (((src->samplerate * src->bytepersample * ((osGetTime() - src->tick) / 1000)) > ((src->mem_size / 2) * src->moltiplier) && (src->isPlaying)){
            if ((src->moltiplier % 2) == 1){
                u32 bytesRead;
                //Update and flush first half-buffer
                if (src->audiobuf2 == NULL){
                    FSFILE_Read(src->sourceFile, &bytesRead, src->startRead+(src->mem_size)*(src->moltiplier), src->audiobuf, (src->mem_size)/2);
                    src->moltiplier = src->moltiplier + 1;
                    GSPGPU_FlushDataCache(NULL, src->audiobuf, (src->mem_size)/2);
                }else{
                    u8* tmp_buffer = (u8*)linearAlloc((src->mem_size)/2);
                    FSFILE_Read(src->sourceFile, &bytesRead, src->startRead+(src->mem_size)*(src->moltiplier), tmp_buffer, (src->mem_size)/2);
                    src->moltiplier = src->moltiplier + 1;
                    u32 size_tbp = (src->mem_size)/2;
                    u32 off=0;
                    u32 i=0;
                    u16 z;
                    while (i < size_tbp){
                        z=0;
                        while (z < (src->bytepersample/2)){
                            src->audiobuf[off+z] = tmp_buffer[i+z];
                            src->audiobuf2[off+z] = tmp_buffer[i+z+(src->bytepersample/2)];
                            z++;
                        }
                        z=0;
                        i=i+src->bytepersample;
                        off=off+(src->bytepersample/2);
                    }
                    linearFree(tmp_buffer);
                    GSPGPU_FlushDataCache(NULL, src->audiobuf, (src->mem_size)/4);
                    GSPGPU_FlushDataCache(NULL, src->audiobuf2, (src->mem_size)/4);
                }
            }else{
                u32 bytesRead;
                //Update and flush second half-buffer
                if (src->audiobuf2 == NULL){
                    FSFILE_Read(src->sourceFile, &bytesRead, src->startRead+(src->mem_size)*(src->moltiplier), src->audiobuf+((src->mem_size)/2), (src->mem_size)/2);
                    src->moltiplier = src->moltiplier + 1;
                    GSPGPU_FlushDataCache(NULL, src->audiobuf+((src->mem_size)/2), (src->mem_size)/2);
                }else{
                    u8* tmp_buffer = (u8*)linearAlloc((src->mem_size)/2);
                    FSFILE_Read(src->sourceFile, &bytesRead, src->startRead+(src->mem_size)*(src->moltiplier), tmp_buffer, (src->mem_size)/2);
                    src->moltiplier = src->moltiplier + 1;
                    u32 size_tbp = (src->mem_size)/2;
                    u32 off=0;
                    u32 i=0;
                    u16 z;
                    while (i < size_tbp){
                        z=0;
                        while (z < (src->bytepersample/2)){
                            src->audiobuf[(src->mem_size)/2+off+z] = tmp_buffer[i+z];
                            src->audiobuf2[(src->mem_size)/2+off+z] = tmp_buffer[i+z+(src->bytepersample/2)];
                            z++;
                        }
                    i=i+src->bytepersample;
                    off=off+(src->bytepersample/2);
                    }
                    linearFree(tmp_buffer);
                    GSPGPU_FlushDataCache(NULL, src->audiobuf+((src->mem_size)/2), (src->mem_size)/4);
                    GSPGPU_FlushDataCache(NULL, src->audiobuf2+((src->mem_size)/2), (src->mem_size)/4);
                }
            }
        }
        return 0;
    }
     
  4. titegtnodI

    titegtnodI Advanced Member

    Newcomer
    82
    67
    Nov 25, 2014
    Canada
    I'll look at it when I get a chance but maybe try asking on #3dsdev on Efnet and Freenode.
     
  5. Rinnegatamante
    OP

    Rinnegatamante GBAtemp Psycho!

    Member
    3,127
    3,260
    Nov 24, 2014
    Italy
    Bologna
    It seems the problem is here:

    (src->samplerate * src->bytepersample * ((osGetTime() - src->tick) / 1000)

    I tried to return this value for debug and i get a thing like this:

    0 second: 0
    1 second: 17k
    2 seconds: 34k
    3 seconds: 51k
    4 seconds: 7 * 10^18 (O.o)

    Where src->samplerate is 44100
    src->bytepersample is 4
    src->tick is the osGetTime result of the start wav

    P.S. Solved recompiling libctru (O.o), finished also streaming functions both mono and stereo sounds (i must add only restart for looping music and stop for no looping music at streaming end.).

    If someone is interested, here's the code:
    Code:
    int lua_streamWav(lua_State *L)
    {
        int argc = lua_gettop(L);
        if (argc != 1) return luaL_error(L, "wrong number of arguments");
        wav* src = (wav*)luaL_checkint(L, 1);
        u32 size;
        if (((src->samplerate * src->bytepersample * ((osGetTime() - src->tick) / 1000)) > ((src->mem_size / 2) * src->moltiplier)) && (src->isPlaying)){
            if ((src->moltiplier % 2) == 1){
                u32 bytesRead;
                //Update and flush first half-buffer
                if (src->audiobuf2 == NULL){
                    FSFILE_Read(src->sourceFile, &bytesRead, src->startRead+(((src->mem_size)/2)*(src->moltiplier + 1)), src->audiobuf, (src->mem_size)/2);
                    src->moltiplier = src->moltiplier + 1;
                    GSPGPU_FlushDataCache(NULL, src->audiobuf, src->mem_size);
                }else{
                    u8* tmp_buffer = (u8*)linearAlloc((src->mem_size)/2);
                    FSFILE_Read(src->sourceFile, &bytesRead, src->startRead+(src->mem_size/2)*(src->moltiplier + 1), tmp_buffer, (src->mem_size)/2);
                    src->moltiplier = src->moltiplier + 1;
                    u32 size_tbp = (src->mem_size)/2;
                    u32 off=0;
                    u32 i=0;
                    u16 z;
                    while (i < size_tbp){
                        z=0;
                        while (z < (src->bytepersample/2)){
                            src->audiobuf[off+z] = tmp_buffer[i+z];
                            src->audiobuf2[off+z] = tmp_buffer[i+z+(src->bytepersample/2)];
                            z++;
                        }
                        z=0;
                        i=i+src->bytepersample;
                        off=off+(src->bytepersample/2);
                    }
                    linearFree(tmp_buffer);
                GSPGPU_FlushDataCache(NULL, src->audiobuf, (src->mem_size)/2);
                GSPGPU_FlushDataCache(NULL, src->audiobuf2, (src->mem_size)/2);
                }
            }else{
                u32 bytesRead;
                //Update and flush second half-buffer
                if (src->audiobuf2 == NULL){
                    FSFILE_Read(src->sourceFile, &bytesRead, src->startRead+(((src->mem_size)/2)*(src->moltiplier + 1)), src->audiobuf+((src->mem_size)/2), (src->mem_size)/2);
                    src->moltiplier = src->moltiplier + 1;
                    GSPGPU_FlushDataCache(NULL, src->audiobuf, src->mem_size);
                }else{
                    u8* tmp_buffer = (u8*)linearAlloc((src->mem_size)/2);
                    FSFILE_Read(src->sourceFile, &bytesRead, src->startRead+(src->mem_size/2)*(src->moltiplier + 1), tmp_buffer, (src->mem_size)/2);
                    src->moltiplier = src->moltiplier + 1;
                    u32 size_tbp = (src->mem_size)/2;
                    u32 off=0;
                    u32 i=0;
                    u16 z;
                    while (i < size_tbp){
                        z=0;
                        while (z < (src->bytepersample/2)){
                            src->audiobuf[(src->mem_size)/4+off+z] = tmp_buffer[i+z];
                            src->audiobuf2[(src->mem_size)/4+off+z] = tmp_buffer[i+z+(src->bytepersample/2)];
                            z++;
                        }
                    i=i+src->bytepersample;
                    off=off+(src->bytepersample/2);
                    }
                    linearFree(tmp_buffer);
                    GSPGPU_FlushDataCache(NULL, src->audiobuf, (src->mem_size)/2);
                    GSPGPU_FlushDataCache(NULL, src->audiobuf2, (src->mem_size)/2);
                }
            }