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

 This example shows how to rip streaming audio from the internet to local files, using
 System::attachFileSystem.
 
 This example also uses tags from the net stream to name the files as they are ripped.

 Some internet radio station only broadcast new tag information on fixed intervals.  This 
 means that the rip might not be exactly in line with the filenames that are produced.  
 For example if a radio station only broadcast the track name every 10 seconds, and the 
 music changed half way inbetween this period, then the first file would contain 5 seconds 
 of the new song, and the second song would be missing  the first 5 seconds of the track.
 Silence detection might help this problem, but most radio stations do not offer silence 
 between  tracks.
==============================================================================================='/
#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

dim shared as FMOD_SOUND_TYPE gSoundType = FMOD_SOUND_TYPE_MPEG
dim shared as integer             gFileBufferSize = 128*1024
dim shared as zstring * 256            gCurrentTrackArtist
dim shared as zstring *256           gCurrentTrackTitle
dim shared as integer             gUpdateFileName = FALSE
dim shared as zstring * 1024            gOutputFileName
dim shared as FILE           ptr gFileHandle = 0


/'
    File callbacks
'/
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
    gFileHandle = fopen(@gOutputFileName, "wb")
    if (gFileHandle) = 0 then
        return FMOD_ERR_FILE_NOTFOUND
    end if

    return FMOD_OK
end function

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

    fclose(gFileHandle)

    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 (gFileHandle) = 0 then
        return FMOD_ERR_INVALID_PARAM
    end if

    /'
        If the main thread detected a new tag name for artist / title, close the file and open a new one with the new name.
    '/
    if (gUpdateFileName) then
        dim as zstring ptr ext = any

        gUpdateFileName = FALSE

        fclose(gFileHandle)

        select case gSoundType
            case FMOD_SOUND_TYPE_MPEG:       /' MP2/MP3 '/
                ext = @".mp3"
            case FMOD_SOUND_TYPE_OGGVORBIS:  /' Ogg vorbis '/
                ext = @".ogg"
            case else:
                ext = @".unknown"
        end select
    
        /'
            If it is the 'temp file name' then rename the file and append to it instead of starting a new file
        '/
        if (strcmp(@gOutputFileName, "output.mp3")) = 0 then
            sprintf(gOutputFileName, "%s%s%s%s", @gCurrentTrackArtist, iif(strlen(@gCurrentTrackTitle),@" - ",@""), gCurrentTrackTitle, ext)
            rename("output.mp3", @gOutputFileName)
            gFileHandle = fopen(@gOutputFileName, "ab+")
        else
            sprintf(@gOutputFileName, "%s%s%s%s", @gCurrentTrackArtist, iif(strlen(gCurrentTrackTitle),@" - ",@""), gCurrentTrackTitle, ext)
            gFileHandle = fopen(@gOutputFileName, "wb")
        end if

        if (gFileHandle) = 0 then
            return FMOD_ERR_FILE_NOTFOUND
        end if
    end if

    fwrite(buffer, 1, sizebytes, gFileHandle)

    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

    clear(gCurrentTrackArtist, 0, 256)
    clear(gCurrentTrackTitle, 0, 256)
    strcpy(@gOutputFileName, "output.mp3")   /' Start off like this then rename if a title tag comes along '/

    printf(!"======================================================================\n")
    printf(!"RipNetStream Example.  Copyright (c) Firelight Technologies 2004-2011.\n")
    printf(!"======================================================================\n\n")

    if (__FB_ARGC__ < 2) then
        printf(!"Usage:   ripnetstream <url>\n")
        end -1
    end if

    /'
        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, 100, FMOD_INIT_NORMAL, NULL)
    ERRCHECK(result)

    result = FMOD_System_SetStreamBufferSize(fsystem, gFileBufferSize, FMOD_TIMEUNIT_RAWBYTES)
    ERRCHECK(result)

    result = FMOD_System_AttachFileSystem(fsystem, @myopen, @myclose, @myread, 0)
    ERRCHECK(result)

    printf(!"Buffering...\n\n")

    result = FMOD_System_CreateSound(fsystem, __FB_ARGV__[1], FMOD_HARDWARE or FMOD_2D or FMOD_CREATESTREAM or FMOD_NONBLOCKING, 0, @sound)
    ERRCHECK(result)

    /'
        Main loop
    '/
    do
        if (sound andalso channel = 0) then
            result = FMOD_System_PlaySound(fsystem, FMOD_CHANNEL_FREE, sound, FALSE, @channel)
        end if

            key = inkey

            select case key
                case " " :
                    if (channel) then
                        dim as integer paused = any
                        FMOD_Channel_GetPaused(channel, @paused)
paused xor=1
                        FMOD_Channel_SetPaused(channel, paused)
                    end if
                case "m","M" :
                    if (channel) then
                       dim as integer mute = any
                        FMOD_Channel_GetMute(channel, @mute)
mute xor= 1
                        FMOD_Channel_SetMute(channel, mute)
                    end if
        end select

        FMOD_System_Update(fsystem)

        if (channel) then
            dim as uinteger ms = 0
            dim as integer          playing = FALSE
            dim as integer          paused = FALSE
            dim as integer          tagsupdated = 0

            FMOD_Sound_GetNumTags(sound, 0, @tagsupdated)

            if (tagsupdated) then
                printf(!"\n")
                printf(!"\n")
                while 1
                    dim as FMOD_TAG tag = any

                    if (FMOD_Sound_GetTag(sound, 0, -1, @tag) <> FMOD_OK) then
                        exit while
                    end if

                    if (tag.datatype = FMOD_TAGDATATYPE_STRING) then
                        printf(!"[%-11s] %s (%d bytes)\n", tag.name, tag.data, tag.datalen)
                        
                        FMOD_Sound_GetFormat(sound, @gSoundType, 0, 0, 0)
                    
                        if (strcmp(tag.name, "ARTIST")) = 0 then
                            if (strncmp(@gCurrentTrackArtist, @tag.data, 256)) then
                                strncpy(@gCurrentTrackArtist, @tag.data, 256)
                                gUpdateFileName = TRUE
                            end if
                        end if
                        if (strcmp(tag.name, "TITLE")) = 0 then
                            if (strncmp(@gCurrentTrackTitle, @tag.data, 256)) then
                                strncpy(@gCurrentTrackTitle, @tag.data, 256)
                                gUpdateFileName = TRUE
                            end if
                        end if
                    end if
                wend
                printf(!"\n")
            end if

            result = FMOD_Channel_IsPlaying(channel, @playing)
            if (result <> FMOD_OK or playing = 0) then
                FMOD_Sound_Release(sound)
                sound = 0               
                channel = 0
            else
                result = FMOD_Channel_GetPaused(channel, @paused)
                result = FMOD_Channel_GetPosition(channel, @ms, FMOD_TIMEUNIT_MS)
                printf(!"Time %02d:%02d:%02d : %s : Press SPACE to pause. 'm' to mute. ESC to quit.\r", ms \ 1000 \ 60, ms \ 1000 mod 60, ms \ 10 mod 100, iif(paused,@"Paused ",iif(playing,@"Playing",@"Stopped")))
            end if
        end if

       
        if (sound) then
            dim as FMOD_OPENSTATE openstate = FMOD_OPENSTATE_READY

            FMOD_Sound_GetOpenState(sound, @openstate, 0, 0, 0)

            if (openstate = FMOD_OPENSTATE_ERROR) then
                FMOD_Sound_Release(sound)
                sound = 0               
                channel = 0
            end if
        end if

        if (sound) = 0 then
            printf(!"\n")
            printf(!"Error occurred or stream ended.  Restarting stream..\n")
            result = FMOD_System_CreateSound(fsystem, __FB_ARGV__[1], FMOD_HARDWARE or FMOD_2D or FMOD_CREATESTREAM or FMOD_NONBLOCKING, 0, @sound)
            ERRCHECK(result)
            Sleep(1000)
        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)
