/* ------------------------------------------------------------------------ */
/*  @@ Source Documentation                         *** C Version ***       */
/*                                                                          */
/*  TITLE : DEMOVXR.C                                                       */
/*                                                                          */
/*  DESCRIPTION :                                                           */
/*      This program demostrates how to perform voice recording using       */
/*      CT-VOICE.DRV driver. The record is done using the Extended          */
/*      memory method.                                                      */
/*                                                                          */
/*      Data moving from extended memory is done by invoking XMS            */
/*      driver. The Input sources are CD and MIC.                           */
/*                                                                          */
/*      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 CT-VOICE.DRV into memory.                              */
/*      The VOC file size to be recorded is set by xmsbufSize.              */
/*                                                                          */
/*  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 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.
## Since this program uses default DMA buffer, increase DMA_UNIT
## will cause no effect.
*/
#define DMA_UNIT    4
#define DMA_SIZE    ((DMA_UNIT * TWO_KBYTES * 2l) + PARA_ADJ)


/* Local function prototypes */
int PrepareCTVOICEDrv(char * BlasterEnv) ;
int RecordVoice (WORD xmshd,WORD bufsize) ;
int SetInputParam(void) ;
void SaveVoiceFile (char *szFilename,WORD xmshd) ;


/* Global variable */
volatile WORD ct_voice_status ;         /* i/o voice status */
char far * lpOrigin ;                   /* origin pointer for driver buffer */

main(int argc, char * argv[])
{
    WORD xmshd, xmsbufSize = 300 ;      /* 300 kbytes */
    char * BlasterEnv ;


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

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

    /* Retrieve the BLASTER environment settings */
    if ((BlasterEnv = getenv("BLASTER")) != NULL)
    {
        /* Load the CT-VOICE driver into memory */
        if (!PrepareCTVOICEDrv(BlasterEnv))
        {
            /* Himem.sys laoded ? */
            if (sbkGetXMSEntry())
            {
                /* allocate extended memory */
                if ((xmshd = (WORD)sbkAllocXM(xmsbufSize)) != 0)
                {
                    if (!ctvmInit())
                    {
                        /* record and save */
                        if (!RecordVoice(xmshd,xmsbufSize))
                            SaveVoiceFile(argv[1],xmshd) ;

                        ctvmTerminate() ;
                    }
                    else
                        printf("\nDriver : Error initialization.") ;

                    /* free allocated extended memory */
                    sbkFreeXM(xmshd);
                }
                else
		    printf("\nHimem.sys : Error allocating extended memory.") ;
            }
            else
                printf ("\nHimem.sys not installed.") ;
        }
    }
    else
        printf("\nBLASTER environment not set or incomplete or invalid.");

    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 with embedded buffer */
    if ((voice_drv = sbkLoadDriver("CT-VOICE.DRV",UNUSED,
                        (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                                                                */
/*                                                                          */
/*  int RecordVoice (WORD xmshd, WORD bufsize)                              */
/*                                                                          */
/*  Description :                                                           */
/*      Start recording voice to the extended memory.                       */
/*                                                                          */
/*  Entry :                                                                 */
/*      xmshd   - extended memory handle.                                   */
/*      bufsize - extended memory buffer size. (in unit of kilo bytes)      */
/*                                                                          */
/*  Exit :                                                                  */
/*      zero if successful else return non-zero.                            */
/*                                                                          */
/* ------------------------------------------------------------------------ */

int RecordVoice (WORD xmshd, WORD bufsize)
{
    int     iRetVal = 1 ;
    WORD    wIOHandle ;


    wIOHandle = (WORD)SetInputParam() ;
    if ((int)wIOHandle != -1)
    {
        ctvmSetSpeaker(0) ;

        /* Start input to extended memory */
        if (!ctvmInputXM(wIOHandle,xmshd,0l,bufsize))
        {
            iRetVal = 0 ;
            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(wIOHandle) ;
                }
            }
            printf("\nRecording end.") ;
        }
        else
        {
            printf("\nDriver : Error input voice.") ;
            printf(" - %x",ctvmGetDrvError()) ;
        }
    }
    return(iRetVal) ;
}


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

int SetInputParam(void)
{
    DWORD     dwValue ;
    WORD      wIOHandle ;


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

            /* Set the I/O voice status - ct_voice_status */
            if (!ctvmSetIOParam(wIOHandle,CTVOC_IO_LPSTATUSWORD,
                (DWORD)(WORD far *)&ct_voice_status))
            {
                /* 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) ;
            }

            printf ("\nError setting ct_voice_status.") ;
        }
        else
            printf ("\nI/O voice handle not available.") ;
    }
    else
        printf ("\nError retrieving I/O voice handles.") ;

    return (-1) ;
}


/* ------------------------------------------------------------------------ */
/*  @@ Usage                                                                */
/*                                                                          */
/*   SaveVoiceFile (char *szFilename, WORD xmshd)                           */
/*                                                                          */
/*   DESCRIPTION:                                                           */
/*       Save recorded voice from memory to file.                           */
/*                                                                          */
/*   ENTRY:                                                                 */
/*       szFilename  - file name to be saved to.                            */
/*       xmshd   - recorded voice XMS handle.                               */
/*                                                                          */
/*   EXIT:                                                                  */
/*       None                                                               */
/*                                                                          */
/* ------------------------------------------------------------------------ */

void SaveVoiceFile (char *szFilename, WORD xmshd)
{
    long        lXferBufSize = 8192 ;
    char        far * lpXmsXferBuf ;
    int         Handle ;
    long        lVoiceSize = 0L ;
    long        lCurXmsOff = 0L;
    WORD        wByteToMove, wByteMove;
    VOCHDR      stHeader ;


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

    if ((Handle = sbkDosCreate(szFilename)) == -1)
        printf("\nDos : Error creating %s .",szFilename) ;
    else
    {
        printf("\nStart saving %s...",szFilename);

        /* write voice header */
        if (!sbkDosWrite(Handle,(void far *)&stHeader,sizeof(VOCHDR),
                         (WORD far *)&wByteMove))
        {
            /* allocate memory for XMS to CMM data transfer */
            if ((lpXmsXferBuf = sbkAllocMem(lXferBufSize + 16)) == NULL)
            {
                printf("Dos : Error allocating memory for data transfer.\n");
                return ;
            }

            /* move data length from recorded XMS buffer     */
            if (sbkMoveXMtoCM((BYTE far *)lpXmsXferBuf,(DWORD)4L,
                               xmshd,(DWORD)0L))
            {
                /* retrieve the recorded data block size */
                lVoiceSize = *(lpXmsXferBuf + 3) ;
                lVoiceSize <<= 16 ;
                lVoiceSize += *(unsigned far *)(lpXmsXferBuf + 1) ;

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

                lVoiceSize += 5 ;
            }

            while (lVoiceSize)
            {
                wByteToMove = (WORD)lXferBufSize;

                if (lVoiceSize < lXferBufSize)
                    wByteToMove = (WORD)lVoiceSize;

                if (sbkMoveXMtoCM((BYTE far *)lpXmsXferBuf,
                   (DWORD)wByteToMove,(WORD)xmshd,(DWORD)lCurXmsOff))
                {
                    /* write to the file */
                    if (!sbkDosWrite(Handle,(char far *)lpXmsXferBuf,
                                  wByteToMove,(WORD far *)&wByteMove))
                    {
                        if (wByteMove != wByteToMove)
                        {
                            printf("\nDisk full.") ;
                            break ;
                        }
                        else
                        {
                            lVoiceSize -= wByteMove;
                            lCurXmsOff += wByteMove;
                        }
                    }
                    else
                    {
                        printf("\nWrite %s file error.",szFilename) ;
                        break ;
                    }
                }
                else
                {
                    printf("\nDos : Error moving data from XMS memory.") ;
                    break ;
                }
            }
            /* free buffer */
            sbkFreeMem(lpXmsXferBuf) ;
        }
        sbkDosClose(Handle) ;
    }
}
/* end of file */
