summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libwavpack/wputils.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/libwavpack/wputils.c')
-rw-r--r--lib/rbcodec/codecs/libwavpack/wputils.c555
1 files changed, 555 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libwavpack/wputils.c b/lib/rbcodec/codecs/libwavpack/wputils.c
new file mode 100644
index 0000000000..b0ccd3ba83
--- /dev/null
+++ b/lib/rbcodec/codecs/libwavpack/wputils.c
@@ -0,0 +1,555 @@
1////////////////////////////////////////////////////////////////////////////
2// **** WAVPACK **** //
3// Hybrid Lossless Wavefile Compressor //
4// Copyright (c) 1998 - 2004 Conifer Software. //
5// All Rights Reserved. //
6// Distributed under the BSD Software License (see license.txt) //
7////////////////////////////////////////////////////////////////////////////
8
9// wputils.c
10
11// This module provides a high-level interface for decoding WavPack 4.0 audio
12// streams and files. WavPack data is read with a stream reading callback. No
13// direct seeking is provided for, but it is possible to start decoding
14// anywhere in a WavPack stream. In this case, WavPack will be able to provide
15// the sample-accurate position when it synchs with the data and begins
16// decoding.
17
18#include "wavpack.h"
19
20#include <string.h>
21
22static void strcpy_loc (char *dst, char *src) { while ((*dst++ = *src++) != 0); }
23
24///////////////////////////// local table storage ////////////////////////////
25
26const uint32_t sample_rates [] = { 6000, 8000, 9600, 11025, 12000, 16000, 22050,
27 24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 };
28
29///////////////////////////// executable code ////////////////////////////////
30
31static uint32_t read_next_header (read_stream infile, WavpackHeader *wphdr);
32
33// This function reads data from the specified stream in search of a valid
34// WavPack 4.0 audio block. If this fails in 1 megabyte (or an invalid or
35// unsupported WavPack block is encountered) then an appropriate message is
36// copied to "error" and NULL is returned, otherwise a pointer to a
37// WavpackContext structure is returned (which is used to call all other
38// functions in this module). This can be initiated at the beginning of a
39// WavPack file, or anywhere inside a WavPack file. To determine the exact
40// position within the file use WavpackGetSampleIndex(). For demonstration
41// purposes this uses a single static copy of the WavpackContext structure,
42// so obviously it cannot be used for more than one file at a time. Also,
43// this function will not handle "correction" files, plays only the first
44// two channels of multi-channel files, and is limited in resolution in some
45// large integer or floating point files (but always provides at least 24 bits
46// of resolution).
47
48static WavpackContext wpc IBSS_ATTR;
49
50WavpackContext *WavpackOpenFileInput (read_stream infile, char *error)
51{
52 WavpackStream *wps = &wpc.stream;
53 uint32_t bcount;
54
55 CLEAR (wpc);
56 wpc.infile = infile;
57 wpc.total_samples = (uint32_t) -1;
58 wpc.norm_offset = 0;
59 wpc.open_flags = 0;
60
61 // open the source file for reading and store the size
62
63 while (!wps->wphdr.block_samples) {
64
65 bcount = read_next_header (wpc.infile, &wps->wphdr);
66
67 if (bcount == (uint32_t) -1) {
68 strcpy_loc (error, "invalid WavPack file!");
69 return NULL;
70 }
71
72 wps->block_bytes_left = wps->wphdr.ckSize - 24;
73
74 if ((wps->wphdr.flags & UNKNOWN_FLAGS) || wps->wphdr.version < MIN_STREAM_VERS ||
75 wps->wphdr.version > MAX_STREAM_VERS) {
76 strcpy_loc (error, "invalid WavPack file!");
77 return NULL;
78 }
79
80 if (wps->wphdr.block_samples && wps->wphdr.total_samples != (uint32_t) -1)
81 wpc.total_samples = wps->wphdr.total_samples;
82
83 if (!unpack_init (&wpc)) {
84 strcpy_loc (error, wpc.error_message [0] ? wpc.error_message :
85 "invalid WavPack file!");
86
87 return NULL;
88 }
89 }
90
91 wpc.config.flags &= ~0xff;
92 wpc.config.flags |= wps->wphdr.flags & 0xff;
93 wpc.config.bytes_per_sample = (wps->wphdr.flags & BYTES_STORED) + 1;
94 wpc.config.float_norm_exp = wps->float_norm_exp;
95
96 wpc.config.bits_per_sample = (wpc.config.bytes_per_sample * 8) -
97 ((wps->wphdr.flags & SHIFT_MASK) >> SHIFT_LSB);
98
99 if (!wpc.config.sample_rate) {
100 if (!wps || !wps->wphdr.block_samples || (wps->wphdr.flags & SRATE_MASK) == SRATE_MASK)
101 wpc.config.sample_rate = 44100;
102 else
103 wpc.config.sample_rate = sample_rates [(wps->wphdr.flags & SRATE_MASK) >> SRATE_LSB];
104 }
105
106 if (!wpc.config.num_channels) {
107 wpc.config.num_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2;
108 wpc.config.channel_mask = 0x5 - wpc.config.num_channels;
109 }
110
111 if (!(wps->wphdr.flags & FINAL_BLOCK))
112 wpc.reduced_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2;
113
114 return &wpc;
115}
116
117// This function obtains general information about an open file and returns
118// a mask with the following bit values:
119
120// MODE_LOSSLESS: file is lossless (pure lossless only)
121// MODE_HYBRID: file is hybrid mode (lossy part only)
122// MODE_FLOAT: audio data is 32-bit ieee floating point
123// MODE_HIGH: file was created in "high" mode (information only)
124// MODE_FAST: file was created in "fast" mode (information only)
125
126int WavpackGetMode (WavpackContext *wpc)
127{
128 int mode = 0;
129
130 if (wpc) {
131 if (wpc->config.flags & CONFIG_HYBRID_FLAG)
132 mode |= MODE_HYBRID;
133 else if (!(wpc->config.flags & CONFIG_LOSSY_MODE))
134 mode |= MODE_LOSSLESS;
135
136 if (wpc->lossy_blocks)
137 mode &= ~MODE_LOSSLESS;
138
139 if (wpc->config.flags & CONFIG_FLOAT_DATA)
140 mode |= MODE_FLOAT;
141
142 if (wpc->config.flags & CONFIG_HIGH_FLAG)
143 mode |= MODE_HIGH;
144
145 if (wpc->config.flags & CONFIG_FAST_FLAG)
146 mode |= MODE_FAST;
147 }
148
149 return mode;
150}
151
152// Unpack the specified number of samples from the current file position.
153// Note that "samples" here refers to "complete" samples, which would be
154// 2 int32_t's for stereo files. The audio data is returned right-justified in
155// 32-bit int32_t's in the endian mode native to the executing processor. So,
156// if the original data was 16-bit, then the values returned would be
157// +/-32k. Floating point data can also be returned if the source was
158// floating point data (and this is normalized to +/-1.0). The actual number
159// of samples unpacked is returned, which should be equal to the number
160// requested unless the end of fle is encountered or an error occurs.
161
162uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples)
163{
164 WavpackStream *wps = &wpc->stream;
165 uint32_t bcount, samples_unpacked = 0, samples_to_unpack;
166 int num_channels = wpc->config.num_channels;
167
168 while (samples) {
169 if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) ||
170 wps->sample_index >= wps->wphdr.block_index + wps->wphdr.block_samples) {
171 bcount = read_next_header (wpc->infile, &wps->wphdr);
172
173 if (bcount == (uint32_t) -1)
174 break;
175
176 wps->block_bytes_left = wps->wphdr.ckSize - 24;
177
178 if (wps->wphdr.version < MIN_STREAM_VERS || wps->wphdr.version > MAX_STREAM_VERS) {
179 strcpy_loc (wpc->error_message, "invalid WavPack file!");
180 break;
181 }
182
183 if (!wps->wphdr.block_samples || wps->sample_index == wps->wphdr.block_index)
184 if (!unpack_init (wpc))
185 break;
186 }
187
188 if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) ||
189 wps->sample_index >= wps->wphdr.block_index + wps->wphdr.block_samples)
190 continue;
191
192 if (wps->sample_index < wps->wphdr.block_index) {
193 samples_to_unpack = wps->wphdr.block_index - wps->sample_index;
194
195 if (samples_to_unpack > samples)
196 samples_to_unpack = samples;
197
198 wps->sample_index += samples_to_unpack;
199 samples_unpacked += samples_to_unpack;
200 samples -= samples_to_unpack;
201
202 if (wpc->reduced_channels)
203 samples_to_unpack *= wpc->reduced_channels;
204 else
205 samples_to_unpack *= num_channels;
206
207 while (samples_to_unpack--)
208 *buffer++ = 0;
209
210 continue;
211 }
212
213 samples_to_unpack = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index;
214
215 if (samples_to_unpack > samples)
216 samples_to_unpack = samples;
217
218 unpack_samples (wpc, buffer, samples_to_unpack);
219
220 if (wpc->reduced_channels)
221 buffer += samples_to_unpack * wpc->reduced_channels;
222 else
223 buffer += samples_to_unpack * num_channels;
224
225 samples_unpacked += samples_to_unpack;
226 samples -= samples_to_unpack;
227
228 if (wps->sample_index == wps->wphdr.block_index + wps->wphdr.block_samples) {
229 if (check_crc_error (wpc))
230 wpc->crc_errors++;
231 }
232
233 if (wps->sample_index == wpc->total_samples)
234 break;
235 }
236
237 return samples_unpacked;
238}
239
240// Get total number of samples contained in the WavPack file, or -1 if unknown
241
242uint32_t WavpackGetNumSamples (WavpackContext *wpc)
243{
244 return wpc ? wpc->total_samples : (uint32_t) -1;
245}
246
247// Get the current sample index position, or -1 if unknown
248
249uint32_t WavpackGetSampleIndex (WavpackContext *wpc)
250{
251 if (wpc)
252 return wpc->stream.sample_index;
253
254 return (uint32_t) -1;
255}
256
257// Get the number of errors encountered so far
258
259int WavpackGetNumErrors (WavpackContext *wpc)
260{
261 return wpc ? wpc->crc_errors : 0;
262}
263
264// return TRUE if any uncorrected lossy blocks were actually written or read
265
266int WavpackLossyBlocks (WavpackContext *wpc)
267{
268 return wpc ? wpc->lossy_blocks : 0;
269}
270
271// Returns the sample rate of the specified WavPack file
272
273uint32_t WavpackGetSampleRate (WavpackContext *wpc)
274{
275 return wpc ? wpc->config.sample_rate : 44100;
276}
277
278// Returns the number of channels of the specified WavPack file. Note that
279// this is the actual number of channels contained in the file, but this
280// version can only decode the first two.
281
282int WavpackGetNumChannels (WavpackContext *wpc)
283{
284 return wpc ? wpc->config.num_channels : 2;
285}
286
287// Returns the actual number of valid bits per sample contained in the
288// original file, which may or may not be a multiple of 8. Floating data
289// always has 32 bits, integers may be from 1 to 32 bits each. When this
290// value is not a multiple of 8, then the "extra" bits are located in the
291// LSBs of the results. That is, values are right justified when unpacked
292// into int32_t's, but are left justified in the number of bytes used by the
293// original data.
294
295int WavpackGetBitsPerSample (WavpackContext *wpc)
296{
297 return wpc ? wpc->config.bits_per_sample : 16;
298}
299
300// Returns the number of bytes used for each sample (1 to 4) in the original
301// file. This is required information for the user of this module because the
302// audio data is returned in the LOWER bytes of the int32_t buffer and must be
303// left-shifted 8, 16, or 24 bits if normalized int32_t's are required.
304
305int WavpackGetBytesPerSample (WavpackContext *wpc)
306{
307 return wpc ? wpc->config.bytes_per_sample : 2;
308}
309
310// This function will return the actual number of channels decoded from the
311// file (which may or may not be less than the actual number of channels, but
312// will always be 1 or 2). Normally, this will be the front left and right
313// channels of a multi-channel file.
314
315int WavpackGetReducedChannels (WavpackContext *wpc)
316{
317 if (wpc)
318 return wpc->reduced_channels ? wpc->reduced_channels : wpc->config.num_channels;
319 else
320 return 2;
321}
322
323// Read from current file position until a valid 32-byte WavPack 4.0 header is
324// found and read into the specified pointer. The number of bytes skipped is
325// returned. If no WavPack header is found within 1 meg, then a -1 is returned
326// to indicate the error. No additional bytes are read past the header and it
327// is returned in the processor's native endian mode. Seeking is not required.
328
329static uint32_t read_next_header (read_stream infile, WavpackHeader *wphdr)
330{
331 char buffer [sizeof (*wphdr)], *sp = buffer + sizeof (*wphdr), *ep = sp;
332 uint32_t bytes_skipped = 0;
333 int bleft;
334
335 while (1) {
336 if (sp < ep) {
337 bleft = ep - sp;
338 memcpy (buffer, sp, bleft);
339 }
340 else
341 bleft = 0;
342
343 if (infile (buffer + bleft, sizeof (*wphdr) - bleft) != (int32_t) sizeof (*wphdr) - bleft)
344 return -1;
345
346 sp = buffer;
347
348 if (*sp++ == 'w' && *sp == 'v' && *++sp == 'p' && *++sp == 'k' &&
349 !(*++sp & 1) && sp [2] < 16 && !sp [3] && sp [5] == 4 &&
350 sp [4] >= (MIN_STREAM_VERS & 0xff) && sp [4] <= (MAX_STREAM_VERS & 0xff)) {
351 memcpy (wphdr, buffer, sizeof (*wphdr));
352 little_endian_to_native (wphdr, WavpackHeaderFormat);
353 return bytes_skipped;
354 }
355
356 while (sp < ep && *sp != 'w')
357 sp++;
358
359 if ((bytes_skipped += sp - buffer) > 1024 * 1024)
360 return -1;
361 }
362}
363
364// Open context for writing WavPack files. The returned context pointer is used
365// in all following calls to the library. A return value of NULL indicates
366// that memory could not be allocated for the context.
367
368WavpackContext *WavpackOpenFileOutput (void)
369{
370 CLEAR (wpc);
371 return &wpc;
372}
373
374// Set configuration for writing WavPack files. This must be done before
375// sending any actual samples, however it is okay to send wrapper or other
376// metadata before calling this. The "config" structure contains the following
377// required information:
378
379// config->bytes_per_sample see WavpackGetBytesPerSample() for info
380// config->bits_per_sample see WavpackGetBitsPerSample() for info
381// config->num_channels self evident
382// config->sample_rate self evident
383
384// In addition, the following fields and flags may be set:
385
386// config->flags:
387// --------------
388// o CONFIG_HYBRID_FLAG select hybrid mode (must set bitrate)
389// o CONFIG_JOINT_STEREO select joint stereo (must set override also)
390// o CONFIG_JOINT_OVERRIDE override default joint stereo selection
391// o CONFIG_HYBRID_SHAPE select hybrid noise shaping (set override &
392// shaping_weight != 0.0)
393// o CONFIG_SHAPE_OVERRIDE override default hybrid noise shaping
394// (set CONFIG_HYBRID_SHAPE and shaping_weight)
395// o CONFIG_FAST_FLAG "fast" compression mode
396// o CONFIG_HIGH_FLAG "high" compression mode
397// o CONFIG_BITRATE_KBPS hybrid bitrate is kbps, not bits / sample
398
399// config->bitrate hybrid bitrate in either bits/sample or kbps
400// config->shaping_weight hybrid noise shaping coefficient override
401// config->float_norm_exp select floating-point data (127 for +/-1.0)
402
403// If the number of samples to be written is known then it should be passed
404// here. If the duration is not known then pass -1. In the case that the size
405// is not known (or the writing is terminated early) then it is suggested that
406// the application retrieve the first block written and let the library update
407// the total samples indication. A function is provided to do this update and
408// it should be done to the "correction" file also. If this cannot be done
409// (because a pipe is being used, for instance) then a valid WavPack will still
410// be created, but when applications want to access that file they will have
411// to seek all the way to the end to determine the actual duration. Also, if
412// a RIFF header has been included then it should be updated as well or the
413// WavPack file will not be directly unpackable to a valid wav file (although
414// it will still be usable by itself). A return of FALSE indicates an error.
415
416int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples)
417{
418 WavpackStream *wps = &wpc->stream;
419 uint32_t flags = (config->bytes_per_sample - 1), shift = 0;
420 int num_chans = config->num_channels;
421 int i;
422
423 if ((wpc->config.flags & CONFIG_HYBRID_FLAG) ||
424 wpc->config.float_norm_exp ||
425 num_chans < 1 || num_chans > 2)
426 return FALSE;
427
428 wpc->total_samples = total_samples;
429 wpc->config.sample_rate = config->sample_rate;
430 wpc->config.num_channels = config->num_channels;
431 wpc->config.bits_per_sample = config->bits_per_sample;
432 wpc->config.bytes_per_sample = config->bytes_per_sample;
433 wpc->config.flags = config->flags;
434
435 shift = (config->bytes_per_sample * 8) - config->bits_per_sample;
436
437 for (i = 0; i < 15; ++i)
438 if (wpc->config.sample_rate == sample_rates [i])
439 break;
440
441 flags |= i << SRATE_LSB;
442 flags |= shift << SHIFT_LSB;
443 flags |= CROSS_DECORR;
444
445 if (!(config->flags & CONFIG_JOINT_OVERRIDE) || (config->flags & CONFIG_JOINT_STEREO))
446 flags |= JOINT_STEREO;
447
448 flags |= INITIAL_BLOCK | FINAL_BLOCK;
449
450 if (num_chans == 1) {
451 flags &= ~(JOINT_STEREO | CROSS_DECORR | HYBRID_BALANCE);
452 flags |= MONO_FLAG;
453 }
454
455 flags &= ~MAG_MASK;
456 flags += (1 << MAG_LSB) * ((flags & BYTES_STORED) * 8 + 7);
457
458 memcpy (wps->wphdr.ckID, "wvpk", 4);
459 wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
460 wps->wphdr.total_samples = wpc->total_samples;
461 wps->wphdr.version = CUR_STREAM_VERS;
462 wps->wphdr.flags = flags;
463
464 pack_init (wpc);
465 return TRUE;
466}
467
468// Add wrapper (currently RIFF only) to WavPack blocks. This should be called
469// before sending any audio samples. If the exact contents of the RIFF header
470// are not known because, for example, the file duration is uncertain or
471// trailing chunks are possible, simply write a "dummy" header of the correct
472// length. When all data has been written it will be possible to read the
473// first block written and update the header directly. An example of this can
474// be found in the Audition filter.
475
476void WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount)
477{
478 wpc->wrapper_data = data;
479 wpc->wrapper_bytes = bcount;
480}
481
482// Start a WavPack block to be stored in the specified buffer. This must be
483// called before calling WavpackPackSamples(). Note that writing CANNOT wrap
484// in the buffer; the entire output block must fit in the buffer.
485
486int WavpackStartBlock (WavpackContext *wpc, uchar *begin, uchar *end)
487{
488 wpc->stream.blockbuff = begin;
489 wpc->stream.blockend = end;
490 return pack_start_block (wpc);
491}
492
493// Pack the specified samples. Samples must be stored in int32_ts in the native
494// endian format of the executing processor. The number of samples specified
495// indicates composite samples (sometimes called "frames"). So, the actual
496// number of data points would be this "sample_count" times the number of
497// channels. The caller must decide how many samples to place in each
498// WavPack block (1/2 second is common), but this function may be called as
499// many times as desired to build the final block (and performs the actual
500// compression during the call). A return of FALSE indicates an error.
501
502int WavpackPackSamples (WavpackContext *wpc, int32_t *sample_buffer, uint32_t sample_count)
503{
504 if (!sample_count || pack_samples (wpc, sample_buffer, sample_count))
505 return TRUE;
506
507 strcpy_loc (wpc->error_message, "output buffer overflowed!");
508 return FALSE;
509}
510
511// Finish the WavPack block being built, returning the total size of the
512// block in bytes. Note that the possible conversion of the WavPack header to
513// little-endian takes place here.
514
515uint32_t WavpackFinishBlock (WavpackContext *wpc)
516{
517 WavpackStream *wps = &wpc->stream;
518 uint32_t bcount;
519
520 pack_finish_block (wpc);
521 bcount = ((WavpackHeader *) wps->blockbuff)->ckSize + 8;
522 native_to_little_endian ((WavpackHeader *) wps->blockbuff, WavpackHeaderFormat);
523
524 return bcount;
525}
526
527// Given the pointer to the first block written (to either a .wv or .wvc file),
528// update the block with the actual number of samples written. This should
529// be done if WavpackSetConfiguration() was called with an incorrect number
530// of samples (or -1). It is the responsibility of the application to read and
531// rewrite the block. An example of this can be found in the Audition filter.
532
533void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block)
534{
535 little_endian_to_native (wpc, WavpackHeaderFormat);
536 ((WavpackHeader *) first_block)->total_samples = WavpackGetSampleIndex (wpc);
537 native_to_little_endian (wpc, WavpackHeaderFormat);
538}
539
540// Given the pointer to the first block written to a WavPack file, this
541// function returns the location of the stored RIFF header that was originally
542// written with WavpackAddWrapper(). This would normally be used to update
543// the wav header to indicate that a different number of samples was actually
544// written or if additional RIFF chunks are written at the end of the file.
545// It is the responsibility of the application to read and rewrite the block.
546// An example of this can be found in the Audition filter.
547
548void *WavpackGetWrapperLocation (void *first_block)
549{
550 if (((uchar *) first_block) [32] == ID_RIFF_HEADER)
551 return ((uchar *) first_block) + 34;
552 else
553 return NULL;
554}
555