wputils.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:12k
源码类别:

Windows CE

开发平台:

C/C++

  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. // wputils.c
  9. // This module provides a high-level interface for decoding WavPack 4.0 audio
  10. // streams and files. WavPack data is read with a stream reading callback. No
  11. // direct seeking is provided for, but it is possible to start decoding
  12. // anywhere in a WavPack stream. In this case, WavPack will be able to provide
  13. // the sample-accurate position when it synchs with the data and begins
  14. // decoding.
  15. #include "wavpack.h"
  16. #include <string.h>
  17. ///////////////////////////// local table storage ////////////////////////////
  18. const ulong sample_rates [] = { 6000, 8000, 9600, 11025, 12000, 16000, 22050,
  19.     24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 };
  20. ///////////////////////////// executable code ////////////////////////////////
  21. static ulong read_next_header (WavpackContext *wpc, WavpackHeader *wphdr);
  22. // This function reads data from the specified stream in search of a valid
  23. // WavPack 4.0 audio block. If this fails in 1 megabyte (or an invalid or
  24. // unsupported WavPack block is encountered) then an appropriate message is
  25. // copied to "error" and NULL is returned, otherwise a pointer to a
  26. // WavpackContext structure is returned (which is used to call all other
  27. // functions in this module). This can be initiated at the beginning of a
  28. // WavPack file, or anywhere inside a WavPack file. To determine the exact
  29. // position within the file use WavpackGetSampleIndex(). For demonstration
  30. // purposes this uses a single static copy of the WavpackContext structure,
  31. // so obviously it cannot be used for more than one file at a time. Also,
  32. // this function will not handle "correction" files, plays only the first
  33. // two channels of multi-channel files, and is limited in resolution in some
  34. // large integer or floating point files (but always provides at least 24 bits
  35. // of resolution).
  36. WavpackContext *WavpackOpenFileInput (read_stream infile, char *error, void *privdata)
  37. {
  38.   WavpackContext *wpc = (WavpackContext *)malloc(sizeof(WavpackContext));
  39.     WavpackStream *wps = &wpc->stream;
  40.     ulong bcount;
  41.     memset(wpc, 0, sizeof(WavpackContext));
  42.     wpc->infile = infile;
  43.     wpc->privdata = privdata;
  44.     wpc->total_samples = (ulong) -1;
  45.     wpc->norm_offset = 0;
  46.     wpc->open_flags = 0;
  47.     wps->wvbits.privdata = privdata;
  48.     // open the source file for reading and store the size
  49.     while (!wps->wphdr.block_samples) {
  50. bcount = read_next_header (wpc, &wps->wphdr);
  51. if (bcount == (ulong) -1) {
  52.     //strcpy (error, "not compatible with this version of WavPack file!");
  53.     return NULL;
  54. }
  55. if ((wps->wphdr.flags & UNKNOWN_FLAGS) || wps->wphdr.version < 0x402 || wps->wphdr.version > 0x40f) {
  56.     //strcpy (error, "not compatible with this version of WavPack file!");
  57.     return NULL;
  58. }
  59. if (wps->wphdr.block_samples && wps->wphdr.total_samples != (ulong) -1)
  60.     wpc->total_samples = wps->wphdr.total_samples;
  61. if (!unpack_init (wpc)) {
  62.     //strcpy (error, wpc->error_message [0] ? wpc->error_message :
  63. //"not compatible with this version of WavPack file!");
  64.     return NULL;
  65. }
  66.     }
  67.     wpc->config.flags &= ~0xff;
  68.     wpc->config.flags |= wps->wphdr.flags & 0xff;
  69.     wpc->config.bytes_per_sample = (wps->wphdr.flags & BYTES_STORED) + 1;
  70.     wpc->config.float_norm_exp = wps->float_norm_exp;
  71.     wpc->config.bits_per_sample = (wpc->config.bytes_per_sample * 8) - 
  72. ((wps->wphdr.flags & SHIFT_MASK) >> SHIFT_LSB);
  73.     if (!wpc->config.sample_rate) {
  74. if (!wps || !wps->wphdr.block_samples || (wps->wphdr.flags & SRATE_MASK) == SRATE_MASK)
  75.     wpc->config.sample_rate = 44100;
  76. else
  77.     wpc->config.sample_rate = sample_rates [(wps->wphdr.flags & SRATE_MASK) >> SRATE_LSB];
  78.     }
  79.     if (!wpc->config.num_channels) {
  80. wpc->config.num_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2;
  81. wpc->config.channel_mask = 0x5 - wpc->config.num_channels;
  82.     }
  83.     if (!(wps->wphdr.flags & FINAL_BLOCK))
  84. wpc->reduced_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2;
  85.     return wpc;
  86. }
  87. int WavpackClose(WavpackContext *wpc)
  88. {
  89.   if (wpc != NULL) {
  90.     free(wpc);
  91.   }
  92.   return 0;
  93. }
  94. // This function obtains general information about an open file and returns
  95. // a mask with the following bit values:
  96. // MODE_LOSSLESS:  file is lossless (pure lossless only)
  97. // MODE_HYBRID:  file is hybrid mode (lossy part only)
  98. // MODE_FLOAT:  audio data is 32-bit ieee floating point
  99. // MODE_HIGH:  file was created in "high" mode (information only)
  100. // MODE_FAST:  file was created in "fast" mode (information only)
  101. int WavpackGetMode (WavpackContext *wpc)
  102. {
  103.     int mode = 0;
  104.     if (wpc) {
  105. if (wpc->config.flags & CONFIG_HYBRID_FLAG)
  106.     mode |= MODE_HYBRID;
  107. else if (!(wpc->config.flags & CONFIG_LOSSY_MODE))
  108.     mode |= MODE_LOSSLESS;
  109. if (wpc->lossy_blocks)
  110.     mode &= ~MODE_LOSSLESS;
  111. if (wpc->config.flags & CONFIG_FLOAT_DATA)
  112.     mode |= MODE_FLOAT;
  113. if (wpc->config.flags & CONFIG_HIGH_FLAG)
  114.     mode |= MODE_HIGH;
  115. if (wpc->config.flags & CONFIG_FAST_FLAG)
  116.     mode |= MODE_FAST;
  117.     }
  118.     return mode;
  119. }
  120. void WavpackFlush (WavpackContext *wpc)
  121. {
  122. //TCPMP
  123.     wpc->stream.sample_index = (ulong)-1;
  124. }
  125. // Unpack the specified number of samples from the current file position.
  126. // Note that "samples" here refers to "complete" samples, which would be
  127. // 2 longs for stereo files. The audio data is returned right-justified in
  128. // 32-bit longs in the endian mode native to the executing processor. So,
  129. // if the original data was 16-bit, then the values returned would be
  130. // +/-32k. Floating point data can also be returned if the source was
  131. // floating point data (and this is normalized to +/-1.0). The actual number
  132. // of samples unpacked is returned, which should be equal to the number
  133. // requested unless the end of fle is encountered or an error occurs.
  134. ulong WavpackUnpackSamples (WavpackContext *wpc, long *buffer, ulong samples)
  135. {
  136.     WavpackStream *wps = &wpc->stream;
  137.     ulong bcount, samples_unpacked = 0, samples_to_unpack;
  138.     int num_channels = wpc->config.num_channels;
  139.     while (samples) {
  140. if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) ||
  141.     wps->sample_index >= wps->wphdr.block_index + wps->wphdr.block_samples) {
  142. bcount = read_next_header (wpc, &wps->wphdr);
  143. if (bcount == (ulong) -1)
  144.     break;
  145. if (wps->wphdr.version < 0x402 || wps->wphdr.version > 0x40f) {
  146.     //strcpy (wpc->error_message, "not compatible with this version of WavPack file!");
  147.     break;
  148. }
  149. if (!wps->wphdr.block_samples || wps->sample_index == wps->wphdr.block_index)
  150.     if (!unpack_init (wpc))
  151. break;
  152. }
  153. if (wps->sample_index==(ulong)-1 && wps->wphdr.block_samples && (wps->wphdr.flags & INITIAL_BLOCK))
  154. wps->sample_index = wps->wphdr.block_index; //TCPMP
  155. if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) ||
  156.     wps->sample_index >= wps->wphdr.block_index + wps->wphdr.block_samples)
  157. continue;
  158. if (wps->sample_index < wps->wphdr.block_index) {
  159.     samples_to_unpack = wps->wphdr.block_index - wps->sample_index;
  160.     if (samples_to_unpack > samples)
  161. samples_to_unpack = samples;
  162.     wps->sample_index += samples_to_unpack;
  163.     samples_unpacked += samples_to_unpack;
  164.     samples -= samples_to_unpack;
  165.     if (wpc->reduced_channels)
  166. samples_to_unpack *= wpc->reduced_channels;
  167.     else
  168. samples_to_unpack *= num_channels;
  169.     while (samples_to_unpack--)
  170. *buffer++ = 0;
  171.     continue;
  172. }
  173. samples_to_unpack = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index;
  174. if (samples_to_unpack > samples)
  175.     samples_to_unpack = samples;
  176. unpack_samples (wpc, buffer, samples_to_unpack);
  177. if (wpc->reduced_channels)
  178.     buffer += samples_to_unpack * wpc->reduced_channels;
  179. else
  180.     buffer += samples_to_unpack * num_channels;
  181. samples_unpacked += samples_to_unpack;
  182. samples -= samples_to_unpack;
  183. if (wps->sample_index == wps->wphdr.block_index + wps->wphdr.block_samples) {
  184.     if (check_crc_error (wpc))
  185. wpc->crc_errors++;
  186. }
  187. if (wps->sample_index == wpc->total_samples)
  188.     break;
  189.     }
  190.     return samples_unpacked;
  191. }
  192. // Get total number of samples contained in the WavPack file, or -1 if unknown
  193. ulong WavpackGetNumSamples (WavpackContext *wpc)
  194. {
  195.     return wpc ? wpc->total_samples : (ulong) -1;
  196. }
  197. // Get the current sample index position, or -1 if unknown
  198. ulong WavpackGetSampleIndex (WavpackContext *wpc)
  199. {
  200.     if (wpc)
  201. return wpc->stream.sample_index;
  202.     return (ulong) -1;
  203. }
  204. // Get the number of errors encountered so far
  205. int WavpackGetNumErrors (WavpackContext *wpc)
  206. {
  207.     return wpc ? wpc->crc_errors : 0;
  208. }
  209. // return TRUE if any uncorrected lossy blocks were actually written or read
  210. int WavpackLossyBlocks (WavpackContext *wpc)
  211. {
  212.     return wpc ? wpc->lossy_blocks : 0;
  213. }
  214. // Returns the sample rate of the specified WavPack file
  215. ulong WavpackGetSampleRate (WavpackContext *wpc)
  216. {
  217.     return wpc ? wpc->config.sample_rate : 44100;
  218. }
  219. // Returns the number of channels of the specified WavPack file. Note that
  220. // this is the actual number of channels contained in the file, but this
  221. // version can only decode the first two.
  222. int WavpackGetNumChannels (WavpackContext *wpc)
  223. {
  224.     return wpc ? wpc->config.num_channels : 2;
  225. }
  226. // Returns the actual number of valid bits per sample contained in the
  227. // original file, which may or may not be a multiple of 8. Floating data
  228. // always has 32 bits, integers may be from 1 to 32 bits each. When this
  229. // value is not a multiple of 8, then the "extra" bits are located in the
  230. // LSBs of the results. That is, values are right justified when unpacked
  231. // into longs, but are left justified in the number of bytes used by the
  232. // original data.
  233. int WavpackGetBitsPerSample (WavpackContext *wpc)
  234. {
  235.     return wpc ? wpc->config.bits_per_sample : 16;
  236. }
  237. // Returns the number of bytes used for each sample (1 to 4) in the original
  238. // file. This is required information for the user of this module because the
  239. // audio data is returned in the LOWER bytes of the long buffer and must be
  240. // left-shifted 8, 16, or 24 bits if normalized longs are required.
  241. int WavpackGetBytesPerSample (WavpackContext *wpc)
  242. {
  243.     return wpc ? wpc->config.bytes_per_sample : 2;
  244. }
  245. // This function will return the actual number of channels decoded from the
  246. // file (which may or may not be less than the actual number of channels, but
  247. // will always be 1 or 2). Normally, this will be the front left and right
  248. // channels of a multi-channel file.
  249. int WavpackGetReducedChannels (WavpackContext *wpc)
  250. {
  251.     if (wpc)
  252. return wpc->reduced_channels ? wpc->reduced_channels : wpc->config.num_channels;
  253.     else
  254. return 2;
  255. }
  256. // Read from current file position until a valid 32-byte WavPack 4.0 header is
  257. // found and read into the specified pointer. The number of bytes skipped is
  258. // returned. If no WavPack header is found within 1 meg, then a -1 is returned
  259. // to indicate the error. No additional bytes are read past the header and it
  260. // is returned in the processor's native endian mode. Seeking is not required.
  261. static ulong read_next_header (WavpackContext *wpc, WavpackHeader *wphdr)
  262. {
  263.     char buffer [sizeof (*wphdr)], *sp = buffer + sizeof (*wphdr), *ep = sp;
  264.     ulong bytes_skipped = 0;
  265.     int bleft;
  266.     while (1) {
  267. if (sp < ep) {
  268.     bleft = ep - sp;
  269.     memcpy (buffer, sp, bleft);
  270. }
  271. else
  272.     bleft = 0;
  273. if (wpc->infile (buffer + bleft, sizeof (*wphdr) - bleft, wpc->privdata) != (long) sizeof (*wphdr) - bleft)
  274.     return -1;
  275. sp = buffer;
  276. if (*sp++ == 'w' && *sp == 'v' && *++sp == 'p' && *++sp == 'k' &&
  277.     !(*++sp & 1) && sp [2] < 16 && !sp [3] && sp [5] == 4 && sp [4] >= 2 && sp [4] <= 0xf) {
  278. memcpy (wphdr, buffer, sizeof (*wphdr));
  279. little_endian_to_native (wphdr, WavpackHeaderFormat);
  280. return bytes_skipped;
  281.     }
  282. while (sp < ep && *sp != 'w')
  283.     sp++;
  284. if ((bytes_skipped += sp - buffer) > 1024 * 1024)
  285.     return -1;
  286.     }
  287. }