/*

			Read .WAV audio files
			
*/

#include "netfone.h"

int readWaveInit(HWND hwndApp, LPCLIENT_DATA d, LPSTR szFileName)
{
    MMCKINFO mmckinfoParent;
    MMCKINFO mmckinfoSubchunk;
    DWORD dwFmtSize;
    char *err;

#define hmmio	d->mmioHandle
#define pFormat	d->mmioFormat

    // Open the given file for reading using buffered I/O
 
    if (!(hmmio = mmioOpen(szFileName, NULL, MMIO_READ | MMIO_ALLOCBUF))) {
        MessageBox(hwndApp, rstring(IDS_T_OPEN_ERR), NULL, MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
    }

    /* Locate a 'RIFF' chunk with a 'WAVE' form type to make 
       sure it's a WAVE file. */ 
     
    mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
    if (mmioDescend(hmmio, (LPMMCKINFO) &mmckinfoParent, NULL, MMIO_FINDRIFF)) {
        err = rstring(IDS_T_NOT_WAVE_FILE);
		goto bail1;
    }

    /* Now, find the format chunk (form type 'fmt '). It should be
       a subchunk of the 'RIFF' parent chunk.  */
     
    mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
    if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent,
			MMIO_FINDCHUNK)) {
        err = rstring(IDS_T_WAVE_FILE_CORRUPT);
		goto bail1;
    }

    /* Get the size of the format chunk, allocate and lock memory for it.  */
    
    dwFmtSize = mmckinfoSubchunk.cksize;
    pFormat = (LPWAVEFORMAT) GlobalAllocPtr(GPTR, LOWORD(dwFmtSize));
    if (pFormat == NULL) {
        err = rstring(IDS_T_WAVE_NO_MEMORY);
        goto bail1;
    }

    /* Read the format chunk.  */
    
    if (mmioRead(hmmio, (HPSTR) pFormat, dwFmtSize) != (LONG) dwFmtSize) {
        err = rstring(IDS_T_WAVE_NO_FORMAT);
        goto bail2;
    }

    /* Make sure it's a PCM file. */
    
    if (pFormat->wFormatTag != WAVE_FORMAT_PCM) {
	    err = rstring(IDS_T_NOT_PCM_FILE);
		goto bail2;
    }

    /* Ascend out of the format subchunk. */
    
    mmioAscend(hmmio, &mmckinfoSubchunk, 0);

    /* Find the data subchunk. */
    
    mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
    if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent,
			MMIO_FINDCHUNK)) {
        err = rstring(IDS_T_WAVE_NO_DATA);
		goto bail2;
    }

    /* Get the size of the data subchunk. */
    
    d->mmioDataLeft = mmckinfoSubchunk.cksize;
    if (d->mmioDataLeft == 0L) {
        err = rstring(IDS_T_NO_DATA_IN_CHUNK);
		goto bail2;
    }
	return TRUE;

bail2:	
	GlobalFreePtr(pFormat);
bail1:
	mmioClose(hmmio, 0);
	hmmio = NULL;
	return FALSE;
}

/*  READWAVENEXT  --  Fill a sound buffer with the next block
					  of data from the WAVE file.  When the end
					  of file is reached, FALSE is returned,
					  otherwise the return is the number of samples
					  stored in the sound buffer.  */

int readWaveNext(HWND hwnd, LPCLIENT_DATA d)
{
	LPSTR lpData;
	DWORD lengthToRead, sampleRate;
	int is8bit, chan, sampinc, nsamp;

	// If we've reached the end of file, return FALSE
	
	if (d->mmioDataLeft == 0) {
		return FALSE;
	}
	
	//	Force odd sample rates to the closest standard rate
	
	sampleRate = d->mmioFormat->nSamplesPerSec;
	if (sampleRate < 9512) {
		sampleRate = 8000;
	} else if (sampleRate < 16537) {
		sampleRate = 11025;
	} else if (sampleRate < 33075) {
		sampleRate = 22050;
	} else {
		sampleRate = 44100;
	}  
	
	if (sampleRate == 8000) {
		lengthToRead = currentInputSamples * d->mmioFormat->nBlockAlign;
	} else {
		lengthToRead = ((11025L * currentInputSamples * d->mmioFormat->nBlockAlign *
								(sampleRate / 11025)) / 8000L);
	}
								
    /* Allocate memory for the next block of waveform data. */
    
    lpData = GlobalAllocPtr(GPTR, lengthToRead);
    if (lpData == NULL) {
        MessageBox(hwnd, rstring(IDS_T_WAVE_MEM_ALLOC_ERR),
		   NULL, MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
    }

    /* Read from the waveform data subchunk. */
    
    if ((lengthToRead = (DWORD) mmioRead(hmmio, (HPSTR) lpData, lengthToRead)) == 0) {
		GlobalFreePtr(lpData);
		return FALSE;
    }
    
    is8bit = (d->mmioFormat->nBlockAlign / d->mmioFormat->nChannels) == 1;  
    
    /* Transform the data in the buffer into 11025 samples per
       second 8 or 16 bit monaural, if necessary. */
       
	chan = d->mmioFormat->nChannels;
	sampinc = sampleRate == 8000 ? 1 : ((int) (sampleRate / 11025));
	nsamp = (int) (lengthToRead / (sampinc * chan * (is8bit ? 1 : 2)));
			 
	if (sampleRate > 11025 || d->mmioFormat->nChannels != 1 || !is8bit) {
		if (is8bit) {
			int i;
			BYTE *ibuf = (BYTE *) lpData,
				 *obuf = (BYTE *) lpData;
			
			for (i = 0; i < nsamp; i++) {
				BYTE s = *ibuf;
				
				if (chan > 1) {
					short sum = s - 0x80;
					int j;
					BYTE *cbuf = ibuf + 1;
					
					for (j = 1; j < chan; j++) {
						sum += (*cbuf++) - 0x80; 
					}
					s = 0x80 + (BYTE) (sum / chan);
				}
				*obuf++ = s;
				ibuf += sampinc * chan;
			} 
		} else {
			int i;
			short *ibuf = (short *) lpData,
				  *obuf = (short *) lpData;
			
			for (i = 0; i < nsamp; i++) {
				short s = *ibuf;
				
				if (chan > 1) {
					long sum = s;
					int j;
					short *cbuf = ibuf + 1;
					
					for (j = 1; j < chan; j++) {
						sum += *cbuf++; 
					}
					s = (short) (sum / chan);
				}
				*obuf++ = s;
				ibuf += sampinc * chan;
			}
			nsamp *= sizeof(short); 
		}
	} 	
       
    /* Transfer the data to the sound buffer, converting the sampling
       rate and encoding in u-law. */
    
    if (sampleRate != 8000) {
    	sampleRate = 11025;
    }
    isWaveSound = TRUE;
	createSoundBuffer(lpData, (WORD) nsamp, 1, sampleRate, (is8bit ? 1 : 2) * sampleRate,
					  (WORD) (is8bit ? 1 : 2));
	shipSoundBuffer(hwnd, d);
    
    GlobalFreePtr(lpData);
	return (int) (nsamp / chan);
}

/*	READWAVETERM  --  Terminate wave file input.  OK to call even
					  if input isn't open.  */
					  
void readWaveTerm(LPCLIENT_DATA d)
{
	if (d->mmioHandle != NULL) {
		mmioClose(d->mmioHandle, 0);
		d->mmioHandle = NULL;
	}
	if (d->mmioFormat != NULL) {
		GlobalFreePtr(d->mmioFormat);
		d->mmioFormat = NULL;
	}
}			
