2 Copyright (c) 2005-2006, 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 / 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.SampleRate = 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;
73 ASDCP::Wav::SimpleWaveHeader::WriteToFile(Kumu::FileWriter& OutFile) const
76 byte_t tmp_header[SimpleWavHeaderLength];
77 byte_t* p = tmp_header;
79 static ui32_t fmt_len =
82 + sizeof(samplespersec)
85 + sizeof(bitspersample)
88 ui32_t RIFF_len = data_len + SimpleWavHeaderLength - 8;
90 memcpy(p, &FCC_RIFF, sizeof(fourcc)); p += 4;
91 *((ui32_t*)p) = KM_i32_LE(RIFF_len); p += 4;
92 memcpy(p, &FCC_WAVE, sizeof(fourcc)); p += 4;
93 memcpy(p, &FCC_fmt_, sizeof(fourcc)); p += 4;
94 *((ui32_t*)p) = KM_i32_LE(fmt_len); p += 4;
95 *((ui16_t*)p) = KM_i16_LE(format); p += 2;
96 *((ui16_t*)p) = KM_i16_LE(nchannels); p += 2;
97 *((ui32_t*)p) = KM_i32_LE(samplespersec); p += 4;
98 *((ui32_t*)p) = KM_i32_LE(avgbps); p += 4;
99 *((ui16_t*)p) = KM_i16_LE(blockalign); p += 2;
100 *((ui16_t*)p) = KM_i16_LE(bitspersample); p += 2;
101 *((ui16_t*)p) = KM_i16_LE(cbsize); p += 2;
102 memcpy(p, &FCC_data, sizeof(fourcc)); p += 4;
103 *((ui32_t*)p) = KM_i32_LE(data_len); p += 4;
105 return OutFile.Write(tmp_header, SimpleWavHeaderLength, &write_count);
110 ASDCP::Wav::SimpleWaveHeader::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start)
112 ui32_t read_count = 0;
113 ui32_t local_data_start = 0;
114 ASDCP::PCM::FrameBuffer TmpBuffer(MaxWavHeader);
116 if ( data_start == 0 )
117 data_start = &local_data_start;
119 Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count);
121 if ( ASDCP_SUCCESS(result) )
122 result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start);
128 ASDCP::Wav::SimpleWaveHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start)
130 if ( buf_len < SimpleWavHeaderLength )
131 return RESULT_SMALLBUF;
134 const byte_t* p = buf;
135 const byte_t* end_p = p + buf_len;
137 fourcc test_RIFF(p); p += 4;
138 if ( test_RIFF != FCC_RIFF )
140 DefaultLogSink().Debug("File does not begin with RIFF header\n");
141 return RESULT_RAW_FORMAT;
144 ui32_t RIFF_len = KM_i32_LE(*(ui32_t*)p); p += 4;
146 fourcc test_WAVE(p); p += 4;
147 if ( test_WAVE != FCC_WAVE )
149 DefaultLogSink().Debug("File does not contain a WAVE header\n");
150 return RESULT_RAW_FORMAT;
157 test_fcc = fourcc(p); p += 4;
158 ui32_t chunk_size = KM_i32_LE(*(ui32_t*)p); p += 4;
160 if ( test_fcc == FCC_data )
162 if ( chunk_size > RIFF_len )
164 DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len);
165 return RESULT_RAW_FORMAT;
168 data_len = chunk_size;
169 *data_start = p - buf;
173 if ( test_fcc == FCC_fmt_ )
175 ui16_t format = KM_i16_LE(*(ui16_t*)p); p += 2;
179 DefaultLogSink().Error("Expecting uncompressed essence, got format type %hu\n", format);
180 return RESULT_RAW_FORMAT;
183 nchannels = KM_i16_LE(*(ui16_t*)p); p += 2;
184 samplespersec = KM_i32_LE(*(ui32_t*)p); p += 4;
185 avgbps = KM_i32_LE(*(ui32_t*)p); p += 4;
186 blockalign = KM_i16_LE(*(ui16_t*)p); p += 2;
187 bitspersample = KM_i16_LE(*(ui16_t*)p); p += 2;
188 p += chunk_size - 16;
196 if ( *data_start == 0 ) // can't have no data!
198 DefaultLogSink().Error("No data chunk found, file contains no essence\n");
199 return RESULT_RAW_FORMAT;
205 //------------------------------------------------------------------------------------------
206 // conversion algorithms from http://www.borg.com/~jglatt/tech/aiff.htm
210 Rat_to_extended(ASDCP::Rational rate, byte_t* buf)
213 ui32_t value = (ui32_t)ceil(rate.Quotient());
218 for ( ; i < 32; i++ )
227 for ( i = 32; i != 0 ; i-- )
229 if ( value & 0x80000000 )
234 *(ui32_t*)(buf+2) = KM_i32_BE(value);
239 extended_to_Rat(const byte_t* buf)
242 ui32_t mantissa = KM_i32_BE(*(ui32_t*)(buf+2));
244 byte_t exp = 30 - *(buf+1);
252 if ( last & 0x00000001 )
255 return ASDCP::Rational(mantissa, 1);
260 ASDCP::AIFF::SimpleAIFFHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const
262 ADesc.SampleRate = PictureRate;
264 ADesc.ChannelCount = numChannels;
265 ADesc.AudioSamplingRate = extended_to_Rat(sampleRate);
266 ADesc.QuantizationBits = sampleSize;
267 ADesc.BlockAlign = sampleSize / 8;
268 ADesc.AvgBps = (ui32_t) (ADesc.BlockAlign * ADesc.AudioSamplingRate.Quotient());
269 ui32_t FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(ADesc);
270 ADesc.ContainerDuration = data_len / FrameBufferSize;
275 ASDCP::AIFF::SimpleAIFFHeader::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start)
277 ui32_t read_count = 0;
278 ui32_t local_data_start = 0;
279 ASDCP::PCM::FrameBuffer TmpBuffer(Wav::MaxWavHeader);
281 if ( data_start == 0 )
282 data_start = &local_data_start;
284 Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count);
286 if ( ASDCP_SUCCESS(result) )
287 result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start);
294 ASDCP::AIFF::SimpleAIFFHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start)
297 return RESULT_SMALLBUF;
300 const byte_t* p = buf;
301 const byte_t* end_p = p + buf_len;
303 fourcc test_FORM(p); p += 4;
304 if ( test_FORM != FCC_FORM )
306 DefaultLogSink().Debug("File does not begin with FORM header\n");
307 return RESULT_RAW_FORMAT;
310 ui32_t RIFF_len = KM_i32_BE(*(ui32_t*)p); p += 4;
312 fourcc test_AIFF(p); p += 4;
313 if ( test_AIFF != FCC_AIFF )
315 DefaultLogSink().Debug("File does not contain an AIFF header\n");
316 return RESULT_RAW_FORMAT;
323 test_fcc = fourcc(p); p += 4;
324 ui32_t chunk_size = KM_i32_BE(*(ui32_t*)p); p += 4;
326 if ( test_fcc == FCC_COMM )
328 numChannels = KM_i16_BE(*(ui16_t*)p); p += 2;
329 numSampleFrames = KM_i32_BE(*(ui32_t*)p); p += 4;
330 sampleSize = KM_i16_BE(*(ui16_t*)p); p += 2;
331 memcpy(sampleRate, p, 10);
334 else if ( test_fcc == FCC_SSND )
336 if ( chunk_size > RIFF_len )
338 DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len);
339 return RESULT_RAW_FORMAT;
342 ui32_t offset = KM_i32_BE(*(ui32_t*)p); p += 4;
343 p += 4; // blockSize;
345 data_len = chunk_size - 8;
346 *data_start = (p - buf) + offset;
355 if ( *data_start == 0 ) // can't have no data!
357 DefaultLogSink().Error("No data chunk found, file contains no essence\n");
358 return RESULT_RAW_FORMAT;