TWaveFileFormat.hpp

Go to the documentation of this file.
00001 #ifndef __TWaveFileFormat__
00002 #define __TWaveFileFormat__
00003 
00004 #include <Host/CEndian.hpp>
00005 #include "IAudioFileFormat.hpp"
00006 using Exponent::Audio::IAudioFileFormat;
00007 using Exponent::Host::CEndian;
00008 
00009 //  ===========================================================================
00010 
00011 namespace Exponent
00012 {
00013     namespace Audio
00014     {
00033         template<typename TypeName> class TWaveFileFormat : public IAudioFileFormat<TypeName>
00034         {
00035         public:
00036 
00040             TWaveFileFormat()
00041             {
00042                 m_bitDepth = IAudioFileFormat<TypeName>::e_sixteenBit;
00043             }
00044 
00048             virtual ~TWaveFileFormat()
00049             {
00050                 m_stream.closeStream();
00051             }
00052 
00053 //  ===========================================================================
00054 
00061             virtual bool openFile(CFileStream::EStreamMode mode, const CSystemString &filename)
00062             {
00063                 return m_stream.openStream(filename, mode, true);
00064             }
00065 
00070             virtual bool closeFile()
00071             {
00072                 m_stream.closeStream();
00073                 return true;
00074             }
00075 
00076 //  ===========================================================================
00077 
00082             virtual void getFileExtension(TStringCountedPointerArray &array) const
00083             {
00084                 array.addElement(new CString("wav"));
00085             }
00086 
00092             virtual bool isValidFormat(const CSystemString &filename) const
00093             {
00094                 // Create the stream
00095                 CFileStream stream(filename, CFileStream::e_input, true);
00096 
00097                 // Check open
00098                 if (!stream.isStreamOpen())
00099                 {
00100                     return false;
00101                 }
00102 
00103                 // Read in the header
00104                 typename TWaveFileFormat<TypeName>::SWaveFileFormat diskFormat;
00105                 return readFileHeader(stream, diskFormat);
00106             }
00107 
00108 //  ===========================================================================
00109 
00115             virtual bool readHeader(typename IAudioFileFormat<TypeName>::SAudioFileFormat &format)
00116             {
00117                 // Read in the header
00118                 typename TWaveFileFormat<TypeName>::SWaveFileFormat diskFormat;
00119                 if (!readFileHeader(m_stream, diskFormat))
00120                 {
00121                     return false;
00122                 }
00123 
00124                 // STore the output information
00125                 format.m_sampleRate       = diskFormat.m_sampleRate;
00126                 format.m_numberOfChannels = diskFormat.m_numberOfChannels;
00127                 format.m_numberOfSamples  = diskFormat.m_numberOfSamples;
00128                 format.m_bitDepth         = (unsigned long)diskFormat.m_bitsPerSample;
00129                 m_bitDepth                = (typename IAudioFileFormat<TypeName>::EBitDepth)format.m_bitDepth;
00130 
00131                 // Done :)
00132                 return true;
00133             }
00134 
00140             virtual bool readData(TAudioBuffer< TypeName > &buffer)
00141             {
00142                 // Handle based upon the depth
00143                 switch(m_bitDepth)
00144                 {
00145                     case IAudioFileFormat<TypeName>::e_eightBit:
00146                         {
00147                             // Store the entire size of the buffer to be read in
00148                             const unsigned long size = buffer.getBufferSize();
00149 
00150                             // Pointer to the data that we will iterate through
00151                             TypeName *data = buffer.getMutableData();
00152 
00153                             // The sample we read in to
00154                             //unsigned char sample = 0;
00155                             unsigned char *sample = new unsigned char[size];
00156 
00157                             // Read the audio data
00158                             if (!m_stream.readDataFromStream(sample, size))
00159                             {
00160                                 FREE_ARRAY_POINTER(sample);
00161                                 return false;
00162                             }
00163 
00164                             // Save doing multiple divisions...
00165                             const TypeName inversion = (TypeName)(1.0 / 255.0);
00166 
00167                             // For the number of samples, we want to read in and convert to floating point range..
00168                             for (unsigned long i = 0; i < size; i++)
00169                             {
00170                                 //m_stream >> sample;
00171                                 //*data++ = (TypeName)((((TypeName)sample / (TypeName)255) * 2.0) - 1.0);
00172                                 *data++ = (TypeName)((((TypeName)sample[i] * inversion) * 2.0) - 1.0);
00173                             }
00174 
00175                             // Delete the buffer we loaded with
00176                             FREE_ARRAY_POINTER(sample);
00177                         }
00178                     break;
00179                     case IAudioFileFormat<TypeName>::e_sixteenBit:
00180                         {
00181                             // Store the entire size of the buffer to be read in
00182                             const unsigned long size = buffer.getBufferSize();
00183 
00184                             // Pointer to the data that we will iterate through
00185                             TypeName *data = buffer.getMutableData();
00186 
00187                             // The sample we read in to
00188                             short *sample = new short[size];
00189 
00190                             // Read the audio data
00191                             if(!m_stream.readShortsFromStream(sample, size))
00192                             {
00193                                 FREE_ARRAY_POINTER(sample);
00194                                 return false;
00195                             }
00196 
00197                             // Save doing multiple divisions...
00198                             const TypeName inversion = (TypeName)(1.0 / 32768.0);
00199 
00200                             // For the number of samples, we want to read in and convert to floating point range..
00201                             for (unsigned long i = 0; i < size; i++)
00202                             {
00203                                 *data++ = (TypeName)sample[i] * inversion;
00204                             }
00205 
00206                             // Delete the sample buffer...
00207                             FREE_ARRAY_POINTER(sample);
00208                         }
00209                     break;
00210                     case IAudioFileFormat<TypeName>::e_twentyFourBit:
00211                         {
00212                             // Store the entire size of the buffer to be read in
00213                             const unsigned long size = buffer.getBufferSize();
00214 
00215                             // Pointer to the data that we will iterate through
00216                             TypeName *data = buffer.getMutableData();
00217 
00218                             // The sample we read in to
00219                             char streamBuffer[3];
00220 
00221                             // For the number of samples, we want to read in and convert to floating point range..
00222                             for (unsigned long i = 0; i < size; i++)
00223                             {
00224                                 // Read the 3 bytes from the buffer
00225                                 m_stream.readDataFromStream(streamBuffer, 3);
00226 
00227                                 // Convert sample
00228                                 *data++ = (TypeName)((int)CEndian::convertThreeBytesToTwentyFourBitInt(streamBuffer) << 8) / (TypeName)0x7fffffff;
00229                             }
00230                         }
00231                     break;
00232                     default:
00233                         return false;
00234                     break;
00235                 }
00236 
00237                 // Sucess!
00238                 return true;
00239             }
00240 
00241 //  ===========================================================================
00242 
00248             virtual bool writeHeader(const typename IAudioFileFormat<TypeName>::SAudioFileFormat &format)
00249             {
00250                 // Check open
00251                 if (!m_stream.isStreamOpen())
00252                 {
00253                     return false;
00254                 }
00255 
00256                 // Store all the information that we need
00257                 const long depth          = (const long)format.m_bitDepth;
00258                 const long sampleRate     = (const long)format.m_sampleRate;
00259                 const long numberOfBytes  = format.m_numberOfChannels * depth / 8;
00260                 const long totalSize      = format.m_numberOfSamples * numberOfBytes + 44 - 8;
00261                 const long bytesPerSample = numberOfBytes * sampleRate;
00262                 const long chunkSize      = numberOfBytes * format.m_numberOfSamples;
00263                 m_bitDepth                = (typename IAudioFileFormat<TypeName>::EBitDepth)format.m_bitDepth;
00264 
00265                 // Stream the header information
00266                 m_stream << 'R' << 'I' << 'F' << 'F'                // RIFF header
00267                          << totalSize                               // File size
00268                          << 'W' << 'A' << 'V' << 'E'                // WAVE header
00269                          << 'f' << 'm' << 't' << ' '                // Format tag
00270                          << (long)16                                // Always 16 for wav
00271                          << (short)1                                // Format 1 PCM
00272                          << (short)format.m_numberOfChannels        // Number of channels
00273                          << sampleRate                              // Sample rate
00274                          << (long)bytesPerSample                    // bytes per sample
00275                          << (short)numberOfBytes                    // total number of bytes
00276                          << (short)depth                            // bit depth
00277                          << 'd' << 'a' << 't' << 'a'                // Data tag
00278                          << chunkSize;                              // Size of the data chunk
00279 
00280                 // Check we wrote correctly
00281                 return true;
00282             }
00283 
00289             virtual bool writeData(const TAudioBuffer< TypeName > &buffer)
00290             {
00291                 switch(m_bitDepth)
00292                 {
00293                     case IAudioFileFormat<TypeName>::e_eightBit:
00294                         {
00295                             const TypeName *data = buffer.getData();
00296                             for (unsigned long i = 0; i < buffer.getNumberOfChannels() * buffer.getNumberOfSamples(); i++)
00297                             {
00298                                 //unsigned char sample = (unsigned char)(255.0 * ((data[i] + 1.0) * 0.5));
00299                                 m_stream << (unsigned char)(255.0 * ((data[i] + 1.0) * 0.5));//sample;
00300                             }
00301                         }
00302                     break;
00303                     case IAudioFileFormat<TypeName>::e_sixteenBit:
00304                         {
00305                             const TypeName *data = buffer.getData();
00306                             for (unsigned long i = 0; i < buffer.getNumberOfChannels() * buffer.getNumberOfSamples(); i++)
00307                             {
00308                                 //short sample = (short)(data[i] * 32768);
00309                                 m_stream << (short)(data[i] * 32768);//sample;
00310                             }
00311                         }
00312                     break;
00313                     case IAudioFileFormat<TypeName>::e_twentyFourBit:
00314                         {
00315                             const TypeName *data = buffer.getData();
00316                             char samples[3];
00317                             for (unsigned long i = 0; i < buffer.getNumberOfChannels() * buffer.getNumberOfSamples(); i++)
00318                             {
00319                                 CEndian::convertTwentyFourBitIntToThreeBytes((int)(data[i] * (double)0x7fffffff) >> 8, samples);
00320                                 m_stream.writeDataToStream(samples, 3);
00321                             }
00322                         }
00323                     break;
00324                     default:
00325                         return false;
00326                     break;
00327                 }
00328 
00329                 // Done! :)
00330                 return true;
00331             }
00332 
00333 //  ===========================================================================
00334 
00335         protected:
00336 
00337 //  ===========================================================================
00338 
00343             struct SWaveFileFormat
00344             {
00345                 // RIFF chunk
00346                 char m_riffId[4];                   
00347                 unsigned long m_riffSize;           
00348                 char m_riffFormatId[4];             
00350                 // Format chunk
00351                 char m_formatId[4];                 
00352                 unsigned long m_formatSize;         
00354                 // Wave format chunk
00355                 unsigned short m_formatTag;         
00356                 unsigned short m_numberOfChannels;  
00357                 unsigned long m_sampleRate;         
00358                 unsigned long m_bytesPerSecond;     
00359                 unsigned short m_blockAlignment;    
00360                 unsigned short m_bitsPerSample;     
00361                 unsigned long m_numberOfSamples;    
00363                 // Data chunk
00364                 char m_dataId[4];                   
00365                 unsigned long m_dataSize;           
00366             };
00367 
00368 //  ===========================================================================
00369 
00376             static bool readFileHeader(CFileStream &stream, SWaveFileFormat &diskFormat)
00377             {
00378                 if (!stream.isStreamOpen())
00379                 {
00380                     return false;
00381                 }
00382 
00383                 // Read the riff header
00384                 stream >> diskFormat.m_riffId[0]
00385                        >> diskFormat.m_riffId[1]
00386                        >> diskFormat.m_riffId[2]
00387                        >> diskFormat.m_riffId[3]
00388                        >> diskFormat.m_riffSize
00389                        >> diskFormat.m_riffFormatId[0]
00390                        >> diskFormat.m_riffFormatId[1]
00391                        >> diskFormat.m_riffFormatId[2]
00392                        >> diskFormat.m_riffFormatId[3];
00393 
00394                 // Is this actually a wave format file?
00395                 if (!isValidRiffWaveChunk(diskFormat))
00396                 {
00397                     return false;
00398                 }
00399 
00400                 // ADDED HERE!!
00401 
00402                 bool foundTag = false;
00403                 do
00404                 {
00405                     // Read the format
00406                     stream >> diskFormat.m_formatId[0] >> diskFormat.m_formatId[1] >> diskFormat.m_formatId[2] >> diskFormat.m_formatId[3];
00407 
00408                     // Read the size of the format
00409                     stream >> diskFormat.m_formatSize;
00410 
00411                     // If we found the tag
00412                     foundTag = isValidFormatChunk(diskFormat);
00413 
00414                     // Likeyly off the end of the file
00415                     if (stream.hasErrorOccurred())
00416                     {
00417                         return false;
00418                     }
00419 
00420                     // If we didnt find the tag
00421                     if (!foundTag)
00422                     {
00423                         stream.advanceStream(diskFormat.m_formatSize);
00424                     }
00425 
00426                 }while(!foundTag);
00427 
00428                 // Store the format
00429                 stream >> diskFormat.m_formatTag;
00430 
00431                 // END ADDED HERE!!
00432 
00433                 // Read the format chunk
00434                 //stream >> diskFormat.m_formatId[0] >> diskFormat.m_formatId[1] >> diskFormat.m_formatId[2] >> diskFormat.m_formatId[3];
00435 
00436                 // Check that the file is valid for format
00437                 //if (!isValidFormatChunk(diskFormat))
00438                 //{
00439                 //  return false;
00440                 //}
00441 
00442                 // Store size and format
00443                 //stream >> diskFormat.m_formatSize >> diskFormat.m_formatTag;
00444 
00445                 // Check its PCM encoding
00446                 if (diskFormat.m_formatTag != 1)
00447                 {
00448                     return false;
00449                 }
00450 
00451                 // Stream in the format
00452                 stream >> diskFormat.m_numberOfChannels
00453                        >> diskFormat.m_sampleRate
00454                        >> diskFormat.m_bytesPerSecond
00455                        >> diskFormat.m_blockAlignment
00456                        >> diskFormat.m_bitsPerSample;
00457 
00458                 /*
00459                 // REad the data id
00460                 stream >> diskFormat.m_dataId[0]
00461                        >> diskFormat.m_dataId[1]
00462                        >> diskFormat.m_dataId[2]
00463                        >> diskFormat.m_dataId[3];
00464 
00465                 // Check that its actually a valid data header
00466                 if (!isValidDataChunk(diskFormat))
00467                 {
00468                     return false;
00469                 }
00470 
00471                 // Store the size of the data
00472                 stream >> diskFormat.m_dataSize;
00473                 */
00474 
00475                 foundTag = false;
00476                 
00477                 do
00478                 {
00479                     // REad the data id
00480                     stream >> diskFormat.m_dataId[0] >> diskFormat.m_dataId[1] >> diskFormat.m_dataId[2] >> diskFormat.m_dataId[3] >> diskFormat.m_dataSize;
00481                     
00482                     // If we found the tag
00483                     foundTag = isValidDataChunk(diskFormat);
00484 
00485                     // Likeyly off the end of the file
00486                     if (stream.hasErrorOccurred())
00487                     {
00488                         return false;
00489                     }
00490 
00491                     // If we didnt find the tag
00492                     if (!foundTag)
00493                     {
00494                         stream.advanceStream(diskFormat.m_dataSize);
00495                     }
00496                 }while(!foundTag);
00497 
00498                 // Compute the number of samples
00499                 diskFormat.m_numberOfSamples = diskFormat.m_dataSize / diskFormat.m_blockAlignment;
00500 
00501                 // We are done :)
00502                 return true;
00503             }
00504 
00510             static bool isValidRiffWaveChunk(const SWaveFileFormat &format)
00511             {
00512                 return (format.m_riffId[0]       == 'R' &&
00513                         format.m_riffId[1]       == 'I' &&
00514                         format.m_riffId[2]       == 'F' &&
00515                         format.m_riffId[3]       == 'F' &&
00516                         format.m_riffFormatId[0] == 'W' &&
00517                         format.m_riffFormatId[1] == 'A' &&
00518                         format.m_riffFormatId[2] == 'V' &&
00519                         format.m_riffFormatId[3] == 'E');
00520             }
00521 
00527             static bool isValidFormatChunk(const SWaveFileFormat &format)
00528             {
00529                 return (format.m_formatId[0] == 'f' &&
00530                         format.m_formatId[1] == 'm' &&
00531                         format.m_formatId[2] == 't' &&
00532                         format.m_formatId[3] == ' ');
00533             }
00534 
00540             static bool isValidDataChunk(const SWaveFileFormat &format)
00541             {
00542                 return (format.m_dataId[0] == 'd' &&
00543                         format.m_dataId[1] == 'a' &&
00544                         format.m_dataId[2] == 't' &&
00545                         format.m_dataId[3] == 'a');
00546             }
00547 
00548 //  ===========================================================================
00549 
00550             CFileStream m_stream;                                                   
00551             typename IAudioFileFormat<TypeName>::EBitDepth m_bitDepth;              
00552         };
00553     }
00554 }
00555 #endif  // End Of TWaveFileFormat.hpp

Infinity API - TWaveFileFormat.hpp Source File generated on 7 Mar 2007