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
00105 CFileStream stream(filename, CFileStream::e_input, true);
00106
00107
00108 if (!stream.isStreamOpen())
00109 {
00110 return false;
00111 }
00112
00113
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
00128 typename TAiffFileFormat<TypeName>::SAiffFileFormat diskFormat;
00129 if (!readFileHeader(m_stream, diskFormat))
00130 {
00131 return false;
00132 }
00133
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
00141 return true;
00142 }
00143
00149 virtual bool readData(TAudioBuffer< TypeName > &buffer)
00150 {
00151
00152
00153
00154 switch(m_bitDepth)
00155 {
00156 case IAudioFileFormat<TypeName>::e_eightBit:
00157 {
00158
00159 const unsigned long size = buffer.getBufferSize();
00160
00161
00162 TypeName *data = buffer.getMutableData();
00163
00164
00165
00166 unsigned char *sample = new unsigned char[size];
00167
00168
00169 if (!m_stream.readDataFromStream(sample, size))
00170 {
00171 FREE_ARRAY_POINTER(sample);
00172 return false;
00173 }
00174
00175
00176 const TypeName inversion = (TypeName)(1.0 / 255.0);
00177
00178
00179 for (unsigned long i = 0; i < size; i++)
00180 {
00181
00182
00183 *data++ = (TypeName)((((TypeName)sample[i] * inversion) * 2.0) - 1.0);
00184 }
00185
00186
00187 FREE_ARRAY_POINTER(sample);
00188 }
00189 break;
00190 case IAudioFileFormat<TypeName>::e_sixteenBit:
00191 {
00192
00193 const unsigned long size = buffer.getBufferSize();
00194
00195
00196 TypeName *data = buffer.getMutableData();
00197
00198
00199 short *sample = new short[size];
00200
00201
00202 if(!m_stream.readShortsFromStream(sample, size))
00203 {
00204 FREE_ARRAY_POINTER(sample);
00205 return false;
00206 }
00207
00208
00209 const TypeName inversion = (TypeName)(1.0 / 32768.0);
00210
00211
00212 for (unsigned long i = 0; i < size; i++)
00213 {
00214 *data++ = (TypeName)sample[i] * inversion;
00215 }
00216
00217
00218 FREE_ARRAY_POINTER(sample);
00219 }
00220 break;
00221 case IAudioFileFormat<TypeName>::e_twentyFourBit:
00222 {
00223
00224 const unsigned long size = buffer.getBufferSize();
00225
00226
00227 TypeName *data = buffer.getMutableData();
00228
00229
00230 char streamBuffer[3];
00231
00232
00233 for (unsigned long i = 0; i < size; i++)
00234 {
00235
00236 m_stream.readDataFromStream(streamBuffer, 3);
00237
00238
00239 *data++ = (TypeName)((int)CEndian::convertThreeBytesToTwentyFourBitInt(streamBuffer) << 8) / (TypeName)0x7fffffff;
00240 }
00241 }
00242 break;
00243 default:
00244 return false;
00245 break;
00246 }
00247
00248
00249
00250
00251 return true;
00252 }
00253
00254
00255
00261 virtual bool writeHeader(const typename IAudioFileFormat<TypeName>::SAudioFileFormat &format)
00262 {
00263
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 +
00274 10 +
00275 8 +
00276 12 +
00277 4 +
00278 4 -
00279 8;
00280
00281
00282
00283 m_stream << 'F' << 'O' << 'R' << 'M'
00284 << totalSize
00285 << 'A' << 'I' << 'F' << 'F'
00286 << 'C' << 'O' << 'M' << 'M'
00287 << (long)18
00288 << (short)format.m_numberOfChannels
00289 << (unsigned long)format.m_numberOfSamples
00290 << (short)format.m_bitDepth;
00291
00292
00293 if (!write80BitSampleRate(m_stream, format.m_sampleRate))
00294 {
00295 return false;
00296 }
00297
00298
00299 m_stream << 'S' << 'S' << 'N' << 'D'
00300 << sndSize
00301 << (unsigned long)0
00302 << (unsigned long)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
00322 m_stream << (unsigned char)(255.0 * ((data[i] + 1.0) * 0.5));
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
00332 m_stream << (short)(data[i] * 32768);
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
00353 return true;
00354 }
00355
00356
00357
00358 protected:
00359
00360
00361
00366 struct SAiffFileFormat
00367 {
00368
00369 char m_formId[4];
00370 long m_formSize;
00371 char m_aiffFormatId[4];
00373
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
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
00400 if (!stream.isStreamOpen())
00401 {
00402 return false;
00403 }
00404
00405
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
00417 if (!isValidAiffWaveChunk(diskFormat))
00418 {
00419 return false;
00420 }
00421
00422
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
00430 if (!isValidCommChunk(diskFormat))
00431 {
00432 return false;
00433 }
00434
00435
00436 stream >> diskFormat.m_numberOfChannels
00437 >> diskFormat.m_numberOfSampleFrames
00438 >> diskFormat.m_bitsPerSample;
00439
00440
00441 read80BitSampleRate(stream, diskFormat);
00442
00443
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
00453 if (!isValidSSNDChunk(diskFormat))
00454 {
00455 return false;
00456 }
00457
00458
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
00501 if (!stream.readDataFromStream(diskFormat.m_sampleRateBuffer, 10 * sizeof(char)))
00502 {
00503 return false;
00504 }
00505
00506
00507 unsigned long last = 0;
00508 unsigned char *buffer = (unsigned char *)diskFormat.m_sampleRateBuffer;
00509
00510
00511 CEndian::swapFourBytesIfSystemIsLittleEndian((unsigned char *)((unsigned long *)(buffer + 2)));
00512
00513
00514 diskFormat.m_sampleRate = foolToLong((unsigned long *)(buffer + 2));
00515 unsigned char exponent = 30 - *(buffer + 1);
00516
00517
00518 while (exponent--)
00519 {
00520 last = diskFormat.m_sampleRate;
00521 diskFormat.m_sampleRate >>= 1;
00522 }
00523
00524
00525 if (last & 0x00000001) diskFormat.m_sampleRate++;
00526
00527
00528 return true;
00529 }
00530
00537 static bool write80BitSampleRate(CFileStream &stream, const unsigned long sampleRate)
00538 {
00539
00540 if (!stream.isStreamOpen())
00541 {
00542 return false;
00543 }
00544
00545
00546 unsigned char buff[10];
00547 memset(buff, 0, 10 * sizeof(char));
00548
00549
00550 unsigned long sr = sampleRate;
00551
00552
00553 get80BitFloatingPointNumber(buff, sr);
00554
00555
00556 return stream.writeDataToStream(buff, 10 * sizeof(char));
00557 }
00558
00565 static void get80BitFloatingPointNumber(unsigned char *buffer, unsigned long value)
00566 {
00567
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
00577 if (doubleValue < 0)
00578 {
00579 sign = 0x8000;
00580 doubleValue *= -1;
00581 }
00582 else
00583 {
00584 sign = 0;
00585 }
00586
00587
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
00600 exponent = sign | 0x7FFF;
00601 highBitMantissa = 0;
00602 lowBitMantissa = 0;
00603 }
00604 else
00605 {
00606
00607 exponent += 16382;
00608 if (exponent < 0)
00609 {
00610
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
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