/****************************************************************************

   File              : sosmawe.c

   Purpose           : Module to handle AWE32 .SBK file uploads

   Date              : 1-20-95

   Programmer(s)     : Don Fowler

   Last Updated      : 1-29-95

****************************************************************************
               Copyright(c) 1992,1995 Human Machine Interfaces 
                            All Rights Reserved
****************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <fcntl.h> 
#include <bios.h>
#include <io.h>
#include <malloc.h>
#include <conio.h>
#include <ctype.h>
#include "sosm.h" 

WORD  sosMIDIAWE32SetSBKFile( WORD, PSTR );
WORD  sosMIDIAWE32ReleaseSBKFiles( WORD );
WORD  sosMIDIAWE32NoteOn( WORD, WORD, WORD, WORD, WORD, WORD );
WORD  sosMIDIAWE32NoteOff( WORD, WORD, WORD );

// maximum number of .SBK files that can be set on the chip
#define _MAX_SBKS   0x10

// offset into slot list for .SBK files to start
#define _SBK_SLOT_OFFSET  0x01

// size of buffer needed to read in a chunk of .SBK file  
#define _READ_BUFFER_SIZE  0x2000

// pointer to preset data for awe32 
#ifdef BORLAND
PSTR _lpSOSMIDIAwe32PresetBuffer[ _SOS_MIDI_MAX_DRIVERS ][ _MAX_SBKS ] = {
#else
LPSTR _lpSOSMIDIAwe32PresetBuffer[ _SOS_MIDI_MAX_DRIVERS ][ _MAX_SBKS ] = {
#endif

   { _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL,
   _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL },
   { _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL,
   _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL },
   { _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL,
   _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL },
   { _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL,
   _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL },
   { _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL,
   _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL, _NULL }

                                                     };

// index into list of presets to the currently available slot, 
// start the index at 0 to leave slot 0 open for general midi
// rom on the AWE32
WORD  _wSOSMIDIAwe32PresetIndex[ _SOS_MIDI_MAX_DRIVERS ] = {

   _SBK_SLOT_OFFSET, _SBK_SLOT_OFFSET, _SBK_SLOT_OFFSET, 
   _SBK_SLOT_OFFSET, _SBK_SLOT_OFFSET
                                                           };

/***************************************************************************

Function    :  WORD sosMIDIAWE32SetSBKFile

Parameters  :  WORD hDriver
                  Handle of SOS driver to set SBK file on.
               PSTR szFileName
                  Name of .SBK file to set.
 
Returns     :  -1 if error; otherwise, slot that the .SBK file was 
               assigned to on the AWE32.

Description :  Stream a .SBK file onto the awe32 and return the slot 
               streamed to.    

****************************************************************************/

WORD sosMIDIAWE32SetSBKFile( WORD hDriver, PSTR szFileName )
{
   WORD  wIndex;
   WORD  hFile;
   WORD  wReadSize;
   PSTR  pDataPtr;
#ifdef BORLAND
   SFAR lpTemp;
#endif

   // attempt to find a slot to use for the .SBK file
   if( _wSOSMIDIAwe32PresetIndex[ hDriver ] == ( _MAX_SBKS - 1 ) )
      return( -1 );
       
   // attempt to open the sbk file 
   if( ( hFile = open( ( const char * )szFileName, O_RDONLY | O_BINARY ) ) == -1 )
      return( -1 );

   // attempt to allocate a buffer to use for transfer
   if( !( pDataPtr = ( PSTR )malloc( _READ_BUFFER_SIZE ) ) )
   {
      // close the file
      close( hFile );

      // return an error
      return( -1 );
   }

   // open the awe32 stream
#ifdef BORLAND
   if( ( wReadSize = sosMIDIDRVCall32Func( _lpSOSMIDIDrvFunction[ hDriver ][ 5 ],
      lpTemp, _wSOSMIDIAwe32PresetIndex[ hDriver ], 0x00 ) ) == -1 )
#else
   if( ( wReadSize = _lpSOSMIDIDrvFunction[ hDriver ][ 5 ]( _NULL,
      _wSOSMIDIAwe32PresetIndex[ hDriver ], 0x00 ) ) == -1 )
#endif
   {
      // free the previously allocated memory
      free( pDataPtr );

      // close the file
      close( hFile );

      // return error
      return( -1 );
   }

   // read in a chunk of data from the file
   if( read( hFile, pDataPtr, wReadSize ) == -1 )
      return( -1 );

   // get the sample data seek location
#ifdef BORLAND
   lpTemp.sel = getDS();
   lpTemp.off = pDataPtr;
   if( ( wIndex = sosMIDIDRVCall32Func( _lpSOSMIDIDrvFunction[ hDriver ][ 8 ],
      lpTemp, _wSOSMIDIAwe32PresetIndex[ hDriver ], 0x00 ) ) == -1 )
#else
   if( ( wIndex = _lpSOSMIDIDrvFunction[ hDriver ][ 8 ]( ( LPSTR )pDataPtr,
      _wSOSMIDIAwe32PresetIndex[ hDriver ], 0x00 ) ) == -1 )
#endif
   {
      // free the previously allocated memory
      free( pDataPtr );

      // close the file
      close( hFile );

      // return error
      return( -1 );
   }

   // seek the file to the sample location
   if( lseek( hFile, wIndex, SEEK_SET ) == -1 )
   {
      // close the file
      close( hFile );

      // free the preset memory
      free( ( PSTR )_lpSOSMIDIAwe32PresetBuffer[ hDriver ][ _wSOSMIDIAwe32PresetIndex[ hDriver ] ] );

      // return an error
      return( -1 );
   }

   // send chunks of data to the driver
   do
   {
      // read in a chunk of data from the file
      if( read( hFile, pDataPtr, wReadSize ) == -1 )
         return( -1 );

      // send the data to the driver
#ifdef BORLAND
      lpTemp.sel = getDS();
      lpTemp.off = pDataPtr;
      if( ( wReadSize = sosMIDIDRVCall32Func( _lpSOSMIDIDrvFunction[ hDriver ]
         [ 6 ], lpTemp, _wSOSMIDIAwe32PresetIndex[ hDriver ], 0x00 ) ) == -1 )
#else
      if( ( wReadSize = _lpSOSMIDIDrvFunction[ hDriver ][ 6 ](
         ( LPSTR )pDataPtr, _wSOSMIDIAwe32PresetIndex[ hDriver ], 0x00 ) ) == -1 )
#endif
      {
         // close the file
         close( hFile );

         // free the memory
         free( pDataPtr );

         // return an error
         return( -1 ); 
      }
   } while( wReadSize );  

   // free the temporary memory buffer
   free( pDataPtr );

   // get the preset data size
#ifdef BORLAND
   wReadSize = sosMIDIDRVCall32Func( _lpSOSMIDIDrvFunction[ hDriver ][ 7 ],
      lpTemp, 0x00, 0x00 );
#else
   wReadSize = _lpSOSMIDIDrvFunction[ hDriver ][ 7 ]( _NULL, 0x00, 0x00 );
#endif

   // get the preset location in the file
#ifdef BORLAND
   lpTemp.sel = getDS();
   lpTemp.off = &wIndex;
   sosMIDIDRVCall32Func( _lpSOSMIDIDrvFunction[ hDriver ][ 9 ], lpTemp,
      0x00, 0x00 );
#else
   _lpSOSMIDIDrvFunction[ hDriver ][ 9 ]( ( LPSTR )&wIndex, 0x00, 0x00 );
#endif

   // allocate the memory for the preset information
#ifdef BORLAND
   if( !( _lpSOSMIDIAwe32PresetBuffer[ hDriver ][ _wSOSMIDIAwe32PresetIndex[ hDriver ] ] =
      ( PSTR )malloc( wReadSize ) ) )
#else
   if( !( _lpSOSMIDIAwe32PresetBuffer[ hDriver ][ _wSOSMIDIAwe32PresetIndex[ hDriver ] ] =
      ( LPSTR )malloc( wReadSize ) ) )
#endif
   {
      // close the file
      close( hFile );

      // return an error
      return( -1 );
   }

   // seek the file to the preset location
   if( lseek( hFile, wIndex, SEEK_SET ) == -1 )
   {
      // close the file
      close( hFile );

      // free the preset memory
      free( ( PSTR )_lpSOSMIDIAwe32PresetBuffer[ hDriver ][ _wSOSMIDIAwe32PresetIndex[ hDriver ] ] );

      // return an error
      return( -1 );
   }

   // read in the preset information
   if( read( hFile, ( PSTR )_lpSOSMIDIAwe32PresetBuffer[ hDriver ][ 
      _wSOSMIDIAwe32PresetIndex[ hDriver ] ], wReadSize ) == -1 )
   {
      // close the file
      close( hFile );

      // free the preset memory
      free( ( PSTR )_lpSOSMIDIAwe32PresetBuffer[ hDriver ][ _wSOSMIDIAwe32PresetIndex[ hDriver ] ] );

      // return an error
      return( -1 );
   }

   // send the preset information to the driver
#ifdef BORLAND
   lpTemp.sel = getDS();
   lpTemp.off = _lpSOSMIDIAwe32PresetBuffer[ hDriver ][ _wSOSMIDIAwe32PresetIndex[ hDriver ] ];
   if( ( sosMIDIDRVCall32Func( _lpSOSMIDIDrvFunction[ hDriver ][ 10 ],
      lpTemp, 0x00, 0x00 ) ) == -1 ) 
#else
   if( ( _lpSOSMIDIDrvFunction[ hDriver ][ 10 ]( ( LPSTR )
      _lpSOSMIDIAwe32PresetBuffer[ hDriver ][ _wSOSMIDIAwe32PresetIndex[ hDriver ] ], 0x00, 0x00 ) ) == -1 )
#endif
   {
      // free the preset memory
      free( ( PSTR )_lpSOSMIDIAwe32PresetBuffer[ hDriver ][ _wSOSMIDIAwe32PresetIndex[ hDriver ] ] );

      // close the file
      close( hFile );

      // return an error
      return( -1 );
   }

   // close the SBK file
   close( hFile );

   // increment the preset buffer index to the next available slot
   _wSOSMIDIAwe32PresetIndex[ hDriver ]++;

   // return no error 
   return( _wSOSMIDIAwe32PresetIndex[ hDriver ] );
}

/***************************************************************************

Function    :  WORD sosMIDIAWE32ReleaseAllSBKFiles

Parameters  :  WORD hDriver
                  Handle of SOS driver to release .SBK files from
 
Returns     :  -1 if error; otherwise, _ERR_NO_ERROR

Description :  Release all of the memory associated to the .SBK files
               uploaded to the awe32.   

****************************************************************************/

WORD sosMIDIAWE32ReleaseSBKFiles( WORD hDriver )
{
   WORD  wIndex;
#ifdef BORLAND
   SFAR  lpTemp;
#endif

   // call the driver to release all of the .SBK files
#ifdef BORLAND
   if( sosMIDIDRVCall32Func( _lpSOSMIDIDrvFunction[ hDriver ][ 9 ], lpTemp,
      0x01, 0x00 ) == -1 )
#else
   if( _lpSOSMIDIDrvFunction[ hDriver ][ 9 ]( ( LPSTR )_NULL, 0x01, 0x00 )
      == -1 )
#endif
      return( -1 );

   // free the memory allocated for the awe32 preset information 
   for( wIndex = _SBK_SLOT_OFFSET; wIndex < _wSOSMIDIAwe32PresetIndex[ hDriver ]; 
      wIndex++ )
      free( ( PSTR )_lpSOSMIDIAwe32PresetBuffer[ hDriver ][ wIndex ] ); 

   // reset the available slot index
   _wSOSMIDIAwe32PresetIndex[ hDriver ] = _SBK_SLOT_OFFSET;

   // return no error 
   return( _ERR_NO_ERROR );
}

/***************************************************************************

Function    :  WORD sosMIDIAWE32NoteOn

Parameters  :  WORD hDriver
                  Handle of SOS driver
               WORD wSlot
                  .SBK file slot to associate patch to
               WORD wChannel
                  Channel to use
               WORD wPatch
                  Patch to use
               WORD wNote
                  MIDI relative pitch to use
               WORD wVelocity
                  Velocity to use
 
Returns     :  -1 if error; otherwise, _ERR_NO_ERROR

Description :  Turn a note on 

****************************************************************************/

WORD sosMIDIAWE32NoteOn( WORD hDriver, WORD wSlot, WORD wChannel, 
   WORD wPatch, WORD wNote, WORD wVelocity )
{
   BYTE szMIDIData[ 0x10 ];

   // setup the midi data structure to associate a slot to a channel
   szMIDIData[ 0 ] = 0xb0 | wChannel; 
   szMIDIData[ 1 ] = 0x00;
   szMIDIData[ 2 ] = wSlot;
#ifdef BORLAND
   sosMIDISendMIDIData( hDriver, ( PSTR )szMIDIData, 0x03 );
#else
   sosMIDISendMIDIData( hDriver, ( LPSTR )szMIDIData, 0x03 );
#endif

   // select the patch for the channel
   szMIDIData[ 0 ] = 0xc0 | wChannel; 
   szMIDIData[ 1 ] = wPatch;
#ifdef BORLAND
   sosMIDISendMIDIData( hDriver, ( PSTR )szMIDIData, 0x02 );
#else
   sosMIDISendMIDIData( hDriver, ( LPSTR )szMIDIData, 0x02 );
#endif

   // turn the note on with the correct pitch and attack
   szMIDIData[ 0 ] = 0x90 | wChannel; 
   szMIDIData[ 1 ] = wNote;
   szMIDIData[ 2 ] = wVelocity;
#ifdef BORLAND
   sosMIDISendMIDIData( hDriver, ( PSTR )szMIDIData, 0x02 );
#else
   sosMIDISendMIDIData( hDriver, ( LPSTR )szMIDIData, 0x02 );
#endif
                                 
   // return no error 
   return( _ERR_NO_ERROR );
}

/***************************************************************************

Function    :  WORD sosMIDIAWE32NoteOff

Parameters  :  WORD hDriver
                  Handle of SOS driver
               WORD wChannel
                  Channel to use
               WORD wNote
                  MIDI relative pitch to use
 
Returns     :  -1 if error; otherwise, _ERR_NO_ERROR

Description :  Turn a note on 

****************************************************************************/

WORD sosMIDIAWE32NoteOff( WORD hDriver, WORD wChannel, WORD wNote )
{
   BYTE szMIDIData[ 0x10 ];

   // turn the note off
   szMIDIData[ 0 ] = 0x90 | wChannel; 
   szMIDIData[ 1 ] = wNote;
   szMIDIData[ 2 ] = 0x00;
#ifdef BORLAND
   sosMIDISendMIDIData( hDriver, ( PSTR )szMIDIData, 0x03 );
#else
   sosMIDISendMIDIData( hDriver, ( LPSTR )szMIDIData, 0x03 );
#endif
                                 
   // return no error 
   return( _ERR_NO_ERROR );
}








