'' ------------------------------------------------------------------------ ''
''  @@ Source Documentation                     *** BASIC Version ***       ''
''                                                                          ''
''  TITLE : DEMOWDP.BAS                                                     ''
''                                                                          ''
''  DESCRIPTION :                                                           ''
''      This program demonstrates how to perform wave output by using       ''
''      the CTWDSK.DRV driver. The wave output is using the Disk            ''
''      Double Buffering method.                                            ''
''                                                                          ''
''      The program retrieves BLASTER environment for the Card settings     ''
''      and passes it to the driver.                                        ''
''                                                                          ''
''  Note :                                                                  ''
''      Use switch /Fs for Microsoft Basic PDS 7.1 compiler.                ''
''                                                                          ''
''  Copyright (c) Creative Technology Ltd, 1993. All rights reserved.       ''
''                                                                          ''
'' ------------------------------------------------------------------------ ''

' $INCLUDE: 'SBKWAVE.BI'
' $INCLUDE: 'SBKAUX.BI'
' $INCLUDE: 'SBKX.BI'


DECLARE SUB PlayWave(WaveFile$)
DECLARE SUB ShowError()
DECLARE FUNCTION PrepareCTWDSKDrv%(BlasterAddx AS LONG)
DECLARE FUNCTION SetOutputParam%()

CONST DRIVERxSIZE = 51200&

CONST TWOxKBYTES  = 2048&
CONST PARAxADJ	  = 15&		'* 15 bytes for paragraph adjustment *'

'*
'## DMAxUNIT is unit of half embedded DMA in size of 2 kbytes .
'## Change this value (from 1 - 16) if allocating own DMA buffer.
'## This value effect the smoothy of sound output proportionally.
'## Increase this value will be more efficient compare to DDxUNIT.
'*
CONST DMAxUNIT	  = 4
CONST DMAxSIZE	  = ((DMAxUNIT * TWOxKBYTES * 2&) + PARAxADJ)

'*
'## DDxUNIT is unit of half double disk buffer in size of 2 kbytes.
'## Change this value (from 2 - 32) when allocating dd buffer.
'## It is recommended that this unit is at least double the DMAxUNIT.
'## This value effect the smoothy of sound output proportionally.
'*
CONST DDxUNIT	  = 16
CONST DDxSIZE     = ((DDxUNIT * TWOxKBYTES * 2&) + PARAxADJ)


REM $DYNAMIC
CLEAR

' Following statements free memory for the loadable drivers.
' You must free sufficient memory for the loadable drivers.
' The free memory must be larger than the driver file size.

' Free memory for the CTWDSK.DRV, DMA buffer and double disk buffer
DUMMY = SETMEM(-DRIVERxSIZE)
DUMMY = SETMEM(-DMAxSIZE * 2&)
DUMMY = SETMEM(-DDxSIZE)

DIM SHARED CtWaveStatus AS INTEGER      ' Wave i/o status
DIM BlasterEnv AS String
DIM BlasterAddx AS LONG
DIM NumArg AS INTEGER
DIM szCmdArg(1 TO 1) AS STRING


    ' get command line argument
    CALL sbkGetCmdLine(NumArg,szCmdArg(),1)
    IF NumArg < 1 THEN
        PRINT "Usage : DEMOWDP wav_filename"
        SYSTEM
    END IF

    PRINT "Playback ";szCmdArg(1);" through double disk buffer."

    ' retrieves BLASTER environment setting
    BlasterEnv = ENVIRON$("BLASTER")
    IF BlasterEnv <> "" THEN

        ' converts BLASTER string to null terminated string
        ' and return the far address of the string
        BlasterAddx = sbkMakeAsciizString&(BlasterEnv)

        ' loads CTWDSK.DRV driver into memory
        IF PrepareCTWDSKDrv%(BlasterAddx) <> 0 THEN

            ' initialises driver and Sound Blaster card
            IF ctwdInit% = 0 THEN

                ' Output the voice file
                CALL PlayWave(szCmdArg(1))

                ' Terminate the driver
                CALL ctwdTerminate

            ELSE
                CALL ShowError
            END IF
       END IF
    ELSE
        PRINT "BLASTER environment not set or incomplete or invalid."
    ENDIF


' Return the memory to BASIC
DUMMY = SETMEM(DDxSIZE)
DUMMY = SETMEM(DMAxSIZE * 2&)
DUMMY = SETMEM(DRIVERxSIZE)

END


'---------------------------------------------------------------------------'
'   @@ Usage                                                                '
'                                                                           '
'   FUNCTION PrepareCTWDSKDrv%(BlasterAddx AS LONG)                         '
'                                                                           '
'   Description :                                                           '
'      Loads and endorses CTWDSK.DRV.                                       '
'                                                                           '
'   Entry :                                                                 '
'      BlasterAddx - Far address of the BLASTER setting.                    '
'                                                                           '
'   Exit :                                                                  '
'      segment of the loaded driver else return 0.                          '
'                                                                           '
'---------------------------------------------------------------------------'

FUNCTION PrepareCTWDSKDrv%(BlasterAddx AS LONG)

    DIM dwVersion AS LONG
    DIM CTwdskDrv AS INTEGER

    ' loads CTWDSK.DRV into memory
    CTwdskDrv = sbkLoadDriver%("CTWDSK.DRV",UNUSED)
    IF CTwdskDrv <> 0 THEN

        ' initialises the CTWDSK.DRV driver entry point
        CALL ctwdSetDriverEntry((CTwdskDrv))

        ' Retrieves CT-VOICE.DRV version
        IF ctwdGetParam%(CTWAVxDRIVERVERSION,dwVersion) = 0 THEN
            IF ABS(CINT(dwVersion)) >= &H0305 THEN

                ' Passes BLASTER environment settings to driver
                IF ctwdGetEnvSettings((BlasterAddx)) = 0 THEN
                    PrepareCTWDSKDrv% = CTwdskDrv
                    EXIT FUNCTION
                ELSE
                    PRINT "BLASTER environment is not valid"
                END IF
            ELSE
                PRINT "Invalid CTWDSK.DRV - ";
                PRINT "I need CTWDSK.DRV version 3.05 or higher."
            END IF
        ELSE
            PRINT "Unrecognized CTWDSK.DRV."
        END IF

        CALL sbkFreeMem(CTwdskDrv)
    ELSE
        PRINT "Error loading CTWDSK.DRV or CTWDSK.DRV not found."
    END IF

    PrepareCTWDSKDrv% = 0

END FUNCTION


' ------------------------------------------------------------------------- '
'   @@ Usage                                                                '
'                                                                           '
'   SUB PlayWave(WaveFile$)                                                 '
'                                                                           '
'   Description :                                                           '
'       Open the wave file and start playing back.                          '
'                                                                           '
'   Entry :                                                                 '
'       WaveFile$ - file name to store voice input.                         '
'                                                                           '
'   Exit :                                                                  '
'       none.                                                               '
'                                                                           '
' ------------------------------------------------------------------------- '

REM %STATIC
SUB  PlayWave(WaveFile$)

     DIM  iFileHandle AS INTEGER, userkey AS INTEGER
     DIM  wIOHandle AS INTEGER, retVal AS INTEGER
     DIM  Pause AS INTEGER
     


     ' set the necessary wave input parameters
     wIOHandle = SetOutputParam%
     IF wIOHandle >= 0 THEN

        ' creates file to store wave input
        iFileHandle = sbkDosOpen%(sbkMakeAsciizString&(WaveFile$))

        IF (iFileHandle <> -1) THEN

            ' turns on DAC speaker
            CALL ctwdSetSpeaker(1)

            ' starts the wave output
            IF ctwdOutput%(wIOHandle,iFileHandle) = 0 THEN

                PRINT "Start playing back..."
                PRINT "    [Esc] - to stop"
                PRINT "    [P  ] - to pause"
                PRINT "    [C  ] - to continue"

                Pause = 0

                ' polls if wave output is end
                WHILE CtWaveStatus <> 0

                    c$ = INKEY$
                    IF (c$ <> "") THEN
                        userkey = INT(ASC(LEFT$(c$, 1)))

                        SELECT CASE userkey
                            CASE 27
                                retVal = ctwdStop%(wIOHandle)

                            CASE ASC("P"), ASC("p")
                                IF Pause = 0 THEN
                                    PRINT "Wave pause..."
                                    retVal = ctwdPause%(wIOHandle)
                                    Pause = 1
                                END IF

                            CASE ASC("C"), ASC("c")
                                IF Pause = 1 THEN
                                    PRINT "Wave continue..."
                                    retVal = ctwdContinue%(wIOHandle)
                                    Pause = 0
                                END IF
                        END SELECT
                    END IF
                WEND

                CALL sbkDosClose(iFileHandle%)
                PRINT "Wave stop."
            ELSE
                PRINT "Error output Wave"
                CALL ShowError
            END IF
        END IF
     END IF

END SUB


' ------------------------------------------------------------------------- '
'   @@ Usage                                                                '
'                                                                           '
'   FUNCTION SetOutputParam%()                                              '
'                                                                           '
'   Description :                                                           '
'       Set up the neccessary wave output parameters.                       '
'                                                                           '
'   Entry :                                                                 '
'       none.                                                               '
'                                                                           '
'   Exit :                                                                  '
'       i/o wave handle if successful otherwise return -1.                  '
'                                                                           '
' ------------------------------------------------------------------------- '

FUNCTION SetOutputParam%

    DIM wDiskBuf AS INTEGER, wDmaBuf AS INTEGER
    DIM dwValue AS LONG
    DIM wIOHandle AS INTEGER, retVal AS INTEGER


    SetOutputParam% = -1

    ' Allocate double disk buffer
    wDiskBuf = sbkAllocMem%(INT(DDxSIZE / 16))
    IF wDiskBuf = 0 THEN
        PRINT "DOS : Error allocating Double Disk buffer."
        EXIT FUNCTION
    END IF

    ' Allocate two DMA buffers. The 2nd is used when
    ' the 1st buffer crosses the 64k boundary
    wDmaBuf = sbkAllocMem%(INT((DMAxSIZE * 2 ) / 16))
    IF wDmaBuf = 0 THEN
        PRINT "DOS : Error allocating DMA buffer."
        EXIT FUNCTION
    END IF

    ' Retrieves total i/o wave handles supported
    IF ctwdGetParam%(CTWAVxIOHANDLES,dwValue) = 0 THEN

        IF dwValue <> 0 THEN
            ' wIOHandle - i/o wave handle to be used
            wIOHandle = ABS(INT(dwValue - 1))

            ' convert to 32-bit logical address
            dwValue = sbkMakeDWord&((wDiskBuf),0)

            ' Set double disk buffer
            IF ctwdSetDiskBuffer%(wIOHandle,dwValue,DDxUNIT) = 0 THEN
                ' Get 32-bit logical address of the CtWaveStatus
                dwValue = sbkMakeDWord&((VARSEG(CtWaveStatus)),_
                                         (VARPTR(CtWaveStatus)))

                ' Set i/o wave status - CtWaveStatus
                IF ctwdSetIOParam%(wIOHandle,CTWAVxIOxLPSTATUSWORD,_
                                   dwValue) = 0 THEN
                    ' convert to 32-bit linear address
                    dwValue = sbkMakeDWord&(0,(wDmaBuf)) * 16

                    ' Sets DMA buffer. If fails, the DMA buffer
                    ' may have crossed the 64 kb boundary.
                    ' Try again with the 2nd DMA buffer

                    IF ctwdSetDMABuffer%(wIOHandle,dwValue,DMAxUNIT) <> 0 THEN
                       dwValue = dwValue + DMAxSIZE
                       IF ctwdSetDMABuffer%(wIOHandle,dwValue,DMAxUNIT) <> 0 THEN
                            PRINT "Driver : Error setting DMA buffer."
                        ELSE
                            SetOutputParam% = wIOHandle
                        END IF
                    ELSE
                        SetOutputParam% = wIOHandle
                    END IF
                ELSE
                    PRINT "Error setting CtWaveStatus."
                END IF
            ELSE
                PRINT "Driver : Error setting double disk buffer."
            END IF
        ELSE
            PRINT "I/O wave handle not available."
        END IF
    ELSE
        PRINT "Error retrieving I/O wave handles."
    END IF

END FUNCTION


'-------------------------------------------------------------------------- '
'   @@ Usage                                                                '
'                                                                           '
'   SUB ShowError                                                           '
'                                                                           '
'   Description :                                                           '
'       Retrieves driver error or DOS error                                 '
'                                                                           '
'   Entry :                                                                 '
'       none.                                                               '
'                                                                           '
'   Exit :                                                                  '
'       none.                                                               '
'                                                                           '
'---------------------------------------------------------------------------'

SUB ShowError

     DIM  errcode AS INTEGER

     errcode = ctwdGetDrvError%

     PRINT "Driver error = "; errcode

     errcode = ctwdGetExtError%

     IF (errcode <> 0) THEN
        PRINT "Dos error = "; errcode
     ENDIF

END SUB
