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

 This example shows how to basic 3d positioning
==============================================================================================='/
#include "windows.bi"
#include "crt.bi"
#include "fmodex/fmodex.bi"
#include "fmodex/fmod_errors.bi"

#define INTERFACE_UPDATETIME 50      ' 50ms update for interface
#define DISTANCEFACTOR       1.0f    ' Units per meter.  I.e feet would = 3.28.  centimeters would = 100.


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_SYSTEM ptr    fsystem = any
    dim as FMOD_SOUND ptr     sound1 = any, sound2 = any, sound3 = any
    dim as FMOD_CHANNEL ptr   channel1 = 0, channel2 = 0, channel3 = 0
    dim as FMOD_RESULT      result = any
    dim as integer              numdrivers = any
    dim as integer              listenerflag = TRUE
    dim as FMOD_VECTOR      listenerpos  = type( 0.0f, 0.0f, -1.0f * DISTANCEFACTOR )
    dim as uinteger     version = any
    dim as FMOD_SPEAKERMODE speakermode = any
    dim as FMOD_CAPS        caps = any
    dim as zstring * 256           deviceName = any

    printf(!"===============================================================\n")
    printf(!"3d Example.  Copyright (c) Firelight Technologies 2004-2011.\n")
    printf(!"===============================================================\n")
    printf(!"This example plays 2 3D sounds in hardware.  Optionally you can\n")
    printf(!"play a 2D hardware sound as well.\n")
    printf(!"===============================================================\n\n")

    /'
        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_GetNumDrivers(fsystem, @numdrivers)
    ERRCHECK(result)

    if (numdrivers=  0) then
        result = FMOD_System_SetOutput(fsystem, FMOD_OUTPUTTYPE_NOSOUND)
        ERRCHECK(result)
    else
        result = FMOD_System_GetDriverCaps(fsystem, 0, @caps, 0, @speakermode)
        ERRCHECK(result)

        result = FMOD_System_SetSpeakerMode(fsystem, speakermode)       /' Set the user selected speaker mode. '/
        ERRCHECK(result)

        if (caps and FMOD_CAPS_HARDWARE_EMULATED) then            /' The user has the 'Acceleration' slider set to off!  This is really bad for latency!. '/
                                                          /' You might want to warn the user about this. '/
            result = FMOD_System_SetDSPBufferSize(fsystem, 1024, 10)
            ERRCHECK(result)
        end if

        result = FMOD_System_GetDriverInfo(fsystem, 0, @deviceName, 256, 0)
        ERRCHECK(result)

        if (strstr(deviceName, "SigmaTel")) then  /' Sigmatel sound devices crackle for some reason if the format is PCM 16bit.  PCM floating point output seems to solve it. '/
            result = FMOD_System_SetSoftwareFormat(fsystem, 48000, FMOD_SOUND_FORMAT_PCMFLOAT, 0,0, FMOD_DSP_RESAMPLER_LINEAR)
            ERRCHECK(result)
end if
end if

    result = FMOD_System_Init(fsystem, 100, FMOD_INIT_NORMAL, 0)
    if (result = FMOD_ERR_OUTPUT_CREATEBUFFER) then        /' Ok, the speaker mode selected isn't supported by this soundcard.  Switch it back to stereo... '/
        result = FMOD_System_SetSpeakerMode(fsystem, FMOD_SPEAKERMODE_STEREO)
        ERRCHECK(result)
                
        result = FMOD_System_Init(fsystem, 100, FMOD_INIT_NORMAL, 0)/' ... and re-init. '/
        ERRCHECK(result)
    end if

    /'
        Set the distance units. (meters/feet etc).
    '/
    result = FMOD_System_Set3DSettings(fsystem, 1.0, DISTANCEFACTOR, 1.0f)
    ERRCHECK(result)

    /'
        Load some sounds
    '/
    result = FMOD_System_CreateSound(fsystem, "media/drumloop.wav", FMOD_HARDWARE or FMOD_3D, 0, @sound1)
    ERRCHECK(result)
    result = FMOD_Sound_Set3DMinMaxDistance(sound1, 2.0f * DISTANCEFACTOR, 10000.0f * DISTANCEFACTOR)
    ERRCHECK(result)
    result = FMOD_Sound_SetMode(sound1, FMOD_LOOP_NORMAL)
    ERRCHECK(result)

    result = FMOD_System_CreateSound(fsystem, "media/jaguar.wav", FMOD_HARDWARE or FMOD_3D, 0, @sound2)
    ERRCHECK(result)
    result = FMOD_Sound_Set3DMinMaxDistance(sound2, 2.0f * DISTANCEFACTOR, 10000.0f * DISTANCEFACTOR)
    ERRCHECK(result)
    result = FMOD_Sound_SetMode(sound2, FMOD_LOOP_NORMAL)
    ERRCHECK(result)

    result = FMOD_System_CreateSound(fsystem, "media/swish.wav", FMOD_HARDWARE or FMOD_2D, 0, @sound3)
    ERRCHECK(result)

    /'
        Play sounds at certain positions
    '/

    scope
        dim as FMOD_VECTOR position = type( -10.0f * DISTANCEFACTOR, 0.0f, 0.0f )
        dim as FMOD_VECTOR vel = type( 0.0f, 0.0f, 0.0f )

        result = FMOD_System_PlaySound(fsystem, FMOD_CHANNEL_FREE, sound1, TRUE, @channel1)
        ERRCHECK(result)
        result = FMOD_Channel_Set3DAttributes(channel1, @position, @vel)
        ERRCHECK(result)
        result = FMOD_Channel_SetPaused(channel1, FALSE)
        ERRCHECK(result)
    end scope

    scope
        dim as FMOD_VECTOR position = type( 15.0f * DISTANCEFACTOR, 0.0f, 0.0f )
        dim as FMOD_VECTOR vel = type(  0.0f,  0.0f,  0.0f )

        result = FMOD_System_PlaySound(fsystem, FMOD_CHANNEL_FREE, sound2, TRUE, @channel2)
        ERRCHECK(result)
        result = FMOD_Channel_Set3DAttributes(channel2, @position, @vel)
        ERRCHECK(result)
        result = FMOD_Channel_SetPaused(channel2, FALSE)
        ERRCHECK(result)
    end scope

    /'
        Display help
    '/
    scope
        dim as integer numchannels = 0

        result = FMOD_System_GetHardwareChannels(fsystem, @numchannels)
        ERRCHECK(result)
    
        printf(!"Hardware channels : %d\n", numchannels)
   end scope

    printf(!"=========================================================================\n")
    printf(!"Press 1        Pause/Unpause 16bit 3D sound at any time\n")
    printf(!"      2        Pause/Unpause 8bit 3D sound at any time\n")
    printf(!"      3        Play 16bit STEREO 2D sound at any time\n")
    printf(!"      <        Move listener left (in still mode)\n")
    printf(!"      >        Move listener right (in still mode)\n")
    printf(!"      SPACE    Stop/Start listener automatic movement\n")
    printf(!"      ESC      Quit\n")
    printf(!"=========================================================================\n")

    /'
        Main loop
    '/
dim key as string
    do

            key = inkey

            if (key = "1") then
                dim as integer paused
                FMOD_Channel_GetPaused(channel1, @paused)
paused xor=1
                FMOD_Channel_SetPaused(channel1, paused)
            end if

            if (key = "2") then
                dim as integer paused
                FMOD_Channel_GetPaused(channel2, @paused)
paused xor=1
                FMOD_Channel_SetPaused(channel2, paused)
            end if

            if (key = "3") then
                result = FMOD_System_PlaySound(fsystem, FMOD_CHANNEL_FREE, sound3, FALSE, @channel3)
                ERRCHECK(result)
end if

            if (key = " ") then
listenerflag xor= 1
end if

            if (listenerflag = FALSE) then
                if (key = "<") then
                    listenerpos.x -= 1.0f * DISTANCEFACTOR
                    if (listenerpos.x < -35 * DISTANCEFACTOR) then
                        listenerpos.x = -35 * DISTANCEFACTOR
end if
end if
                if (key = ">") then
                    listenerpos.x += 1.0f * DISTANCEFACTOR
                    if (listenerpos.x > 36 * DISTANCEFACTOR) then
                        listenerpos.x = 36 * DISTANCEFACTOR
end if
end if
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

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

            ' ********* NOTE ******* READ NEXT COMMENT!!!!!
            ' 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_System_Set3DListenerAttributes(fsystem, 0, @listenerpos, @vel, @forward, @up)
            ERRCHECK(result)

            t += (30 * (1.0f / cast(float,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

                sprintf(s, "|.......................<1>......................<2>....................|")
                
                s[int(listenerpos.x / DISTANCEFACTOR) + 35] = asc("L")                
                printf(!"%s\r", s)
end scope
end scope

        FMOD_System_Update(fsystem)

        Sleep(INTERFACE_UPDATETIME - 1)

    loop  while (key <> chr(27))

    printf(!"\n")

    /'
        Shut down
    '/
    result = FMOD_Sound_Release(sound1)
    ERRCHECK(result)
    result = FMOD_Sound_Release(sound2)
    ERRCHECK(result)
    result = FMOD_Sound_Release(sound3)
    ERRCHECK(result)

    result = FMOD_System_Close(fsystem)
    ERRCHECK(result)
    result = FMOD_System_Release(fsystem)
    ERRCHECK(result)
