/* ------------------------------------------------------------------------ */
/*  @@ Source Documentation                         *** C Version ***       */
/*                                                                          */
/*  TITLE : MIDIIN.C                                                        */
/*                                                                          */
/*  DESCRIPTION :                                                           */
/*      This program demostrates how to use the CTMIDI.DRV driver           */
/*      to input MIDI codes from external MIDI instrunment.                 */
/*                                                                          */
/*      Note that the BLASTER environment has to be set before executing    */
/*      this program.                                                       */
/*                                                                          */
/*  Note :                                                                  */
/*      For Turbo C, Turbo C++ and Borland C++ compilers,                   */
/*      use switches -N- and -B.                                            */
/*                                                                          */
/*  Copyright (c) Creative Technology Ltd, 1993. All rights reserved.       */
/*                                                                          */
/* ------------------------------------------------------------------------ */

#include  <io.h>
#include  <dos.h>
#include  <bios.h>
#include  <fcntl.h>
#include  <stdlib.h>
#include  <io.h>
#include  <conio.h>
#include  <dos.h>

#include  "sbkmidi.h"
#include  "sbkmacro.h"
#include  "sbkx.h"
#include  "Loaddrv.c"

#define MAX_EVENT       8192    /* input temporary storage size */
#define NOT_USED        0

/* Local functions */
int PrepareCTMIDIDrv(char * BlasterEnv) ;
void InputMidi (char * szRawFile) ;
void SaveFile (char * szFilename, DWORD far * lpMidiBuffer) ;
int pascal far CallBack(char far * lpMidiCode,DWORD dwToken) ;
void DispHexChar (BYTE bDispChar) ;


/* Global variable */
volatile WORD wMidiInStatus ;       /* External Midi input status */
char far * lpOrigin ;               /* original pointer of driver buffer */


void main (int argc, char *argv[])
{
    char * BlasterEnv ;
    char * szRawFile = NULL ;


    printf("\nCreative Demo External MIDI Instrument Input.") ;

    if (argc > 1)
    {
        printf("\nRaw MIDI code will be saved into <%s> ",argv[1]) ;
        szRawFile = argv[1] ;
    }
    else
    {
        printf("\nUsage : MIDIIN [record.raw]") ;
        printf("\n\tWhere with [record.raw] specified, "  \
               "MIDI codes will be saved.");
    }

    if ((BlasterEnv = getenv("BLASTER")) == NULL)
    {
        printf("\nBLASTER environment not set.");
        exit(1);
    }

    /* Load CTMIDI.DRV into memory */
    if (!PrepareCTMIDIDrv(BlasterEnv))
    {
        /* Initialize CTMIDI.DRV driver */
        if (!ctmdInit())
        {
            /* Get Midi input */
            InputMidi(szRawFile) ;

            /* Terminate CTMIDI.DRV driver */
            ctmdTerminate() ;
        }
    }
}


/* ------------------------------------------------------------------------ */
/*  @@ Usage                                                                */
/*                                                                          */
/*  PrepareCTMIDIDrv(char * BlasterEnv)                                     */
/*                                                                          */
/*  Description :                                                           */
/*      Load and endorses CTMIDI.DRV.                                       */
/*                                                                          */
/*  Entry :                                                                 */
/*      BlasterEnv - pointer to the BLASTER enviroment setting.             */
/*                                                                          */
/*  Exit :                                                                  */
/*      zero if sucessful, non-zero otherwise.                              */
/*                                                                          */
/* ------------------------------------------------------------------------ */

int PrepareCTMIDIDrv(char * BlasterEnv)
{
    /* load CTMIDI.DRV driver into memory. */
    if ((CTmidiDrv = (char far *)sbkLoadDriver("CTMIDI.DRV",UNUSED,(char far **)&lpOrigin)) != NULL)
    {
        if (ctmdGetDrvVer() >= 0x0100)
        {
            if (!ctmdGetEnvSettings((char far *)BlasterEnv))
                return(0) ;
            else
                printf("\nBLASTER environment is not valid") ;
        }
        else
        {
            printf("\nInvalid CTMIDI.DRV - ") ;
            printf("I need CTMIDI.DRV version 1.00 or higher.\n") ;
        }
    }
    return(1) ;
}


/* ------------------------------------------------------------------------ */
/*  @@ Usage                                                                */
/*                                                                          */
/*   void InputMidi (char * szRawFile)                                      */
/*                                                                          */
/*   DESCRIPTION:                                                           */
/*       Input Midi code.                                                   */
/*                                                                          */
/*   ENTRY:                                                                 */
/*       lpRawFile - pointer to the file name the raw data to be saved.     */
/*                                                                          */
/*   EXIT:                                                                  */
/*      none.                                                               */
/*                                                                          */
/* ------------------------------------------------------------------------ */

void InputMidi (char * szRawFile)
{
    DWORD far * lpMidiBuffer = NULL ;


    if (ctmdResetMidiDriver())
        exit(4) ;

    /* Set MIDI input status address */
    if (!ctmdSetInputStatusAddx((WORD far *)&wMidiInStatus))
    {
        /* Set time stamping mode - default is DIFFERENTIATE_MODE */
        /*ctmdSetTimeStampMode (ELAPSED_MODE) ;*/

        /* Input midi to file */
        if (szRawFile != NULL)
        {
            /* allocate temporary buffer */
            lpMidiBuffer = (DWORD far *)
                    sbkAllocMem((long)(MAX_EVENT * sizeof(DWORD))) ;

            if (lpMidiBuffer == NULL)
            {
                printf("\nError allocating MIDI input buffer.") ;
                return ;
            }

            /* set the first DWORD to 0 */
                *lpMidiBuffer = 0l ;

            /* set input buffer */
            if (ctmdSetMidiInputBuffer(lpMidiBuffer,(DWORD)MAX_EVENT))
            {
                printf("\nError setting MIDI input buffer.") ;
                sbkFreeMem(lpMidiBuffer) ;
                return ;
            }
            printf("\nNumber of MIDI events can be stored is %d",MAX_EVENT-1) ;
        }

        /* set MIDI call back function to print out MIDI code */
        if (ctmdSetMidiCallBackFunct((MIDICALLBACK)CallBack, NOT_USED))
        {
            printf("\nError setting up call back function.") ;
            return ;
        }

        /* start MIDI input */
        if (!ctmdStartMidiInput())
        {
            printf("\nPress [ESC] to stop...\n") ;
            /* poll for MIDI input status */
            while (wMidiInStatus)
            {
                /* stop MIDI input */
                if (sbkBiosKeybrd(KEYBRD_READY))

                    if ((sbkBiosKeybrd(KEYBRD_READ) & 0xff) == 27)
                        ctmdStopMidiInput() ;
            }
            printf("\nInput end.") ;
        }
        else
        {
            printf("Error during MIDI input.") ;
            sbkFreeMem(lpMidiBuffer) ;
            return ;
        }

        /* save into file */
        if (szRawFile)
        {
            SaveFile(szRawFile,lpMidiBuffer) ;
            sbkFreeMem(lpMidiBuffer) ;
        }
    }
    else
        printf("\nError setting MIDI input status address.") ;
}


/* ------------------------------------------------------------------------ */
/*  @@ Usage                                                                */
/*                                                                          */
/*   void SaveFile (char *szFilename, DWORD far * lpMidiBuffer)             */
/*                                                                          */
/*   DESCRIPTION:                                                           */
/*      Save MIDI code into file.                                           */
/*                                                                          */
/*   ENTRY:                                                                 */
/*      szFileName :- pointer to the file to be saved.                      */
/*      lpMidiBuffer :- pointer to MIDI code buffer.                        */
/*                                                                          */
/*   EXIT:                                                                  */
/*      none.                                                               */
/*                                                                          */
/* ------------------------------------------------------------------------ */

void SaveFile (char *szFilename, DWORD far * lpMidiBuffer)
{
    int         Handle ;
    WORD    wByteToWrite, wByteWritten = 1 ;
    DWORD   dwFileSize ;


    printf("\nSaving file < %s > ...\n", szFilename) ;

    /* open file */
    if ((Handle = sbkDosCreate((char far *)szFilename)) != -1)
    {
        /* file size */
        dwFileSize = (DWORD)(*(lpMidiBuffer ++) * sizeof(DWORD));

        wByteToWrite = 0x8000 ;

        while (dwFileSize && wByteWritten)
        {
            FPSEG(lpMidiBuffer) += (FPOFF(lpMidiBuffer) >> 4) ;
            FPOFF(lpMidiBuffer) &= 0x000f ;

            if (dwFileSize < (DWORD)wByteToWrite)
                wByteToWrite = (WORD)dwFileSize ;

            if (sbkDosWrite(Handle,(char far *)lpMidiBuffer,wByteToWrite,
                            (WORD far *)&wByteWritten))
            {
                printf("\nDOS : Read file error.");
                wByteWritten = 0 ;
            }
            else
            {
                if (wByteWritten != wByteToWrite)
                {
                    printf("\nDisk is full. Write file aborted.") ;
                    wByteWritten = 0 ;
                }

                FPOFF(lpMidiBuffer) += wByteWritten ;
                dwFileSize -= wByteWritten ;
            }
        }
        sbkDosClose(Handle) ;
    }
    else
        printf("\nCreate %s failed.",szFilename) ;
}

/* ------------------------------------------------------------------------ */
/*  @@ Usage                                                                */
/*                                                                          */
/*  int pascal far  CallBack (char far * lpMidiCode,DWORD dwToken)          */
/*                                                                          */
/*  Description :                                                           */
/*      Call back function by CTMIDI.DRV driver which displays the MIDI     */
/*      codes to the screen. The method of displaying is as below:-         */
/*                                                                          */
/*          Code-Time_stamp                                                 */
/*      where                                                               */
/*          Code       :- Status, data, control number or control value     */
/*          Time_stamp :- Signifies the time (in milisecond) the Code is    */
/*                        received. Either in DIFFERENTIATE_MODE or         */
/*                        ELAPSED_MODE.                                     */
/*                                                                          */
/*  Entry :                                                                 */
/*      lpMidiCode   :- far pointer to the MIDI code.                       */
/*                      lower one byte is the Code and upper three bytes    */
/*                      are Time_stamp.                                     */
/*      dwToken      :- contains the value which passed to the function     */
/*                      ctmdSetMidiCallBackFunct through the second         */
/*                      parameter. For example If default data segment      */
/*                      need to be accessed, an address of the default      */
/*                      data segment can be passed as second parameter      */
/*                      during call to ctmdSetMidiCallBackFunct function.   */
/*                                                                          */
/*  Exit :                                                                  */
/*      none.                                                               */
/*                                                                          */
/*  NOTE !!!!                                                               */
/*      1. Call back function must be in Pascal calling convention.         */
/*      2. Turn check_stack off.                                            */
/*      3. Data segment is belong to CTMIDI.DRV driver. You need to swap    */
/*         to application data segment if you want to access global         */
/*         variables.                                                       */
/*      4. Stack segment is belong to CTMIDI.DRV driver.                    */
/*      5. Cannot call DOS INT 21 function since it is not re-entrance.     */
/*                                                                          */
/* ------------------------------------------------------------------------ */

#if defined _MSC_VER
    #define ASM     _asm
#else
    #define ASM     asm
#endif

#pragma check_stack(off)
int FAR PASCAL CallBack (char far * lpMidiCode,DWORD dwToken)
{
    DispHexChar(*lpMidiCode) ;

    ASM     mov     ah,0EH
    ASM     mov     bl,7
    ASM     mov     al,'-'
    ASM     int     10H

    DispHexChar(*(lpMidiCode+3)) ;
    DispHexChar(*(lpMidiCode+2)) ;
    DispHexChar(*(lpMidiCode+1)) ;

    ASM     mov     ah,0EH
    ASM     mov     bl,7
    ASM     mov     al,' '
    ASM     int     10H

    return ((int)dwToken);
}
#pragma check_stack()


/* ------------------------------------------------------------------------ */
/*  Display Hexadecimal character                                           */
/* ------------------------------------------------------------------------ */

#pragma check_stack (off)

void DispHexChar (BYTE bDispChar)
{

    ASM     push    ax
    ASM     push    bx
    ASM     push    dx

    ASM     mov     dh,0
    ASM     mov     dl,bDispChar

    ASM     push    dx
    ASM     shr     dx,1            /* shift the high nibble to lsb */
    ASM     shr     dx,1
    ASM     shr     dx,1
    ASM     shr     dx,1
    ASM     and     dx,0FH

    ASM         clc                  /* clear CARRY flag */
    ASM         cmp     dl,9
    ASM         jg          DISPH10

    ASM         add     dl,'0'
    ASM         jmp     DISPH20

    DISPH10:
    ASM         sub     dl,0ah
    ASM         add     dl,'A'

    DISPH20:
    ASM     mov     al,dl
    ASM     mov     ah,0EH
    ASM     mov     bl,7
    ASM     int     10H


    ASM     pop     dx
    ASM     and     dx,0FH

    ASM         clc                      /* clear CARRY flag */
    ASM         cmp     dl,9
    ASM         jg          DISPH30

    ASM         add     dl,'0'
    ASM         jmp     DISPH40

    DISPH30:
    ASM         sub     dl,0ah
    ASM         add     dl,'A'

    DISPH40:
    ASM     mov     al,dl
    ASM     mov     ah,0EH
    ASM     mov     bl,7
    ASM     int     10H

    ASM     pop     dx
    ASM     pop     bx
    ASM     pop     ax

}

#pragma check_stack ()
/* End of file */
