/'===============================================================================================
 File Callbacks Example
 Copyright (c), Firelight Technologies Pty, Ltd 2004-2011.

 This example is a modified version of the playstream example.
 It shows the correct way declare and handle fmod file callbacks with System::setFileSystem.
==============================================================================================='/

#include "windows.bi"
#include "crt.bi"

#include "fmodex/fmodex.bi"
#include "fmodex/fmod_errors.bi"

sub ERRCHECK(byval result as FMOD_RESULT)
    if (result <> FMOD_OK) then
        printf(!"FMOD error! (%d) %s\n", result, FMOD_ErrorString(result))
        end -1
    end if
end sub


/'
    TIPS:

    1. use F_CALLBACK.  Do NOT force cast your own function to fmod's callback type.
    2. return FMOD_ERR_FILE_NOTFOUND in open as required.
    3. return number of bytes read in read callback.  Do not get the size and count 
       around the wrong way in fread for example, this would return 1 instead of the number of bytes read.

    QUESTIONS:

    1. Why does fmod seek to the end and read?  Because it is looking for ID3V1 tags.  
       Use FMOD_IGNORETAGS in FMOD_System_CreateSound / FMOD_System_CreateStream if you don't like this behaviour.
'/

function myopen(byval fname as zstring ptr, byval unicode as integer, byval filesize as uinteger ptr, byval handle as any ptr ptr, byval userdata as any ptr ptr) as FMOD_RESULT
    if (fname) then
        dim as FILE ptr fp

        fp = fopen(fname, "rb")
        if (fp = 0) then
            return FMOD_ERR_FILE_NOTFOUND
        end if

        fseek(fp, 0, SEEK_END)
        *filesize = ftell(fp)
        fseek(fp, 0, SEEK_SET)

        *userdata = cast(any ptr,&h12345678)
        *handle = fp
    end if

    return FMOD_OK
end function

function myclose(byval handle as any ptr, byval userdata as any ptr) as FMOD_RESULT
    if (handle = 0) then
        return FMOD_ERR_INVALID_PARAM
    end if

    fclose(handle)

    return FMOD_OK
end function

function myread(byval handle as any ptr, byval buffer as any ptr, byval sizebytes as uinteger, byval bytesread as uinteger ptr, byval userdata as any ptr) as FMOD_RESULT
    if (handle = 0) then
        return FMOD_ERR_INVALID_PARAM
    end if

    if (bytesread) then
        *bytesread = fread(buffer, 1, sizebytes, handle)
        if (*bytesread < sizebytes) then
            return FMOD_ERR_FILE_EOF
        end if
    end if

    return FMOD_OK
end function

function myseek(byval handle as any ptr, byval position as uinteger, byval userdata as any ptr) as FMOD_RESULT
    if (handle = 0) then
        return FMOD_ERR_INVALID_PARAM
    end if

    fseek(handle, position, SEEK_SET)

    return FMOD_OK
end function


' program start
    dim as FMOD_SYSTEM      ptr fsystem = any
    dim as FMOD_SOUND       ptr sound = any
    dim as FMOD_CHANNEL     ptr channel = 0
    dim as FMOD_RESULT       result = any
    dim as string               key
    dim as uinteger      version = any

    /'
        Create a System object and initialize.
    '/
    result = FMOD_System_Create(@fsystem)
    ERRCHECK(result)

    result = FMOD_System_GetVersion(fsystem, @version)
    ERRCHECK(result)

    if (version < FMOD_VERSION) then
        printf(!"Error!  You are using an old version of FMOD %08x.  This program requires %08x\n", version, FMOD_VERSION)
end 0
    end if

    result = FMOD_System_Init(fsystem, 1, FMOD_INIT_NORMAL, NULL)
    ERRCHECK(result)

    result = FMOD_System_SetFileSystem(fsystem, @myopen, @myclose, @myread, @myseek, 0, 0, 2048)
    ERRCHECK(result)

    result = FMOD_System_CreateStream(fsystem, "media/wave.mp3", FMOD_HARDWARE or FMOD_LOOP_NORMAL or FMOD_2D, 0, @sound)
    ERRCHECK(result)

    printf(!"====================================================================\n")
    printf(!"PlayStream Example.  Copyright (c) Firelight Technologies 2004-2011.\n")
    printf(!"====================================================================\n")
    printf(!"\n")
    printf(!"Press space to pause, Esc to quit\n")
    printf(!"\n")

    /'
        Play the sound.
    '/

    result = FMOD_System_PlaySound(fsystem, FMOD_CHANNEL_FREE, sound, 0, @channel)
    ERRCHECK(result)

    /'
        Main loop.
    '/

    do
key = inkey
select case key
                case " " :
                    dim as integer paused = any
                    FMOD_Channel_GetPaused(channel, @paused)
paused xor=1
                    FMOD_Channel_SetPaused(channel, paused)
end select

        FMOD_System_Update(fsystem)

        if (channel) then
            dim as uinteger ms = any
            dim as uinteger lenms = any
            dim as integer          playing = any
            dim as integer          paused = any

            FMOD_Channel_IsPlaying(channel, @playing)
            if ((result <> FMOD_OK) and (result <> FMOD_ERR_INVALID_HANDLE) and (result <> FMOD_ERR_CHANNEL_STOLEN)) then
                ERRCHECK(result)
            end if

            result = FMOD_Channel_GetPaused(channel, @paused)
            if ((result <> FMOD_OK) and (result <> FMOD_ERR_INVALID_HANDLE) and (result <> FMOD_ERR_CHANNEL_STOLEN)) then
                ERRCHECK(result)
            end if

            result = FMOD_Channel_GetPosition(channel, @ms, FMOD_TIMEUNIT_MS)
            if ((result <> FMOD_OK) and (result <> FMOD_ERR_INVALID_HANDLE) and (result <> FMOD_ERR_CHANNEL_STOLEN)) then
                ERRCHECK(result)
            end if

            result = FMOD_Sound_GetLength(sound, @lenms, FMOD_TIMEUNIT_MS)
            if ((result <> FMOD_OK) and (result <> FMOD_ERR_INVALID_HANDLE) and (result <> FMOD_ERR_CHANNEL_STOLEN)) then
                ERRCHECK(result)
            end if

            printf(!"Time %02d:%02d:%02d/%02d:%02d:%02d : %s\r", ms \ 1000 \ 60, (ms \ 1000) mod 60, (ms \ 10) mod 100, lenms \ 1000 \ 60, (lenms \ 1000) mod 60, (lenms \ 10) mod 100, iif(paused, @"Paused ", iif(playing, @"Playing", @"Stopped")))

        end if

        Sleep(10)

    loop while (key <> chr(27))

    printf(!"\n")

    /'
        Shut down
    '/
    result = FMOD_Sound_Release(sound)
    ERRCHECK(result)
    result = FMOD_System_Close(fsystem)
    ERRCHECK(result)
    result = FMOD_System_Release(fsystem)
    ERRCHECK(result)
