ee1e93d56169faf017934db8dc62d8c6084ff729
[libdcp.git] / asdcplib / src / Wav.cpp
1 /*
2 Copyright (c) 2005-2009, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
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.
15
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.
26 */
27 /*! \file    Wav.cpp
28     \version $Id: Wav.cpp,v 1.11 2010/02/16 18:40:57 jhurst Exp $
29     \brief   Wave file common elements
30 */
31
32 #include "Wav.h"
33 #include <assert.h>
34 #include <KM_log.h>
35 using Kumu::DefaultLogSink;
36
37
38 const ui32_t SimpleWavHeaderLength = 46;
39
40 //
41 ASDCP::Wav::SimpleWaveHeader::SimpleWaveHeader(ASDCP::PCM::AudioDescriptor& ADesc)
42 {
43   format = 1;
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;
49   cbsize = 0;     
50   data_len = ASDCP::PCM::CalcFrameBufferSize(ADesc) * ADesc.ContainerDuration;
51 }
52
53 //
54 void
55 ASDCP::Wav::SimpleWaveHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const
56 {
57   ADesc.EditRate = PictureRate;
58
59   ADesc.LinkedTrackID = 0;
60   ADesc.Locked = 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;
69 }
70
71
72 //
73 ASDCP::Result_t
74 ASDCP::Wav::SimpleWaveHeader::WriteToFile(Kumu::FileWriter& OutFile) const
75 {
76   ui32_t write_count;
77   byte_t tmp_header[SimpleWavHeaderLength];
78   byte_t* p = tmp_header;
79
80   static ui32_t fmt_len =
81     sizeof(format)
82     + sizeof(nchannels)
83     + sizeof(samplespersec)
84     + sizeof(avgbps)
85     + sizeof(blockalign)
86     + sizeof(bitspersample)
87     + sizeof(cbsize);
88
89   ui32_t RIFF_len = data_len + SimpleWavHeaderLength - 8;
90
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;
105
106   return OutFile.Write(tmp_header, SimpleWavHeaderLength, &write_count);
107 }
108
109 //
110 ASDCP::Result_t
111 ASDCP::Wav::SimpleWaveHeader::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start)
112 {
113   ui32_t read_count = 0;
114   ui32_t local_data_start = 0;
115   ASDCP::PCM::FrameBuffer TmpBuffer(MaxWavHeader);
116
117   if ( data_start == 0 )
118     data_start = &local_data_start;
119
120   Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count);
121
122   if ( ASDCP_SUCCESS(result) )
123     result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start);
124
125     return result;
126 }
127
128 ASDCP::Result_t
129 ASDCP::Wav::SimpleWaveHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start)
130 {
131   if ( buf_len < SimpleWavHeaderLength )
132     return RESULT_SMALLBUF;
133
134   *data_start = 0;
135   const byte_t* p = buf;
136   const byte_t* end_p = p + buf_len;
137
138   fourcc test_RIFF(p); p += 4;
139   if ( test_RIFF != FCC_RIFF )
140     {
141       //      DefaultLogSink().Debug("File does not begin with RIFF header\n");      
142       return RESULT_RAW_FORMAT;
143     }
144
145   ui32_t RIFF_len = KM_i32_LE(*(ui32_t*)p); p += 4;
146
147   fourcc test_WAVE(p); p += 4;
148   if ( test_WAVE != FCC_WAVE )
149     {
150       DefaultLogSink().Debug("File does not contain a WAVE header\n");
151       return RESULT_RAW_FORMAT;
152     }
153
154   fourcc test_fcc;
155
156   while ( p < end_p )
157     {
158       test_fcc = fourcc(p); p += 4;
159       ui32_t chunk_size = KM_i32_LE(*(ui32_t*)p); p += 4;
160
161       if ( test_fcc == FCC_data )
162         {
163           if ( chunk_size > RIFF_len )
164             {
165               DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len);
166               return RESULT_RAW_FORMAT;
167             }
168
169           data_len = chunk_size;
170           *data_start = p - buf;
171           break;
172         }
173
174       if ( test_fcc == FCC_fmt_ )
175         {
176           ui16_t format = KM_i16_LE(*(ui16_t*)p); p += 2;
177
178           if ( format != WAVE_FORMAT_PCM && format != WAVE_FORMAT_EXTENSIBLE )
179             {
180               DefaultLogSink().Error("Expecting uncompressed PCM data, got format type %hd\n", format);
181               return RESULT_RAW_FORMAT;
182             }
183
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
190         }
191       else
192         {
193           p += chunk_size;
194         }
195     }
196
197   if ( *data_start == 0 ) // can't have no data!
198     {
199       DefaultLogSink().Error("No data chunk found, file contains no essence\n");
200       return RESULT_RAW_FORMAT;
201     }
202
203   return RESULT_OK;
204 }
205
206 //------------------------------------------------------------------------------------------
207 // conversion algorithms from http://www.borg.com/~jglatt/tech/aiff.htm
208
209 //
210 void
211 Rat_to_extended(ASDCP::Rational rate, byte_t* buf)
212 {
213   memset(buf, 0, 10);
214   ui32_t value = (ui32_t)ceil(rate.Quotient()); 
215   ui32_t exp = value;
216   exp >>= 1;
217   ui8_t i = 0;
218
219   for ( ; i < 32; i++ )
220     {
221       exp >>= 1;
222       if ( ! exp )
223         break;
224     }
225
226   *(buf+1) = i;
227
228    for ( i = 32; i != 0 ; i-- )
229      {
230        if ( value & 0x80000000 )
231          break;
232        value <<= 1;
233      }
234
235    *(ui32_t*)(buf+2) = KM_i32_BE(value);
236 }
237
238 //
239 ASDCP::Rational
240 extended_to_Rat(const byte_t* buf)
241 {
242   ui32_t last = 0;
243   ui32_t mantissa = KM_i32_BE(*(ui32_t*)(buf+2));
244
245   byte_t exp = 30 - *(buf+1);
246
247   while ( exp-- )
248     {
249       last = mantissa;
250       mantissa >>= 1;
251     }
252
253   if ( last & 0x00000001 )
254     mantissa++;
255
256   return ASDCP::Rational(mantissa, 1);
257 }
258
259 //
260 void
261 ASDCP::AIFF::SimpleAIFFHeader::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const
262 {
263   ADesc.EditRate = PictureRate;
264
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;
273 }
274
275 //
276 ASDCP::Result_t
277 ASDCP::AIFF::SimpleAIFFHeader::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start)
278 {
279   ui32_t read_count = 0;
280   ui32_t local_data_start = 0;
281   ASDCP::PCM::FrameBuffer TmpBuffer(Wav::MaxWavHeader);
282
283   if ( data_start == 0 )
284     data_start = &local_data_start;
285
286   Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count);
287
288   if ( ASDCP_SUCCESS(result) )
289     result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start);
290
291     return result;
292 }
293
294 //
295 ASDCP::Result_t
296 ASDCP::AIFF::SimpleAIFFHeader::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start)
297 {
298   if ( buf_len < 32 )
299     return RESULT_SMALLBUF;
300
301   *data_start = 0;
302   const byte_t* p = buf;
303   const byte_t* end_p = p + buf_len;
304
305   fourcc test_FORM(p); p += 4;
306   if ( test_FORM != FCC_FORM )
307     {
308       //      DefaultLogSink().Debug("File does not begin with FORM header\n");
309       return RESULT_RAW_FORMAT;
310     }
311
312   ui32_t RIFF_len = KM_i32_BE(*(ui32_t*)p); p += 4;
313
314   fourcc test_AIFF(p); p += 4;
315   if ( test_AIFF != FCC_AIFF )
316     {
317       DefaultLogSink().Debug("File does not contain an AIFF header\n");
318       return RESULT_RAW_FORMAT;
319     }
320
321   fourcc test_fcc;
322
323   while ( p < end_p )
324     {
325       test_fcc = fourcc(p); p += 4;
326       ui32_t chunk_size = KM_i32_BE(*(ui32_t*)p); p += 4;
327
328       if ( test_fcc == FCC_COMM )
329         {
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);
334           p += 10;
335         }
336       else if ( test_fcc == FCC_SSND )
337         {
338           if ( chunk_size > RIFF_len )
339             {
340               DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len);
341               return RESULT_RAW_FORMAT;
342             }
343
344           ui32_t offset = KM_i32_BE(*(ui32_t*)p); p += 4;
345           p += 4; // blockSize;
346
347           data_len = chunk_size - 8;
348           *data_start = (p - buf) + offset;
349           break;
350         }
351       else
352         {
353           p += chunk_size;
354         }
355     }
356
357   if ( *data_start == 0 ) // can't have no data!
358     {
359       DefaultLogSink().Error("No data chunk found, file contains no essence\n");
360       return RESULT_RAW_FORMAT;
361     }
362
363   return RESULT_OK;
364 }
365
366
367
368 //
369 // end Wav.cpp
370 //