'' ------------------------------------------------------------------------- ''
''  @@ Source Documentation                         *** BASIC Version ***    ''
''                                                                           ''
''  TITLE : DEMOXMS.BAS                                                      ''
''                                                                           ''
''  DESCRIPTION :                                                            ''
''      This program demostrates how to playback voice using the             ''
''      CT-VOICE.DRV driver. The voice playback is done using the            ''
''      Extended memory method. Instead of using the DMA buffer              ''
''      embedded in the driver, it will set its own DMA buffer and           ''
''      make use of the embedded buffer as data transfer buffer              ''
''      between extended conventional memory.                                ''
''                                                                           ''
''      Data moving to extended memory is done by invoking XMS               ''
''      driver.                                                              ''
''                                                                           ''
''      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.                 ''
''      The input VOC file size is limited by the extended memory            ''
''      available.                                                           ''
''                                                                           ''
''  Copyright (c) Creative Technology Ltd 1993. All rights reserved.         ''
''                                                                           ''
'' ------------------------------------------------------------------------- ''

' $INCLUDE: 'SBKVOICE.BI'
' $INCLUDE: 'SBKX.BI'

DECLARE FUNCTION Load2Xms% (szFilename$)
DECLARE SUB PlayVoiceXM (xmshd%)
DECLARE FUNCTION SetOutputParam%()
DECLARE FUNCTION PrepareCTVOICEDrv%(BlasterAddx AS LONG)

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.
'*
CONST DMAxUNIT    = 4
CONST DMAxSIZE    = ((DMAxUNIT * TWOxKBYTES * 2&) + PARAxADJ)


REM $DYNAMIC
CLEAR


' Set  memory for the CT-VOICE.DRV and two DMA buffers
DUMMY = SETMEM(-DRIVERxSIZE)
DUMMY = SETMEM(-DMAxSIZE * 2)

DIM SHARED CtVoiceStatus AS INTEGER     ' i/o voice status
DIM SHARED wDrvSeg  AS INTEGER
DIM BlasterEnv AS STRING
DIM xmshd AS INTEGER                    ' extended mrmory 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 : DEMOVXP voc_filename"
        SYSTEM
    END IF

    PRINT "Playback ";szCmdArg(1);" at extended memory."

    ' retrieve BLASTER environment settings
    BlasterEnv = ENVIRON$("BLASTER")
    IF BlasterEnv <> "" THEN
        ' convert the BLASTER string to null terminated string
        ' and return the far address of the string
        dwBlasterAddx = sbkMakeAsciizString&(BlasterEnv)

        ' Load CT-VOICE.DRV
        wDrvSeg = PrepareCTVOICEDrv%(dwBlasterAddx)
        IF wDrvSeg <> 0 THEN
            ' extended memory manager loaded ?
            IF sbkGetXMSEntry% <> 0 THEN
                ' initialize driver
                IF ctvmInit% = 0 THEN
                    ' load voice file to extended memory
                    xmshd = Load2Xms%(szCmdArg(1))
                    IF xmshd <> 0 THEN
                        ' output voice
                        CALL PlayVoiceXM(xmshd)
                        ' free extended memory
                        retVal% = sbkFreeXM%(xmshd)
                    END IF

                    ' terminate driver
                    CALL ctvmTerminate
                ELSE
                    PRINT "Driver : Initialization error."
                END IF
            ELSE
                PRINT "Himem.sys not loaded."
            END IF
        END IF
    ELSE
        PRINT "BLASTER environment not set or incomplete or invalid."
    END IF


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

END


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

FUNCTION PrepareCTVOICEDrv%(BlasterAddx AS LONG)

    DIM dwVersion AS LONG
    DIM ctvoice AS INTEGER

    ' load driver with embedded DMA buffer
    ctvoice = sbkLoadDriver%("CT-VOICE.DRV",UNUSED)
    IF ctvoice <> 0 THEN

        ' Initialises the CT-VOICE.DRV driver entry point
        CALL ctvmSetDriverEntry((ctvoice))

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

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

        CALL sbkFreeMem(ctvoice)
    ELSE
        PRINT "Error loading CT-VOICE.DRV or CT-VOICE.DRV not found."
    END IF

    PrepareCTVOICEDrv% = 0

END FUNCTION


'---------------------------------------------------------------------------'
'  @@ Usage                                                                 '
'                                                                           '
'   FUNCTION SetOutputParam%()                                              '
'                                                                           '
'   DESCRIPTION:                                                            '
'       Set up the necessary output parameters.                             '
'                                                                           '
'   ENTRY:                                                                  '
'       none.                                                               '
'                                                                           '
'   EXIT:                                                                   '
'       i/o voice handle if successful otherwise return -1.                 '
'                                                                           '
'---------------------------------------------------------------------------'

FUNCTION SetOutputParam%

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


    SetOutputParam% = -1

    ' Retrieves numbers of IO voice handles supported
    IF ctvmGetParam%(CTVOCxIOHANDLES,dwValue) = 0 THEN

        IF dwValue <> 0 THEN
            ' wIOHandle - IO voice handle to be used
            wIOHandle = ABS(INT(dwValue - 1))

            ' get logical address of the voice i/o status
            dwValue = sbkMakeDWord((VARSEG(CtVoiceStatus)),_
                                   (VARPTR(CtVoiceStatus)))

            ' Set the IO voice status - CtVoiceStatus
            IF ctvmSetIOParam%(wIOHandle,CTVOCxIOxLPSTATUSWORD,_
                               dwValue) = 0 THEN
                ' Allocate two DMA buffer.
                retVal = sbkAllocMem%(INT((DMAxSIZE * 2 ) \ 16))
                IF retVal <> 0 THEN
                    ' convert to 32-bit linear address
                    dwValue = sbkMakeDWord(0,(retVal)) * 16

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

                    IF ctvmSetDMABuffer%(wIOHandle,dwValue,DMAxUNIT) <> 0 THEN
                       dwValue = dwValue + DMAxSIZE
                       IF ctvmSetDMABuffer%(wIOHandle,dwValue,DMAxUNIT) <> 0 THEN
                            PRINT "Driver : Error setting DMA buffer."
                        ELSE
                            SetOutputParam% = wIOHandle
                        END IF
                    ELSE
                        SetOutputParam% = wIOHandle
                    END IF
                ELSE
                    PRINT "Dos : Error allocating DMA buffer."
                END IF
            ELSE
                PRINT "Error setting ct_voice_status."
            END IF
        ELSE
            PRINT "IO voice handle not available."
        END IF
    ELSE
        PRINT "Error retrieving IO voice handles."
    END IF

END FUNCTION


' ------------------------------------------------------------------------- '
'   @@ USAGE                                                                '
'                                                                           '
'   Load2Xms% (szFilename$)                                                 '
'                                                                           '
'   DESCRIPTION:                                                            '
'       Load a file to Extended Memory. Extended memory will be             '
'       allocated and data is transferred to there.                         '
'                                                                           '
'   ENTRY:                                                                  '
'       szFilename - File to be loaded.                                     '
'                                                                           '
'   EXIT:                                                                   '
'        extended memory handle if successful else return 0.                '
'                                                                           '
' ------------------------------------------------------------------------- '

FUNCTION Load2Xms% (szFilename$)

    DIM iHandle AS INTEGER, xmshd AS INTEGER, XferBufSeg AS INTEGER
    DIM BufSize AS LONG, DrvSize AS LONG
    DIM lByteToRead AS LONG, lpXferBuf AS LONG
    DIM lFileSize AS LONG, lCurXmsOff AS LONG
    DIM header AS VOCHDR


    PRINT "Loading ";szFilename$;" into extended memory..."

    Load2Xms% = 0

    ' Retrieving embedded buffer size (in unit of 2k bytes
    ' per half buffer) from the driver and this will be used
    ' as CMM to XMM data transfer buffer
    IF ctvmGetParam%(CTVOCxEMBDDMABUFSIZE,BufSize) <> 0 THEN
        PRINT "Driver : Error retrieving size of embedded DMA buffer."
        EXIT FUNCTION
    END IF

    BufSize = BufSize * 2048 * 2

    ' Retrieving driver size
    IF ctvmGetParam(CTVOCxDRIVERSIZE,DrvSize) <> 0 THEN
        PRINT "Driver : Error retrieving size of driver."
        EXIT FUNCTION
    END IF

    '  making use of embedded buffer as CMM to XMM data transfer area
    XferBufSeg = wDrvSeg + INT((DrvSize + 15)/ 16)
    lpXferBuf = sbkMakeDWord&((XferBufSeg),0)

    ' open file
    iHandle = sbkDosOpen%(sbkMakeAsciizString&(szFilename$))
    IF iHandle <> -1 THEN
        ' get file size
        lFileSize = sbkFileSize&(iHandle)

        ' allocate extended memory
        xmshd = sbkAllocXM%(INT((lFileSize + 1023&) \ 1024&))
        IF Xmshd <> 0 THEN

            ' retrieve voice header
            IF sbkDosRead%(iHandle,VARSEG(header.id),_
                        VARPTR(header.id),LEN(header)) = 0 THEN
                PRINT "Dos : Error reading ";szFilename$;"."
                CALL sbkDosClose(iHandle)
                retVal% = sbkFreeXM%(xmshd)
                EXIT FUNCTION
            END IF

            ' move the file pointer to the start of the voice data
            retVal% = INT(sbkDosLSeek&(iHandle,CLNG(header.offset),0))
            lFileSize = lFileSize - header.offset
            lCurXmsOff = 0

            DO
                lByteToRead = BufSize

                IF lFileSize < BufSize THEN
                    lByteToRead = lFileSize
                END IF
                ' read voice data into transfer buffer
                IF sbkDosRead%(iHandle,XferBufSeg,0,lByteToRead) <> 0 THEN
                    ' move voice data to extended memory
                    IF sbkMoveCMtoXM%((lpXferBuf),(lByteToRead),_
                                      (xmshd),(lCurXmsOff)) <> 0 THEN
                        lFileSize = lFileSize - lByteToRead
                        lCurXmsOff = lCurXmsOff + lByteToRead
                    ELSE
                        PRINT "Error moving data to extended memory."
                        EXIT DO
                    END IF
                ELSE
                    PRINT "Dos : Error reading ";szFilename$;"."
                    EXIT DO
                END IF

            LOOP until lFileSize = 0

            IF lFileSize = 0 THEN
                Load2Xms% = xmshd
            ELSE
                ' free extended memory
                retVal% = sbkFreeXM%(xmshd)
            END IF
        ELSE
            PRINT "Error allocating extended memory."
        END IF

        CALL sbkDosClose(iHandle)
    ELSE
        PRINT "Error open ";szFilename$;"."
    END IF

END FUNCTION


'-------------------------------------------------------------------------- '
'   @@ Usage                                                                '
'                                                                           '
'   SUB PlayVoiceXM (xmshd%)                                                '
'                                                                           '
'   Description :                                                           '
'       Output voice file at extended memory.                               '
'                                                                           '
'   Entry :                                                                 '
'       xmshd - handle of allocated extended memory.                        '
'                                                                           '
'   Exit :                                                                  '
'       none.                                                               '
'                                                                           '
'-------------------------------------------------------------------------- '

REM %STATIC
SUB PlayVoiceXM (xmshd%)


    DIM userkey AS INTEGER, wIOHandle AS INTEGER
    DIM Done AS INTEGER, Pause AS INTEGER
    DIM XSize AS LONG

    ' set output parameters
    wIOHandle = SetOutputParam
    IF wIOHandle <> -1 THEN

        ' turn on DAC speaker
        ctvmSetSpeaker(1)

        ' output voice at extended memory
        IF ctvmOutputXM%(wIOHandle,xmshd%,0) = 0 THEN
            PRINT "    [Esc] - to stop"
            PRINT "    [P  ] - to pause"
            PRINT "    [C  ] - to continue"

            Done = 0
            Pause = 0

            WHILE Done <> 1

                ' repeat when voice end
                IF CtVoiceStatus = 0 THEN
                    IF ctvmOutputXM%(wIOHandle,xmshd%,0) <> 0 THEN
                        PRINT "Error output voice - "; ctvmGetDrvError%
                        Done = 1
                    END IF
                END IF

                c$ = INKEY$

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

                    SELECT CASE userkey
                        CASE 27
                            ' stop voice otuput
                            retVal = ctvmStop%(wIOHandle)
                            Done = 1

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

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

            PRINT "Voice stop."
        ELSE
            PRINT "Error output voice - "; ctvmGetDrvError%
        END IF

        ' turn off speaker
        ctvmSetSpeaker(0)

    END IF

END SUB
' End of file
