Fix a few compiler warnings about misleading indents.
[asdcplib-cth.git] / src / Wav.cpp
1 /*
2 Copyright (c) 2005-2015, 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.15 2015/04/21 03:55:31 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 + 7) / 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 != ASDCP_WAVE_FORMAT_PCM && format != ASDCP_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 ASDCP::RF64::SimpleRF64Header::SimpleRF64Header(ASDCP::PCM::AudioDescriptor& ADesc)
367 {
368   format = 1;
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   cbsize = 0;
375   data_len = static_cast<ui64_t>(ASDCP::PCM::CalcFrameBufferSize(ADesc)) * ADesc.ContainerDuration;
376 }
377
378 //
379 void
380 ASDCP::RF64::SimpleRF64Header::FillADesc(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::Rational PictureRate) const
381 {
382   ADesc.EditRate = PictureRate;
383
384   ADesc.LinkedTrackID = 0;
385   ADesc.Locked = 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;
394 }
395
396 //
397 ASDCP::Result_t
398 ASDCP::RF64::SimpleRF64Header::WriteToFile(Kumu::FileWriter& OutFile) const
399 {
400   static ui32_t fmt_len =
401     sizeof(format)
402     + sizeof(nchannels)
403     + sizeof(samplespersec)
404     + sizeof(avgbps)
405     + sizeof(blockalign)
406     + sizeof(bitspersample)
407     + sizeof(cbsize);
408
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;
414
415   if (RIFF_len > MAX_RIFF_LEN)
416   {
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 =
421             sizeof(RIFF_len)
422             + sizeof(data64_len)
423             + sizeof(SAMPLE_COUNT)
424             + sizeof(TABLE_LEN);
425
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);
450   }
451   else
452   {
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);
472   }
473   if (header_len != write_count)
474   {
475       DefaultLogSink().Warn("Expected to write %u bytes but wrote %u bytes for header.\n",
476                             header_len, write_count);
477   }
478   write_count = 0;
479   ASDCP::Result_t r = OutFile.Write(tmp_header, header_len, &write_count);
480   delete [] tmp_header;
481   return r;
482 }
483
484 //
485 ASDCP::Result_t
486 ASDCP::RF64::SimpleRF64Header::ReadFromFile(const Kumu::FileReader& InFile, ui32_t* data_start)
487 {
488   ui32_t read_count = 0;
489   ui32_t local_data_start = 0;
490   ASDCP::PCM::FrameBuffer TmpBuffer(Wav::MaxWavHeader);
491
492   if ( data_start == 0 )
493     data_start = &local_data_start;
494
495   Result_t result = InFile.Read(TmpBuffer.Data(), TmpBuffer.Capacity(), &read_count);
496
497   if ( ASDCP_SUCCESS(result) )
498     result = ReadFromBuffer(TmpBuffer.RoData(), read_count, data_start);
499   else
500     DefaultLogSink().Error("Failed to read %d bytes from file\n", Wav::MaxWavHeader);
501
502   return result;
503 }
504
505 ASDCP::Result_t
506 ASDCP::RF64::SimpleRF64Header::ReadFromBuffer(const byte_t* buf, ui32_t buf_len, ui32_t* data_start)
507 {
508     if ( buf_len < SIMPLE_RF64_HEADER_LEN )
509         return RESULT_SMALLBUF;
510
511     *data_start = 0;
512     const byte_t* p = buf;
513     const byte_t* end_p = p + buf_len;
514
515     fourcc test_RF64(p); p += 4;
516     if ( test_RF64 != FCC_RF64 )
517     {
518         DefaultLogSink().Debug("File does not begin with RF64 header\n");
519         return RESULT_RAW_FORMAT;
520     }
521
522     ui32_t tmp_len = KM_i32_LE(*(ui32_t*)p); p += 4;
523
524     fourcc test_WAVE(p); p += 4;
525     if ( test_WAVE != Wav::FCC_WAVE )
526     {
527         DefaultLogSink().Debug("File does not contain a WAVE header\n");
528         return RESULT_RAW_FORMAT;
529     }
530
531     fourcc test_ds64(p); p += 4;
532     if ( test_ds64 != FCC_ds64 )
533     {
534         DefaultLogSink().Debug("File does not contain a ds64 chunk\n");
535         return RESULT_RAW_FORMAT;
536     }
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
541
542     fourcc test_fcc;
543
544     while ( p < end_p )
545     {
546         test_fcc = fourcc(p); p += 4;
547         ui32_t chunk_size = KM_i32_LE(*(ui32_t*)p); p += 4;
548
549         if ( test_fcc == Wav::FCC_data )
550         {
551             if ( chunk_size > RIFF_len )
552             {
553                 DefaultLogSink().Error("Chunk size %u larger than file: %u\n", chunk_size, RIFF_len);
554                 return RESULT_RAW_FORMAT;
555             }
556
557             if (chunk_size != MAX_RIFF_LEN)
558                 data_len = chunk_size;
559             *data_start = p - buf;
560             break;
561         }
562
563         if ( test_fcc == Wav::FCC_fmt_ )
564         {
565             ui16_t format = KM_i16_LE(*(ui16_t*)p); p += 2;
566
567             if ( format != Wav::ASDCP_WAVE_FORMAT_PCM && format != Wav::ASDCP_WAVE_FORMAT_EXTENSIBLE )
568             {
569                 DefaultLogSink().Error("Expecting uncompressed PCM data, got format type %hd\n", format);
570                 return RESULT_RAW_FORMAT;
571             }
572
573             nchannels = KM_i16_LE(*(ui16_t*)p); p += 2;
574             samplespersec = KM_i32_LE(*(ui32_t*)p); p += 4;
575             avgbps = KM_i32_LE(*(ui32_t*)p); p += 4;
576             blockalign = KM_i16_LE(*(ui16_t*)p); p += 2;
577             bitspersample = KM_i16_LE(*(ui16_t*)p); p += 2;
578             p += chunk_size - 16; // 16 is the number of bytes read in this block
579         }
580         else
581         {
582             p += chunk_size;
583         }
584     }
585
586     if ( *data_start == 0 ) // can't have no data!
587     {
588         DefaultLogSink().Error("No data chunk found, file contains no essence\n");
589         return RESULT_RAW_FORMAT;
590     }
591
592   return RESULT_OK;
593 }
594
595 //
596 // end Wav.cpp
597 //