/'==================================================================================================
 3D Reverb Example
 Copyright (c), Firelight Technologies Pty, Ltd 2005-2011.

 Example to demonstrate 3d reverb spheres, global reverb, multiple reverb instances and music reverb
==================================================================================================='/

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

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

const as uinteger  MUSICCUE_EXAMPLES_ENTER_MENU_VIBES  = 24
const as integer                           INTERFACE_UPDATETIME = 80                          ' 80ms update for interface
const as float                         DISTANCEFACTOR = 1.0f                              ' Units per meter.  I.e feet would = 3.28
dim as FMOD_VECTOR                         listenerpos  = type( 0.0f, 0.0f, 0.0f * DISTANCEFACTOR )
dim as bool                                listenerflag = true


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


' program start
    dim as FMOD_EventSystem               ptr eventsystem = any
    dim as FMOD_Event                     ptr event = any
    dim as FMOD_MusicSystem               ptr musicsystem = any
    dim as FMOD_MusicPrompt               ptr musicprompt = any
    dim as FMOD_EventReverb               ptr eventreverb1 = any, eventreverb2 = any

    dim as FMOD_REVERB_CHANNELPROPERTIES    reverbchannelproperties    
    dim as FMOD_VECTOR                      reverbposition
    dim as float                            mindistance = any, maxdistance = any
    dim as FMOD_RESULT                      result = any

    printf(!"======================================================================\n")
    printf(!"3D Reverb Example.  Copyright (c) Firelight Technologies 2004-2011.\n")
    printf(!"======================================================================\n")
    printf(!"This demonstrates 3d reverb spheres as well as global reverb,\n")
    printf(!"multiple reverb instances and music reverb\n")
    printf(!"======================================================================\n\n")

    /'
        Create a event system object and initialize.
    '/
result = FMOD_EventSystem_Create(@eventsystem)
    ERRCHECK(result)
result = FMOD_EventSystem_Init(eventsystem, 64, FMOD_INIT_3D_RIGHTHANDED, 0, FMOD_EVENT_INIT_NORMAL)
    ERRCHECK(result)
result = FMOD_EventSystem_SetMediaPath(eventsystem, "media\\")
    ERRCHECK(result)
result = FMOD_EventSystem_Load(eventsystem,"examples.fev", 0, 0)
    ERRCHECK(result)
result = FMOD_EventSystem_GetEvent(eventsystem, "examples/FeatureDemonstration/Basics/FootStep", FMOD_EVENT_DEFAULT, @event)
    ERRCHECK(result)
result = FMOD_EventSystem_getMusicSystem(eventsystem, @musicsystem)
    ERRCHECK(result)
result = FMOD_MusicSystem_PrepareCue(musicsystem,MUSICCUE_EXAMPLES_ENTER_MENU_VIBES, @musicprompt)
    ERRCHECK(result)
result = FMOD_EventSystem_CreateReverb(eventsystem, @eventreverb1)
    ERRCHECK(result)
result = FMOD_EventSystem_CreateReverb(eventsystem, @eventreverb2)
    ERRCHECK(result)

    /'
        Initialize 3D reverb objects
        (uses global reverb instance #0)
    '/    
    dim as FMOD_REVERB_PROPERTIES sphere1reverb = FMOD_PRESET_HANGAR
    reverbposition.x = -10.0
    reverbposition.y = 0
    reverbposition.z = 0
    mindistance = 10.0
    maxdistance = 20.0
result = FMOD_EventReverb_setProperties(eventreverb1, @sphere1reverb)
    ERRCHECK(result)
result = FMOD_EventReverb_Set3DAttributes(eventreverb1, @reverbposition, mindistance, maxdistance)
    ERRCHECK(result)
result = FMOD_EventReverb_SetActive(eventreverb1, true)
    ERRCHECK(result)

    dim as FMOD_REVERB_PROPERTIES sphere2reverb = FMOD_PRESET_SEWERPIPE
    reverbposition.x = 10.0
    reverbposition.y = 0
    reverbposition.z = 0
    mindistance = 10.0
    maxdistance = 20.0
result = FMOD_EventReverb_SetProperties(eventreverb2, @sphere2reverb)
    ERRCHECK(result)
result = FMOD_EventReverb_Set3DAttributes(eventreverb2, @reverbposition, mindistance, maxdistance)
    ERRCHECK(result)
result = FMOD_EventReverb_SetActive(eventreverb2, true)
    ERRCHECK(result)

    /'
        Setup ambient reverb
    '/
    dim as FMOD_REVERB_PROPERTIES ambientreverb = FMOD_PRESET_ROOM
result = FMOD_EventSystem_SetReverbAmbientProperties(eventsystem, @ambientreverb)
    ERRCHECK(result)

    /'
        Setup global reverb instance #1 for music
    '/
    dim as FMOD_REVERB_PROPERTIES musicreverb = FMOD_PRESET_GENERIC
    musicreverb.Room = 0
    musicreverb.Instance = 1
result = FMOD_EventSystem_SetReverbProperties(eventsystem, @musicreverb)
    ERRCHECK(result)

    /'
        Turn off global reverb instance #1 for event
    '/
    reverbchannelproperties.Flags = FMOD_REVERB_CHANNELFLAGS_INSTANCE1

result = FMOD_Event_getReverbProperties(event, @reverbchannelproperties)
    ERRCHECK(result)
    reverbchannelproperties.Room = -10000                                          ' wet level -10000 sets instance #1 off for this event
result = FMOD_Event_SetReverbProperties(event, @reverbchannelproperties)
    ERRCHECK(result)

    /'
        Start music and event
    '/
result = FMOD_MusicPrompt_Begin(musicprompt)
    ERRCHECK(result)
result = FMOD_MusicSystem_setVolume(musicsystem, 0.5f)
    ERRCHECK(result)

    dim as FMOD_VECTOR eventposition = type(0, 0, 5.0f)
    dim as FMOD_VECTOR eventvelocity = type(0, 0, 0)
    ERRCHECK(FMOD_Event_Set3DAttributes(event, @eventposition, @eventvelocity,0))
    ERRCHECK(FMOD_Event_Start(event))


    printf(!"======================================================================\n")
    printf(!"Press 'm'           to activate/deactivate music.\n")
    printf(!"Press '+' / '-'     to decrease/increase music reverb wet level.\n")
    printf(!"Press 'e'           to activate/deactivate event.\n")
    printf(!"Press ' '           to toggle auto listener update mode.\n")
    printf(!"Press '<' / '>'     to move listener while in auto update mode.\n")
    printf(!"Press ESC   to quit\n")
    printf(!"----------------------------------------------------------------------\n")
    printf(!"1, 2 : centre of sphere m : minimum distance x : maximum distance   \n")
    printf(!"======================================================================\n\n")

    dim as string key
    dim as FMOD_EVENT_STATE state = any

    /'
        Main loop
    '/
        do
                key = inkey


select case key
case "e", "E"                ' Toggle event on and off
result = FMOD_Event_GetState(event, @state)
                    ERRCHECK(result)
                    if (state and  FMOD_EVENT_STATE_PLAYING) then
result = FMOD_Event_Stop(event,0)
                        ERRCHECK(result)
                    else
result = FMOD_Event_start(event)
                        ERRCHECK(result)
                    end if
                case "m", "M"                ' Toggle music on and off
                    dim as bool active = any
result = FMOD_MusicPrompt_IsActive(musicprompt, @active)
                    ERRCHECK(result)
                    if (active) then
result = FMOD_MusicPrompt_End(musicprompt)
                        ERRCHECK(result)
result = FMOD_MusicSystem_Reset(musicsystem)
                        ERRCHECK(result)
                    else
result = FMOD_MusicPrompt_Begin(musicprompt)
                        ERRCHECK(result)
                    end if

                case "+", "="               ' Increase music reverb
                    reverbchannelproperties.Flags = FMOD_REVERB_CHANNELFLAGS_INSTANCE1
result = FMOD_MusicSystem_GetReverbProperties(musicsystem, @reverbchannelproperties)
                    ERRCHECK(result)

                    reverbchannelproperties.Room += 100
                    if (reverbchannelproperties.Room > 0) then
                        reverbchannelproperties.Room = 0
                    end if

result = FMOD_MusicSystem_SetReverbProperties(musicsystem, @reverbchannelproperties)
                    ERRCHECK(result)

                case "-", "_"                ' Decrease music reverb
                    reverbchannelproperties.Flags = FMOD_REVERB_CHANNELFLAGS_INSTANCE1
result = FMOD_MusicSystem_GetReverbProperties(musicsystem, @reverbchannelproperties)
                    ERRCHECK(result)

                    reverbchannelproperties.Room -= 100
                    if (reverbchannelproperties.Room < -2000) then
                        reverbchannelproperties.Room = -2000
                    end if

result = FMOD_MusicSystem_SetReverbProperties(musicsystem, @reverbchannelproperties)
                    ERRCHECK(result)

                case " "                ' Toggle listener update
                    listenerflag xor= 1
end select

                if (listenerflag = 0) then
                    select case key
                case "<", ","
                                            listenerpos.x -= 1.0f * DISTANCEFACTOR
                        if (listenerpos.x < -35 * DISTANCEFACTOR) then
                            listenerpos.x = -35 * DISTANCEFACTOR
                        end if
                    case ">", "."
                        listenerpos.x += 1.0f * DISTANCEFACTOR
                        if (listenerpos.x > 36 * DISTANCEFACTOR) then
                            listenerpos.x = 36 * DISTANCEFACTOR
                        end if
            end select
             end if

            ' ==========================================================================================
            ' UPDATE THE LISTENER
            ' ==========================================================================================
            scope
                static as float t = 0
                static as FMOD_VECTOR lastpos = type( 0.0f, 0.0f, 0.0f )
                dim as FMOD_VECTOR forward        = type( 0.0f, 0.0f, 1.0f )
                dim as FMOD_VECTOR up             = type( 0.0f, 1.0f, 0.0f )
                dim as FMOD_VECTOR vel = any

                if (listenerflag) then
                    listenerpos.x = sin(t * 0.05f) * 33.0f * DISTANCEFACTOR ' left right pingpong
                end if

                ' vel = how far we moved last FRAME (m/f), then time compensate it to SECONDS (m/s).
                vel.x = (listenerpos.x - lastpos.x) * (1000 / INTERFACE_UPDATETIME)
                vel.y = (listenerpos.y - lastpos.y) * (1000 / INTERFACE_UPDATETIME)
                vel.z = (listenerpos.z - lastpos.z) * (1000 / INTERFACE_UPDATETIME)

                ' store pos for next time
                lastpos = listenerpos

                result = FMOD_EventSystem_Set3DListenerAttributes(eventsystem, 0, @listenerpos, @vel, @forward, @up)
                ERRCHECK(result)

                t += (30 * (1.0f / INTERFACE_UPDATETIME))    ' t is just a time value .. it increments in 30m/s steps in this example

                ' print out a small visual display
                scope
                    dim as zstring * 80 s = any

                    sprintf(@s, ".....x.........m.........1.........or.........2.........m.........x.......")

                    s[(listenerpos.x / DISTANCEFACTOR) + 35] = asc("L")
                    printf(!"%s\r", @s)
                end scope
            end scope

            FMOD_EventSystem_Update(eventsystem)

            Sleep(INTERFACE_UPDATETIME - 1)

        loop while (key <> chr(27))


result = FMOD_EventSystem_Release(eventsystem)
    ERRCHECK(result)
