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

 This example shows how to record a sound, then write it to a wav file.
 It then shows how to play a sound while it is being recorded to.  Because it is recording, the
 sound playback has to be delayed a little bit so that the playback doesn't play part of the
 buffer that is still being written to.
==============================================================================================='/
#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

/'
[
	[DESCRIPTION]
	Writes out the contents of a record buffer to a file.

	[PARAMETERS]
 
	[RETURN_VALUE]
	void

	[REMARKS]
]
'/
sub SaveToWav(byval sound as FMOD_SOUND ptr)
    dim as FILE ptr fp
    dim as integer             channels = any, bits = any
    dim as float           rate
    dim as any           ptr ptr1 = any, ptr2 = any
    dim as uinteger    lenbytes = any, len1 = any, len2 = any

    if (sound = 0) then
        return
    end if

    FMOD_Sound_GetFormat  (sound, 0, 0, @channels, @bits)
    FMOD_Sound_GetDefaults(sound, @rate, 0, 0, 0)
    FMOD_Sound_GetLength  (sound, @lenbytes, FMOD_TIMEUNIT_PCMBYTES)

    scope
        
        /'
            WAV Structures
        '/
        type RIFFCHUNK field = 4
	        as byte id(0 to 3)
	        as integer 		size
        end type
    
        type FMTCHUNK field = 4
            as RIFFCHUNK       chunk
            as ushort	wFormatTag      /' format type  '/
            as ushort	nChannels       /' number of channels (i.e. mono, stereo...)  '/
            as uinteger	nSamplesPerSec  /' sample rate  '/
            as uinteger	nAvgBytesPerSec /' for buffer estimation  '/
            as ushort	nBlockAlign     /' block size of data  '/
            as ushort	wBitsPerSample  /' number of bits per sample of mono data '/
        end type 

        type DATACHUNK field = 4
            as RIFFCHUNK   chunk
        end type

        type WAVHEADER field = 4
            as RIFFCHUNK   chunk
	        as byte rifftype(0 to 3)
        end type

    dim as FMTCHUNK FmtChunk = _
    type( ({asc("f"),asc("m"),asc("t"),asc(" ")}, sizeof(FMTCHUNK) - sizeof(RIFFCHUNK) ), _
    1, channels, rate, rate * channels * bits / 8, 1 * channels * bits / 8, bits )

    dim as DATACHUNK DataChunk = type( ({asc("d"),asc("a"),asc("t"),asc("a")}, lenbytes ) )

    dim as WAVHEADER WavHeader = _
    type( ({asc("R"),asc("I"),asc("F"),asc("F")}, sizeof(FMTCHUNK) + sizeof(RIFFCHUNK) + lenbytes ), _
    {asc("W"),asc("A"),asc("V"),asc("E")} )

        fp = fopen("record.wav", "wb")
       
        /'
            Write out the WAV header.
        '/
        fwrite(@WavHeader, sizeof(WAVHEADER), 1, fp)
        fwrite(@FmtChunk, sizeof(FMTCHUNK), 1, fp)
        fwrite(@DataChunk, sizeof(DATACHUNK), 1, fp)

        /'
            Lock the sound to get access to the raw data.
        '/
        FMOD_Sound_Lock(sound, 0, lenbytes, @ptr1, @ptr2, @len1, @len2)

        /'
            Write it to disk.
        '/
        fwrite(ptr1, len1, 1, fp)

        /'
            Unlock the sound to allow FMOD to use it again.
        '/
        FMOD_Sound_Unlock(sound, ptr1, ptr2, len1, len2)

        fclose(fp)
    end scope
end sub

' program start
    dim as FMOD_SYSTEM           ptr fsystem  = 0
    dim as FMOD_SOUND            ptr sound   = 0
    dim as FMOD_CHANNEL          ptr channel = 0
    dim as FMOD_RESULT            result = any
    dim as FMOD_CREATESOUNDEXINFO exinfo
    dim as string        key
    dim as integer driver = any, recorddriver = any, numdrivers = any, count = any
    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

    /' 
        System initialization
    '/
    printf(!"---------------------------------------------------------\n")    
    printf(!"Select OUTPUT type\n")    
    printf(!"---------------------------------------------------------\n")    
    printf(!"1 :  DirectSound\n")
    printf(!"2 :  Windows Multimedia WaveOut\n")
    printf(!"3 :  ASIO\n")
    printf(!"---------------------------------------------------------\n")
    printf(!"Press a corresponding number or ESC to quit\n")

    do
       key = inkey
sleep 10
    loop while (key <> chr(27) and key < "1")
    select case key
        case "1" :  result = FMOD_System_SetOutput(fsystem, FMOD_OUTPUTTYPE_DSOUND)
        case "2" :  result = FMOD_System_SetOutput(fsystem, FMOD_OUTPUTTYPE_WINMM)
        case "3" :  result = FMOD_System_SetOutput(fsystem, FMOD_OUTPUTTYPE_ASIO)
        case else  :  end 1 
    end select
    ERRCHECK(result)
    
    /'
        Enumerate playback devices
    '/

    result = FMOD_System_GetNumDrivers(fsystem, @numdrivers)
    ERRCHECK(result)

    printf(!"---------------------------------------------------------\n")    
    printf(!"Choose a PLAYBACK driver\n")
    printf(!"---------------------------------------------------------\n")    
    for count=0 to numdrivers-1
        dim as zstring * 256 sname = any

        result = FMOD_System_GetDriverInfo(fsystem, count, @sname, 256, 0)
        ERRCHECK(result)

        printf(!"%d : %s\n", count + 1, @sname)
    next
    printf(!"---------------------------------------------------------\n")
    printf(!"Press a corresponding number or ESC to quit\n")

    do
        key = inkey
        if (key = chr(27)) then
            end 0
        end if
        driver = asc(key) - asc("1")
sleep 10
    loop while (driver < 0 or driver >= numdrivers)

    result = FMOD_System_SetDriver(fsystem, driver)
    ERRCHECK(result)

    /'
        Enumerate record devices
    '/

    result = FMOD_System_GetRecordNumDrivers(fsystem, @numdrivers)
    ERRCHECK(result)

    printf(!"---------------------------------------------------------\n")    
    printf(!"Choose a RECORD driver\n")
    printf(!"---------------------------------------------------------\n")    
    for count=0 to numdrivers-1
        dim as zstring * 256 sname = any

        result = FMOD_System_GetRecordDriverInfo(fsystem, count, @sname, 256, 0)
        ERRCHECK(result)

        printf(!"%d : %s\n", count + 1, @sname)
    next
    printf(!"---------------------------------------------------------\n")
    printf(!"Press a corresponding number or ESC to quit\n")

    recorddriver = 0
    do
        key = inkey
        if (key = chr(27)) then
            end 0
        end if
        recorddriver = asc(key) - asc("1")
sleep 10
    loop while (recorddriver < 0 or recorddriver >= numdrivers)

    printf(!"\n")
  
    result = FMOD_System_Init(fsystem, 32, FMOD_INIT_NORMAL, NULL)
    ERRCHECK(result)


    exinfo.cbsize           = sizeof(FMOD_CREATESOUNDEXINFO)
    exinfo.numchannels      = 1
    exinfo.format           = FMOD_SOUND_FORMAT_PCM16
    exinfo.defaultfrequency = 44100
    exinfo.length           = exinfo.defaultfrequency * sizeof(short) * exinfo.numchannels * 5
    
    result = FMOD_System_CreateSound(fsystem, 0, FMOD_2D or FMOD_SOFTWARE or FMOD_OPENUSER, @exinfo, @sound)
    ERRCHECK(result)

    printf(!"===================================================================\n")
    printf(!"Recording example.  Copyright (c) Firelight Technologies 2004-2011.\n")
    printf(!"===================================================================\n")
    printf(!"\n")
    printf(!"Press 'r' to record a 5 second segment of audio and write it to a wav file.\n")
    printf(!"Press 'p' to play the 5 second segment of audio.\n")
    printf(!"Press 'l' to turn looping on/off.\n")
    printf(!"Press 's' to stop recording and playback.\n")
    printf(!"Press 'w' to save the 5 second segment to a wav file.\n")
    printf(!"Press 'Esc' to quit\n")
    printf(!"\n")

    /'
        Main loop.
    '/
    do
        static as FMOD_CHANNEL ptr channel = 0
        static as integer   looping   = 0
        dim as integer          recording = 0
        dim as integer          playing   = 0
        dim as uinteger recordpos = 0
        dim as uinteger playpos   = 0
        dim as uinteger length = any

            key = inkey

            select case key
                case "r","R" :
                    result = FMOD_System_RecordStart(fsystem, recorddriver, sound, looping)
                    ERRCHECK(result)
                case "p","P" :
                    if (looping) then
                        FMOD_Sound_SetMode(sound, FMOD_LOOP_NORMAL)
                    else
                        FMOD_Sound_SetMode(sound, FMOD_LOOP_OFF)
                    end if
                    ERRCHECK(result)

                    result = FMOD_System_PlaySound(fsystem, FMOD_CHANNEL_REUSE, sound, 0, @channel)
                    ERRCHECK(result)
                case "l","L" :
                    looping xor= 1
                case "s","S" :
                    result = FMOD_System_RecordStop(fsystem, recorddriver)
                    if (channel) then
                        FMOD_Channel_Stop(channel)
                        channel = 0
                    end if
                case "w","W" :
                    printf(!"Writing to record.wav ...                                                     \r")

                    SaveToWav(sound)
                    Sleep 1000

        end select

        FMOD_Sound_GetLength(sound, @length, FMOD_TIMEUNIT_PCM)
        ERRCHECK(result)

        FMOD_System_IsRecording(fsystem, recorddriver, @recording)
        ERRCHECK(result)

        FMOD_System_GetRecordPosition(fsystem, recorddriver, @recordpos)
        ERRCHECK(result)

        if (channel) then
            FMOD_Channel_IsPlaying(channel, @playing)
            ERRCHECK(result)

            FMOD_Channel_GetPosition(channel, @playpos, FMOD_TIMEUNIT_PCM)
            ERRCHECK(result)
        end if

        printf(!"State: %-19s. Record pos = %6d : Play pos = %6d : Loop %-3s\r", _
        iif(recording,iif(playing,@"Recording / playing",@"Recording"),iif(playing,@"Playing",@"Idle")), _
recordpos, playpos, iif(looping,@"On",@"Off"))

        FMOD_System_Update(fsystem)

        Sleep(10)

    loop while (key <> chr(27))

    printf(!"\n")

    /'
        Shut down
    '/
    result = FMOD_Sound_Release(sound)
    ERRCHECK(result)

    result = FMOD_System_Release(fsystem)
    ERRCHECK(result)
