TAiffFileFormat.hpp

Go to the documentation of this file.
00001 #ifndef __TAiffFileFormat__
00002 #define __TAiffFileFormat__
00003 
00004 #include <Host/CEndian.hpp>
00005 #include "IAudioFileFormat.hpp"
00006 using Exponent::Audio::IAudioFileFormat;
00007 using Exponent::Host::CEndian;
00008 
00013 #define DOUBLE_TO_UNSIGNED_LONG(f)((unsigned long)(((long)(f - 2147483648.0)) + 2147483647L) + 1)
00014 
00015 //  ===========================================================================
00016 
00017 namespace Exponent
00018 {
00019     namespace Audio
00020     {
00041         template<typename TypeName> class TAiffFileFormat : public IAudioFileFormat<TypeName>
00042         {
00043         public:
00044 
00048             TAiffFileFormat()
00049             {
00050                 m_bitDepth = IAudioFileFormat<TypeName>::e_sixteenBit;
00051             }
00052 
00056             virtual ~TAiffFileFormat()
00057             {
00058                 m_stream.closeStream();
00059             }
00060 
00061 //  ===========================================================================
00062 
00069             virtual bool openFile(CFileStream::EStreamMode mode, const CSystemString &filename)
00070             {
00071                 return m_stream.openStream(filename, mode, false);
00072             }
00073 
00078             virtual bool closeFile()
00079             {
00080                 m_stream.closeStream();
00081                 return true;
00082             }
00083 
00084 //  ===========================================================================
00085 
00090             virtual void getFileExtension(TStringCountedPointerArray &array) const
00091             {
00092                 array.addElement(new CString("aif"));
00093                 array.addElement(new CString("aiff"));
00094                 array.addElement(new CString("aifc"));
00095             }
00096 
00102             virtual bool isValidFormat(const CSystemString &filename) const
00103             {
00104                 // Create the stream
00105                 CFileStream stream(filename, CFileStream::e_input, true);
00106 
00107                 // Check open
00108                 if (!stream.isStreamOpen())
00109                 {
00110                     return false;
00111                 }
00112 
00113                 // Read in the header
00114                 typename TAiffFileFormat<TypeName>::SAiffFileFormat diskFormat;
00115                 return readFileHeader(stream, diskFormat);
00116             }
00117 
00118 //  ===========================================================================
00119 
00125             virtual bool readHeader(typename IAudioFileFormat<TypeName>::SAudioFileFormat &format)
00126             {
00127                 // Read in the header
00128                 typename TAiffFileFormat<TypeName>::SAiffFileFormat diskFormat;
00129                 if (!readFileHeader(m_stream, diskFormat))
00130                 {
00131                     return false;
00132                 }
00133                 // STore the output information
00134                 format.m_sampleRate       = diskFormat.m_sampleRate;
00135                 format.m_numberOfChannels = diskFormat.m_numberOfChannels;
00136                 format.m_numberOfSamples  = diskFormat.m_numberOfSampleFrames;
00137                 format.m_bitDepth         = (unsigned long)diskFormat.m_bitsPerSample;
00138                 m_bitDepth                = (typename IAudioFileFormat<TypeName>::EBitDepth)format.m_bitDepth;
00139 
00140                 // Done :)
00141                 return true;
00142             }
00143 
00149             virtual bool readData(TAudioBuffer< TypeName > &buffer)
00150             {
00151                 //m_stream.setStreamEndianess(true);
00152 
00153                 // Handle based upon the depth
00154                 switch(m_bitDepth)
00155                 {
00156                     case IAudioFileFormat<TypeName>::e_eightBit:
00157                         {
00158                             // Store the entire size of the buffer to be read in
00159                             const unsigned long size = buffer.getBufferSize();
00160 
00161                             // Pointer to the data that we will iterate through
00162                             TypeName *data = buffer.getMutableData();
00163 
00164                             // The sample we read in to
00165                             //unsigned char sample = 0;
00166                             unsigned char *sample = new unsigned char[size];
00167 
00168                             // Read the audio data
00169                             if (!m_stream.readDataFromStream(sample, size))
00170                             {
00171                                 FREE_ARRAY_POINTER(sample);
00172                                 return false;
00173                             }
00174 
00175                             // Save doing multiple divisions...
00176                             const TypeName inversion = (TypeName)(1.0 / 255.0);
00177 
00178                             // For the number of samples, we want to read in and convert to floating point range..
00179                             for (unsigned long i = 0; i < size; i++)
00180                             {
00181                                 //m_stream >> sample;
00182                                 //*data++ = (TypeName)((((TypeName)sample / (TypeName)255) * 2.0) - 1.0);
00183                                 *data++ = (TypeName)((((TypeName)sample[i] * inversion) * 2.0) - 1.0);
00184                             }
00185 
00186                             // Delete the buffer we loaded with
00187                             FREE_ARRAY_POINTER(sample);
00188                         }
00189                     break;
00190                     case IAudioFileFormat<TypeName>::e_sixteenBit:
00191                         {
00192                             // Store the entire size of the buffer to be read in
00193                             const unsigned long size = buffer.getBufferSize();
00194 
00195                             // Pointer to the data that we will iterate through
00196                             TypeName *data = buffer.getMutableData();
00197 
00198                             // The sample we read in to
00199                             short *sample = new short[size];
00200 
00201                             // Read the audio data
00202                             if(!m_stream.readShortsFromStream(sample, size))
00203                             {
00204                                 FREE_ARRAY_POINTER(sample);
00205                                 return false;
00206                             }
00207 
00208                             // Save doing multiple divisions...
00209                             const TypeName inversion = (TypeName)(1.0 / 32768.0);
00210 
00211                             // For the number of samples, we want to read in and convert to floating point range..
00212                             for (unsigned long i = 0; i < size; i++)
00213                             {
00214                                 *data++ = (TypeName)sample[i] * inversion;
00215                             }
00216 
00217                             // Delete the sample buffer...
00218                             FREE_ARRAY_POINTER(sample);
00219                         }
00220                     break;
00221                     case IAudioFileFormat<TypeName>::e_twentyFourBit:
00222                         {
00223                             // Store the entire size of the buffer to be read in
00224                             const unsigned long size = buffer.getBufferSize();
00225 
00226                             // Pointer to the data that we will iterate through
00227                             TypeName *data = buffer.getMutableData();
00228 
00229                             // The sample we read in to
00230                             char streamBuffer[3];
00231 
00232                             // For the number of samples, we want to read in and convert to floating point range..
00233                             for (unsigned long i = 0; i < size; i++)
00234                             {
00235                                 // Read the 3 bytes from the buffer
00236                                 m_stream.readDataFromStream(streamBuffer, 3);
00237 
00238                                 // Convert sample
00239                                 *data++ = (TypeName)((int)CEndian::convertThreeBytesToTwentyFourBitInt(streamBuffer) << 8) / (TypeName)0x7fffffff;
00240                             }
00241                         }
00242                     break;
00243                     default:
00244                         return false;
00245                     break;
00246                 }
00247 
00248                 //m_stream.setStreamEndianess(false);
00249 
00250                 // Sucess!
00251                 return true;
00252             }
00253 
00254 //  ===========================================================================
00255 
00261             virtual bool writeHeader(const typename IAudioFileFormat<TypeName>::SAudioFileFormat &format)
00262             {
00263                 // Check open
00264                 if (!m_stream.isStreamOpen())
00265                 {
00266                     return false;
00267                 }
00268 
00269                 const long numberOfBytes  = format.m_numberOfChannels * ((const long)format.m_bitDepth) / 8;
00270                 const long bytesPerSample = numberOfBytes * (const long)format.m_sampleRate;
00271                 const long sndSize        = numberOfBytes * format.m_numberOfSamples + 8;
00272                 const long totalSize      = sndSize +
00273                                             8  /* SSND Chunk */ +
00274                                             10 /* 80 Bit SR */  +
00275                                             8  /* FORM Chunk */ +
00276                                             12 /* AIFF / COMM / Chunk */ +
00277                                             4  /* Num channels + bit depth */ +
00278                                             4  /* Num samples */ -
00279                                             8;
00280 
00281 
00282                 // Stream the header information
00283                 m_stream << 'F' << 'O' << 'R' << 'M'                // FORM header
00284                          << totalSize                               // File size
00285                          << 'A' << 'I' << 'F' << 'F'                // AIFF header
00286                          << 'C' << 'O' << 'M' << 'M'                // COMM header
00287                          << (long)18                                // Comm size                // 4
00288                          << (short)format.m_numberOfChannels        // Number of channels       // 2
00289                          << (unsigned long)format.m_numberOfSamples // Sample frames            // 4
00290                          << (short)format.m_bitDepth;               // Bit depth                // 2
00291 
00292                 // Write the 80 bit sample rate
00293                 if (!write80BitSampleRate(m_stream, format.m_sampleRate))
00294                 {
00295                     return false;
00296                 }
00297 
00298                 // Stream the SSND header
00299                 m_stream << 'S' << 'S' << 'N' << 'D'                // SSND header
00300                          << sndSize                                 // Size of chunk
00301                          << (unsigned long)0                        // Offset 0
00302                          << (unsigned long)0;                       // Block size 0
00303 
00304                 return true;
00305             }
00306 
00312             virtual bool writeData(const TAudioBuffer< TypeName > &buffer)
00313             {
00314                 switch(m_bitDepth)
00315                 {
00316                     case IAudioFileFormat<TypeName>::e_eightBit:
00317                         {
00318                             const TypeName *data = buffer.getData();
00319                             for (unsigned long i = 0; i < buffer.getNumberOfChannels() * buffer.getNumberOfSamples(); i++)
00320                             {
00321                                 //unsigned char sample = (unsigned char)(255.0 * ((data[i] + 1.0) * 0.5));
00322                                 m_stream << (unsigned char)(255.0 * ((data[i] + 1.0) * 0.5));//sample;
00323                             }
00324                         }
00325                     break;
00326                     case IAudioFileFormat<TypeName>::e_sixteenBit:
00327                         {
00328                             const TypeName *data = buffer.getData();
00329                             for (unsigned long i = 0; i < buffer.getNumberOfChannels() * buffer.getNumberOfSamples(); i++)
00330                             {
00331                                 //short sample = (short)(data[i] * 32768);
00332                                 m_stream << (short)(data[i] * 32768);//sample;
00333                             }
00334                         }
00335                     break;
00336                     case IAudioFileFormat<TypeName>::e_twentyFourBit:
00337                         {
00338                             const TypeName *data = buffer.getData();
00339                             char samples[3];
00340                             for (unsigned long i = 0; i < buffer.getNumberOfChannels() * buffer.getNumberOfSamples(); i++)
00341                             {
00342                                 CEndian::convertTwentyFourBitIntToThreeBytes((int)(data[i] * (double)0x7fffffff) >> 8, samples);
00343                                 m_stream.writeDataToStream(samples, 3);
00344                             }
00345                         }
00346                     break;
00347                     default:
00348                         return false;
00349                     break;
00350                 }
00351 
00352                 // Done! :)
00353                 return true;
00354             }
00355 
00356 //  ===========================================================================
00357 
00358         protected:
00359 
00360 //  ===========================================================================
00361 
00366             struct SAiffFileFormat
00367             {
00368                 // FORM chunk
00369                 char m_formId[4];                       
00370                 long m_formSize;                        
00371                 char m_aiffFormatId[4];                 
00373                 // COMM chunk
00374                 char m_commId[4];                       
00375                 long m_commSize;                        
00376                 short m_numberOfChannels;               
00377                 unsigned long m_numberOfSampleFrames;   
00378                 short m_bitsPerSample;                  
00379                 char m_sampleRateBuffer[10];            
00380                 unsigned long m_sampleRate;             
00382                 // SSND chunk
00383                 char m_ssndId[4];                       
00384                 long m_ssndSize;                        
00385                 unsigned long m_offset;                 
00386                 unsigned long m_blockSize;              
00387             };
00388 
00389 //  ===========================================================================
00390 
00397             static bool readFileHeader(CFileStream &stream, SAiffFileFormat &diskFormat)
00398             {
00399                 // Check stream is open
00400                 if (!stream.isStreamOpen())
00401                 {
00402                     return false;
00403                 }
00404 
00405                 // Read the riff header
00406                 stream >> diskFormat.m_formId[0]
00407                        >> diskFormat.m_formId[1]
00408                        >> diskFormat.m_formId[2]
00409                        >> diskFormat.m_formId[3]
00410                        >> diskFormat.m_formSize
00411                        >> diskFormat.m_aiffFormatId[0]
00412                        >> diskFormat.m_aiffFormatId[1]
00413                        >> diskFormat.m_aiffFormatId[2]
00414                        >> diskFormat.m_aiffFormatId[3];
00415 
00416                 // Is this actually a wave format file?
00417                 if (!isValidAiffWaveChunk(diskFormat))
00418                 {
00419                     return false;
00420                 }
00421 
00422                 // REad the comm id
00423                 stream >> diskFormat.m_commId[0]
00424                        >> diskFormat.m_commId[1]
00425                        >> diskFormat.m_commId[2]
00426                        >> diskFormat.m_commId[3]
00427                        >> diskFormat.m_commSize;
00428 
00429                 // Check the comm chuink
00430                 if (!isValidCommChunk(diskFormat))
00431                 {
00432                     return false;
00433                 }
00434 
00435                 // Read the channel information
00436                 stream >> diskFormat.m_numberOfChannels
00437                        >> diskFormat.m_numberOfSampleFrames
00438                        >> diskFormat.m_bitsPerSample;
00439 
00440                 // Read the sample rate format...
00441                 read80BitSampleRate(stream, diskFormat);
00442 
00443                 // Read the SSND format
00444                 stream >> diskFormat.m_ssndId[0]
00445                        >> diskFormat.m_ssndId[1]
00446                        >> diskFormat.m_ssndId[2]
00447                        >> diskFormat.m_ssndId[3]
00448                        >> diskFormat.m_ssndSize
00449                        >> diskFormat.m_offset
00450                        >> diskFormat.m_blockSize;
00451 
00452                 // Check its a valid SSND chunk...
00453                 if (!isValidSSNDChunk(diskFormat))
00454                 {
00455                     return false;
00456                 }
00457 
00458                 // We are done!
00459                 return true;
00460             }
00461 
00467             static bool isValidAiffWaveChunk(const SAiffFileFormat &format)
00468             {
00469                 return (format.m_formId[0]       == 'F' &&
00470                         format.m_formId[1]       == 'O' &&
00471                         format.m_formId[2]       == 'R' &&
00472                         format.m_formId[3]       == 'M' &&
00473                         format.m_aiffFormatId[0] == 'A' &&
00474                         format.m_aiffFormatId[1] == 'I' &&
00475                         format.m_aiffFormatId[2] == 'F' &&
00476                         format.m_aiffFormatId[3] == 'F');
00477             }
00478 
00484             static bool isValidCommChunk(const SAiffFileFormat &format)
00485             {
00486                 return (format.m_commId[0] == 'C' &&
00487                         format.m_commId[1] == 'O' &&
00488                         format.m_commId[2] == 'M' &&
00489                         format.m_commId[3] == 'M');
00490             }
00491 
00498             static bool read80BitSampleRate(CFileStream &stream, SAiffFileFormat &diskFormat)
00499             {
00500                 // Stream in the samples
00501                 if (!stream.readDataFromStream(diskFormat.m_sampleRateBuffer, 10 * sizeof(char)))
00502                 {
00503                     return false;
00504                 }
00505 
00506                 // Setup some temporary variables
00507                 unsigned long last    = 0;
00508                 unsigned char *buffer = (unsigned char *)diskFormat.m_sampleRateBuffer;
00509 
00510                 // Swap the bytes over
00511                 CEndian::swapFourBytesIfSystemIsLittleEndian((unsigned char *)((unsigned long *)(buffer + 2)));
00512 
00513                 // First convert
00514                 diskFormat.m_sampleRate = foolToLong((unsigned long *)(buffer + 2));
00515                 unsigned char exponent  = 30 - *(buffer + 1);
00516 
00517                 // Work out the long value
00518                 while (exponent--)
00519                 {
00520                     last = diskFormat.m_sampleRate;
00521                     diskFormat.m_sampleRate >>= 1;
00522                 }
00523 
00524                 // Move on by one to avoid rounding error
00525                 if (last & 0x00000001) diskFormat.m_sampleRate++;
00526 
00527                 // done
00528                 return true;
00529             }
00530 
00537             static bool write80BitSampleRate(CFileStream &stream, const unsigned long sampleRate)
00538             {
00539                 // Check its open
00540                 if (!stream.isStreamOpen())
00541                 {
00542                     return false;
00543                 }
00544 
00545                 // Construct the buffer to write to
00546                 unsigned char buff[10];
00547                 memset(buff, 0, 10 * sizeof(char));
00548 
00549                 // Store local
00550                 unsigned long sr = sampleRate;
00551 
00552                 // Get the SR
00553                 get80BitFloatingPointNumber(buff, sr);
00554 
00555                 // Stream out the sample rate
00556                 return stream.writeDataToStream(buff, 10 * sizeof(char));
00557             }
00558 
00565             static void get80BitFloatingPointNumber(unsigned char *buffer, unsigned long value)
00566             {
00567                 // Setup some temporary variables
00568                 double doubleValue            = (double)value;
00569                 int sign                      = 0;
00570                 int exponent                  = 0;
00571                 double mantissa               = 0.0;
00572                 double fullScaleMantissa      = 0.0;
00573                 unsigned long highBitMantissa = 0;
00574                 unsigned long lowBitMantissa  = 0;
00575 
00576                 // First check if the value is negative and iff we have a sign bit
00577                 if (doubleValue < 0)
00578                 {
00579                     sign         = 0x8000;
00580                     doubleValue *= -1;
00581                 }
00582                 else
00583                 {
00584                     sign = 0;
00585                 }
00586 
00587                 // Now compute the exponent and mantissa
00588                 if (doubleValue == 0)
00589                 {
00590                     exponent        = 0;
00591                     highBitMantissa = 0;
00592                     lowBitMantissa  = 0;
00593                 }
00594                 else
00595                 {
00596                     mantissa = frexp(doubleValue, &exponent);
00597                     if ((exponent > 16384) || !(mantissa < 1))
00598                     {
00599                         // Number is infinite or NaN
00600                         exponent        = sign | 0x7FFF;
00601                         highBitMantissa = 0;
00602                         lowBitMantissa  = 0;
00603                     }
00604                     else
00605                     {
00606                         // Finite number
00607                         exponent += 16382;
00608                         if (exponent < 0)
00609                         {
00610                             // Denormalized
00611                             mantissa = ldexp(mantissa, exponent);
00612                             exponent = 0;
00613                         }
00614                         exponent         |= sign;
00615                         mantissa          = ldexp(mantissa, 32);
00616                         fullScaleMantissa = floor(mantissa);
00617                         highBitMantissa   = DOUBLE_TO_UNSIGNED_LONG(fullScaleMantissa);
00618                         mantissa          = ldexp(mantissa - fullScaleMantissa, 32);
00619                         fullScaleMantissa = floor(mantissa);
00620                         lowBitMantissa    = DOUBLE_TO_UNSIGNED_LONG(fullScaleMantissa);
00621                     }
00622                 }
00623 
00624                 // Bit shift the buffer to the correct places
00625                 buffer[0] = exponent >> 8;
00626                 buffer[1] = exponent;
00627                 buffer[2] = highBitMantissa >> 24;
00628                 buffer[3] = highBitMantissa >> 16;
00629                 buffer[4] = highBitMantissa >> 8;
00630                 buffer[5] = highBitMantissa;
00631                 buffer[6] = lowBitMantissa >> 24;
00632                 buffer[7] = lowBitMantissa >> 16;
00633                 buffer[8] = lowBitMantissa >> 8;
00634                 buffer[9] = lowBitMantissa;
00635             }
00636 
00642             static bool isValidSSNDChunk(const SAiffFileFormat &format)
00643             {
00644                 return (format.m_ssndId[0] == 'S' &&
00645                         format.m_ssndId[1] == 'S' &&
00646                         format.m_ssndId[2] == 'N' &&
00647                         format.m_ssndId[3] == 'D');
00648             }
00649 
00655             static unsigned long foolToLong(unsigned long *ptr)
00656             {
00657                 return(*ptr);
00658             }
00659 
00660 //  ===========================================================================
00661 
00662             CFileStream m_stream;                                                   
00663             typename IAudioFileFormat<TypeName>::EBitDepth m_bitDepth;              
00664         };
00665     }
00666 }
00667 #endif  // End Of TAiffFileFormat.hpp

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