/* ------------------------------------------------------------------------ */
/*  @@ Source Documentation                         *** C Version ***       */
/*                                                                          */
/*  TITLE : DEMOVXP.C                                                       */
/*                                                                          */
/*  DESCRIPTION :                                                           */
/*      This program demostrates how to perform voice playback using        */
/*      CT-VOICE.DRV driver. The playback is done using the Extended        */
/*      memory method.It also demonstrates how to set up its own DMA        */
/*      buffer (e.g DMA buffer needed is larger than 4 kilobytes) and       */
/*      making use of the 8k bytes DMA buffer embedded in the               */
/*      driver.                                                             */
/*                                                                          */
/*      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 that the program included the module LOADDRV.C to load         */
/*      the loadable CT-VOICE.DRV into memory.                              */
/*      The input VOC file size is limited by extended memory availabe.     */
/*                                                                          */
/*  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.
*/
#define DMA_UNIT    4
#define DMA_SIZE    ((DMA_UNIT * TWO_KBYTES * 2l) + PARA_ADJ)


/* Local function prototypes */
int PrepareCTVOICEDrv(char * BlasterEnv) ;
int Load2Xms (char *szFilename) ;
void PlayVoiceXM (int xmshd) ;
int SetOutputParam(void) ;


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

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


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

    printf("\nPlayback voice %s at 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())
            {
                /* initialise driver */
                if (!ctvmInit())
                {
                    /* Load file into extended memory */
                    if ((xmshd = Load2Xms(argv[1])) != 0)
                    {
                        PlayVoiceXM(xmshd) ;

                        /* free extended memory handle */
                        sbkFreeXM((WORD)xmshd);
                    }
                    /* terminate driver */
                    ctvmTerminate() ;
                }
                else
                    printf("\nDriver : Error initialiazation.") ;
            }
            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 DMA 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                                                                */
/*                                                                          */
/*  Load2Xms (char *szFilename)                                             */
/*                                                                          */
/*  DESCRIPTION:                                                            */
/*      Load a file to Extended Memory. The routine will first              */
/*      allocate a CMM for data transferring from CMM to XMM.               */
/*                                                                          */
/*  ENTRY:                                                                  */
/*      szFilename - file to be loaded.                                     */
/*                                                                          */
/*  EXIT:                                                                   */
/*      extended memory handle if sucessful else return 0.                  */
/*                                                                          */
/* ------------------------------------------------------------------------ */

int Load2Xms (char *szFilename)
{
    char        far *XmsTransfBuf ;
    int         Handle, xmshd=0 ;
    WORD        wByteToRead, wByteRead ;
    long        lFileSize, lCurXmsOff=0, lDrvSize, lBufSize ;
    VOCHDR      header;


    printf("\nLoading %s into extended memory...",szFilename) ;

    /* 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(CTVOC_EMBDDMABUFSIZE,(DWORD far *)&lBufSize))
    {
        printf("\nDriver : Error retrieving size of embedded DMA buffer.") ;
        return 0 ;
    }

    lBufSize *= (2048 * 4) ;

    /* Retrieving driver size */
    if (ctvmGetParam(CTVOC_DRIVERSIZE,(DWORD far *)&lDrvSize))
    {
        printf("\nDriver : Error retrieving size of driver.") ;
        return 0 ;
    }
    /* making use of embedded buffer as CMM to XMM data transfer area */
    if (((DWORD)(FPOFF(voice_drv) + lDrvSize)) > 0xffff)
        XmsTransfBuf = MK_FP((unsigned)(FPSEG(voice_drv) + 0x1000),
                            (unsigned)(FPOFF(voice_drv) + lDrvSize)) ;
    else
        XmsTransfBuf = MK_FP(FPSEG(voice_drv),
                             (unsigned)(FPOFF(voice_drv) + lDrvSize)) ;

    /* open file */
    if ((Handle = sbkDosOpen(szFilename)) != -1)
    {
        lFileSize = filelength(Handle) ;
        /* allocate extended memory */
        if ((xmshd = sbkAllocXM((WORD)((lFileSize + 1024) / 1024))) == 0)
        {
            printf("\nError allocating extended memory - ") ;
            printf("%s not loaded",szFilename) ;
            sbkDosClose(Handle) ;
            return(xmshd) ;
        }
        /*  retrieve the header and point to the voice data offset  */
        if (!sbkDosRead(Handle,(char far *)&header,
                      sizeof(VOCHDR),(WORD far *)&wByteRead))
        {
            lseek(Handle,(long)header.voice_offset,SEEK_SET);
            lFileSize -= header.voice_offset;

            while (lFileSize)
            {
                wByteToRead = (WORD)lBufSize;

                if (lFileSize < lBufSize)
                    wByteToRead = (WORD)lFileSize ;

                /* read file into data transfer buffer */
                if ((sbkDosRead(Handle,(char far *)XmsTransfBuf,
                            wByteToRead,(WORD far *)&wByteRead)) == 0)
                {
                    /* move data from data transfer buffer to XMM */
                    if (sbkMoveCMtoXM((BYTE far *)XmsTransfBuf,
                             (DWORD)wByteRead,(WORD)xmshd,(DWORD)lCurXmsOff))
                    {
                        lFileSize -= wByteRead;
                        lCurXmsOff += wByteRead;
                    }
                    else
                    {
                        printf("\nHimem.sys : Error moving data to") ;
                        printf(" extended memory.") ;
                        break ;
                    }
                }
                else
                {
                    printf("Dos : Error reading %s file.",szFilename) ;
                    break ;
                }
            }
        }
        else
            printf("Dos : Error reading %s file.",szFilename) ;

        sbkDosClose(Handle) ;
    }
    else
        printf("\nDos : Error open %s file.",szFilename) ;

    if (lFileSize)
    {
        sbkFreeXM((WORD)xmshd) ;
        xmshd = 0 ;
    }

    return (xmshd) ;

}


/* ------------------------------------------------------------------------ */
/*  @@ Usage                                                                */
/*                                                                          */
/*  PlayVoiceXM   (int xmshd)                                               */
/*                                                                          */
/*  Description :                                                           */
/*      Start recording voice to the extended memory.                       */
/*                                                                          */
/*  Entry :                                                                 */
/*      xmshd   - extended memory handle.                                   */
/*                                                                          */
/*  Exit :                                                                  */
/*      none.                                                               */
/*                                                                          */
/* ------------------------------------------------------------------------ */

void PlayVoiceXM (int xmshd)
{
    WORD    wKey, wIOHandle ;
    int     fExit = 0, Pause = 0 ;


    /* Set output parameters */
    wIOHandle = (WORD)SetOutputParam() ;
    if ((int)wIOHandle != -1)
    {
        /* turn on speaker */
        ctvmSetSpeaker(1) ;

        /* start outputing voice from extended memory */
        if (!ctvmOutputXM(wIOHandle,(WORD)xmshd,0L))
        {
            printf("\nStart playing back...") ;
            printf("\n\t[Esc] - to stop\n");
            printf("\t[P  ] - to pause\n");
            printf("\t[C  ] - to continue\n");

            /* loop until ESC key is pressed */
            while (!fExit)
            {
                if(!ct_voice_status)
                    fExit = 1 ;

                /* get user input */
                if (sbkBiosKeybrd(KEYBRD_READY))
                {
                    wKey = (WORD)(sbkBiosKeybrd((WORD)KEYBRD_READ) & 0xff) ;

                    switch (wKey)
                    {
                        case 0x1b :
                            printf ("\nVoice stop.") ;
                            ctvmStop((WORD)wIOHandle) ;
                            fExit = 1 ;
                            break ;

                        case 'P' :
                        case 'p' :
                            if (!Pause)
                            {
                                printf("\nVoice pauses...") ;
                                ctvmPause((WORD)wIOHandle) ;
                                Pause = 1 ;
                            }
                            break ;

                        case 'C' :
                        case 'c' :
                            if (Pause)
                            {
                                printf("\nVoice continues...") ;
                                ctvmContinue((WORD)wIOHandle) ;
                                Pause = 0 ;
                            }
                            break ;
                    }
                }
            }
        }
        else
        {
            printf("\nDriver : Error output voice.") ;
            printf(" - %x",ctvmGetDrvError()) ;
        }

        ctvmSetSpeaker(0) ;
    }
}


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

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


    /* 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))
            {
                /* Allocate two 8k DMA buffer */
                if ((lpDmaBuf = sbkAllocMem((DWORD)(DMA_SIZE * 2))) != NULL)
                {
                    /* convert the pointer to 32-bit linaer address */
                    dwValue = (DWORD)((DWORD)FPSEG(lpDmaBuf) << 4) +
                                       FPOFF(lpDmaBuf) ;

                    /* set DMA buffer */
                    if (ctvmSetDMABuffer(wIOHandle,dwValue,(WORD)DMA_UNIT))
                    {
                        /* the first DMA buffer may has crossed segment */
                        /* try the second buffer */
                        dwValue += DMA_SIZE ;
                        if (!ctvmSetDMABuffer(wIOHandle,dwValue,DMA_UNIT))
                            return ((int)wIOHandle) ;
                        printf("\nDriver : Error setting DMA buffer.") ;
                        sbkFreeMem(lpDmaBuf) ;
                    }
                    else
                        return ((int)wIOHandle) ;
                }
                else
                    printf("\nDos : Error allocating DMA buffer.") ;
            }
            else
                printf ("\nError setting ct_voice_status.") ;
        }
        else
            printf ("\nI/O voice handle not available.") ;
    }
    else
        printf ("\nError retrieving I/O voice handles.") ;

    return (-1) ;
}
/* end of file */
