'' ------------------------------------------------------------------------ ''
''  @@ Source Documentation                     *** BASIC Version ***       ''
''                                                                          ''
''  TITLE : DEMOVXR.BAS                                                     ''
''                                                                          ''
''  DESCRIPTION :                                                           ''
''      This program demostrates how to perform voice recording using       ''
''      the CT-VOICE.DRV driver. The voice recording is done using          ''
''      the Extended memory method. The input sources are CD and MIC.       ''
''                                                                          ''
''      Data moving from 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 size of VOC file to be recorded is limited by XMSxSIZE.         ''
''      This program will overwrite the output file if it exists.           ''
''                                                                          ''
''  Copyright (c) Creative Technology Ltd, 1993. All rights reserved.       ''
''                                                                          ''
'' ------------------------------------------------------------------------ ''

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


DECLARE FUNCTION RecordVocXM% (xmshd%)
DECLARE SUB SaveVoice (szFilename$, xmshd%)
DECLARE FUNCTION PrepareCTVOICEDrv% (BlasterAddx AS LONG)
DECLARE FUNCTION SetInputParam% ()

CONST XMSxSIZE    = 300%    ' size of extended memory in unit of kilobytes
CONST XFERxSIZE   = 8192%   ' size of XM to CM data transfer buffer

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.
'## Since this program uses default DMA buffer, increase DMAxUNIT
'## will cause no effect.
'*
CONST DMAxUNIT    = 4
CONST DMAxSIZE    = ((DMAxUNIT * TWOxKBYTES * 2&) + PARAxADJ)


REM $DYNAMIC
CLEAR

' Free memory for the CT-VOICE.DRV and Conventional to Extended memory
' transfer buffer
DUMMY = SETMEM(-DRIVERxSIZE)
DUMMY = SETMEM(-XFERxSIZE)

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

    PRINT "Record ";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
                ' allocate extended memory
                xmshd = sbkAllocXM%(XMSxSIZE)
                IF xmshd <> 0 THEN
                    ' initialize driver
                    IF ctvmInit% = 0 THEN
                        ' Start recording
                        IF RecordVocXM%(xmshd) <> 0 THEN
                            CALL SaveVoice(szCmdArg(1),xmshd)
                        END IF
                        ' terminate driver
                        CALL ctvmTerminate
                    ELSE
                        PRINT "Driver : Initialization error."
                    END IF

                    retVal% = sbkFreeXM%(xmshd)
                ELSE
                    PRINT "Error allocating extended memory."
                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(XFERxSIZE)
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 RecordVocXM% (xmshd%)                                          '
'                                                                           '
'   Description :                                                           '
'       Set up input parameters and start recording.                        '
'                                                                           '
'   Entry :                                                                 '
'       xmshd - extended memory handle.                                     '
'                                                                           '
'   Exit :                                                                  '
'       non-zero if successful else return zero.                            '
'                                                                           '
' ------------------------------------------------------------------------- '

FUNCTION RecordVocXM% (xmshd%)


    DIM userkey AS INTEGER
    DIM wIOHandle AS INTEGER


    RecordVocXM% = 0

    ' set input parameters
    wIOHandle = SetInputParam%
    IF wIOHandle <> -1 THEN
        ' turn off DAC speaker
        CALL ctvmSetSpeaker(0)

        ' start input voice
        IF ctvmInputXM%((wIOHandle),(xmshd%),0&,(XMSxSIZE)) = 0 THEN
            PRINT "Start recording, press ESC key to terminate ....."

            WHILE CtVoiceStatus% <> 0

                c$ = INKEY$

                IF c$ <> "" THEN

                    userkey = INT(ASC(LEFT$(c$, 1)))

                    '  check for escape key
                    IF userkey = 27 THEN
                        retVa% = ctvmStop%(wIOHandle)
                    END IF

                END IF

            WEND

            RecordVocXM% = 1
            PRINT "Recording end."
        ELSE
            PRINT "Error input voice - "; ctvmGetDrvError%
        END IF
    END IF

END FUNCTION


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

FUNCTION SetInputParam%

    DIM dwValue AS LONG
    DIM wIOHandle AS INTEGER


    SetInputParam% = -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

                ' Set stereo mode input
                retVal% = ctvmSetIOParam%(wIOHandle,CTVOCxINxNCHANNELS,2)

                ' Set CD and MIC as input source
                retVal% = ctvmSetIOParam%(wIOHandle,CTVOCxINxLEFTINPUTS,_
                                                    MIXERSWIxCDxL OR MIXERSWIxMIC)
                retVal% = ctvmSetIOParam%(wIOHandle,CTVOCxINxRIGHTINPUTS,_
                                                    MIXERSWIxCDxR OR MIXERSWIxMIC)

                '* sample rate 22050 *'
                retVal% = ctvmSetIOParam%(wIOHandle,CTVOCxINxSAMPLESPERSEC,22050)

                ' By defaults : sampling rate  : 11025 Hz
                '               voice format   : 8 bits PCM
                '               bit per sample : 8 bits

                SetInputParam% = wIOHandle
            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                                                                '
'                                                                           '
'    SUB SaveVoice (szFilename$, xmshd%)                                    '
'                                                                           '
'    DESCRIPTION:                                                           '
'        Save recorded voice from extended memory to file.                  '
'                                                                           '
'    ENTRY:                                                                 '
'        szFilename - file name to be saved to.                             '
'        xmshd - recorded voice extended memory handle.                     '
'                                                                           '
'    EXIT:                                                                  '
'        None                                                               '
'                                                                           '
'  ------------------------------------------------------------------------ '

SUB SaveVoice (szFilename$, xmshd%)

    DIM header AS VOCHDR
    DIM lVocSize AS LONG, lCurXmsOff AS LONG
    DIM lByteToMove AS LONG, lpXferBuf AS LONG
    DIM iHandle AS INTEGER, XferBufSeg AS INTEGER


    PRINT "Start saving ";szFilename$;"..."

    ' Setup the voice file format
    header.id = "Creative Voice File" + CHR$(26)
    header.offset = 26
    header.version = &H114
    header.checkcode = &H111F

    ' allocate memory for CM to XM data transfer
    XferBufSeg = sbkAllocMem%(INT((XFERxSIZE + 15) \ 16))
    IF XferBufSeg = 0 THEN
        PRINT "Error allocating XM to CM transfer buffer."
        PRINT "Voice recorded not saved."
        EXIT SUB
    END IF

    ' convert to 32-bit logical address
    lpXferBuf = sbkMakeDword((XferBufSeg),0)

    ' create voice file
    iHandle = sbkDosCreate%(sbkMakeAsciizString&(szFilename$))
    IF iHandle = -1 THEN
        PRINT "Error creating ";szFilename$;"."
    ELSE
        ' write voice header
        IF sbkDosWrite%(iHandle,VARSEG(header.id),_
                        VARPTR(header.id),len(header)) = 0 THEN
            PRINT "Error writing ";szFilename$;"."
        ELSE
            ' retreive data length from recorded XM buffer
            IF sbkMoveXMtoCM%(lpXferBuf, 4, xmshd%, 0) = 0 THEN
                PRINT "Error moving data from extended memory."
            ELSE
                ' Get the voice block length from buffer
                DEF SEG = XferBufSeg
                    lVocSize = PEEK(1)
                    lVocSize = lVocSize + INT(PEEK(2)) * &H100
                    lVocSize = lVocSize + CLNG(PEEK(3)) * &H10000
                DEF SEG

                ' include the block type, block length
                ' and terminator block type
                lVocSize = lVocSize + 5
                lCurXmsOff = 0

                DO
                    lByteToMove = XFERxSIZE

                    IF lVocSize < XFERxSIZE THEN
                        lByteToMove = lVocSize
                    END IF

                    ' move voice data from extended memory
                    IF sbkMoveXMtoCM%(lpXferBuf,lByteToMove,_
                                      xmshd%, lCurXmsOff) <> 0 THEN
                        IF sbkDosWrite%((iHandle),(XferBufSeg),_
                                        0,(lByteToMove)) <> 0 THEN
                            lVocSize = lVocSize - lByteToMove
                            lCurXmsOff = lCurXmsOff + lByteToMove
                        ELSE
                            PRINT "Error writing ";szFilename$;"."
                            EXIT DO
                        END IF
                    ELSE
                        PRINT "Error moving data from extended memory."
                        EXIT DO
                    END IF

                LOOP UNTIL lVocSize = 0
            END IF
        END IF

        CALL sbkDosClose(iHandle)
    END IF

    CALL sbkFreeMem(XferBufSeg)

END SUB
'End Of File
