2 Copyright (c) 2005-2009, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 \brief Wave file common elements
35 using Kumu::DefaultLogSink;
38 const ui32_t SimpleWavHeaderLength = 46;
41 ASDCP::Wav::SimpleWaveHeader::SimpleWaveHeader(ASDCP::PCM::AudioDescriptor& ADesc)
44 nchannels = ADesc.ChannelCount;
45 bitspersample = ADesc.QuantizationBits;
46 samplespersec = (ui32_t)ceil(ADesc.AudioSamplingRate.Quotient());
47 blockalign = nchannels * ((bitspersample + 7) / 8);
48 avgbps = samplespersec * blockalign;
50 data_len = ASDCP::PCM::CalcFrameBufferSize(ADesc) * ADesc.ContainerDuration;
55 ASDCP::Wav::SimpleWaveHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const
57 ADesc.EditRate = PictureRate;
59 ADesc.LinkedTrackID = 0;
61 ADesc.ChannelCount = nchannels;
62 ADesc.AudioSamplingRate = Rational(samplespersec, 1);
63 ADesc.AvgBps = avgbps;
64 ADesc.BlockAlign = blockalign;
65 ADesc.QuantizationBits = bitspersample;
66 ui32_t FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(ADesc);
67 ADesc.ContainerDuration = data_len / FrameBufferSize;
68 ADesc.ChannelFormat = PCM::CF_NONE;
74 ASDCP::Wav::SimpleWaveHeader::WriteToFile(Kumu::FileWriter& OutFile) const
77 byte_t tmp_header[SimpleWavHeaderLength];
78 byte_t* p = tmp_header;
80 static ui32_t fmt_len =
83 + sizeof(samplespersec)
86 + sizeof(bitspersample)
89 ui32_t RIFF_len = data_len + SimpleWavHeaderLength - 8;
91 memcpy(p, &FCC_RIFF, sizeof(fourcc)); p += 4;
92 *((ui32_t*)p) = KM_i32_LE(RIFF_len); p += 4;
93 memcpy(p, &FCC_WAVE, sizeof(fourcc)); p += 4;
94 memcpy(p, &FCC_fmt_, sizeof(fourcc)); p += 4;
95 *((ui32_t*)p) = KM_i32_LE(fmt_len); p += 4;
96 *((ui16_t*)p) = KM_i16_LE(format); p += 2;
97 *((ui16_t*)p) = KM_i16_LE(nchannels); p += 2;
98 *((ui32_t*)p) = KM_i32_LE(samplespersec); p += 4;
99 *((ui32_t*)p) = KM_i32_LE(avgbps); p += 4;
100 *((ui16_t*)p) = KM_i16_LE(blockalign); p += 2;
101 *((ui16_t*)p) = KM_i16_LE(bitspersample); p += 2;
102 *((ui16_t*)p) = KM_i16_LE(cbsize); p += 2;
103 memcpy(p, &FCC_data, sizeof(fourcc)); p += 4;
104 *((ui32_t*)p) = KM_i32_LE(data_len); p += 4;
106 return OutFile.Write(tmp_header, SimpleWavHeaderLength, &write_count);
111 ASDCP::Wav::SimpleWaveHeader::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start)
113 ui32_t read_count = 0;
114 ui32_t local_data_start = 0;
115 ASDCP::PCM::FrameBuffer TmpBuffer(MaxWavHeader);
117 if ( data_start == 0 )
118 data_start = &local_data_start;
120 Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count);
122 if ( ASDCP_SUCCESS(result) )
123 result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start);
129 ASDCP::Wav::SimpleWaveHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start)
131 if ( buf_len < SimpleWavHeaderLength )
132 return RESULT_SMALLBUF;
135 const byte_t* p = buf;
136 const byte_t* end_p = p + buf_len;
138 fourcc test_RIFF(p); p += 4;
139 if ( test_RIFF != FCC_RIFF )
141 // DefaultLogSink().Debug("File does not begin with RIFF header\n");
142 return RESULT_RAW_FORMAT;
145 ui32_t RIFF_len = KM_i32_LE(*(ui32_t*)p); p += 4;
147 fourcc test_WAVE(p); p += 4;
148 if ( test_WAVE != FCC_WAVE )
150 DefaultLogSink().Debug("File does not contain a WAVE header\n");
151 return RESULT_RAW_FORMAT;
158 test_fcc = fourcc(p); p += 4;
159 ui32_t chunk_size = KM_i32_LE(*(ui32_t*)p); p += 4;
161 if ( test_fcc == FCC_data )
163 if ( chunk_size > RIFF_len )
165 DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len);
166 return RESULT_RAW_FORMAT;
169 data_len = chunk_size;
170 *data_start = p - buf;
174 if ( test_fcc == FCC_fmt_ )
176 ui16_t format = KM_i16_LE(*(ui16_t*)p); p += 2;
178 if ( format != WAVE_FORMAT_PCM && format != WAVE_FORMAT_EXTENSIBLE )
180 DefaultLogSink().Error("Expecting uncompressed PCM data, got format type %hd\n", format);
181 return RESULT_RAW_FORMAT;
184 nchannels = KM_i16_LE(*(ui16_t*)p); p += 2;
185 samplespersec = KM_i32_LE(*(ui32_t*)p); p += 4;
186 avgbps = KM_i32_LE(*(ui32_t*)p); p += 4;
187 blockalign = KM_i16_LE(*(ui16_t*)p); p += 2;
188 bitspersample = KM_i16_LE(*(ui16_t*)p); p += 2;
189 p += chunk_size - 16; // 16 is the number of bytes read in this block
197 if ( *data_start == 0 ) // can't have no data!
199 DefaultLogSink().Error("No data chunk found, file contains no essence\n");
200 return RESULT_RAW_FORMAT;
206 //------------------------------------------------------------------------------------------
207 // conversion algorithms from http://www.borg.com/~jglatt/tech/aiff.htm
211 Rat_to_extended(ASDCP::Rational rate, byte_t* buf)
214 ui32_t value = (ui32_t)ceil(rate.Quotient());
219 for ( ; i < 32; i++ )
228 for ( i = 32; i != 0 ; i-- )
230 if ( value & 0x80000000 )
235 *(ui32_t*)(buf+2) = KM_i32_BE(value);
240 extended_to_Rat(const byte_t* buf)
243 ui32_t mantissa = KM_i32_BE(*(ui32_t*)(buf+2));
245 byte_t exp = 30 - *(buf+1);
253 if ( last & 0x00000001 )
256 return ASDCP::Rational(mantissa, 1);
261 ASDCP::AIFF::SimpleAIFFHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const
263 ADesc.EditRate = PictureRate;
265 ADesc.ChannelCount = numChannels;
266 ADesc.AudioSamplingRate = extended_to_Rat(sampleRate);
267 ADesc.QuantizationBits = sampleSize;
268 ADesc.BlockAlign = sampleSize / 8;
269 ADesc.AvgBps = (ui32_t) (ADesc.BlockAlign * ADesc.AudioSamplingRate.Quotient());
270 ui32_t FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(ADesc);
271 ADesc.ContainerDuration = data_len / FrameBufferSize;
272 ADesc.ChannelFormat = PCM::CF_NONE;
277 ASDCP::AIFF::SimpleAIFFHeader::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start)
279 ui32_t read_count = 0;
280 ui32_t local_data_start = 0;
281 ASDCP::PCM::FrameBuffer TmpBuffer(Wav::MaxWavHeader);
283 if ( data_start == 0 )
284 data_start = &local_data_start;
286 Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count);
288 if ( ASDCP_SUCCESS(result) )
289 result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start);
296 ASDCP::AIFF::SimpleAIFFHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start)
299 return RESULT_SMALLBUF;
302 const byte_t* p = buf;
303 const byte_t* end_p = p + buf_len;
305 fourcc test_FORM(p); p += 4;
306 if ( test_FORM != FCC_FORM )
308 // DefaultLogSink().Debug("File does not begin with FORM header\n");
309 return RESULT_RAW_FORMAT;
312 ui32_t RIFF_len = KM_i32_BE(*(ui32_t*)p); p += 4;
314 fourcc test_AIFF(p); p += 4;
315 if ( test_AIFF != FCC_AIFF )
317 DefaultLogSink().Debug("File does not contain an AIFF header\n");
318 return RESULT_RAW_FORMAT;
325 test_fcc = fourcc(p); p += 4;
326 ui32_t chunk_size = KM_i32_BE(*(ui32_t*)p); p += 4;
328 if ( test_fcc == FCC_COMM )
330 numChannels = KM_i16_BE(*(ui16_t*)p); p += 2;
331 numSampleFrames = KM_i32_BE(*(ui32_t*)p); p += 4;
332 sampleSize = KM_i16_BE(*(ui16_t*)p); p += 2;
333 memcpy(sampleRate, p, 10);
336 else if ( test_fcc == FCC_SSND )
338 if ( chunk_size > RIFF_len )
340 DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len);
341 return RESULT_RAW_FORMAT;
344 ui32_t offset = KM_i32_BE(*(ui32_t*)p); p += 4;
345 p += 4; // blockSize;
347 data_len = chunk_size - 8;
348 *data_start = (p - buf) + offset;
357 if ( *data_start == 0 ) // can't have no data!
359 DefaultLogSink().Error("No data chunk found, file contains no essence\n");
360 return RESULT_RAW_FORMAT;
366 ASDCP::RF64::SimpleRF64Header::SimpleRF64Header(ASDCP::PCM::AudioDescriptor& ADesc)
369 nchannels = ADesc.ChannelCount;
370 bitspersample = ADesc.QuantizationBits;
371 samplespersec = (ui32_t)ceil(ADesc.AudioSamplingRate.Quotient());
372 blockalign = nchannels * ((bitspersample + 7) / 8);
373 avgbps = samplespersec * blockalign;
374 data_len = ASDCP::PCM::CalcFrameBufferSize(ADesc) * ADesc.ContainerDuration;
379 ASDCP::RF64::SimpleRF64Header::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const
381 ADesc.EditRate = PictureRate;
383 ADesc.LinkedTrackID = 0;
385 ADesc.ChannelCount = nchannels;
386 ADesc.AudioSamplingRate = Rational(samplespersec, 1);
387 ADesc.AvgBps = avgbps;
388 ADesc.BlockAlign = blockalign;
389 ADesc.QuantizationBits = bitspersample;
390 ui32_t FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(ADesc);
391 ADesc.ContainerDuration = data_len / FrameBufferSize;
392 ADesc.ChannelFormat = PCM::CF_NONE;
397 ASDCP::RF64::SimpleRF64Header::WriteToFile(Kumu::FileWriter& OutFile) const
399 static ui32_t fmt_len =
402 + sizeof(samplespersec)
405 + sizeof(bitspersample);
407 ui32_t write_count = 0;
408 ui64_t RIFF_len = data_len + SimpleWavHeaderLength - 8;
409 DefaultLogSink().Debug("RIFF_len is %llu.\n", RIFF_len);
410 byte_t* tmp_header = NULL;
411 ui32_t header_len = 0;
413 if (RIFF_len > MAX_RIFF_LEN)
415 DefaultLogSink().Debug("Will write out an RF64 wave file.\n");
416 ui32_t data32_len = ((data_len < MAX_RIFF_LEN) ? data_len : MAX_RIFF_LEN);
417 ui64_t data64_len = ((data_len < MAX_RIFF_LEN) ? 0 : data_len);
418 static ui32_t ds64_len =
421 + sizeof(SAMPLE_COUNT)
424 header_len = SIMPLE_RF64_HEADER_LEN;
425 tmp_header = new byte_t[header_len];
426 byte_t* p = tmp_header;
427 memcpy(p, &FCC_RF64, sizeof(fourcc)); p += 4;
428 *((ui32_t*)p) = KM_i32_LE(MAX_RIFF_LEN); p += 4;
429 memcpy(p, &Wav::FCC_WAVE, sizeof(fourcc)); p += 4;
430 memcpy(p, &FCC_ds64, sizeof(fourcc)); p += 4;
431 *((ui32_t*)p) = KM_i32_LE(ds64_len); p += 4;
432 *((ui64_t*)p) = KM_i64_LE(RIFF_len); p += 8;
433 *((ui64_t*)p) = KM_i64_LE(data64_len); p += 8;
434 *((ui64_t*)p) = KM_i64_LE(SAMPLE_COUNT); p += 8;
435 *((ui32_t*)p) = KM_i32_LE(TABLE_LEN); p += 4;
436 memcpy(p, &Wav::FCC_fmt_, sizeof(fourcc)); p += 4;
437 *((ui32_t*)p) = KM_i32_LE(fmt_len); p += 4;
438 *((ui16_t*)p) = KM_i16_LE(format); p += 2;
439 *((ui16_t*)p) = KM_i16_LE(nchannels); p += 2;
440 *((ui32_t*)p) = KM_i32_LE(samplespersec); p += 4;
441 *((ui32_t*)p) = KM_i32_LE(avgbps); p += 4;
442 *((ui16_t*)p) = KM_i16_LE(blockalign); p += 2;
443 *((ui16_t*)p) = KM_i16_LE(bitspersample); p += 2;
444 memcpy(p, &Wav::FCC_data, sizeof(fourcc)); p += 4;
445 *((ui32_t*)p) = KM_i32_LE(data32_len); p += 4;
446 write_count = (p - tmp_header);
450 DefaultLogSink().Debug("Will write out a regular wave file.\n");
451 header_len = SimpleWavHeaderLength;
452 tmp_header = new byte_t[header_len];
453 byte_t* p = tmp_header;
454 memcpy(p, &Wav::FCC_RIFF, sizeof(fourcc)); p += 4;
455 *((ui32_t*)p) = KM_i32_LE(RIFF_len); p += 4;
456 memcpy(p, &Wav::FCC_WAVE, sizeof(fourcc)); p += 4;
457 memcpy(p, &Wav::FCC_fmt_, sizeof(fourcc)); p += 4;
458 *((ui32_t*)p) = KM_i32_LE(fmt_len); p += 4;
459 *((ui16_t*)p) = KM_i16_LE(format); p += 2;
460 *((ui16_t*)p) = KM_i16_LE(nchannels); p += 2;
461 *((ui32_t*)p) = KM_i32_LE(samplespersec); p += 4;
462 *((ui32_t*)p) = KM_i32_LE(avgbps); p += 4;
463 *((ui16_t*)p) = KM_i16_LE(blockalign); p += 2;
464 *((ui16_t*)p) = KM_i16_LE(bitspersample); p += 2;
465 memcpy(p, &Wav::FCC_data, sizeof(fourcc)); p += 4;
466 *((ui32_t*)p) = KM_i32_LE(data_len); p += 4;
467 write_count = (p - tmp_header);
469 if (header_len != write_count)
471 DefaultLogSink().Warn("Expected to write %u bytes but wrote %u bytes for header.\n",
472 header_len, write_count);
475 ASDCP::Result_t r = OutFile.Write(tmp_header, header_len, &write_count);
476 delete [] tmp_header;
482 ASDCP::RF64::SimpleRF64Header::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start)
484 ui32_t read_count = 0;
485 ui32_t local_data_start = 0;
486 ASDCP::PCM::FrameBuffer TmpBuffer(Wav::MaxWavHeader);
488 if ( data_start == 0 )
489 data_start = &local_data_start;
491 Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count);
493 if ( ASDCP_SUCCESS(result) )
494 result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start);
496 DefaultLogSink().Error("Failed to read %d bytes from file\n", Wav::MaxWavHeader);
502 ASDCP::RF64::SimpleRF64Header::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start)
504 if ( buf_len < SIMPLE_RF64_HEADER_LEN )
505 return RESULT_SMALLBUF;
508 const byte_t* p = buf;
509 const byte_t* end_p = p + buf_len;
511 fourcc test_RF64(p); p += 4;
512 if ( test_RF64 != FCC_RF64 )
514 DefaultLogSink().Debug("File does not begin with RF64 header\n");
515 return RESULT_RAW_FORMAT;
518 ui32_t tmp_len = KM_i32_LE(*(ui32_t*)p); p += 4;
520 fourcc test_WAVE(p); p += 4;
521 if ( test_WAVE != Wav::FCC_WAVE )
523 DefaultLogSink().Debug("File does not contain a WAVE header\n");
524 return RESULT_RAW_FORMAT;
527 fourcc test_ds64(p); p += 4;
528 if ( test_ds64 != FCC_ds64 )
530 DefaultLogSink().Debug("File does not contain a ds64 chunk\n");
531 return RESULT_RAW_FORMAT;
533 ui32_t ds64_len = KM_i32_LE(*(ui32_t*)p); p += 4;
534 ui64_t RIFF_len = ((tmp_len == MAX_RIFF_LEN) ? KM_i64_LE(*(ui64_t*)p) : tmp_len); p += 8;
535 data_len = KM_i64_LE(*(ui64_t*)p); p += 8;
536 p += (ds64_len - 16); // skip rest of ds64 chunk
542 test_fcc = fourcc(p); p += 4;
543 ui32_t chunk_size = KM_i32_LE(*(ui32_t*)p); p += 4;
545 if ( test_fcc == Wav::FCC_data )
547 if ( chunk_size > RIFF_len )
549 DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len);
550 return RESULT_RAW_FORMAT;
553 if (chunk_size != MAX_RIFF_LEN)
554 data_len = chunk_size;
555 *data_start = p - buf;
559 if ( test_fcc == Wav::FCC_fmt_ )
561 ui16_t format = KM_i16_LE(*(ui16_t*)p); p += 2;
563 if ( format != Wav::WAVE_FORMAT_PCM && format != Wav::WAVE_FORMAT_EXTENSIBLE )
565 DefaultLogSink().Error("Expecting uncompressed PCM data, got format type %hd\n", format);
566 return RESULT_RAW_FORMAT;
569 nchannels = KM_i16_LE(*(ui16_t*)p); p += 2;
570 samplespersec = KM_i32_LE(*(ui32_t*)p); p += 4;
571 avgbps = KM_i32_LE(*(ui32_t*)p); p += 4;
572 blockalign = KM_i16_LE(*(ui16_t*)p); p += 2;
573 bitspersample = KM_i16_LE(*(ui16_t*)p); p += 2;
574 p += chunk_size - 16; // 16 is the number of bytes read in this block
582 if ( *data_start == 0 ) // can't have no data!
584 DefaultLogSink().Error("No data chunk found, file contains no essence\n");
585 return RESULT_RAW_FORMAT;