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
00095 CFileStream stream(filename, CFileStream::e_input, true);
00096
00097
00098 if (!stream.isStreamOpen())
00099 {
00100 return false;
00101 }
00102
00103
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
00118 typename TWaveFileFormat<TypeName>::SWaveFileFormat diskFormat;
00119 if (!readFileHeader(m_stream, diskFormat))
00120 {
00121 return false;
00122 }
00123
00124
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
00132 return true;
00133 }
00134
00140 virtual bool readData(TAudioBuffer< TypeName > &buffer)
00141 {
00142
00143 switch(m_bitDepth)
00144 {
00145 case IAudioFileFormat<TypeName>::e_eightBit:
00146 {
00147
00148 const unsigned long size = buffer.getBufferSize();
00149
00150
00151 TypeName *data = buffer.getMutableData();
00152
00153
00154
00155 unsigned char *sample = new unsigned char[size];
00156
00157
00158 if (!m_stream.readDataFromStream(sample, size))
00159 {
00160 FREE_ARRAY_POINTER(sample);
00161 return false;
00162 }
00163
00164
00165 const TypeName inversion = (TypeName)(1.0 / 255.0);
00166
00167
00168 for (unsigned long i = 0; i < size; i++)
00169 {
00170
00171
00172 *data++ = (TypeName)((((TypeName)sample[i] * inversion) * 2.0) - 1.0);
00173 }
00174
00175
00176 FREE_ARRAY_POINTER(sample);
00177 }
00178 break;
00179 case IAudioFileFormat<TypeName>::e_sixteenBit:
00180 {
00181
00182 const unsigned long size = buffer.getBufferSize();
00183
00184
00185 TypeName *data = buffer.getMutableData();
00186
00187
00188 short *sample = new short[size];
00189
00190
00191 if(!m_stream.readShortsFromStream(sample, size))
00192 {
00193 FREE_ARRAY_POINTER(sample);
00194 return false;
00195 }
00196
00197
00198 const TypeName inversion = (TypeName)(1.0 / 32768.0);
00199
00200
00201 for (unsigned long i = 0; i < size; i++)
00202 {
00203 *data++ = (TypeName)sample[i] * inversion;
00204 }
00205
00206
00207 FREE_ARRAY_POINTER(sample);
00208 }
00209 break;
00210 case IAudioFileFormat<TypeName>::e_twentyFourBit:
00211 {
00212
00213 const unsigned long size = buffer.getBufferSize();
00214
00215
00216 TypeName *data = buffer.getMutableData();
00217
00218
00219 char streamBuffer[3];
00220
00221
00222 for (unsigned long i = 0; i < size; i++)
00223 {
00224
00225 m_stream.readDataFromStream(streamBuffer, 3);
00226
00227
00228 *data++ = (TypeName)((int)CEndian::convertThreeBytesToTwentyFourBitInt(streamBuffer) << 8) / (TypeName)0x7fffffff;
00229 }
00230 }
00231 break;
00232 default:
00233 return false;
00234 break;
00235 }
00236
00237
00238 return true;
00239 }
00240
00241
00242
00248 virtual bool writeHeader(const typename IAudioFileFormat<TypeName>::SAudioFileFormat &format)
00249 {
00250
00251 if (!m_stream.isStreamOpen())
00252 {
00253 return false;
00254 }
00255
00256
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
00266 m_stream << 'R' << 'I' << 'F' << 'F'
00267 << totalSize
00268 << 'W' << 'A' << 'V' << 'E'
00269 << 'f' << 'm' << 't' << ' '
00270 << (long)16
00271 << (short)1
00272 << (short)format.m_numberOfChannels
00273 << sampleRate
00274 << (long)bytesPerSample
00275 << (short)numberOfBytes
00276 << (short)depth
00277 << 'd' << 'a' << 't' << 'a'
00278 << chunkSize;
00279
00280
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
00299 m_stream << (unsigned char)(255.0 * ((data[i] + 1.0) * 0.5));
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
00309 m_stream << (short)(data[i] * 32768);
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
00330 return true;
00331 }
00332
00333
00334
00335 protected:
00336
00337
00338
00343 struct SWaveFileFormat
00344 {
00345
00346 char m_riffId[4];
00347 unsigned long m_riffSize;
00348 char m_riffFormatId[4];
00350
00351 char m_formatId[4];
00352 unsigned long m_formatSize;
00354
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
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
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
00395 if (!isValidRiffWaveChunk(diskFormat))
00396 {
00397 return false;
00398 }
00399
00400
00401
00402 bool foundTag = false;
00403 do
00404 {
00405
00406 stream >> diskFormat.m_formatId[0] >> diskFormat.m_formatId[1] >> diskFormat.m_formatId[2] >> diskFormat.m_formatId[3];
00407
00408
00409 stream >> diskFormat.m_formatSize;
00410
00411
00412 foundTag = isValidFormatChunk(diskFormat);
00413
00414
00415 if (stream.hasErrorOccurred())
00416 {
00417 return false;
00418 }
00419
00420
00421 if (!foundTag)
00422 {
00423 stream.advanceStream(diskFormat.m_formatSize);
00424 }
00425
00426 }while(!foundTag);
00427
00428
00429 stream >> diskFormat.m_formatTag;
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446 if (diskFormat.m_formatTag != 1)
00447 {
00448 return false;
00449 }
00450
00451
00452 stream >> diskFormat.m_numberOfChannels
00453 >> diskFormat.m_sampleRate
00454 >> diskFormat.m_bytesPerSecond
00455 >> diskFormat.m_blockAlignment
00456 >> diskFormat.m_bitsPerSample;
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475 foundTag = false;
00476
00477 do
00478 {
00479
00480 stream >> diskFormat.m_dataId[0] >> diskFormat.m_dataId[1] >> diskFormat.m_dataId[2] >> diskFormat.m_dataId[3] >> diskFormat.m_dataSize;
00481
00482
00483 foundTag = isValidDataChunk(diskFormat);
00484
00485
00486 if (stream.hasErrorOccurred())
00487 {
00488 return false;
00489 }
00490
00491
00492 if (!foundTag)
00493 {
00494 stream.advanceStream(diskFormat.m_dataSize);
00495 }
00496 }while(!foundTag);
00497
00498
00499 diskFormat.m_numberOfSamples = diskFormat.m_dataSize / diskFormat.m_blockAlignment;
00500
00501
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