status _af_wave_read_init (AFfilesetup setup, AFfilehandle filehandle)
{
	_Track		*track;
	uint32_t	type, size, formtype;
	uint32_t	index = 0;
	bool		hasFormat, hasData, hasCue, hasList, hasPlayList, hasFrameCount,
			hasINST, hasINFO;
	_WAVEInfo	*wave = _af_malloc(sizeof (_WAVEInfo));

	assert(filehandle != NULL);
	assert(filehandle->fh != NULL);

	hasFormat = AF_FALSE;
	hasData = AF_FALSE;
	hasCue = AF_FALSE;
	hasList = AF_FALSE;
	hasPlayList = AF_FALSE;
	hasFrameCount = AF_FALSE;
	hasINST = AF_FALSE;
	hasINFO = AF_FALSE;

	filehandle->formatSpecific = wave;
	filehandle->instruments = NULL;
	filehandle->instrumentCount = 0;
	filehandle->miscellaneous = NULL;
	filehandle->miscellaneousCount = 0;

	track = _af_track_new();
	filehandle->tracks = track;
	filehandle->trackCount = 1;

	af_fseek(filehandle->fh, 0, SEEK_SET);

	af_fread(&type, 4, 1, filehandle->fh);
	af_read_uint32_le(&size, filehandle->fh);
	af_fread(&formtype, 4, 1, filehandle->fh);

	assert(!memcmp(&type, "RIFF", 4));
	assert(!memcmp(&formtype, "WAVE", 4));

#ifdef DEBUG
	printf("size: %d\n", size);
#endif

	/* Include the offset of the form type. */
	index += 4;

	while (index < size)
	{
		uint32_t	chunkid = 0, chunksize = 0;
		status		result;

#ifdef DEBUG
		printf("index: %d\n", index);
#endif
		af_fread(&chunkid, 4, 1, filehandle->fh);
		af_read_uint32_le(&chunksize, filehandle->fh);

#ifdef DEBUG
		_af_printid(BENDIAN_TO_HOST_INT32(chunkid));
		printf(" size: %d\n", chunksize);
#endif

		if (memcmp(&chunkid, "fmt ", 4) == 0)
		{
			result = ParseFormat(filehandle, filehandle->fh, chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;

			hasFormat = AF_TRUE;
		}
		else if (memcmp(&chunkid, "data", 4) == 0)
		{
			/* The format chunk must precede the data chunk. */
			if (!hasFormat)
			{
				_af_error(AF_BAD_HEADER, "missing format chunk in WAVE file");
				return AF_FAIL;
			}

			result = ParseData(filehandle, filehandle->fh, chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;

			hasData = AF_TRUE;
		}
		else if (memcmp(&chunkid, "inst", 4) == 0)
		{
			result = ParseInstrument(filehandle, filehandle->fh, chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}
		else if (memcmp(&chunkid, "fact", 4) == 0)
		{
			hasFrameCount = AF_TRUE;
			result = ParseFrameCount(filehandle, filehandle->fh, chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}
		else if (memcmp(&chunkid, "cue ", 4) == 0)
		{
			hasCue = AF_TRUE;
			result = ParseCues(filehandle, filehandle->fh, chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}
		else if (memcmp(&chunkid, "LIST", 4) == 0 || memcmp(&chunkid, "list", 4) == 0)
		{
			hasList = AF_TRUE;
			result = ParseList(filehandle, filehandle->fh, chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}
		else if (memcmp(&chunkid, "INST", 4) == 0)
		{
			hasINST = AF_TRUE;
			result = ParseInstrument(filehandle, filehandle->fh, chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}
		else if (memcmp(&chunkid, "plst", 4) == 0)
		{
			hasPlayList = AF_TRUE;
			result = ParsePlayList(filehandle, filehandle->fh, chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}

		index += chunksize + 8;

		/* All chunks must be aligned on an even number of bytes */
		if ((index % 2) != 0)
			index++;

		af_fseek(filehandle->fh, index + 8, SEEK_SET);
	}

	/* The format chunk and the data chunk are required. */
	if (!hasFormat || !hasData)
	{
		return AF_FAIL;
	}

	/*
		At this point we know that the file has a format chunk
		and a data chunk, so we can assume that track->f and
		track->data_size have been initialized.
	*/
	if (hasFrameCount == AF_FALSE)
	{
		/*
			Perform arithmetic in double-precision so as
			to preserve accuracy.
		*/
		track->totalfframes = ceil((double) track->data_size /
			_af_format_frame_size(&track->f, AF_FALSE));
	}

	if (track->f.compressionType != AF_COMPRESSION_NONE &&
		(track->f.compressionType == AF_COMPRESSION_G711_ULAW ||
		track->f.compressionType == AF_COMPRESSION_G711_ALAW))
	{
		track->totalfframes = track->data_size / track->f.channelCount;
	}

	/*
		A return value of AF_SUCCEED indicates successful parsing.
	*/
	return AF_SUCCEED;
}
status _af_wave_read_init (AFfilesetup setup, AFfilehandle filehandle)
{
	_Track		*track;
	uint32_t	type, size, formtype;
	uint32_t	index = 0;
	bool		hasFormat, hasData, hasCue, hasList, hasPlayList, hasFrameCount,
			hasINST, hasINFO;
	_WAVEInfo	*wave = _af_malloc(sizeof (_WAVEInfo));

	assert(filehandle != NULL);
	assert(filehandle->fh != NULL);

	hasFormat = AF_FALSE;
	hasData = AF_FALSE;
	hasCue = AF_FALSE;
	hasList = AF_FALSE;
	hasPlayList = AF_FALSE;
	hasFrameCount = AF_FALSE;
	hasINST = AF_FALSE;
	hasINFO = AF_FALSE;

	filehandle->formatSpecific = wave;
	filehandle->instruments = NULL;
	filehandle->instrumentCount = 0;
	filehandle->miscellaneous = NULL;
	filehandle->miscellaneousCount = 0;

	track = _af_track_new();
	filehandle->tracks = track;
	filehandle->trackCount = 1;

	af_fseek(filehandle->fh, 0, SEEK_SET);

	af_fread(&type, 4, 1, filehandle->fh);
	af_read_uint32_le(&size, filehandle->fh);
	af_fread(&formtype, 4, 1, filehandle->fh);

	assert(!memcmp(&type, "RIFF", 4));
	assert(!memcmp(&formtype, "WAVE", 4));

#ifdef DEBUG
	printf("size: %d\n", size);
#endif

	 
	index += 4;

	while (index < size)
	{
		uint32_t	chunkid = 0, chunksize = 0;
		status		result;

#ifdef DEBUG
		printf("index: %d\n", index);
#endif
		af_fread(&chunkid, 4, 1, filehandle->fh);
		af_read_uint32_le(&chunksize, filehandle->fh);

#ifdef DEBUG
		_af_printid(BENDIAN_TO_HOST_INT32(chunkid));
		printf(" size: %d\n", chunksize);
#endif

		if (memcmp(&chunkid, "fmt ", 4) == 0)
		{
			result = ParseFormat(filehandle, filehandle->fh, chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;

			hasFormat = AF_TRUE;
		}
		else if (memcmp(&chunkid, "data", 4) == 0)
		{
			 
			if (!hasFormat)
			{
				_af_error(AF_BAD_HEADER, "missing format chunk in WAVE file");
				return AF_FAIL;
			}

			result = ParseData(filehandle, filehandle->fh, chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;

			hasData = AF_TRUE;
		}
		else if (memcmp(&chunkid, "inst", 4) == 0)
		{
			result = ParseInstrument(filehandle, filehandle->fh, chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}
		else if (memcmp(&chunkid, "fact", 4) == 0)
		{
			hasFrameCount = AF_TRUE;
			result = ParseFrameCount(filehandle, filehandle->fh, chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}
		else if (memcmp(&chunkid, "cue ", 4) == 0)
		{
			hasCue = AF_TRUE;
			result = ParseCues(filehandle, filehandle->fh, chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}
		else if (memcmp(&chunkid, "LIST", 4) == 0 || memcmp(&chunkid, "list", 4) == 0)
		{
			hasList = AF_TRUE;
			result = ParseList(filehandle, filehandle->fh, chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}
		else if (memcmp(&chunkid, "INST", 4) == 0)
		{
			hasINST = AF_TRUE;
			result = ParseInstrument(filehandle, filehandle->fh, chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}
		else if (memcmp(&chunkid, "plst", 4) == 0)
		{
			hasPlayList = AF_TRUE;
			result = ParsePlayList(filehandle, filehandle->fh, chunkid, chunksize);
			if (result == AF_FAIL)
				return AF_FAIL;
		}

		index += chunksize + 8;

		 
		if ((index % 2) != 0)
			index++;

		af_fseek(filehandle->fh, index + 8, SEEK_SET);
	}

	 
	if (!hasFormat || !hasData)
	{
		return AF_FAIL;
	}

	 
	if (hasFrameCount == AF_FALSE)
	{
		 
		track->totalfframes = ceil((double) track->data_size /
			_af_format_frame_size(&track->f, AF_FALSE));
	}

	if (track->f.compressionType != AF_COMPRESSION_NONE &&
		(track->f.compressionType == AF_COMPRESSION_G711_ULAW ||
		track->f.compressionType == AF_COMPRESSION_G711_ALAW))
	{
		track->totalfframes = track->data_size / track->f.channelCount;
	}

	 
	return AF_SUCCEED;
}