text: /*
   * Copyright 2007-2010 (C) - Frictional Games
   *
   * This file is part of OALWrapper
   *
   * For conditions of distribution and use, see copyright notice in LICENSE
   */
  /**
  	@file OAL_WAVSample.cpp
  	@author Luis Rodero
  	@date 2006-10-02
  	@version 0.1
  	Derived class for containing WAV Sample data 
  */
  
  #include "OALWrapper/OAL_WAVSample.h"
  #include "OALWrapper/OAL_Buffer.h"
  #include "OALWrapper/OAL_Helper.h"
  #include "OALWrapper/OAL_Device.h"
  
  // Pull in for OAL Types
  #include <ogg/ogg.h>
  #include <cstdlib>
  #include <cstdio>
  #include <cstring>
  
  using namespace std;
  
  //------------------------------------------------------------------
  
  ///////////////////////////////////////////////////////////
  //	void Load ( const string &asFilename )
  //	-	Loads sample data from a WAV file
  ///////////////////////////////////////////////////////////
  
  //------------------------------------------------------------------
  
  bool cOAL_WAVSample::CreateFromFile(const wstring &asFilename)
  {
  	FILE *fileHandle = OpenFileW(asFilename, L"rb");
  	fseek(fileHandle, 0, SEEK_END);
  	size_t pos = ftell(fileHandle);
  	fseek(fileHandle, 0, SEEK_SET);
  
  	void *buffer = malloc(pos);
  	
  	fread(buffer, pos, 1, fileHandle);
  	fclose(fileHandle);
  	bool result = CreateFromBuffer(buffer, pos);
  	free(buffer);
  
  	return result;
  }
  
  struct RIFF_Header {
  	char chunkID[4];
  	ogg_int32_t chunkSize;
  	char format[4];
  };
  
  struct WAVE_Format {
  	char subChunkID[4];
  	ogg_int32_t subChunkSize;
  	ogg_int16_t audioFormat;
  	ogg_int16_t numChannels;
  	ogg_int32_t sampleRate;
  	ogg_int32_t byteRate;
  	ogg_int16_t blockAlign;
  	ogg_int16_t bitsPerSample;
  };
  
  struct WAVE_Data {
    char subChunkID[4]; //should contain the word data
    ogg_int32_t subChunkSize; //Stores the size of the data block
  };
  
  struct RIFF_SubChunk {
    char subChunkID[4]; //should contain the word data
    ogg_int32_t subChunkSize; //Stores the size of the data block
  };
  
  static const char* find_chunk(const char* start, const char* end, const char* chunkID)
  {
  	RIFF_SubChunk chunk;
  	const char* ptr = start;
  	while (ptr < (end - sizeof(RIFF_SubChunk)))
  	{
  		memcpy(&chunk, ptr, sizeof(RIFF_SubChunk));
  
  		if (chunk.subChunkID[0] == chunkID[0] &&
  			chunk.subChunkID[1] == chunkID[1] &&
  			chunk.subChunkID[2] == chunkID[2] &&
  			chunk.subChunkID[3] == chunkID[3])
  		{
  			return ptr;
  		}
  		ptr += sizeof(RIFF_SubChunk) + chunk.subChunkSize;
  	}
  	return 0;
  }
  
  template<typename T>
  inline const char*readStruct(T& dest, const char*& ptr)
  {
  	const char* ret;
  	memcpy(&dest, ptr, sizeof(T));
  	ptr += sizeof(RIFF_SubChunk);
  	ret = ptr;
  	ptr += dest.subChunkSize;
  	return ret;
  }
  
  bool cOAL_WAVSample::CreateFromBuffer(const void* apBuffer, size_t aSize)
  {
  	const char* start = (const char*)apBuffer;
  	const char* end = start + aSize;
  	const char* ptr = start;
  	RIFF_Header riff_header;
  	WAVE_Format wave_format;
  	WAVE_Data wave_data;
  
  	memcpy(&riff_header, ptr, sizeof(RIFF_Header));
  	ptr += sizeof(RIFF_Header);
  
  	if (riff_header.chunkID[0] != 'R' ||
  		riff_header.chunkID[1] != 'I' ||
  		riff_header.chunkID[2] != 'F' ||
  		riff_header.chunkID[3] != 'F' ||
  		riff_header.format[0] != 'W' ||
  		riff_header.format[1] != 'A' ||
  		riff_header.format[2] != 'V' ||
  		riff_header.format[3] != 'E')
  	{
  		return false;
  	}
  	
  	ptr = find_chunk(ptr, end, "fmt ");
  	if (!ptr) {
  		return false;
  	}
  	readStruct(wave_format, ptr);
  	
  	if (wave_format.audioFormat != 1) {
  		return false;
  	}
  
  	ptr = find_chunk(ptr, end, "data");
  	if (!ptr) {
  		return false;
  	}
  
  	const char* base = readStruct(wave_data, ptr);
  
  	size_t size = wave_data.subChunkSize;
  	if (size > (end - base)) {
  		return false;
  	}
  
  	mlChannels = wave_format.numChannels;
  	if (mlChannels == 2)
  	{
  		if (wave_format.bitsPerSample == 8)
  		{
  			mFormat = AL_FORMAT_STEREO8;
  			mlSamples = size / 2;
  		}
  		else //if (wave_format.bitsPerSample == 16)
  		{
  			mlSamples = size / 4;
  			mFormat = AL_FORMAT_STEREO16;
  		}
  	} else //if (mlChannels == 1)
  	{
  		if (wave_format.bitsPerSample == 8)
  		{
  			mlSamples = size;
  			mFormat = AL_FORMAT_MONO8;
  		}
  		else //if (wave_format.bitsPerSample == 16)
  		{
  			mlSamples = size / 2;
  			mFormat = AL_FORMAT_MONO16;
  		}
  	}
  	mlFrequency = wave_format.sampleRate;
  	mfTotalTime = float(mlSamples) / float(mlFrequency);
  	
  	cOAL_Buffer* pBuffer = mvBuffers[0];
  	mbStatus = pBuffer->Feed((ALvoid*)base, size);
  
  	return true;
  }
  
  //------------------------------------------------------------------
  
  
  