/'===============================================================================================
 Real-time stitching example
 Copyright (c), Firelight Technologies Pty, Ltd 2004-2011.

 This example shows how you can create your own multi-subsound stream, then in realtime replace
 each the subsound as it plays them.  Using a looping sentence, it will seamlessly stich between
 2 subsounds in this example, and each time it switches to a new sound, it will replace the old
 one with another sound in our list.

 These sounds can go on forever as long as they are the same bitdepth (when decoded) and number
 of channels (ie mono / stereo).  The reason for this is the hardware channel cannot change 
 formats mid sentence, and using different hardware channels would mean it wouldn't be gapless.

==============================================================================================='/
#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

#define NUMSOUNDS 32

' program start
    dim as FMOD_SYSTEM      ptr fsystem = any
    dim as FMOD_SOUND       ptr sound = any
    dim as FMOD_SOUND       ptr subsound(2--1) = any
    dim as FMOD_CREATESOUNDEXINFO exinfo
    dim as FMOD_CHANNEL     ptr channel = 0
    dim as FMOD_RESULT       result = any
    dim as string               key
    dim as uinteger      subsoundid = any, sentenceid = any
    dim as uinteger      version = any
    dim as const zstring       ptr soundname(NUMSOUNDS-1) = _
    { _
        @"media/e.ogg", _  /' Ma-    '/
        @"media/d.ogg", _  /' ry     '/
        @"media/c.ogg", _  /' had    '/
        @"media/d.ogg", _  /' a      '/
        @"media/e.ogg", _  /' lit-   '/
        @"media/e.ogg", _  /' tle    '/
        @"media/e.ogg", _  /' lamb,  '/
        @"media/e.ogg", _  /' .....  '/
        @"media/d.ogg", _  /' lit-   '/
        @"media/d.ogg", _  /' tle    '/
        @"media/d.ogg", _  /' lamb,  '/
        @"media/d.ogg", _  /' .....  '/
        @"media/e.ogg", _  /' lit-   '/
        @"media/e.ogg", _  /' tle    '/
        @"media/e.ogg", _  /' lamb,  '/
        @"media/e.ogg", _  /' .....  '/
        @"media/e.ogg", _  /' Ma-    '/
        @"media/d.ogg", _  /' ry     '/
        @"media/c.ogg", _  /' had    '/
        @"media/d.ogg", _  /' a      '/
        @"media/e.ogg", _  /' lit-   '/
        @"media/e.ogg", _  /' tle    '/
        @"media/e.ogg", _  /' lamb,  '/
        @"media/e.ogg", _  /' its    '/
        @"media/d.ogg", _  /' fleece '/
        @"media/d.ogg", _  /' was    '/
        @"media/e.ogg", _  /' white  '/
        @"media/d.ogg", _   /' as     '/
        @"media/c.ogg", _  /' snow.  '/
        @"media/c.ogg", _  /' .....  '/
        @"media/c.ogg", _  /' .....  '/
        @"media/c.ogg" _  /' .....  '/
    }

    /'
        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)

    /'
        Set up the FMOD_CREATESOUNDEXINFO structure for the user stream with room for 2 subsounds. (our subsound double buffer)
    '/
    exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO)
    exinfo.defaultfrequency = 44100
    exinfo.numsubsounds = 2
    exinfo.numchannels = 1
    exinfo.format = FMOD_SOUND_FORMAT_PCM16

    /'
        Create the 'parent' stream that contains the substreams.  Set it to loop so that it loops between subsound 0 and 1.
    '/
    result = FMOD_System_CreateStream(fsystem, 0, FMOD_LOOP_NORMAL or FMOD_OPENUSER, @exinfo, @sound)
    ERRCHECK(result)

    /'
        Add 2 of our streams as children of the parent.  They should be the same format (ie mono/stereo and bitdepth) as the parent sound.
        When subsound 0 has finished and it is playing subsound 1, we will swap subsound 0 with a new sound, and the same for when subsound 1 has finished,
        causing a continual double buffered flip, which means continuous sound.
    '/
    result = FMOD_System_CreateStream(fsystem, soundname(0), FMOD_DEFAULT, 0, @subsound(0))
    ERRCHECK(result)

    result = FMOD_System_CreateStream(fsystem, soundname(1), FMOD_DEFAULT, 0, @subsound(1))
    ERRCHECK(result)

    result = FMOD_Sound_SetSubSound(sound, 0, subsound(0))
    ERRCHECK(result)

    result = FMOD_Sound_SetSubSound(sound, 1, subsound(1))
    ERRCHECK(result)

    /'
        Set up the gapless sentence to contain these first 2 streams.
    '/
    scope
        dim as integer soundlist(2-1) = { 0, 1 }
     
        result = FMOD_Sound_SetSubSoundSentence(sound, @soundlist(0), 2)
        ERRCHECK(result)
    end scope

    subsoundid = 0     
    sentenceid = 2     /' The next sound to be appeneded to the stream. '/

    printf(!"=============================================================================\n")
    printf(!"Real-time stitching example.  Copyright (c) Firelight Technologies 2004-2011.\n")
    printf(!"=============================================================================\n")
    printf(!"\n")
    printf(!"Press space to pause, Esc to quit\n")
    printf(!"\n")

    printf(!"Inserted subsound %d / 2 with sound %d / %d\n", 0, 0, NUMSOUNDS)
    printf(!"Inserted subsound %d / 2 with sound %d / %d\n", 1, 1, NUMSOUNDS)

    /'
        Play the sound.
    '/

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

    /'
        Main loop.
    '/
    do
        dim as uinteger currentsubsoundid = any

            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)

        /'
            Replace the subsound that just finished with a new subsound, to create endless seamless stitching!

            Note that this polls the currently playing subsound using the FMOD_TIMEUNIT_BUFFERED flag.  
            Remember streams are decoded / buffered ahead in advance! 
            Don't use the 'audible time' which is FMOD_TIMEUNIT_SENTENCE_SUBSOUND by itself.  When streaming, sound is 
            processed ahead of time, and things like stream buffer / sentence manipulation (as done below) is required 
            to be in 'buffered time', or else there will be synchronization problems and you might end up releasing a
            sub-sound that is still playing!
        '/
        result = FMOD_Channel_GetPosition(channel, @currentsubsoundid, (FMOD_TIMEUNIT_SENTENCE_SUBSOUND or FMOD_TIMEUNIT_BUFFERED))
        ERRCHECK(result)

        if (currentsubsoundid <> subsoundid) then
            /' 
                Release the sound that isn't playing any more. 
            '/
            result = FMOD_Sound_Release(subsound(subsoundid))       
            ERRCHECK(result)
   
            /' 
                Replace it with a new sound in our list.
            '/
            result = FMOD_System_CreateStream(fsystem, soundname(sentenceid), FMOD_DEFAULT, 0, @subsound(subsoundid))
            ERRCHECK(result)

            result = FMOD_Sound_SetSubSound(sound, subsoundid, subsound(subsoundid))
            ERRCHECK(result)

            printf(!"Replacing subsound %d / 2 with sound %d / %d\n", subsoundid, sentenceid, NUMSOUNDS)

            sentenceid+=1
            if (sentenceid >= NUMSOUNDS) then
                sentenceid = 0
            end if

            subsoundid = currentsubsoundid
        end if
        
        Sleep(50)

    loop while (key <> chr(27))

    printf(!"\n")

    /'
        Shut down
    '/
    result = FMOD_Sound_Release(subsound(1))
    ERRCHECK(result)
    result = FMOD_Sound_Release(subsound(0))
    ERRCHECK(result)
    result = FMOD_Sound_Release(sound)     /' Freeing a parent subsound also frees its children. '/
    ERRCHECK(result)
    result = FMOD_System_Close(fsystem)
    ERRCHECK(result)
    result = FMOD_System_Release(fsystem)
    ERRCHECK(result)
