'' ------------------------------------------------------------------------ ''
''  @@ Source Documentation                     *** BASIC Version ***       ''
''                                                                          ''
''  TITLE : DEMOWMP.BAS                                                     ''
''                                                                          ''
''  DESCRIPTION :                                                           ''
''      This program demostrates how to perform wave out using the          ''
''      CTWMEM.DRV driver. The Wave out is using the Conventional           ''
''      memory method.                                                      ''
''                                                                          ''
''      The program retrieves BLASTER environment for the Card settings     ''
''      and passes it to the driver.                                        ''
''                                                                          ''
''      Note that the program included the module LOADDRV.C to load         ''
''      the loadable CTWMEM.DRV into memory.                                ''
''                                                                          ''
''  Note :                                                                  ''
''      Use switch /Fs for Microsoft Basic PDS 7.1 compiler.                ''
''      The WAV file size to be played back is limited by WAVExSIZE.        ''
''                                                                          ''
''  Copyright (c) Creative Technology Ltd, 1993. All rights reserved.       ''
''                                                                          ''
'' ------------------------------------------------------------------------ ''

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

' Local function prototypes
DECLARE FUNCTION PrepareCTWMEMDrv%(BlasterAddx AS LONG)
DECLARE FUNCTION LoadFile% (filename$)
DECLARE SUB OutputWave (wIOHandle AS INTEGER,szFilename$)
DECLARE FUNCTION SetOutputParam% ()

CONST DRIVERxSIZE = 51200&
CONST WAVExSIZE   = &H4B000&

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)


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 CTWMEM.DRV, DMA buffers and wave buffer
Dummy = SETMEM(-DRIVERxSIZE)
Dummy = SETMEM(-DMAxSIZE * 2&)
Dummy = SETMEM(-WAVExSIZE)

DIM SHARED CtWaveStatus AS INTEGER      ' Wave output status
DIM BlasterEnv AS STRING
DIM wIOHandle AS INTEGER                ' Wave i/o handle
DIM dwBlasterAddx 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 : DEMOWMP wav_filename"
        SYSTEM
    END IF

    PRINT "Playing ";szCmdArg(1);" at conventional memory."

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

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

        ' Load the CTWMEM.DRV into memory
        IF PrepareCTWMEMDrv(dwBlasterAddx) <> 0 THEN

            ' Initialises driver and Sound Blaster card
            IF ctwmInit% = 0 THEN

                ' set up necessary output parameters
                wIOHandle = SetOutputParam%
                IF wIOHandle >= 0 THEN
                    CALL OutputWave(wIOHandle,szCmdArg(1))
                END IF

                ' Terminate driver before exit
                CALL ctwmTerminate
            END IF
        END IF
    ELSE
        PRINT "BLASTER environment not set or incomplete or invalid."
    ENDIF

' Return memory to BASIC
Dummy = SETMEM(WAVExSIZE)
Dummy = SETMEM(DMAxSIZE * 2&)
Dummy = SETMEM(DRIVERxSIZE)

END


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

FUNCTION PrepareCTWMEMDrv%(BlasterAddx AS LONG)

    DIM dwVersion AS LONG
    DIM ctwmem AS INTEGER

    ' Load driver into memory
    ctwmem = sbkLoadDriver%("CTWMEM.DRV",UNUSED)
    IF ctwmem <> 0 THEN

        ' Initialises the CTWMEM.DRV driver entry point
        CALL ctwmSetDriverEntry((ctwmem))

        ' Retrieves CTWMEM.DRV version
        IF ctwmGetParam%(CTWAVxDRIVERVERSION,dwVersion) = 0 THEN
            IF ABS(CINT(dwVersion)) >= &H0305 THEN

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

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

    PrepareCTWMEMDrv% = 0

END FUNCTION


'-------------------------------------------------------------------------- '
'   @@ Usage                                                                '
'                                                                           '
'   FUNCTION LoadFile% (filename$)                                          '
'                                                                           '
'   Description :                                                           '
'       Loads wave file into memory.                                        '
'                                                                           '
'   Entry :                                                                 '
'       filename - wave file to be loaded.                                  '
'                                                                           '
'   Exit :                                                                  '
'      wave buffer segment  if successful otherwise zero.                   '
'                                                                           '
'---------------------------------------------------------------------------'

REM $STATIC
FUNCTION LoadFile% (filename$)

    DIM iHandle%, filelen&, segment%


    LoadFile% = 0
    iHandle% = sbkDosOpen%(sbkMakeAsciizString&(filename$))

    IF (iHandle% <> -1) THEN
        filelen& = sbkFileSize&(iHandle%)
        segment% = sbkAllocMem%(INT((filelen& + 15) / 16))
        IF segment% <> 0 THEN

            IF sbkDosRead%(iHandle%, segment%, 0, filelen&) <> 0 THEN
                LoadFile% = segment%
            ELSE
                PRINT "Read file error."
                CALL sbkFreeMem(segment%)
            END IF
        ELSE
            PRINT "DOS : Error allocating wave output buffer."
        END IF

        CALL sbkDosClose(iHandle%)
    ELSE
        PRINT "Open " + filename$ + "error."
    END IF

END FUNCTION


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

FUNCTION SetOutputParam%

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


    SetOutputParam% = -1

    ' 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

        IF ctwmGetParam%(CTWAVxIOHANDLES,dwValue) = 0 THEN

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

                ' get address of the i/o wave status
                dwValue = sbkMakeDWord((VARSEG(CtWaveStatus)),_
                                       (VARPTR(CtWaveStatus)))
                ' set i/o wave status
                IF ctwmSetIOParam%(wIOHandle,CTWAVxIOxLPSTATUSWORD,_
                                    dwValue) = 0 THEN
                    ' convert to 32-bit linear address
                    dwValue = sbkMakeDWord(0,(wDmaBuf)) * 16

                    ' Set DMA buffer. If failed, the DMA buffer might have
                    ' crossed the 64 k boundary, thus use the 2nd Dma buffer
                    IF ctwmSetDMABuffer%((wIOHandle),(dwValue),DMAxUNIT) <> 0 THEN
                        dwValue = dwValue + DMAxSIZE

                        IF ctwmSetDMABuffer%((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 "I/O wave handle unavailable."
            END IF
        ELSE
            PRINT "Error retrieving i/o wave handles."
        END IF
    ELSE
        PRINT "DOS : Error allocating DMA buffer."
    END IF

END FUNCTION


'-------------------------------------------------------------------------- '
'   @@ Usage                                                                '
'                                                                           '
'   SUB OutputWave (wIOHAndle AS INTEGER,  buffer%())                       '
'                                                                           '
'   Description :                                                           '
'       This function output the wave file loaded and check for the         '
'       keyboard input to pause, stop and break the wave output.            '
'                                                                           '
'   Entry :                                                                 '
'       wIOHandle - i/o wave handle.                                        '
'       buffer    - wave data buffer.                                       '
'                                                                           '
'   Exit :                                                                  '
'       none.                                                               '
'                                                                           '
'-------------------------------------------------------------------------- '

SUB OutputWave (wIOHandle AS INTEGER,szFilename$)

    DIM userkey AS INTEGER
    DIM retVal AS INTEGER, Done AS INTEGER, Pause AS INTEGER
    DIM dwWaveBuf AS LONG


    ' Load wave file
    retVal =  LoadFile%(szFilename$)
    IF retVal <> 0 THEN
        ' convert to 32-bit logical address
        dwWaveBuf = sbkMakeDWord((retVal),0)

        ' turn on speaker
        ctwmSetSpeaker(1)

        IF ctwmOutputCM%(wIOHandle,dwWaveBuf) = 0 THEN
            PRINT "    [Esc] - to stop"
            PRINT "    [P  ] - to pause"
            PRINT "    [C  ] - to continue"

            Done = 0
            Pause = 0

            WHILE Done <> 1

                IF CtWaveStatus = 0 THEN
                    retVal = ctwmOutputCM%(wIOHandle,dwWaveBuf)
                END IF

                c$ = INKEY$

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

                    SELECT CASE userkey
                        CASE 27
                            retVal = ctwmStop%(wIOHandle)
                            Done = 1

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

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

            CALL sbkFreeMem(sbkHighWord((dwWaveBuf)))
            PRINT "Wave stop."
        ELSE
            PRINT "Error output wave - "; ctwmGetDrvError%
        END IF

        ' turn off speaker
        ctwmSetSpeaker(0)

    END IF

END SUB
' End of file
