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

- File List
- File Members

# 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