/*
+-----------------------------------------------------------------------+
|                                                                       |
|          Program Name: WaveLib                                        |
|                Author: Michael Krämer                                 |
|                        DK8PP@ish.de                 (private)         |
|                  Date: 20-Apr-2005                                    |
|              Language: Open Watcom C 1.3                              |
|                        Green Hills 3.5.1                              |
|               Version: 1.0                                            |
|                                                                       |
+-----------------------------------------------------------------------+
|                                                                       |
| These functions were written by the author in his spare time at home, |
| not during his work for NEC. They are released to the public domain.  |
| That means that they are free of charge and they come without any     |
| warranty.                                                             |
|                                                                       |
| As NEC distributes these functions along with some application notes, |
| the standard NEC disclaimer is included as follows:                   |
|                                                                       |
| Warranty Disclaimer :                                                 |
| Because the Product(s) is licensed free of charge, there is no        |
| warranty of any kind whatsoever and expressly disclaimed and excluded |
| by NEC, either expressed or implied, including but not limited to     |
| those for non-infringement of intellectual property, merchantability  |
| and/or fitness for the particular purpose. NEC shall not have any     |
| obligation to maintain, service or provide bug fixes for the supplied |
| Product(s) and/or the Application.                                    |
|                                                                       |
| Each User is solely responsible for determining the appropriateness   |
| of using the Product(s) and assumes all risks associated with its     |
| exercise of rights under this Agreement, including, but not limited   |
| to the risks and costs of program errors, compliance with applicable  |
| laws, damage to or loss of data, programs or equipment, and           |
| unavailability or interruption of operations.                         |
|                                                                       |
| Limitation of Liability :                                             |
| In no event shall NEC be liable to the User for any incidental,       |
| consequential, indirect, or punitive damage (including but not limited|
| to lost profits) regardless of whether such liability is based on     |
| breach of contract, tort, strict liability, breach of warranties,     |
| failure of essential purpose or otherwise and even if advised of the  |
| possibility of such damages. NEC shall not be liable for any services |
| or products provided by third party vendors, developers or consultants|
| identified or referred to the User by NEC in connection with the      |
| Product(s) and/or the Application.                                    |
+-----------------------------------------------------------------------+
|                                                                       |
|  Purpose: Provide functions to read and write wave files.             |
|                                                                       |
+-----------------------------------------------------------------------+
|                                                                       |
|  Usage: linked to other programs                                      |
|                                                                       |
|  Provided functions:                                                  |
|  WFILE *wfopen(const char *filename) ; existing file for read only    |
|  WFILE *wfcreate(const char *filename, WFILE *wstream) ;  create      |
|  int wfeof(WFILE *wstream) ;                                          |
|  void *wfgetsample(void *sample, WFILE *wstream) ;                    |
|  void *wfputsample(void *sample, WFILE *wstream) ;                    |
|  void wfclose(WFILE *wstream) ;                                       |
|                                                                       |
+-----------------------------------------------------------------------+
*/

/*
+-----------------------------------------------------------------------+
|       Includes                                                        |
+-----------------------------------------------------------------------+
*/
#ifndef __ghs
/* GHS does not provide and does not need malloc.h */
#include <malloc.h>
#endif
#include <string.h>
#include <stdio.h>
#include "mytype.h"
#include "wavelib.h"

/*
+-----------------------------------------------------------------------+
|       void wfeof(WFILE *wstream)                                      |
+-----------------------------------------------------------------------+
|                                                                       |
| Check for end of file.                                                |
|                                                                       |
+-----------------------------------------------------------------------+
*/
int wfeof(WFILE *wstream)
{
   return(feof(wstream->cfileptr)) ;
}

/*
+-----------------------------------------------------------------------+
|       void wfclose(WFILE *wstream)                                    |
+-----------------------------------------------------------------------+
|                                                                       |
| Close Wave file.                                                      |
|                                                                       |
+-----------------------------------------------------------------------+
*/
void wfclose(WFILE *wstream)
{
FILE *file = wstream->cfileptr ;
_LONG len = wstream->TotalDataChunkLength ;
   if (wstream->mode == Mode_Write)
   {
      fseek(file,40,SEEK_SET) ; /* remaining data chunk length */
      fwrite(&len,sizeof(_LONG),1,file) ;
      fseek(file, 4,SEEK_SET) ; /* remaining length after header */
      len += 36l ;
      fwrite(&len,sizeof(_LONG),1,file) ;
   }
   free(wstream) ;
   fclose(file) ;
}

/*
+-----------------------------------------------------------------------+
|       void *wfputsample(void *sample, WFILE *wstream)                 |
+-----------------------------------------------------------------------+
|                                                                       |
| Write next samples for all channels. Returns pointer to samples or    |
| NULL on error.                                                        |
|                                                                       |
+-----------------------------------------------------------------------+
*/
void *wfputsample(void *sample, WFILE *wstream)
{
void *rc ;
   rc = NULL ;
   if (fwrite(sample, (wstream->BitsPerSample/8) * (wstream->Channels),
         1, wstream->cfileptr) == 1)
   {
      rc = sample ;
      wstream->TotalDataChunkLength
        += (wstream->BitsPerSample/8) * (wstream->Channels);
   }
   return(rc) ;
}

/*
+-----------------------------------------------------------------------+
|       void *wfgetsample(void *sample, WFILE *wstream)                 |
+-----------------------------------------------------------------------+
|                                                                       |
| Get next samples for all channels. Returns pointer to samples or      |
| NULL on error.                                                        |
|                                                                       |
+-----------------------------------------------------------------------+
*/
void *wfgetsample(void *sample, WFILE *wstream)
{
void *rc ;
   rc = NULL ;
   if (fread(sample, (wstream->BitsPerSample/8) * (wstream->Channels),
         1, wstream->cfileptr) == 1)
   {
      rc = sample ;
      wstream->RemainDataChunkLength
        -= (wstream->BitsPerSample/8) * (wstream->Channels);
   }
   return(rc) ;
}

/*
+-----------------------------------------------------------------------+
|       WFILE *wfcreate(const char *filename, SHORT bps,                |
|                       SHORT chs, LONG sps) ;                          |
+-----------------------------------------------------------------------+
|                                                                       |
| Create a wavefile. Return NULL on error.                              |
| filename is a pointer to the name of the file.                        |
| bps is the number of bits per sample                                  |
| chs is the number of channels                                         |
| sps is the number of samples per second                               |
|                                                                       |
+-----------------------------------------------------------------------+
*/
WFILE *wfcreate(const char *filename, _SHORT bps, _SHORT chs, _LONG sps)
{
FILE *outputfile ;
WFILE *woutputfile ;
_BOOL err ;
RIFF header = {"RIFF",0,"WAVE"} ;
CHUNK_HDR cheader = {"fmt ",16} ;
CHUNK_HDR dheader = {"data",0} ;
FMT_CK fmtck ;
   err = FALSE ;
/* create output file */
   if ((outputfile = fopen(filename,"wb")) != NULL)
   {
      if ((woutputfile = (WFILE *) malloc(sizeof(WFILE))) != NULL)
      {
         woutputfile->cfileptr = outputfile ;
         woutputfile->BitsPerSample = bps ;
         woutputfile->Channels = chs ;
         woutputfile->SamplesPerSecond = sps ;
         woutputfile->TotalDataChunkLength = 0l ;
         woutputfile->RemainDataChunkLength = 0l ;
         woutputfile->mode = Mode_Write ;
         fmtck.wFormatTag = 1 ; /* Windows PCM */
         fmtck.wChannels  = chs ; /* number of channels */
         fmtck.dwSamplesPerSecond = sps ; /* samples per second */
         fmtck.dwAvgBytesPerSecond = sps * chs * bps/8 ; /* average bytes per second */
         fmtck.wBlockAlign = (_SHORT) (chs * bps/8) ; /* 1 channel * BitsPerSample/8 */
         fmtck.wBitsPerSample = bps ; /* Bits per Sample */
         err = (fwrite(&header, sizeof(RIFF), 1, outputfile) != 1) ;
         if (!err)
            err = err | (fwrite(&cheader,
                           sizeof(CHUNK_HDR), 1, outputfile) != 1) ;
         if (!err)
            err = err | (fwrite(&fmtck, sizeof(FMT_CK), 1, outputfile) != 1) ;
         if (!err)
            err = err | (fwrite(&dheader, sizeof(CHUNK_HDR), 1, outputfile) != 1) ;
      }
   }
   if (err | (outputfile == NULL)) return(NULL) ;
   else
      return(woutputfile) ;
}

/*
+-----------------------------------------------------------------------+
|       WFILE *wfopen(const char *filename)                             |
+-----------------------------------------------------------------------+
|                                                                       |
| Open a wavefile. Return NULL on error.                                |
|                                                                       |
+-----------------------------------------------------------------------+
*/
WFILE *wfopen(const char *filename)
{
FILE *inputfile ;
WFILE *winputfile ;
_BOOL err ;
RIFF header ;
CHUNK_HDR cheader ;
FMT_CK fmtck ;
   err = FALSE ;
/* open input file */
   if ((inputfile = fopen(filename,"rb")) != NULL)
   {
      if ((winputfile = (WFILE *) malloc(sizeof(WFILE))) != NULL)
      {
         winputfile->cfileptr = inputfile ;
         fread(&header,  sizeof(RIFF),         1, inputfile) ;
            err = (strncmp(header.id,"RIFF",4) != 0) ;
            err = err | (strncmp(header.wave_id,"WAVE",4) != 0) ;
         if (!err)
            fread(&cheader, sizeof(CHUNK_HDR), 1, inputfile) ;
            err = err | (strncmp(cheader.id,"fmt ",4) != 0) ;
         err = err | (cheader.len != 16l) ; //only standard WAV files supported
         if (!err)
            fread(&fmtck,   sizeof(FMT_CK),    1, inputfile) ;
         err = err | (fmtck.wFormatTag != 1) ; //only standard WAV files supported
         winputfile->Channels = fmtck.wChannels ;
         winputfile->SamplesPerSecond = fmtck.dwSamplesPerSecond ;
         winputfile->BitsPerSample = fmtck.wBitsPerSample ;
         if (!err)
            fread(&cheader, sizeof(CHUNK_HDR), 1, inputfile) ;
            err = err | (strncmp(cheader.id,"data",4) != 0) ;
         winputfile->TotalDataChunkLength = cheader.len ;
         winputfile->RemainDataChunkLength = cheader.len ;
         winputfile->mode = Mode_Read ;
      }
   }
   if (err | (inputfile == NULL)) return(NULL) ;
   else
      return(winputfile) ;
}
