/* ------------------------------------------------------------------------ */
/*  @@ Source Documentation                         *** C Version ***       */
/*                                                                          */
/*  TITLE : DEMOVMR.C                                                       */
/*                                                                          */
/*  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.     */
/*      This program will also release the 8k embedded DMA buffer from      */
/*      the driver and set up its own 16k DMA buffer. The input sources     */
/*      are CD ans MIC.                                                     */
/*                                                                          */
/*      The program retrieves BLASTER environment for the Card settings     */
/*      and pass it to the driver.                                          */
/*                                                                          */
/*      Note that the program included the module LOADDRV.C to load         */
/*      the loadable CT-VOICE.DRV into memory.                              */
/*      The VOC file size to be recorded is set by BUFSIZE.                 */
/*                                                                          */
/*  Copyright (c) Creative Technology Ltd, 1993. All rights reserved.       */
/*                                                                          */
/* ------------------------------------------------------------------------ */

#include <io.h>
#include <string.h>
#include <stdlib.h>
#include <dos.h>
#include <stdio.h>
#include <fcntl.h>

#include "sbkvoice.h"
#include "sbkmacro.h"
#include "sbkx.h"
#include "loaddrv.c"

#define BUFSIZE     307200l     /* maximum VOC data size to be recorded */

#define TWO_KBYTES  2048l
#define PARA_ADJ    15l         /* 15 bytes for paragraph adjustment */

/*
## DMA_UNIT 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.
*/
#define DMA_UNIT    4
#define DMA_SIZE    ((DMA_UNIT * TWO_KBYTES * 2l) + PARA_ADJ)


/* Function Prototypes */
int PrepareCTVOICEDrv(char * BlasterEnv) ;
int SetInputParam(void) ;
void RecordVoice (int wIOHandle,char * szFilename) ;
void SaveVoiceFile(char *,char far *) ;
int WriteToFile (int Handle,char far *lpBuf,long lSize) ;


volatile WORD ct_voice_status ;         /* voice i/o status */
char far * lpOrigin ;                   /* Origin driver buffer */

main(int argc, char * argv[])
{
    char * BlasterEnv;
    int  wIOHandle ;

    if (argc < 2)
    {
	printf("Usage : DEMOVMR voc_filename\n") ;
        exit(0) ;
    }

    printf ("\nRecord %s to conventional memory.",argv[1]) ;

    /* Retrieve the BLASTER environment settings */
    if ((BlasterEnv = getenv("BLASTER")) != NULL)
    {
        /* Loads CT-VOICE.DRV into memory */
        if (!PrepareCTVOICEDrv(BlasterEnv))
        {
            if (!ctvmInit())
            {
                wIOHandle = SetInputParam() ;
                if ((int)wIOHandle > -1)
                    RecordVoice(wIOHandle,argv[1]);

                ctvmTerminate() ;
            }
        }
    }
    else
        printf("BLASTER environment not set or incomplete or invalid.\n");

    return 0 ;
}


/* ------------------------------------------------------------------------ */
/*  @@ Usage                                                                */
/*                                                                          */
/*  PrepareCTVOICEDrv(char * BlasterEnv)                                    */
/*                                                                          */
/*  Description :                                                           */
/*      Load and endorse CT-VOICE.DRV.                                      */
/*                                                                          */
/*  Entry :                                                                 */
/*      BlasterEnv - pointer to the BLASTER environment.                    */
/*                                                                          */
/*  Exit :                                                                  */
/*      zero if sucessful, non-zero otherwise.                              */
/*                                                                          */
/* ------------------------------------------------------------------------ */

int PrepareCTVOICEDrv(char * BlasterEnv)
{
    DWORD     dwVersion = 0 ;


    /* load driver without embedded DMA buffer */
    if ((voice_drv = sbkLoadDriver("CT-VOICE.DRV", 1,
                        (char far **)&lpOrigin)) != NULL)
    {
        /* Retrieves CT-VOICE.DRV version */
        if (!ctvmGetParam(CTVOC_DRIVERVERSION,
                                  (DWORD far *)&dwVersion))
        {
            if ((dwVersion & 0xffff) >= 0x0305)
            {
                /* Passes BLASTER environment settings to driver */
                if (!ctvmGetEnvSettings((char far *)BlasterEnv))
                    return(0) ;
                else
                    printf("\nBLASTER environment is not valid");
            }
            else
            {
                printf("\nInvalid CT-VOICE.DRV - ") ;
                printf("I need CT-VOICE.DRV version 3.05 or higher.\n") ;
            }
        }
        else
            printf("\nUnrecognized CT-VOICE.DRV\n");
    }
    return(1) ;
}


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

int SetInputParam(void)
{
    DWORD     dwValue ;
    WORD      wIOHandle ;
    char      far * lpDmaBuf ;


    /* Retrieves the total IO voice handles */
    if (!ctvmGetParam(CTVOC_IOHANDLES,(DWORD far *)&dwValue))
    {
        /* wIOHandle - IO voice handle to be used */
        if (dwValue)
        {
            wIOHandle = (WORD)(dwValue - 1) ;

            /* Set the IO voice status - ct_voice_status */
            if (!ctvmSetIOParam(wIOHandle,CTVOC_IO_LPSTATUSWORD,
                (DWORD)(WORD far *)&ct_voice_status))
            {
                /* Allocate two DMA buffer */
                if ((lpDmaBuf = sbkAllocMem((DWORD)(DMA_SIZE * 2))) != NULL)
                {
                    /* convert to 32-bit linear address */
                    dwValue = (DWORD)((DWORD)FPSEG(lpDmaBuf) << 4) +
                                      FPOFF(lpDmaBuf) ;
                    /* Set up DMA buffer. If failed, the 1st DMA buffer
                       might crossed segment. Try again with 2nd DMA
                       buffer */
                    if (ctvmSetDMABuffer(wIOHandle,dwValue,(WORD)DMA_UNIT))
                    {
                        dwValue += DMA_SIZE ;
                        if (ctvmSetDMABuffer(wIOHandle,dwValue,(WORD)DMA_UNIT))
                        {
                            printf("\nDriver : Error setting DMA buffer.") ;
                            sbkFreeMem(lpDmaBuf) ;
                            return (-1) ;
                        }
                    }

                    /* Set stereo mode input */
                    ctvmSetIOParam(wIOHandle,CTVOC_IN_NCHANNELS,2);

                    /* Set CD and MIC as stereo input source */
                    ctvmSetIOParam(wIOHandle,CTVOC_IN_LEFTINPUTS,
                                        MIXERSWI_CD_L | MIXERSWI_MIC) ;
                    ctvmSetIOParam(wIOHandle,CTVOC_IN_RIGHTINPUTS,
                                        MIXERSWI_CD_R | MIXERSWI_MIC) ;

                    /* set input sampling rate */
                    ctvmSetIOParam(wIOHandle,CTVOC_IN_SAMPLESPERSEC,22050);

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

                    return ((int)wIOHandle) ;
                }
                else
                    printf("\nDos : Error allocating DMA buffer.") ;
            }
            else
                printf ("\nError setting ct_voice_status.") ;
        }
        else
            printf ("\nIO voice handle not available.") ;
    }
    else
        printf ("\nError retrieving IO voice handles.") ;

    return (-1) ;
}


/* ------------------------------------------------------------------------ */
/*  @@ Usage                                                                */
/*                                                                          */
/*   RecordVoice (int wIOHandle,char *szFilename)                           */
/*                                                                          */
/*   DESCRIPTION:                                                           */
/*       Start recording voice.                                             */
/*                                                                          */
/*   ENTRY:                                                                 */
/*       szFilename  - name of the voice file                               */
/*       wIOHandle   - i/o voice handle.                                    */
/*                                                                          */
/*   EXIT:                                                                  */
/*       none.                                                              */
/*                                                                          */
/* ------------------------------------------------------------------------ */

void RecordVoice (int wIOHandle,char * szFilename)
{
    BYTE far *lpVoiceBuf ;


    if ((lpVoiceBuf = (BYTE far *)sbkAllocMem(BUFSIZE + 15)) != NULL)
    {
        ctvmSetSpeaker(0) ;

        /* Input voice to conventional memory */
        if (!ctvmInputCM((WORD)wIOHandle,lpVoiceBuf,BUFSIZE))
        {
            printf("\nStart recording...Press ESC key to terminate...");

            while (ct_voice_status)
            {
                if (sbkBiosKeybrd(KEYBRD_READY))
                {
                     /* check for escape key */
                    if ((sbkBiosKeybrd(KEYBRD_READ) & 0xff) == 0x1b)
                        ctvmStop((WORD)wIOHandle) ;
                }
            }
            SaveVoiceFile(szFilename,(char far *)lpVoiceBuf) ;
            sbkFreeMem(lpVoiceBuf) ;
            printf("\nRecording end.");
        }
        else
        {
            printf("\nError recording.") ;
            printf(" - %x",ctvmGetDrvError()) ;
        }
    }
    else
        printf ("\nDos : Error allocating voice buffer.") ;

}


/* ------------------------------------------------------------------------ */
/*  @@ Usage                                                                */
/*                                                                          */
/*   SaveVoiceFile (char *szFilename, char far *lpBuf)                      */
/*                                                                          */
/*   DESCRIPTION:                                                           */
/*       Save recorded voice from memory to file.                           */
/*                                                                          */
/*   ENTRY:                                                                 */
/*       szFilename - file name to be saved to.                             */
/*       lpBuf - recorded voice buffer.                                     */
/*                                                                          */
/*   EXIT:                                                                  */
/*       None                                                               */
/*                                                                          */
/* ------------------------------------------------------------------------ */

void SaveVoiceFile (char *szFilename, char far *lpBuf)
{
    int         Handle ;
    long    lVoiceSize ;
    VOCHDR  stHeader ;

    /* Voice header */
    strcpy(stHeader.id,"Creative Voice File\x1A") ;
    stHeader.voice_offset = sizeof(VOCHDR) ;
    stHeader.version = 0x0114 ;
    stHeader.check_code = (WORD)(~stHeader.version + 0x1234) ;

    if ((Handle = sbkDosCreate(szFilename)) == -1)
        printf("Create %s error.\n",szFilename) ;
    else
    {
        /* write voice header */
        if (!WriteToFile(Handle,(char far*)&stHeader,(long)sizeof(VOCHDR)))
        {
            /* get the recorded data block size */
            lVoiceSize = *(lpBuf+3) ;
            lVoiceSize <<= 16 ;
            lVoiceSize += *(unsigned far *)(lpBuf+1) ;

            /*      include the block type, block length  */
            /*  and terminator block type             */

            lVoiceSize += 5 ;

            WriteToFile(Handle,lpBuf,lVoiceSize) ;
        }

        sbkDosClose(Handle) ;
    }
}


/* ------------------------------------------------------------------------ */
/*  @@ Usage                                                                */
/*                                                                          */
/*   WriteToFile (int Handle, char far *lpBuf, long lSize)                  */
/*                                                                          */
/*   DESCRIPTION:                                                           */
/*       Write data from buffer to file.                                    */
/*                                                                          */
/*   ENTRY:                                                                 */
/*       Handle - File handle where data to be written to.                  */
/*       lpBuf   - buffer to be written to file.                            */
/*       lSize   - Size to be written to file.                              */
/*                                                                          */
/*   EXIT:                                                                  */
/*       Zero if successful, else returns no-zero.                          */
/*                                                                          */
/* ------------------------------------------------------------------------ */

int WriteToFile (int Handle,char far *lpBuf,long lSize)
{
    int         iRetVal = 0 ;
    WORD        wByteToWrite, wByteWritten = 1 ;


    wByteToWrite = 0x8000 ;

    while (lSize && wByteWritten)
    {

        FPSEG(lpBuf) += (FPOFF(lpBuf) >> 4) ;
        FPOFF(lpBuf) &= 0x000f ;

        if (lSize < 0x8000l)
            wByteToWrite = (WORD)lSize ;

        if (sbkDosWrite(Handle,(char far *)lpBuf,wByteToWrite,
                        (WORD far *)&wByteWritten))
        {
            printf("\nWrite file error.") ;
            iRetVal = 1 ;
            wByteWritten = 0 ;
        }
        else
        {
            if (wByteWritten != wByteToWrite)
            {
                printf("\nDisk full.") ;
                iRetVal = 1 ;
                wByteWritten = 0 ;
            }

            FPOFF(lpBuf) += wByteWritten ;
            lSize -= wByteWritten ;
        }
    }
    return(iRetVal) ;
}
/* End of File */
