'' ------------------------------------------------------------------------ ''
''  @@ Source Documentation                    *** BASIC Version ***        ''
''                                                                          ''
''  TITLE : DEMOVMR.BAS                                                     ''
''                                                                          ''
''  DESCRIPTION :                                                           ''
''      This program demostrates how to perform voice recording using the   ''
''      CT-VOICE.DRV driver. The voice recording is using the Conventional  ''
''      memory method. The recording can be terminated by pressing ESC.     ''
''      It will also release the 8k DMA buffer embedded in the driver and   ''
''      set up its own buffer. The input sources are CD and MIC.            ''
''                                                                          ''
''      The program retrieves BLASTER environment for the Card settings     ''
''      and pass it to the driver.                                          ''
''                                                                          ''
''  Note :                                                                  ''
''      Use switch /Fs for Microsoft Basic PDS 7.1 compiler.                ''
''      The VOC file size to be recorded is limited VOICExSIZE.             ''
''      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'


' Local function prototypes
DECLARE FUNCTION PrepareCTVOICEDrv%(BlasterAddx AS LONG)
DECLARE SUB RecordVoice(wIOHandle%,szFilename$)
DECLARE FUNCTION SetInputParam% ()
DECLARE SUB SaveVoiceFile (szFilename$,lpBuf&)

CONST VOICExSIZE  = &H4B000&
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 buffers for voice recording, CT-VOICE.DRV and DMA.
Dummy = SETMEM(-VOICExSIZE)
Dummy = SETMEM(-DRIVERxSIZE)
Dummy = SETMEM(-DMAxSIZE * 2&)

DIM SHARED CtVoiceStatus AS INTEGER     ' Voice i/o status
DIM BlasterEnv AS STRING
DIM BlasterAddx AS LONG
DIM wIOHandle AS INTEGER                ' Voice i/o handle
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 : DEMOVMR voc_filename"
        SYSTEM
    END IF

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

    ' Retrieve the BLASTER environment settings
    BlasterEnv = ENVIRON$("BLASTER")
    IF BlasterEnv <> "" THEN

        ' convert the string to NULL terminated string
        ' and return the far address of the string
        BlasterAddx = sbkMakeAsciizString&(BlasterEnv)

        ' loads CT-VOICE.DRV into memory
        IF PrepareCTVOICEDrv%(BlasterAddx) <> 0 THEN

            ' initialises CT-VOICE.DRV driver and Sound Blaster card
            IF ctvmInit% = 0 THEN

                ' Set up necessary input parameters and
                ' returns the i/o voice handle
                wIOHandle = SetInputParam%
                IF wIOHandle >= 0 THEN
                    CALL RecordVoice(wIOHandle,szCmdArg(1))
                END IF

                ' terminates CT-VOICE driver
                CALL ctvmTerminate
            END IF
        END IF
    ELSE
        PRINT "BLASTER environment not set or incomplete or invalid."
    END IF

' Release memory
Dummy = SETMEM(DMAxSIZE * 2&)
Dummy = SETMEM(DRIVERxSIZE)
Dummy = SETMEM(VOICExSIZE)

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 without embedded DMA buffer
    ctvoice = sbkLoadDriver%("CT-VOICE.DRV",1)
    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 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, retVal 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
                ' 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
                    ' set DMA buffer, if failed, the DMA buffer might
                    ' crossed segment, try again with 2nd DMA buffer
                    IF ctvmSetDMABuffer%(wIOHandle,dwValue,DMAxUNIT) <> 0 THEN
                       dwValue = dwValue + DMAxSIZE
                       IF ctvmSetDMABuffer%(wIOHandle,dwValue,DMAxUNIT) <> 0 THEN
                            PRINT "Error setting DMA buffer."
                            CALL sbkFreeMem(retVal)
                            EXIT FUNCTION
                        END IF
                    END IF

                    ' 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 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                                                                 '
'                                                                           '
'   SUB RecordVoice(wIOHandle%,szFilename$)                                 '
'                                                                           '
'   DESCRIPTION:                                                            '
'       Start recording voice.                                              '
'                                                                           '
'   ENTRY:                                                                  '
'       szFilename  - file name to store the voice input.                   '
'       wIOHandle   - i/o voice handle.                                     '
'                                                                           '
'   EXIT:                                                                   '
'       none.                                                               '
'                                                                           '
' --------------------------------------------------------------------------'

SUB RecordVoice(wIOHandle%,szFilename$)

    DIM retVal AS INTEGER, wSeg AS INTEGER
    DIM lBufSize AS LONG, lpVoiceBuf AS LONG


    lBufSize = &H30000

    ' allocates memory for voice input buffer
    wSeg = sbkAllocMem%(INT((VOICExSIZE+16) / 16))
    IF wSeg <> 0 THEN

        ' convert to 32-bit logical address
        lpVoiceBuf = sbkMakeDWord((wSeg),0)

        ' turns off DAC speaker
        CALL ctvmSetSpeaker(0)

        ' starts input voice to conventional memory
        IF ctvmInputCM%(wIOHandle%,lpVoiceBuf,VOICExSIZE) = 0 THEN

            RetVal = 0
            PRINT "Start recording, press ESC key to terminate..."

            ' polls for CtVoiceStatus if voice input is stopped
            WHILE CtVoiceStatus

                c$ = INKEY$
                IF c$ <> "" THEN

                    ' check for escape key
                    IF INT(ASC(LEFT$(c$,1))) = &H1b THEN
                        ' stops the voice input, this will set
                        ' CtVoiceStatus to zero
                        retVal = ctvmStop%(wIOHandle%)
                    END IF
                END IF
            WEND

            CALL SaveVoiceFile(szFilename$,lpVoiceBuf)
            CALL sbkFreeMem(wSeg)
            PRINT "Recording end."
        ELSE
            PRINT "Error recording voice - "; ctvmGetDrvError%
        END IF
    ELSE
        PRINT "DOS : Error allocating voice buffer."
    END IF

END SUB


' ------------------------------------------------------------------------- '
'  @@ Usage                                                                 '
'                                                                           '
'   SUB SaveVoiceFile (szFilename$,lpBuf&)                                  '
'                                                                           '
'   DESCRIPTION:                                                            '
'       Save recorded voice from memory to file.                            '
'                                                                           '
'   ENTRY:                                                                  '
'       szFilename - file name to be saved to.                              '
'       lpBuf - recorded voice buffer.                                      '
'                                                                           '
'   EXIT:                                                                   '
'       None                                                                '
'                                                                           '
' ------------------------------------------------------------------------- '

SUB SaveVoiceFile (szFilename$,lpBuf&)

' This function save the buffer into a Creative Voice file format

     DIM header AS VOCHDR
     DIM iHandle AS INTEGER, dwBufsize AS LONG
     DIM wBufoff AS INTEGER, wBufseg AS INTEGER


     ' Preceding the voice file with Creative voice file header
     header.id = "Creative Voice File" + CHR$(26)
     header.offset = LEN(header) ' indicates the start of voice data
     header.version = &H114  ' current version 1.20 supports block type 9
     header.checkcode = &H111F ' complement of header.version + &H1234

     ' Create a file
     iHandle = sbkDosCreate%(sbkMakeAsciizString&(szFilename$))

     IF (iHandle <> -1) THEN

          ' Write the file header
          IF (sbkDosWrite%(iHandle,VARSEG(header.id),_
                           VARPTR(header.id),26&) <> 0) THEN

               ' Get the voice block length (3 bytes) from buffer
               wBufoff = 0
               wBufseg = sbkHighWord%(lpBuf&)
               DEF SEG = wBufseg
                    dwBufsize = PEEK(wBufoff + 1)
                    dwBufsize = sbkMakeWord%(CINT(PEEK(wBufoff+2)),CINT(dwBufsize))
                    dwBufsize = sbkMakeDWord&(CINT(PEEK(wBufoff+3)),CINT(dwBufsize))
                    'dwBufsize = dwBufsize + INT(PEEK(wBufoff + 2)) * Shift8Bit
                    'dwBufsize = dwBufsize + CLNG(PEEK(wBufoff + 3)) * Shift16Bit
               DEF SEG


               ' Add 5 bytes for the block header and terminating block
               dwBufsize = dwBufsize + 5

               ' Write the buffer
               IF (sbkDosWrite%(iHandle,wBufseg,wBufoff,dwBufsize) = 0) THEN
                    PRINT "Write file error."
               ENDIF

          ENDIF

          CALL sbkDosClose(iHandle)
     ELSE
          PRINT "Creating file error."
     ENDIF

END SUB
' End of File
