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.
28 \version $Id: Wav.cpp,v 1.11 2010/02/16 18:40:57 jhurst Exp $
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.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;