WavFileLoader.h

Go to the documentation of this file.
00001 #ifndef WAV_FILE_LOADER_H_
00002 #define WAV_FILE_LOADER_H_
00003 
00004 #include <stdexcept>
00005 #include "OpenAL.h"
00006 
00007 class InputStream;
00008 
00009 namespace sound
00010 {
00011 
00018     class WavFileLoader
00019     {
00020         public:
00021 
00027             static ALuint LoadFromStream (InputStream& stream)
00028             {
00029                 // buffers
00030                 char magic[5];
00031                 magic[4] = '\0';
00032                 typedef StreamBase::byte_type byte;
00033 
00034                 byte temp[256];
00035 
00036                 int format = 0;
00037 
00038                 // check magic
00039                 stream.read(reinterpret_cast<byte*> (magic), 4);
00040 
00041                 if (std::string(magic) != "RIFF") {
00042                     throw std::runtime_error("No wav file");
00043                 }
00044 
00045                 // The next 4 bytes are the file size, we can skip this since we get the size from the DataStream
00046                 unsigned int size;
00047                 stream.read(reinterpret_cast<byte*> (&size), 4);
00048 
00049                 // check file format
00050                 stream.read(reinterpret_cast<byte*> (magic), 4);
00051                 if (std::string(magic) != "WAVE") {
00052                     throw std::runtime_error("Wrong wav file format");
00053                 }
00054 
00055                 // check 'fmt ' sub chunk (1)
00056                 stream.read(reinterpret_cast<byte*> (magic), 4);
00057                 if (std::string(magic) != "fmt ") {
00058                     throw std::runtime_error("No 'fmt ' subchunk.");
00059                 }
00060 
00061                 // read (1)'s size
00062                 unsigned int subChunk1Size(0);
00063                 stream.read(reinterpret_cast<byte*> (&subChunk1Size), 4);
00064 
00065                 if (subChunk1Size < 16) {
00066                     throw std::runtime_error("'fmt ' chunk too small.");
00067                 }
00068 
00069                 // check PCM audio format
00070                 unsigned short audioFormat(0);
00071                 stream.read(reinterpret_cast<byte*> (&audioFormat), 2);
00072 
00073                 if (audioFormat != 1) {
00074                     throw std::runtime_error("Audio format is not PCM.");
00075                 }
00076 
00077                 // read number of channels
00078                 unsigned short channels(0);
00079                 stream.read(reinterpret_cast<byte*> (&channels), 2);
00080 
00081                 // read frequency (sample rate)
00082                 unsigned int freq = 0;
00083                 stream.read(reinterpret_cast<byte*> (&freq), 4);
00084 
00085                 // skip 6 bytes (Byte rate (4), Block align (2))
00086                 stream.read(temp, 6);
00087 
00088                 // read bits per sample
00089                 unsigned short bps = 0;
00090                 stream.read(reinterpret_cast<byte*> (&bps), 2);
00091 
00092                 int bufferSize = 0;
00093 
00094                 if (channels == 1) {
00095                     if (bps == 8) {
00096                         format = AL_FORMAT_MONO8;
00097                         // Set BufferSize to 250ms (Frequency divided by 4 (quarter of a second))
00098                         bufferSize = freq / 4;
00099                     } else {
00100                         format = AL_FORMAT_MONO16;
00101                         // Set BufferSize to 250ms (Frequency * 2 (16bit) divided by 4 (quarter of a second))
00102                         bufferSize = freq >> 1;
00103                         // IMPORTANT : The Buffer Size must be an exact multiple of the BlockAlignment ...
00104                         bufferSize -= (bufferSize % 2);
00105                     }
00106                 } else {
00107                     if (bps == 8) {
00108                         format = AL_FORMAT_STEREO16;
00109                         // Set BufferSize to 250ms (Frequency * 2 (8bit stereo) divided by 4 (quarter of a second))
00110                         bufferSize = freq >> 1;
00111                         // IMPORTANT : The Buffer Size must be an exact multiple of the BlockAlignment ...
00112                         bufferSize -= (bufferSize % 2);
00113                     } else {
00114                         format = AL_FORMAT_STEREO16;
00115                         // Set BufferSize to 250ms (Frequency * 4 (16bit stereo) divided by 4 (quarter of a second))
00116                         bufferSize = freq;
00117                         // IMPORTANT : The Buffer Size must be an exact multiple of the BlockAlignment ...
00118                         bufferSize -= (bufferSize % 4);
00119                     }
00120                 }
00121 
00122                 // check 'data' sub chunk (2)
00123                 stream.read(reinterpret_cast<byte*> (magic), 4);
00124                 if (std::string(magic) != "data" && std::string(magic) != "fact") {
00125                     throw std::runtime_error("No 'data' subchunk.");
00126                 }
00127 
00128                 // fact is an option section we don't need to worry about
00129                 if (std::string(magic) == "fact") {
00130                     stream.read(temp, 8);
00131 
00132                     // Now we should hit the data chunk
00133                     stream.read(reinterpret_cast<byte*> (magic), 4);
00134                     if (std::string(magic) != "data") {
00135                         throw std::runtime_error("No 'data' subchunk.");
00136                     }
00137                 }
00138 
00139                 // The next four bytes are the size remaing of the file
00140                 unsigned int remainingSize = 0;
00141                 stream.read(reinterpret_cast<byte*> (&remainingSize), 4);
00142 
00143                 ALuint bufferNum = 0;
00144                 alGenBuffers(1, &bufferNum);
00145 
00146                 byte* buffer = new byte[remainingSize];
00147                 stream.read(buffer, remainingSize);
00148 
00149                 alBufferData(bufferNum, format, buffer, static_cast<ALsizei> (remainingSize), freq);
00150 
00151                 delete[] buffer;
00152 
00153                 return bufferNum;
00154             }
00155     };
00156 
00157 } // namespace sound
00158 
00159 #endif /* WAV_FILE_LOADER_H_ */

Generated by  doxygen 1.6.2