2 Copyright (c) 2005-2018, 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 != ASDCP_WAVE_FORMAT_PCM && format != ASDCP_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;
375 data_len = static_cast<ui64_t>(ASDCP::PCM::CalcFrameBufferSize(ADesc)) * ADesc.ContainerDuration;
380 ASDCP::RF64::SimpleRF64Header::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const
382 ADesc.EditRate = PictureRate;
384 ADesc.LinkedTrackID = 0;
386 ADesc.ChannelCount = nchannels;
387 ADesc.AudioSamplingRate = Rational(samplespersec, 1);
388 ADesc.AvgBps = avgbps;
389 ADesc.BlockAlign = blockalign;
390 ADesc.QuantizationBits = bitspersample;
391 ui32_t FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(ADesc);
392 ADesc.ContainerDuration = data_len / FrameBufferSize;
393 ADesc.ChannelFormat = PCM::CF_NONE;
398 ASDCP::RF64::SimpleRF64Header::WriteToFile(Kumu::FileWriter& OutFile) const
400 static ui32_t fmt_len =
403 + sizeof(samplespersec)
406 + sizeof(bitspersample)
409 ui32_t write_count = 0;
410 ui64_t RIFF_len = data_len + SimpleWavHeaderLength - 8;
411 // DefaultLogSink().Debug("RIFF_len is %llu.\n", RIFF_len);
412 byte_t* tmp_header = NULL;
413 ui32_t header_len = 0;
415 if (RIFF_len > MAX_RIFF_LEN)
417 DefaultLogSink().Debug("Will write out an RF64 wave file.\n");
418 ui32_t data32_len = ((data_len < MAX_RIFF_LEN) ? data_len : MAX_RIFF_LEN);
419 ui64_t data64_len = ((data_len < MAX_RIFF_LEN) ? 0 : data_len);
420 static ui32_t ds64_len =
423 + sizeof(SAMPLE_COUNT)
426 header_len = SIMPLE_RF64_HEADER_LEN;
427 tmp_header = new byte_t[header_len];
428 byte_t* p = tmp_header;
429 memcpy(p, &FCC_RF64, sizeof(fourcc)); p += 4;
430 *((ui32_t*)p) = KM_i32_LE(MAX_RIFF_LEN); p += 4;
431 memcpy(p, &Wav::FCC_WAVE, sizeof(fourcc)); p += 4;
432 memcpy(p, &FCC_ds64, sizeof(fourcc)); p += 4;
433 *((ui32_t*)p) = KM_i32_LE(ds64_len); p += 4;
434 *((ui64_t*)p) = KM_i64_LE(RIFF_len); p += 8;
435 *((ui64_t*)p) = KM_i64_LE(data64_len); p += 8;
436 *((ui64_t*)p) = KM_i64_LE(SAMPLE_COUNT); p += 8;
437 *((ui32_t*)p) = KM_i32_LE(TABLE_LEN); p += 4;
438 memcpy(p, &Wav::FCC_fmt_, sizeof(fourcc)); p += 4;
439 *((ui32_t*)p) = KM_i32_LE(fmt_len); p += 4;
440 *((ui16_t*)p) = KM_i16_LE(format); p += 2;
441 *((ui16_t*)p) = KM_i16_LE(nchannels); p += 2;
442 *((ui32_t*)p) = KM_i32_LE(samplespersec); p += 4;
443 *((ui32_t*)p) = KM_i32_LE(avgbps); p += 4;
444 *((ui16_t*)p) = KM_i16_LE(blockalign); p += 2;
445 *((ui16_t*)p) = KM_i16_LE(bitspersample); p += 2;
446 *((ui16_t*)p) = KM_i16_LE(cbsize); p += 2;
447 memcpy(p, &Wav::FCC_data, sizeof(fourcc)); p += 4;
448 *((ui32_t*)p) = KM_i32_LE(data32_len); p += 4;
449 write_count = (p - tmp_header);
453 DefaultLogSink().Debug("Will write out a regular wave file.\n");
454 header_len = SimpleWavHeaderLength;
455 tmp_header = new byte_t[header_len];
456 byte_t* p = tmp_header;
457 memcpy(p, &Wav::FCC_RIFF, sizeof(fourcc)); p += 4;
458 *((ui32_t*)p) = KM_i32_LE(RIFF_len); p += 4;
459 memcpy(p, &Wav::FCC_WAVE, sizeof(fourcc)); p += 4;
460 memcpy(p, &Wav::FCC_fmt_, sizeof(fourcc)); p += 4;
461 *((ui32_t*)p) = KM_i32_LE(fmt_len); p += 4;
462 *((ui16_t*)p) = KM_i16_LE(format); p += 2;
463 *((ui16_t*)p) = KM_i16_LE(nchannels); p += 2;
464 *((ui32_t*)p) = KM_i32_LE(samplespersec); p += 4;
465 *((ui32_t*)p) = KM_i32_LE(avgbps); p += 4;
466 *((ui16_t*)p) = KM_i16_LE(blockalign); p += 2;
467 *((ui16_t*)p) = KM_i16_LE(bitspersample); p += 2;
468 *((ui16_t*)p) = KM_i16_LE(cbsize); p += 2;
469 memcpy(p, &Wav::FCC_data, sizeof(fourcc)); p += 4;
470 *((ui32_t*)p) = KM_i32_LE(data_len); p += 4;
471 write_count = (p - tmp_header);
473 if (header_len != write_count)
475 DefaultLogSink().Warn("Expected to write %u bytes but wrote %u bytes for header.\n",
476 header_len, write_count);
479 ASDCP::Result_t r = OutFile.Write(tmp_header, header_len, &write_count);
480 delete [] tmp_header;
486 ASDCP::RF64::SimpleRF64Header::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start)
488 ui32_t read_count = 0;
489 ui32_t local_data_start = 0;
490 ASDCP::PCM::FrameBuffer TmpBuffer(Wav::MaxWavHeader);
492 if ( data_start == 0 )
493 data_start = &local_data_start;
495 Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count);
497 if ( ASDCP_SUCCESS(result) )
498 result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start);
500 DefaultLogSink().Error("Failed to read %d bytes from file\n", Wav::MaxWavHeader);
506 ASDCP::RF64::SimpleRF64Header::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start)
508 if ( buf_len < SIMPLE_RF64_HEADER_LEN )
509 return RESULT_SMALLBUF;
512 const byte_t* p = buf;
513 const byte_t* end_p = p + buf_len;
515 fourcc test_RF64(p); p += 4;
516 if ( test_RF64 != FCC_RF64 )
518 DefaultLogSink().Debug("File does not begin with RF64 header\n");
519 return RESULT_RAW_FORMAT;
522 ui32_t tmp_len = KM_i32_LE(*(ui32_t*)p); p += 4;
524 fourcc test_WAVE(p); p += 4;
525 if ( test_WAVE != Wav::FCC_WAVE )
527 DefaultLogSink().Debug("File does not contain a WAVE header\n");
528 return RESULT_RAW_FORMAT;
531 fourcc test_ds64(p); p += 4;
532 if ( test_ds64 != FCC_ds64 )
534 DefaultLogSink().Debug("File does not contain a ds64 chunk\n");
535 return RESULT_RAW_FORMAT;
537 ui32_t ds64_len = KM_i32_LE(*(ui32_t*)p); p += 4;
538 ui64_t RIFF_len = ((tmp_len == MAX_RIFF_LEN) ? KM_i64_LE(*(ui64_t*)p) : tmp_len); p += 8;
539 data_len = KM_i64_LE(*(ui64_t*)p); p += 8;
540 p += (ds64_len - 16); // skip rest of ds64 chunk
546 test_fcc = fourcc(p); p += 4;
547 ui32_t chunk_size = KM_i32_LE(*(ui32_t*)p); p += 4;
549 if ( test_fcc == Wav::FCC_data )
551 if ( chunk_size != MAX_RIFF_LEN )
553 if ( chunk_size > RIFF_len )
555 DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len);
556 return RESULT_RAW_FORMAT;
559 data_len = chunk_size;
562 *data_start = p - buf;
566 if ( test_fcc == Wav::FCC_fmt_ )
568 ui16_t format = KM_i16_LE(*(ui16_t*)p); p += 2;
570 if ( format != Wav::ASDCP_WAVE_FORMAT_PCM && format != Wav::ASDCP_WAVE_FORMAT_EXTENSIBLE )
572 DefaultLogSink().Error("Expecting uncompressed PCM data, got format type %hd\n", format);
573 return RESULT_RAW_FORMAT;
576 nchannels = KM_i16_LE(*(ui16_t*)p); p += 2;
577 samplespersec = KM_i32_LE(*(ui32_t*)p); p += 4;
578 avgbps = KM_i32_LE(*(ui32_t*)p); p += 4;
579 blockalign = KM_i16_LE(*(ui16_t*)p); p += 2;
580 bitspersample = KM_i16_LE(*(ui16_t*)p); p += 2;
581 p += chunk_size - 16; // 16 is the number of bytes read in this block
589 if ( *data_start == 0 ) // can't have no data!
591 DefaultLogSink().Error("No data chunk found, file contains no essence\n");
592 return RESULT_RAW_FORMAT;