diff options
Diffstat (limited to 'apps/codecs/libwavpack/wputils.c')
-rw-r--r-- | apps/codecs/libwavpack/wputils.c | 431 |
1 files changed, 315 insertions, 116 deletions
diff --git a/apps/codecs/libwavpack/wputils.c b/apps/codecs/libwavpack/wputils.c index 8d58b3b4d7..7f2ab14c44 100644 --- a/apps/codecs/libwavpack/wputils.c +++ b/apps/codecs/libwavpack/wputils.c | |||
@@ -1,8 +1,8 @@ | |||
1 | //////////////////////////////////////////////////////////////////////////// | 1 | //////////////////////////////////////////////////////////////////////////// |
2 | // **** WAVPACK **** // | 2 | // **** WAVPACK **** // |
3 | // Hybrid Lossless Wavefile Compressor // | 3 | // Hybrid Lossless Wavefile Compressor // |
4 | // Copyright (c) 1998 - 2004 Conifer Software. // | 4 | // Copyright (c) 1998 - 2004 Conifer Software. // |
5 | // All Rights Reserved. // | 5 | // All Rights Reserved. // |
6 | // Distributed under the BSD Software License (see license.txt) // | 6 | // Distributed under the BSD Software License (see license.txt) // |
7 | //////////////////////////////////////////////////////////////////////////// | 7 | //////////////////////////////////////////////////////////////////////////// |
8 | 8 | ||
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | #include <string.h> | 20 | #include <string.h> |
21 | 21 | ||
22 | static void strcpy_loc (char *dst, char *src) { while (*src) *dst++ = *src++; *dst = 0; } | 22 | static void strcpy_loc (char *dst, char *src) { while ((*dst++ = *src++) != 0); } |
23 | 23 | ||
24 | ///////////////////////////// local table storage //////////////////////////// | 24 | ///////////////////////////// local table storage //////////////////////////// |
25 | 25 | ||
@@ -29,7 +29,7 @@ const ulong sample_rates [] = { 6000, 8000, 9600, 11025, 12000, 16000, 22050, | |||
29 | ///////////////////////////// executable code //////////////////////////////// | 29 | ///////////////////////////// executable code //////////////////////////////// |
30 | 30 | ||
31 | static ulong read_next_header (read_stream infile, WavpackHeader *wphdr); | 31 | static ulong read_next_header (read_stream infile, WavpackHeader *wphdr); |
32 | 32 | ||
33 | // This function reads data from the specified stream in search of a valid | 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 | 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 | 35 | // unsupported WavPack block is encountered) then an appropriate message is |
@@ -62,27 +62,27 @@ WavpackContext *WavpackOpenFileInput (read_stream infile, char *error) | |||
62 | 62 | ||
63 | while (!wps->wphdr.block_samples) { | 63 | while (!wps->wphdr.block_samples) { |
64 | 64 | ||
65 | bcount = read_next_header (wpc.infile, &wps->wphdr); | 65 | bcount = read_next_header (wpc.infile, &wps->wphdr); |
66 | 66 | ||
67 | if (bcount == (ulong) -1) { | 67 | if (bcount == (ulong) -1) { |
68 | strcpy_loc (error, "invalid WavPack file!"); | 68 | strcpy_loc (error, "invalid WavPack file!"); |
69 | return NULL; | 69 | return NULL; |
70 | } | 70 | } |
71 | 71 | ||
72 | if ((wps->wphdr.flags & UNKNOWN_FLAGS) || wps->wphdr.version < 0x402 || wps->wphdr.version > 0x40f) { | 72 | if ((wps->wphdr.flags & UNKNOWN_FLAGS) || wps->wphdr.version < 0x402 || wps->wphdr.version > 0x40f) { |
73 | strcpy_loc (error, "invalid WavPack file!"); | 73 | strcpy_loc (error, "invalid WavPack file!"); |
74 | return NULL; | 74 | return NULL; |
75 | } | 75 | } |
76 | 76 | ||
77 | if (wps->wphdr.block_samples && wps->wphdr.total_samples != (ulong) -1) | 77 | if (wps->wphdr.block_samples && wps->wphdr.total_samples != (ulong) -1) |
78 | wpc.total_samples = wps->wphdr.total_samples; | 78 | wpc.total_samples = wps->wphdr.total_samples; |
79 | 79 | ||
80 | if (!unpack_init (&wpc)) { | 80 | if (!unpack_init (&wpc)) { |
81 | strcpy_loc (error, wpc.error_message [0] ? wpc.error_message : | 81 | strcpy_loc (error, wpc.error_message [0] ? wpc.error_message : |
82 | "invalid WavPack file!"); | 82 | "invalid WavPack file!"); |
83 | 83 | ||
84 | return NULL; | 84 | return NULL; |
85 | } | 85 | } |
86 | } | 86 | } |
87 | 87 | ||
88 | wpc.config.flags &= ~0xff; | 88 | wpc.config.flags &= ~0xff; |
@@ -91,22 +91,22 @@ WavpackContext *WavpackOpenFileInput (read_stream infile, char *error) | |||
91 | wpc.config.float_norm_exp = wps->float_norm_exp; | 91 | wpc.config.float_norm_exp = wps->float_norm_exp; |
92 | 92 | ||
93 | wpc.config.bits_per_sample = (wpc.config.bytes_per_sample * 8) - | 93 | wpc.config.bits_per_sample = (wpc.config.bytes_per_sample * 8) - |
94 | ((wps->wphdr.flags & SHIFT_MASK) >> SHIFT_LSB); | 94 | ((wps->wphdr.flags & SHIFT_MASK) >> SHIFT_LSB); |
95 | 95 | ||
96 | if (!wpc.config.sample_rate) { | 96 | if (!wpc.config.sample_rate) { |
97 | if (!wps || !wps->wphdr.block_samples || (wps->wphdr.flags & SRATE_MASK) == SRATE_MASK) | 97 | if (!wps || !wps->wphdr.block_samples || (wps->wphdr.flags & SRATE_MASK) == SRATE_MASK) |
98 | wpc.config.sample_rate = 44100; | 98 | wpc.config.sample_rate = 44100; |
99 | else | 99 | else |
100 | wpc.config.sample_rate = sample_rates [(wps->wphdr.flags & SRATE_MASK) >> SRATE_LSB]; | 100 | wpc.config.sample_rate = sample_rates [(wps->wphdr.flags & SRATE_MASK) >> SRATE_LSB]; |
101 | } | 101 | } |
102 | 102 | ||
103 | if (!wpc.config.num_channels) { | 103 | if (!wpc.config.num_channels) { |
104 | wpc.config.num_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2; | 104 | wpc.config.num_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2; |
105 | wpc.config.channel_mask = 0x5 - wpc.config.num_channels; | 105 | wpc.config.channel_mask = 0x5 - wpc.config.num_channels; |
106 | } | 106 | } |
107 | 107 | ||
108 | if (!(wps->wphdr.flags & FINAL_BLOCK)) | 108 | if (!(wps->wphdr.flags & FINAL_BLOCK)) |
109 | wpc.reduced_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2; | 109 | wpc.reduced_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2; |
110 | 110 | ||
111 | return &wpc; | 111 | return &wpc; |
112 | } | 112 | } |
@@ -125,22 +125,22 @@ int WavpackGetMode (WavpackContext *wpc) | |||
125 | int mode = 0; | 125 | int mode = 0; |
126 | 126 | ||
127 | if (wpc) { | 127 | if (wpc) { |
128 | if (wpc->config.flags & CONFIG_HYBRID_FLAG) | 128 | if (wpc->config.flags & CONFIG_HYBRID_FLAG) |
129 | mode |= MODE_HYBRID; | 129 | mode |= MODE_HYBRID; |
130 | else if (!(wpc->config.flags & CONFIG_LOSSY_MODE)) | 130 | else if (!(wpc->config.flags & CONFIG_LOSSY_MODE)) |
131 | mode |= MODE_LOSSLESS; | 131 | mode |= MODE_LOSSLESS; |
132 | 132 | ||
133 | if (wpc->lossy_blocks) | 133 | if (wpc->lossy_blocks) |
134 | mode &= ~MODE_LOSSLESS; | 134 | mode &= ~MODE_LOSSLESS; |
135 | 135 | ||
136 | if (wpc->config.flags & CONFIG_FLOAT_DATA) | 136 | if (wpc->config.flags & CONFIG_FLOAT_DATA) |
137 | mode |= MODE_FLOAT; | 137 | mode |= MODE_FLOAT; |
138 | 138 | ||
139 | if (wpc->config.flags & CONFIG_HIGH_FLAG) | 139 | if (wpc->config.flags & CONFIG_HIGH_FLAG) |
140 | mode |= MODE_HIGH; | 140 | mode |= MODE_HIGH; |
141 | 141 | ||
142 | if (wpc->config.flags & CONFIG_FAST_FLAG) | 142 | if (wpc->config.flags & CONFIG_FAST_FLAG) |
143 | mode |= MODE_FAST; | 143 | mode |= MODE_FAST; |
144 | } | 144 | } |
145 | 145 | ||
146 | return mode; | 146 | return mode; |
@@ -163,70 +163,70 @@ ulong WavpackUnpackSamples (WavpackContext *wpc, long *buffer, ulong samples) | |||
163 | int num_channels = wpc->config.num_channels; | 163 | int num_channels = wpc->config.num_channels; |
164 | 164 | ||
165 | while (samples) { | 165 | while (samples) { |
166 | if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || | 166 | if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || |
167 | wps->sample_index >= wps->wphdr.block_index + wps->wphdr.block_samples) { | 167 | wps->sample_index >= wps->wphdr.block_index + wps->wphdr.block_samples) { |
168 | bcount = read_next_header (wpc->infile, &wps->wphdr); | 168 | bcount = read_next_header (wpc->infile, &wps->wphdr); |
169 | 169 | ||
170 | if (bcount == (ulong) -1) | 170 | if (bcount == (ulong) -1) |
171 | break; | 171 | break; |
172 | 172 | ||
173 | if (wps->wphdr.version < 0x402 || wps->wphdr.version > 0x40f) { | 173 | if (wps->wphdr.version < 0x402 || wps->wphdr.version > 0x40f) { |
174 | strcpy_loc (wpc->error_message, "invalid WavPack file!"); | 174 | strcpy_loc (wpc->error_message, "invalid WavPack file!"); |
175 | break; | 175 | break; |
176 | } | 176 | } |
177 | 177 | ||
178 | if (!wps->wphdr.block_samples || wps->sample_index == wps->wphdr.block_index) | 178 | if (!wps->wphdr.block_samples || wps->sample_index == wps->wphdr.block_index) |
179 | if (!unpack_init (wpc)) | 179 | if (!unpack_init (wpc)) |
180 | break; | 180 | break; |
181 | } | 181 | } |
182 | 182 | ||
183 | if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || | 183 | if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || |
184 | wps->sample_index >= wps->wphdr.block_index + wps->wphdr.block_samples) | 184 | wps->sample_index >= wps->wphdr.block_index + wps->wphdr.block_samples) |
185 | continue; | 185 | continue; |
186 | 186 | ||
187 | if (wps->sample_index < wps->wphdr.block_index) { | 187 | if (wps->sample_index < wps->wphdr.block_index) { |
188 | samples_to_unpack = wps->wphdr.block_index - wps->sample_index; | 188 | samples_to_unpack = wps->wphdr.block_index - wps->sample_index; |
189 | 189 | ||
190 | if (samples_to_unpack > samples) | 190 | if (samples_to_unpack > samples) |
191 | samples_to_unpack = samples; | 191 | samples_to_unpack = samples; |
192 | 192 | ||
193 | wps->sample_index += samples_to_unpack; | 193 | wps->sample_index += samples_to_unpack; |
194 | samples_unpacked += samples_to_unpack; | 194 | samples_unpacked += samples_to_unpack; |
195 | samples -= samples_to_unpack; | 195 | samples -= samples_to_unpack; |
196 | 196 | ||
197 | if (wpc->reduced_channels) | 197 | if (wpc->reduced_channels) |
198 | samples_to_unpack *= wpc->reduced_channels; | 198 | samples_to_unpack *= wpc->reduced_channels; |
199 | else | 199 | else |
200 | samples_to_unpack *= num_channels; | 200 | samples_to_unpack *= num_channels; |
201 | 201 | ||
202 | while (samples_to_unpack--) | 202 | while (samples_to_unpack--) |
203 | *buffer++ = 0; | 203 | *buffer++ = 0; |
204 | 204 | ||
205 | continue; | 205 | continue; |
206 | } | 206 | } |
207 | 207 | ||
208 | samples_to_unpack = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index; | 208 | samples_to_unpack = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index; |
209 | 209 | ||
210 | if (samples_to_unpack > samples) | 210 | if (samples_to_unpack > samples) |
211 | samples_to_unpack = samples; | 211 | samples_to_unpack = samples; |
212 | 212 | ||
213 | unpack_samples (wpc, buffer, samples_to_unpack); | 213 | unpack_samples (wpc, buffer, samples_to_unpack); |
214 | 214 | ||
215 | if (wpc->reduced_channels) | 215 | if (wpc->reduced_channels) |
216 | buffer += samples_to_unpack * wpc->reduced_channels; | 216 | buffer += samples_to_unpack * wpc->reduced_channels; |
217 | else | 217 | else |
218 | buffer += samples_to_unpack * num_channels; | 218 | buffer += samples_to_unpack * num_channels; |
219 | 219 | ||
220 | samples_unpacked += samples_to_unpack; | 220 | samples_unpacked += samples_to_unpack; |
221 | samples -= samples_to_unpack; | 221 | samples -= samples_to_unpack; |
222 | 222 | ||
223 | if (wps->sample_index == wps->wphdr.block_index + wps->wphdr.block_samples) { | 223 | if (wps->sample_index == wps->wphdr.block_index + wps->wphdr.block_samples) { |
224 | if (check_crc_error (wpc)) | 224 | if (check_crc_error (wpc)) |
225 | wpc->crc_errors++; | 225 | wpc->crc_errors++; |
226 | } | 226 | } |
227 | 227 | ||
228 | if (wps->sample_index == wpc->total_samples) | 228 | if (wps->sample_index == wpc->total_samples) |
229 | break; | 229 | break; |
230 | } | 230 | } |
231 | 231 | ||
232 | return samples_unpacked; | 232 | return samples_unpacked; |
@@ -244,7 +244,7 @@ ulong WavpackGetNumSamples (WavpackContext *wpc) | |||
244 | ulong WavpackGetSampleIndex (WavpackContext *wpc) | 244 | ulong WavpackGetSampleIndex (WavpackContext *wpc) |
245 | { | 245 | { |
246 | if (wpc) | 246 | if (wpc) |
247 | return wpc->stream.sample_index; | 247 | return wpc->stream.sample_index; |
248 | 248 | ||
249 | return (ulong) -1; | 249 | return (ulong) -1; |
250 | } | 250 | } |
@@ -310,9 +310,9 @@ int WavpackGetBytesPerSample (WavpackContext *wpc) | |||
310 | int WavpackGetReducedChannels (WavpackContext *wpc) | 310 | int WavpackGetReducedChannels (WavpackContext *wpc) |
311 | { | 311 | { |
312 | if (wpc) | 312 | if (wpc) |
313 | return wpc->reduced_channels ? wpc->reduced_channels : wpc->config.num_channels; | 313 | return wpc->reduced_channels ? wpc->reduced_channels : wpc->config.num_channels; |
314 | else | 314 | else |
315 | return 2; | 315 | return 2; |
316 | } | 316 | } |
317 | 317 | ||
318 | // Read from current file position until a valid 32-byte WavPack 4.0 header is | 318 | // Read from current file position until a valid 32-byte WavPack 4.0 header is |
@@ -328,29 +328,228 @@ static ulong read_next_header (read_stream infile, WavpackHeader *wphdr) | |||
328 | int bleft; | 328 | int bleft; |
329 | 329 | ||
330 | while (1) { | 330 | while (1) { |
331 | if (sp < ep) { | 331 | if (sp < ep) { |
332 | bleft = ep - sp; | 332 | bleft = ep - sp; |
333 | memcpy (buffer, sp, bleft); | 333 | memcpy (buffer, sp, bleft); |
334 | } | 334 | } |
335 | else | 335 | else |
336 | bleft = 0; | 336 | bleft = 0; |
337 | 337 | ||
338 | if (infile (buffer + bleft, sizeof (*wphdr) - bleft) != (long) sizeof (*wphdr) - bleft) | 338 | if (infile (buffer + bleft, sizeof (*wphdr) - bleft) != (long) sizeof (*wphdr) - bleft) |
339 | return -1; | 339 | return -1; |
340 | 340 | ||
341 | sp = buffer; | 341 | sp = buffer; |
342 | 342 | ||
343 | if (*sp++ == 'w' && *sp == 'v' && *++sp == 'p' && *++sp == 'k' && | 343 | if (*sp++ == 'w' && *sp == 'v' && *++sp == 'p' && *++sp == 'k' && |
344 | !(*++sp & 1) && sp [2] < 16 && !sp [3] && sp [5] == 4 && sp [4] >= 2 && sp [4] <= 0xf) { | 344 | !(*++sp & 1) && sp [2] < 16 && !sp [3] && sp [5] == 4 && sp [4] >= 2 && sp [4] <= 0xf) { |
345 | memcpy (wphdr, buffer, sizeof (*wphdr)); | 345 | memcpy (wphdr, buffer, sizeof (*wphdr)); |
346 | little_endian_to_native (wphdr, WavpackHeaderFormat); | 346 | little_endian_to_native (wphdr, WavpackHeaderFormat); |
347 | return bytes_skipped; | 347 | return bytes_skipped; |
348 | } | 348 | } |
349 | 349 | ||
350 | while (sp < ep && *sp != 'w') | 350 | while (sp < ep && *sp != 'w') |
351 | sp++; | 351 | sp++; |
352 | 352 | ||
353 | if ((bytes_skipped += sp - buffer) > 1024 * 1024) | 353 | if ((bytes_skipped += sp - buffer) > 1024 * 1024) |
354 | return -1; | 354 | return -1; |
355 | } | 355 | } |
356 | } | 356 | } |
357 | |||
358 | // Open context for writing WavPack files. The returned context pointer is used | ||
359 | // in all following calls to the library. A return value of NULL indicates | ||
360 | // that memory could not be allocated for the context. | ||
361 | |||
362 | WavpackContext *WavpackOpenFileOutput (void) | ||
363 | { | ||
364 | CLEAR (wpc); | ||
365 | return &wpc; | ||
366 | } | ||
367 | |||
368 | // Set the output buffer limits. This must be done before calling | ||
369 | // WavpackPackSamples(), but also may be done afterward to adjust | ||
370 | // the usable buffer. Note that writing CANNOT wrap in the buffer; the | ||
371 | // entire output block must fit in the buffer. | ||
372 | |||
373 | void WavpackSetOutputBuffer (WavpackContext *wpc, uchar *begin, uchar *end) | ||
374 | { | ||
375 | wpc->stream.blockbuff = begin; | ||
376 | wpc->stream.blockend = end; | ||
377 | } | ||
378 | |||
379 | // Set configuration for writing WavPack files. This must be done before | ||
380 | // sending any actual samples, however it is okay to send wrapper or other | ||
381 | // metadata before calling this. The "config" structure contains the following | ||
382 | // required information: | ||
383 | |||
384 | // config->bytes_per_sample see WavpackGetBytesPerSample() for info | ||
385 | // config->bits_per_sample see WavpackGetBitsPerSample() for info | ||
386 | // config->num_channels self evident | ||
387 | // config->sample_rate self evident | ||
388 | |||
389 | // In addition, the following fields and flags may be set: | ||
390 | |||
391 | // config->flags: | ||
392 | // -------------- | ||
393 | // o CONFIG_HYBRID_FLAG select hybrid mode (must set bitrate) | ||
394 | // o CONFIG_JOINT_STEREO select joint stereo (must set override also) | ||
395 | // o CONFIG_JOINT_OVERRIDE override default joint stereo selection | ||
396 | // o CONFIG_HYBRID_SHAPE select hybrid noise shaping (set override & | ||
397 | // shaping_weight != 0.0) | ||
398 | // o CONFIG_SHAPE_OVERRIDE override default hybrid noise shaping | ||
399 | // (set CONFIG_HYBRID_SHAPE and shaping_weight) | ||
400 | // o CONFIG_FAST_FLAG "fast" compression mode | ||
401 | // o CONFIG_HIGH_FLAG "high" compression mode | ||
402 | // o CONFIG_BITRATE_KBPS hybrid bitrate is kbps, not bits / sample | ||
403 | |||
404 | // config->bitrate hybrid bitrate in either bits/sample or kbps | ||
405 | // config->shaping_weight hybrid noise shaping coefficient override | ||
406 | // config->float_norm_exp select floating-point data (127 for +/-1.0) | ||
407 | |||
408 | // If the number of samples to be written is known then it should be passed | ||
409 | // here. If the duration is not known then pass -1. In the case that the size | ||
410 | // is not known (or the writing is terminated early) then it is suggested that | ||
411 | // the application retrieve the first block written and let the library update | ||
412 | // the total samples indication. A function is provided to do this update and | ||
413 | // it should be done to the "correction" file also. If this cannot be done | ||
414 | // (because a pipe is being used, for instance) then a valid WavPack will still | ||
415 | // be created, but when applications want to access that file they will have | ||
416 | // to seek all the way to the end to determine the actual duration. Also, if | ||
417 | // a RIFF header has been included then it should be updated as well or the | ||
418 | // WavPack file will not be directly unpackable to a valid wav file (although | ||
419 | // it will still be usable by itself). A return of FALSE indicates an error. | ||
420 | |||
421 | int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, ulong total_samples) | ||
422 | { | ||
423 | WavpackStream *wps = &wpc->stream; | ||
424 | ulong flags = (config->bytes_per_sample - 1), shift = 0; | ||
425 | int num_chans = config->num_channels; | ||
426 | int i; | ||
427 | |||
428 | if ((wpc->config.flags & CONFIG_HYBRID_FLAG) || | ||
429 | wpc->config.float_norm_exp || | ||
430 | num_chans < 1 || num_chans > 2) | ||
431 | return FALSE; | ||
432 | |||
433 | wpc->total_samples = total_samples; | ||
434 | wpc->config.sample_rate = config->sample_rate; | ||
435 | wpc->config.num_channels = config->num_channels; | ||
436 | wpc->config.bits_per_sample = config->bits_per_sample; | ||
437 | wpc->config.bytes_per_sample = config->bytes_per_sample; | ||
438 | wpc->config.flags = config->flags; | ||
439 | |||
440 | shift = (config->bytes_per_sample * 8) - config->bits_per_sample; | ||
441 | |||
442 | for (i = 0; i < 15; ++i) | ||
443 | if (wpc->config.sample_rate == sample_rates [i]) | ||
444 | break; | ||
445 | |||
446 | flags |= i << SRATE_LSB; | ||
447 | flags |= shift << SHIFT_LSB; | ||
448 | flags |= CROSS_DECORR; | ||
449 | |||
450 | if (!(config->flags & CONFIG_JOINT_OVERRIDE) || (config->flags & CONFIG_JOINT_STEREO)) | ||
451 | flags |= JOINT_STEREO; | ||
452 | |||
453 | memcpy (wps->wphdr.ckID, "wvpk", 4); | ||
454 | wps->wphdr.ckSize = sizeof (WavpackHeader) - 8; | ||
455 | wps->wphdr.total_samples = wpc->total_samples; | ||
456 | wps->wphdr.version = 0x403; | ||
457 | wps->wphdr.flags = flags; | ||
458 | |||
459 | wps->wphdr.flags |= INITIAL_BLOCK; | ||
460 | wps->wphdr.flags |= FINAL_BLOCK; | ||
461 | |||
462 | if (num_chans == 1) { | ||
463 | wps->wphdr.flags &= ~(JOINT_STEREO | CROSS_DECORR | HYBRID_BALANCE); | ||
464 | wps->wphdr.flags |= MONO_FLAG; | ||
465 | } | ||
466 | |||
467 | pack_init (wpc); | ||
468 | return TRUE; | ||
469 | } | ||
470 | |||
471 | // Add wrapper (currently RIFF only) to WavPack blocks. This should be called | ||
472 | // before sending any audio samples for the RIFF header or after all samples | ||
473 | // have been sent for any RIFF trailer. WavpackFlushSamples() should be called | ||
474 | // between sending the last samples and calling this for trailer data to make | ||
475 | // sure that headers and trailers don't get mixed up in very short files. If | ||
476 | // the exact contents of the RIFF header are not known because, for example, | ||
477 | // the file duration is uncertain or trailing chunks are possible, simply write | ||
478 | // a "dummy" header of the correct length. When all data has been written it | ||
479 | // will be possible to read the first block written and update the header | ||
480 | // directly. An example of this can be found in the Audition filter. A | ||
481 | // return of FALSE indicates an error. | ||
482 | |||
483 | void WavpackAddWrapper (WavpackContext *wpc, void *data, ulong bcount) | ||
484 | { | ||
485 | wpc->wrapper_data = data; | ||
486 | wpc->wrapper_bytes = bcount; | ||
487 | } | ||
488 | |||
489 | // Pack the specified samples. Samples must be stored in longs in the native | ||
490 | // endian format of the executing processor. The number of samples specified | ||
491 | // indicates composite samples (sometimes called "frames"). So, the actual | ||
492 | // number of data points would be this "sample_count" times the number of | ||
493 | // channels. Note that samples are accumulated here until enough exist to | ||
494 | // create a complete WavPack block (or several blocks for multichannel audio). | ||
495 | // If an application wants to break a block at a specific sample, then it must | ||
496 | // simply call WavpackFlushSamples() to force an early termination. Completed | ||
497 | // WavPack blocks are send to the function provided in the initial call to | ||
498 | // WavpackOpenFileOutput(). A return of FALSE indicates an error. | ||
499 | |||
500 | ulong WavpackPackSamples (WavpackContext *wpc, long *sample_buffer, ulong sample_count) | ||
501 | { | ||
502 | WavpackStream *wps = &wpc->stream; | ||
503 | ulong flags = wps->wphdr.flags; | ||
504 | ulong bcount; | ||
505 | int result; | ||
506 | |||
507 | flags &= ~MAG_MASK; | ||
508 | flags += (1 << MAG_LSB) * ((flags & BYTES_STORED) * 8 + 7); | ||
509 | |||
510 | wps->wphdr.block_index = wps->sample_index; | ||
511 | wps->wphdr.block_samples = sample_count; | ||
512 | wps->wphdr.flags = flags; | ||
513 | |||
514 | result = pack_block (wpc, sample_buffer); | ||
515 | |||
516 | if (!result) { | ||
517 | strcpy_loc (wpc->error_message, "output buffer overflowed!"); | ||
518 | return 0; | ||
519 | } | ||
520 | |||
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 | |||
533 | void 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 | |||
548 | void *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 | |||