/*

	MakeUEF by Thomas Harte 2000

	Distributed under the GPL - see 'Copying' for details

	WAV file class
*/
#include "defines.h"
#include "misc.h"
#include <string.h>
#include <stdlib.h>
#include <malloc.h>

void C_wav::NewBlock(void)
{
	int c, p;

	if(last)
	{
		pos = -1;
		return;
	}

	target = fread(fbuffer, 1, pos_inc*BUFFER_SIZE, infile);
	p = start_offs;
	for(c = 0; c < BUFFER_SIZE; c++)
	{
		buffer[c] = fbuffer[p];
		p += pos_inc;
	}

	if(small)
		buffer = to_signed_wave((unsigned char *)buffer, BUFFER_SIZE);

	pos = 0;
	target /= pos_inc;

	if(target < BUFFER_SIZE)
		last = true;
}

bool C_wav::Open(char *name)
{
	char textbuffer[13], stereo, bits;
	int length, wave_len;
	unsigned short id;
	int datapos;

	if(infile = fopen(name, "rb"))
	{
		fread(textbuffer, 1, 12, infile);
		textbuffer[12] = textbuffer[4] = '\0';

		if(strcmp(textbuffer, "RIFF") || strcmp(&textbuffer[8], "WAVE"))
		{
			fclose(infile);
			error = "doesn't appear to be a valid wav file";
			return false;
		}

		while(!feof(infile))
		{
			if(fread(textbuffer, 1, 4, infile) != 4)
				break;

			if(fread(&length, 4, 1, infile) != 1)
				break;

			if(!strcmp(textbuffer, "fmt "))
			{
				fread(&id, 1, 2, infile); length -= 2;
				if(id != 1)
				{
					fclose(infile);
					error = "wav file uses unsupported data format";
					return false;
				}

				fread(&id, 1, 2, infile); length -= 2;
				if(id < 1 || id > 2)
				{
					fclose(infile);
					error = "wav file neither stereo nor mono";
					return false;
				}

				stereo = (id == 2) ? 1 : 0;
				fread(&freq, 1, 4, infile); length -= 4;

				fseek(infile, 6, SEEK_CUR); length -= 6;

				fread(&id, 1, 2, infile); length -= 2;
				if(id != 8 && id != 16)
				{
					fclose(infile);
					error = "wav file neither 8 nor 16 bit";
					return false;
				}
				bits = (id == 16) ? 2 : 0;
				small = (id == 16) ? false : true;
			}

			if(!strcmp(textbuffer, "data"))
			{
				datapos = fseek(infile, 0, SEEK_CUR);
				wave_len = length;
			}

			fseek(infile, length, SEEK_CUR);
		}

		switch(stereo | bits)
		{
			case 0 :
				wave_size = wave_len;
				start_offs = 0;
				pos_inc = 1;
			break;

			case 1 :
				wave_size = wave_len >> 1;
				start_offs = 0;
				pos_inc = 2;
			break;

			case 2 :
				wave_size = wave_len >> 1;
				start_offs = 1;
				pos_inc = 2;
			break;

			case 3 :
				wave_size = wave_len >> 2;
				start_offs = 1;
				pos_inc = 4;
			break;
		}

		buffer = (char *)malloc(BUFFER_SIZE);
		fbuffer = (char *)malloc(pos_inc*BUFFER_SIZE);
		fseek(infile, datapos, SEEK_SET);

		last = false;
		NewBlock();

		return true;
	}

	return false;
}

bool C_wav::Close(void)
{
	free(fbuffer);
	free(buffer);
	fclose(infile);

	return true;
}

char C_wav::GetNextValue(void)
{
	char ret = -1;

	if(!Finished())
	{
		ret = buffer[pos];
		pos++;

		if(pos == target)
		{
			NewBlock();
		}

		return ret;
	}
	else
		return -1;
}

bool C_wav::Finished(void)
{
	return last && (pos == -1);
}

