#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "wavpack_local.h"
#ifndef LIBWAVPACK_VERSION_STRING
#include "wavpack_version.h"
#endif
const uint32_t sample_rates [] = { 6000, 8000, 9600, 11025, 12000, 16000, 22050,
24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 };
int WavpackGetMode (WavpackContext *wpc)
{
int mode = 0;
if (wpc) {
if (wpc->config.flags & CONFIG_HYBRID_FLAG)
mode |= MODE_HYBRID;
else if (!(wpc->config.flags & CONFIG_LOSSY_MODE))
mode |= MODE_LOSSLESS;
if (wpc->wvc_flag)
mode |= (MODE_LOSSLESS | MODE_WVC);
if (wpc->lossy_blocks)
mode &= ~MODE_LOSSLESS;
if (wpc->config.flags & CONFIG_FLOAT_DATA)
mode |= MODE_FLOAT;
if (wpc->config.flags & (CONFIG_HIGH_FLAG | CONFIG_VERY_HIGH_FLAG)) {
mode |= MODE_HIGH;
if ((wpc->config.flags & CONFIG_VERY_HIGH_FLAG) ||
(wpc->streams && wpc->streams [0] && wpc->streams [0]->wphdr.version < 0x405))
mode |= MODE_VERY_HIGH;
}
if (wpc->config.flags & CONFIG_FAST_FLAG)
mode |= MODE_FAST;
if (wpc->config.flags & CONFIG_EXTRA_MODE)
mode |= (MODE_EXTRA | (wpc->config.xmode << 12));
if (wpc->config.flags & CONFIG_CREATE_EXE)
mode |= MODE_SFX;
if (wpc->config.flags & CONFIG_MD5_CHECKSUM)
mode |= MODE_MD5;
if ((wpc->config.flags & CONFIG_HYBRID_FLAG) && (wpc->config.flags & CONFIG_DYNAMIC_SHAPING) &&
wpc->streams && wpc->streams [0] && wpc->streams [0]->wphdr.version >= 0x407)
mode |= MODE_DNS;
#ifndef NO_TAGS
if (valid_tag (&wpc->m_tag)) {
mode |= MODE_VALID_TAG;
if (valid_tag (&wpc->m_tag) == 'A')
mode |= MODE_APETAG;
}
#endif
mode |= (wpc->config.qmode << 16) & 0xFF0000;
}
return mode;
}
int WavpackGetQualifyMode (WavpackContext *wpc)
{
return wpc->config.qmode & 0xFF;
}
char *WavpackGetErrorMessage (WavpackContext *wpc)
{
return wpc->error_message;
}
uint32_t WavpackGetNumSamples (WavpackContext *wpc)
{
return (uint32_t) WavpackGetNumSamples64 (wpc);
}
int64_t WavpackGetNumSamples64 (WavpackContext *wpc)
{
return wpc ? wpc->total_samples : -1;
}
uint32_t WavpackGetSampleIndex (WavpackContext *wpc)
{
return (uint32_t) WavpackGetSampleIndex64 (wpc);
}
int64_t WavpackGetSampleIndex64 (WavpackContext *wpc)
{
if (wpc) {
#ifdef ENABLE_LEGACY
if (wpc->stream3)
return get_sample_index3 (wpc);
else if (wpc->streams && wpc->streams [0])
return wpc->streams [0]->sample_index;
#else
if (wpc->streams && wpc->streams [0])
return wpc->streams [0]->sample_index;
#endif
}
return -1;
}
int WavpackGetNumErrors (WavpackContext *wpc)
{
return wpc ? wpc->crc_errors : 0;
}
int WavpackLossyBlocks (WavpackContext *wpc)
{
return wpc ? wpc->lossy_blocks : 0;
}
double WavpackGetProgress (WavpackContext *wpc)
{
if (wpc && wpc->total_samples != -1 && wpc->total_samples != 0)
return (double) WavpackGetSampleIndex64 (wpc) / wpc->total_samples;
else
return -1.0;
}
uint32_t WavpackGetFileSize (WavpackContext *wpc)
{
return (uint32_t) (wpc ? wpc->filelen + wpc->file2len : 0);
}
int64_t WavpackGetFileSize64 (WavpackContext *wpc)
{
return wpc ? wpc->filelen + wpc->file2len : 0;
}
double WavpackGetRatio (WavpackContext *wpc)
{
if (wpc && wpc->total_samples != -1 && wpc->filelen) {
double output_size = (double) wpc->total_samples * wpc->config.num_channels *
wpc->config.bytes_per_sample;
double input_size = (double) wpc->filelen + wpc->file2len;
if (output_size >= 1.0 && input_size >= 1.0)
return input_size / output_size;
}
return 0.0;
}
double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc)
{
if (wpc && wpc->total_samples != -1 && wpc->filelen && WavpackGetSampleRate (wpc)) {
double output_time = (double) wpc->total_samples / WavpackGetSampleRate (wpc);
double input_size = (double) wpc->filelen + (count_wvc ? wpc->file2len : 0);
if (output_time >= 0.1 && input_size >= 1.0)
return input_size * 8.0 / output_time;
}
return 0.0;
}
double WavpackGetInstantBitrate (WavpackContext *wpc)
{
if (wpc && wpc->stream3)
return WavpackGetAverageBitrate (wpc, TRUE);
if (wpc && wpc->streams && wpc->streams [0] && wpc->streams [0]->wphdr.block_samples && WavpackGetSampleRate (wpc)) {
double output_time = (double) wpc->streams [0]->wphdr.block_samples / WavpackGetSampleRate (wpc);
double input_size = 0;
int si;
for (si = 0; si < wpc->num_streams; ++si) {
if (wpc->streams [si]->blockbuff)
input_size += ((WavpackHeader *) wpc->streams [si]->blockbuff)->ckSize;
if (wpc->streams [si]->block2buff)
input_size += ((WavpackHeader *) wpc->streams [si]->block2buff)->ckSize;
}
if (output_time > 0.0 && input_size >= 1.0)
return input_size * 8.0 / output_time;
}
return 0.0;
}
uint32_t WavpackGetChannelLayout (WavpackContext *wpc, unsigned char *reorder)
{
if ((wpc->channel_layout & 0xff) && wpc->channel_reordering && reorder)
memcpy (reorder, wpc->channel_reordering, wpc->channel_layout & 0xff);
return wpc->channel_layout;
}
void WavpackGetChannelIdentities (WavpackContext *wpc, unsigned char *identities)
{
int num_channels = wpc->config.num_channels, index = 1;
uint32_t channel_mask = wpc->config.channel_mask;
unsigned char *src = wpc->channel_identities;
while (num_channels--) {
if (channel_mask) {
while (!(channel_mask & 1)) {
channel_mask >>= 1;
index++;
}
*identities++ = index++;
channel_mask >>= 1;
}
else if (src && *src)
*identities++ = *src++;
else
*identities++ = 0xff;
}
*identities = 0;
}
void install_close_callback (WavpackContext *wpc, void cb_func (void *wpc))
{
wpc->close_callback = cb_func;
}
WavpackContext *WavpackCloseFile (WavpackContext *wpc)
{
if (wpc->close_callback)
wpc->close_callback (wpc);
if (wpc->streams) {
free_streams (wpc);
if (wpc->streams [0])
free (wpc->streams [0]);
free (wpc->streams);
}
#ifdef ENABLE_LEGACY
if (wpc->stream3)
free_stream3 (wpc);
#endif
if (wpc->reader && wpc->reader->close && wpc->wv_in)
wpc->reader->close (wpc->wv_in);
if (wpc->reader && wpc->reader->close && wpc->wvc_in)
wpc->reader->close (wpc->wvc_in);
WavpackFreeWrapper (wpc);
if (wpc->metadata) {
int i;
for (i = 0; i < wpc->metacount; ++i)
if (wpc->metadata [i].data)
free (wpc->metadata [i].data);
free (wpc->metadata);
}
if (wpc->channel_identities)
free (wpc->channel_identities);
if (wpc->channel_reordering)
free (wpc->channel_reordering);
#ifndef NO_TAGS
free_tag (&wpc->m_tag);
#endif
#ifdef ENABLE_DSD
if (wpc->decimation_context)
decimate_dsd_destroy (wpc->decimation_context);
#endif
free (wpc);
return NULL;
}
uint32_t WavpackGetWrapperBytes (WavpackContext *wpc)
{
return wpc ? wpc->wrapper_bytes : 0;
}
unsigned char *WavpackGetWrapperData (WavpackContext *wpc)
{
return wpc ? wpc->wrapper_data : NULL;
}
void WavpackFreeWrapper (WavpackContext *wpc)
{
if (wpc && wpc->wrapper_data) {
free (wpc->wrapper_data);
wpc->wrapper_data = NULL;
wpc->wrapper_bytes = 0;
}
}
uint32_t WavpackGetSampleRate (WavpackContext *wpc)
{
return wpc ? (wpc->dsd_multiplier ? wpc->config.sample_rate * wpc->dsd_multiplier : wpc->config.sample_rate) : 44100;
}
uint32_t WavpackGetNativeSampleRate (WavpackContext *wpc)
{
return wpc ? (wpc->dsd_multiplier ? wpc->config.sample_rate * wpc->dsd_multiplier * 8 : wpc->config.sample_rate) : 44100;
}
int WavpackGetNumChannels (WavpackContext *wpc)
{
return wpc ? wpc->config.num_channels : 2;
}
int WavpackGetChannelMask (WavpackContext *wpc)
{
return wpc ? wpc->config.channel_mask : 0;
}
int WavpackGetFloatNormExp (WavpackContext *wpc)
{
return (wpc->open_flags & OPEN_NORMALIZE) ? 127 + wpc->norm_offset : wpc->config.float_norm_exp;
}
int WavpackGetBitsPerSample (WavpackContext *wpc)
{
return wpc ? wpc->config.bits_per_sample : 16;
}
int WavpackGetBytesPerSample (WavpackContext *wpc)
{
return wpc ? wpc->config.bytes_per_sample : 2;
}
int WavpackGetReducedChannels (WavpackContext *wpc)
{
if (wpc)
return wpc->reduced_channels ? wpc->reduced_channels : wpc->config.num_channels;
else
return 2;
}
void free_streams (WavpackContext *wpc)
{
int si = wpc->num_streams;
while (si--) {
if (wpc->streams [si]->blockbuff) {
free (wpc->streams [si]->blockbuff);
wpc->streams [si]->blockbuff = NULL;
}
if (wpc->streams [si]->block2buff) {
free (wpc->streams [si]->block2buff);
wpc->streams [si]->block2buff = NULL;
}
if (wpc->streams [si]->sample_buffer) {
free (wpc->streams [si]->sample_buffer);
wpc->streams [si]->sample_buffer = NULL;
}
if (wpc->streams [si]->dc.shaping_data) {
free (wpc->streams [si]->dc.shaping_data);
wpc->streams [si]->dc.shaping_data = NULL;
}
#ifdef ENABLE_DSD
free_dsd_tables (wpc->streams [si]);
#endif
if (si) {
wpc->num_streams--;
free (wpc->streams [si]);
wpc->streams [si] = NULL;
}
}
wpc->current_stream = 0;
}
void free_dsd_tables (WavpackStream *wps)
{
if (wps->dsd.probabilities) {
free (wps->dsd.probabilities);
wps->dsd.probabilities = NULL;
}
if (wps->dsd.summed_probabilities) {
free (wps->dsd.summed_probabilities);
wps->dsd.summed_probabilities = NULL;
}
if (wps->dsd.lookup_buffer) {
free (wps->dsd.lookup_buffer);
wps->dsd.lookup_buffer = NULL;
}
if (wps->dsd.value_lookup) {
free (wps->dsd.value_lookup);
wps->dsd.value_lookup = NULL;
}
if (wps->dsd.ptable) {
free (wps->dsd.ptable);
wps->dsd.ptable = NULL;
}
}
void WavpackFloatNormalize (int32_t *values, int32_t num_values, int delta_exp)
{
f32 *fvalues = (f32 *) values;
int exp;
if (!delta_exp)
return;
while (num_values--) {
if ((exp = get_exponent (*fvalues)) == 0 || exp + delta_exp <= 0)
*fvalues = 0;
else if (exp == 255 || (exp += delta_exp) >= 255) {
set_exponent (*fvalues, 255);
set_mantissa (*fvalues, 0);
}
else
set_exponent (*fvalues, exp);
fvalues++;
}
}
void WavpackLittleEndianToNative (void *data, char *format)
{
unsigned char *cp = (unsigned char *) data;
int64_t temp64;
int32_t temp32;
int16_t temp16;
while (*format) {
switch (*format) {
case 'D':
temp64 = cp [0] + ((int64_t) cp [1] << 8) + ((int64_t) cp [2] << 16) + ((int64_t) cp [3] << 24) +
((int64_t) cp [4] << 32) + ((int64_t) cp [5] << 40) + ((int64_t) cp [6] << 48) + ((uint64_t) cp [7] << 56);
memcpy (cp, &temp64, 8);
cp += 8;
break;
case 'L':
temp32 = cp [0] + ((int32_t) cp [1] << 8) + ((int32_t) cp [2] << 16) + ((int64_t) cp [3] << 24);
memcpy (cp, &temp32, 4);
cp += 4;
break;
case 'S':
temp16 = cp [0] + (cp [1] << 8);
memcpy (cp, &temp16, 2);
cp += 2;
break;
default:
if (isdigit (*format))
cp += *format - '0';
break;
}
format++;
}
}
void WavpackNativeToLittleEndian (void *data, char *format)
{
unsigned char *cp = (unsigned char *) data;
int64_t temp64;
int32_t temp32;
int16_t temp16;
while (*format) {
switch (*format) {
case 'D':
memcpy (&temp64, cp, sizeof (temp64));
*cp++ = (unsigned char) temp64;
*cp++ = (unsigned char) (temp64 >> 8);
*cp++ = (unsigned char) (temp64 >> 16);
*cp++ = (unsigned char) (temp64 >> 24);
*cp++ = (unsigned char) (temp64 >> 32);
*cp++ = (unsigned char) (temp64 >> 40);
*cp++ = (unsigned char) (temp64 >> 48);
*cp++ = (unsigned char) (temp64 >> 56);
break;
case 'L':
memcpy (&temp32, cp, sizeof (temp32));
*cp++ = (unsigned char) temp32;
*cp++ = (unsigned char) (temp32 >> 8);
*cp++ = (unsigned char) (temp32 >> 16);
*cp++ = (unsigned char) (temp32 >> 24);
break;
case 'S':
memcpy (&temp16, cp, sizeof (temp16));
*cp++ = (unsigned char) temp16;
*cp++ = (unsigned char) (temp16 >> 8);
break;
default:
if (isdigit (*format))
cp += *format - '0';
break;
}
format++;
}
}
void WavpackBigEndianToNative (void *data, char *format)
{
unsigned char *cp = (unsigned char *) data;
int64_t temp64;
int32_t temp32;
int16_t temp16;
while (*format) {
switch (*format) {
case 'D':
temp64 = cp [7] + ((int64_t) cp [6] << 8) + ((int64_t) cp [5] << 16) + ((int64_t) cp [4] << 24) +
((int64_t) cp [3] << 32) + ((int64_t) cp [2] << 40) + ((int64_t) cp [1] << 48) + ((uint64_t) cp [0] << 56);
memcpy (cp, &temp64, 8);
cp += 8;
break;
case 'L':
temp32 = cp [3] + ((int32_t) cp [2] << 8) + ((int32_t) cp [1] << 16) + ((int64_t) cp [0] << 24);
memcpy (cp, &temp32, 4);
cp += 4;
break;
case 'S':
temp16 = cp [1] + (cp [0] << 8);
memcpy (cp, &temp16, 2);
cp += 2;
break;
default:
if (isdigit (*format))
cp += *format - '0';
break;
}
format++;
}
}
void WavpackNativeToBigEndian (void *data, char *format)
{
unsigned char *cp = (unsigned char *) data;
int64_t temp64;
int32_t temp32;
int16_t temp16;
while (*format) {
switch (*format) {
case 'D':
memcpy (&temp64, cp, sizeof (temp64));
*cp++ = (unsigned char) (temp64 >> 56);
*cp++ = (unsigned char) (temp64 >> 48);
*cp++ = (unsigned char) (temp64 >> 40);
*cp++ = (unsigned char) (temp64 >> 32);
*cp++ = (unsigned char) (temp64 >> 24);
*cp++ = (unsigned char) (temp64 >> 16);
*cp++ = (unsigned char) (temp64 >> 8);
*cp++ = (unsigned char) temp64;
break;
case 'L':
memcpy (&temp32, cp, sizeof (temp32));
*cp++ = (unsigned char) (temp32 >> 24);
*cp++ = (unsigned char) (temp32 >> 16);
*cp++ = (unsigned char) (temp32 >> 8);
*cp++ = (unsigned char) temp32;
break;
case 'S':
memcpy (&temp16, cp, sizeof (temp16));
*cp++ = (unsigned char) (temp16 >> 8);
*cp++ = (unsigned char) temp16;
break;
default:
if (isdigit (*format))
cp += *format - '0';
break;
}
format++;
}
}
uint32_t WavpackGetLibraryVersion (void)
{
return (LIBWAVPACK_MAJOR<<16)
|(LIBWAVPACK_MINOR<<8)
|(LIBWAVPACK_MICRO<<0);
}
const char *WavpackGetLibraryVersionString (void)
{
return LIBWAVPACK_VERSION_STRING;
}