- Main Page
- Namespaces
- Classes
- Files
- Directories
- Related Pages

- File List
- File Members

# 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