adpcm_decode_block one channel
This commit is contained in:
parent
dc27c996fb
commit
129237fb2c
823
extern/adpcm-xq-s/adpcm-lib.c
vendored
823
extern/adpcm-xq-s/adpcm-lib.c
vendored
|
@ -1,415 +1,408 @@
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// **** ADPCM-XQ **** //
|
// **** ADPCM-XQ **** //
|
||||||
// Xtreme Quality ADPCM Encoder/Decoder //
|
// Xtreme Quality ADPCM Encoder/Decoder //
|
||||||
// Copyright (c) 2022 David Bryant. //
|
// Copyright (c) 2022 David Bryant. //
|
||||||
// All Rights Reserved. //
|
// All Rights Reserved. //
|
||||||
// Distributed under the BSD Software License (see license.txt) //
|
// Distributed under the BSD Software License (see license.txt) //
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "adpcm-lib.h"
|
#include "adpcm-lib.h"
|
||||||
|
|
||||||
/* This module encodes and decodes 4-bit ADPCM (DVI/IMA varient). ADPCM data is divided
|
/* This module encodes and decodes 4-bit ADPCM (DVI/IMA varient). ADPCM data is divided
|
||||||
* into independently decodable blocks that can be relatively small. The most common
|
* into independently decodable blocks that can be relatively small. The most common
|
||||||
* configuration is to store 505 samples into a 256 byte block, although other sizes are
|
* configuration is to store 505 samples into a 256 byte block, although other sizes are
|
||||||
* permitted as long as the number of samples is one greater than a multiple of 8. When
|
* permitted as long as the number of samples is one greater than a multiple of 8. When
|
||||||
* multiple channels are present, they are interleaved in the data with an 8-sample
|
* multiple channels are present, they are interleaved in the data with an 8-sample
|
||||||
* interval.
|
* interval.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/********************************* 4-bit ADPCM encoder ********************************/
|
/********************************* 4-bit ADPCM encoder ********************************/
|
||||||
|
|
||||||
#define CLIP(data, min, max) \
|
#define CLIP(data, min, max) \
|
||||||
if ((data) > (max)) data = max; \
|
if ((data) > (max)) data = max; \
|
||||||
else if ((data) < (min)) data = min;
|
else if ((data) < (min)) data = min;
|
||||||
|
|
||||||
/* step table */
|
/* step table */
|
||||||
static const uint16_t step_table[89] = {
|
static const uint16_t step_table[89] = {
|
||||||
7, 8, 9, 10, 11, 12, 13, 14,
|
7, 8, 9, 10, 11, 12, 13, 14,
|
||||||
16, 17, 19, 21, 23, 25, 28, 31,
|
16, 17, 19, 21, 23, 25, 28, 31,
|
||||||
34, 37, 41, 45, 50, 55, 60, 66,
|
34, 37, 41, 45, 50, 55, 60, 66,
|
||||||
73, 80, 88, 97, 107, 118, 130, 143,
|
73, 80, 88, 97, 107, 118, 130, 143,
|
||||||
157, 173, 190, 209, 230, 253, 279, 307,
|
157, 173, 190, 209, 230, 253, 279, 307,
|
||||||
337, 371, 408, 449, 494, 544, 598, 658,
|
337, 371, 408, 449, 494, 544, 598, 658,
|
||||||
724, 796, 876, 963, 1060, 1166, 1282, 1411,
|
724, 796, 876, 963, 1060, 1166, 1282, 1411,
|
||||||
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
|
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
|
||||||
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
|
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
|
||||||
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||||
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
|
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
|
||||||
32767
|
32767
|
||||||
};
|
};
|
||||||
|
|
||||||
/* step index tables */
|
/* step index tables */
|
||||||
static const int index_table[] = {
|
static const int index_table[] = {
|
||||||
/* adpcm data size is 4 */
|
/* adpcm data size is 4 */
|
||||||
-1, -1, -1, -1, 2, 4, 6, 8
|
-1, -1, -1, -1, 2, 4, 6, 8
|
||||||
};
|
};
|
||||||
|
|
||||||
struct adpcm_channel {
|
struct adpcm_channel {
|
||||||
int32_t pcmdata; // current PCM value
|
int32_t pcmdata; // current PCM value
|
||||||
int32_t error, weight, history [2]; // for noise shaping
|
int32_t error, weight, history [2]; // for noise shaping
|
||||||
int8_t index; // current index into step size table
|
int8_t index; // current index into step size table
|
||||||
};
|
};
|
||||||
|
|
||||||
struct adpcm_context {
|
struct adpcm_context {
|
||||||
struct adpcm_channel channels [2];
|
struct adpcm_channel channels [2];
|
||||||
int num_channels, lookahead, noise_shaping;
|
int num_channels, lookahead, noise_shaping;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Create ADPCM encoder context with given number of channels.
|
/* Create ADPCM encoder context with given number of channels.
|
||||||
* The returned pointer is used for subsequent calls. Note that
|
* The returned pointer is used for subsequent calls. Note that
|
||||||
* even though an ADPCM encoder could be set up to encode frames
|
* even though an ADPCM encoder could be set up to encode frames
|
||||||
* independently, we use a context so that we can use previous
|
* independently, we use a context so that we can use previous
|
||||||
* data to improve quality (this encoder might not be optimal
|
* data to improve quality (this encoder might not be optimal
|
||||||
* for encoding independent frames).
|
* for encoding independent frames).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void *adpcm_create_context (int num_channels, int lookahead, int noise_shaping, int32_t initial_deltas [2])
|
void *adpcm_create_context (int num_channels, int lookahead, int noise_shaping, int32_t initial_deltas [2])
|
||||||
{
|
{
|
||||||
struct adpcm_context *pcnxt = malloc (sizeof (struct adpcm_context));
|
struct adpcm_context *pcnxt = malloc (sizeof (struct adpcm_context));
|
||||||
int ch, i;
|
int ch, i;
|
||||||
|
|
||||||
memset (pcnxt, 0, sizeof (struct adpcm_context));
|
memset (pcnxt, 0, sizeof (struct adpcm_context));
|
||||||
pcnxt->noise_shaping = noise_shaping;
|
pcnxt->noise_shaping = noise_shaping;
|
||||||
pcnxt->num_channels = num_channels;
|
pcnxt->num_channels = num_channels;
|
||||||
pcnxt->lookahead = lookahead;
|
pcnxt->lookahead = lookahead;
|
||||||
|
|
||||||
// given the supplied initial deltas, search for and store the closest index
|
// given the supplied initial deltas, search for and store the closest index
|
||||||
|
|
||||||
for (ch = 0; ch < num_channels; ++ch)
|
for (ch = 0; ch < num_channels; ++ch)
|
||||||
for (i = 0; i <= 88; i++)
|
for (i = 0; i <= 88; i++)
|
||||||
if (i == 88 || initial_deltas [ch] < ((int32_t) step_table [i] + step_table [i+1]) / 2) {
|
if (i == 88 || initial_deltas [ch] < ((int32_t) step_table [i] + step_table [i+1]) / 2) {
|
||||||
pcnxt->channels [ch].index = i;
|
pcnxt->channels [ch].index = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pcnxt;
|
return pcnxt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free the ADPCM encoder context.
|
/* Free the ADPCM encoder context.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void adpcm_free_context (void *p)
|
void adpcm_free_context (void *p)
|
||||||
{
|
{
|
||||||
struct adpcm_context *pcnxt = (struct adpcm_context *) p;
|
struct adpcm_context *pcnxt = (struct adpcm_context *) p;
|
||||||
|
|
||||||
free (pcnxt);
|
free (pcnxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_decode_parameters (struct adpcm_context *pcnxt, int32_t *init_pcmdata, int8_t *init_index)
|
static void set_decode_parameters (struct adpcm_context *pcnxt, int32_t *init_pcmdata, int8_t *init_index)
|
||||||
{
|
{
|
||||||
int ch;
|
int ch;
|
||||||
|
|
||||||
for (ch = 0; ch < pcnxt->num_channels; ch++) {
|
for (ch = 0; ch < pcnxt->num_channels; ch++) {
|
||||||
pcnxt->channels[ch].pcmdata = init_pcmdata[ch];
|
pcnxt->channels[ch].pcmdata = init_pcmdata[ch];
|
||||||
pcnxt->channels[ch].index = init_index[ch];
|
pcnxt->channels[ch].index = init_index[ch];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_decode_parameters (struct adpcm_context *pcnxt, int32_t *init_pcmdata, int8_t *init_index)
|
static void get_decode_parameters (struct adpcm_context *pcnxt, int32_t *init_pcmdata, int8_t *init_index)
|
||||||
{
|
{
|
||||||
int ch;
|
int ch;
|
||||||
|
|
||||||
for (ch = 0; ch < pcnxt->num_channels; ch++) {
|
for (ch = 0; ch < pcnxt->num_channels; ch++) {
|
||||||
init_pcmdata[ch] = pcnxt->channels[ch].pcmdata;
|
init_pcmdata[ch] = pcnxt->channels[ch].pcmdata;
|
||||||
init_index[ch] = pcnxt->channels[ch].index;
|
init_index[ch] = pcnxt->channels[ch].index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static double minimum_error (const struct adpcm_channel *pchan, int nch, int32_t csample, const int16_t *sample, int depth, int *best_nibble)
|
static double minimum_error (const struct adpcm_channel *pchan, int nch, int32_t csample, const int16_t *sample, int depth, int *best_nibble)
|
||||||
{
|
{
|
||||||
int32_t delta = csample - pchan->pcmdata;
|
int32_t delta = csample - pchan->pcmdata;
|
||||||
struct adpcm_channel chan = *pchan;
|
struct adpcm_channel chan = *pchan;
|
||||||
uint16_t step = step_table[chan.index];
|
uint16_t step = step_table[chan.index];
|
||||||
uint16_t trial_delta = (step >> 3);
|
uint16_t trial_delta = (step >> 3);
|
||||||
int nibble, nibble2;
|
int nibble, nibble2;
|
||||||
double min_error;
|
double min_error;
|
||||||
|
|
||||||
if (delta < 0) {
|
if (delta < 0) {
|
||||||
int mag = (-delta << 2) / step;
|
int mag = (-delta << 2) / step;
|
||||||
nibble = 0x8 | (mag > 7 ? 7 : mag);
|
nibble = 0x8 | (mag > 7 ? 7 : mag);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int mag = (delta << 2) / step;
|
int mag = (delta << 2) / step;
|
||||||
nibble = mag > 7 ? 7 : mag;
|
nibble = mag > 7 ? 7 : mag;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nibble & 1) trial_delta += (step >> 2);
|
if (nibble & 1) trial_delta += (step >> 2);
|
||||||
if (nibble & 2) trial_delta += (step >> 1);
|
if (nibble & 2) trial_delta += (step >> 1);
|
||||||
if (nibble & 4) trial_delta += step;
|
if (nibble & 4) trial_delta += step;
|
||||||
|
|
||||||
if (nibble & 8)
|
if (nibble & 8)
|
||||||
chan.pcmdata -= trial_delta;
|
chan.pcmdata -= trial_delta;
|
||||||
else
|
else
|
||||||
chan.pcmdata += trial_delta;
|
chan.pcmdata += trial_delta;
|
||||||
|
|
||||||
CLIP(chan.pcmdata, -32768, 32767);
|
CLIP(chan.pcmdata, -32768, 32767);
|
||||||
if (best_nibble) *best_nibble = nibble;
|
if (best_nibble) *best_nibble = nibble;
|
||||||
min_error = (double) (chan.pcmdata - csample) * (chan.pcmdata - csample);
|
min_error = (double) (chan.pcmdata - csample) * (chan.pcmdata - csample);
|
||||||
|
|
||||||
if (depth) {
|
if (depth) {
|
||||||
chan.index += index_table[nibble & 0x07];
|
chan.index += index_table[nibble & 0x07];
|
||||||
CLIP(chan.index, 0, 88);
|
CLIP(chan.index, 0, 88);
|
||||||
min_error += minimum_error (&chan, nch, sample [nch], sample + nch, depth - 1, NULL);
|
min_error += minimum_error (&chan, nch, sample [nch], sample + nch, depth - 1, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return min_error;
|
return min_error;
|
||||||
|
|
||||||
for (nibble2 = 0; nibble2 <= 0xF; ++nibble2) {
|
for (nibble2 = 0; nibble2 <= 0xF; ++nibble2) {
|
||||||
double error;
|
double error;
|
||||||
|
|
||||||
if (nibble2 == nibble)
|
if (nibble2 == nibble)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
chan = *pchan;
|
chan = *pchan;
|
||||||
trial_delta = (step >> 3);
|
trial_delta = (step >> 3);
|
||||||
|
|
||||||
if (nibble2 & 1) trial_delta += (step >> 2);
|
if (nibble2 & 1) trial_delta += (step >> 2);
|
||||||
if (nibble2 & 2) trial_delta += (step >> 1);
|
if (nibble2 & 2) trial_delta += (step >> 1);
|
||||||
if (nibble2 & 4) trial_delta += step;
|
if (nibble2 & 4) trial_delta += step;
|
||||||
|
|
||||||
if (nibble2 & 8)
|
if (nibble2 & 8)
|
||||||
chan.pcmdata -= trial_delta;
|
chan.pcmdata -= trial_delta;
|
||||||
else
|
else
|
||||||
chan.pcmdata += trial_delta;
|
chan.pcmdata += trial_delta;
|
||||||
|
|
||||||
CLIP(chan.pcmdata, -32768, 32767);
|
CLIP(chan.pcmdata, -32768, 32767);
|
||||||
|
|
||||||
error = (double) (chan.pcmdata - csample) * (chan.pcmdata - csample);
|
error = (double) (chan.pcmdata - csample) * (chan.pcmdata - csample);
|
||||||
|
|
||||||
if (error < min_error) {
|
if (error < min_error) {
|
||||||
chan.index += index_table[nibble2 & 0x07];
|
chan.index += index_table[nibble2 & 0x07];
|
||||||
CLIP(chan.index, 0, 88);
|
CLIP(chan.index, 0, 88);
|
||||||
error += minimum_error (&chan, nch, sample [nch], sample + nch, depth - 1, NULL);
|
error += minimum_error (&chan, nch, sample [nch], sample + nch, depth - 1, NULL);
|
||||||
|
|
||||||
if (error < min_error) {
|
if (error < min_error) {
|
||||||
if (best_nibble) *best_nibble = nibble2;
|
if (best_nibble) *best_nibble = nibble2;
|
||||||
min_error = error;
|
min_error = error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return min_error;
|
return min_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t encode_sample (struct adpcm_context *pcnxt, int ch, const int16_t *sample, int num_samples)
|
static uint8_t encode_sample (struct adpcm_context *pcnxt, int ch, const int16_t *sample, int num_samples)
|
||||||
{
|
{
|
||||||
struct adpcm_channel *pchan = pcnxt->channels + ch;
|
struct adpcm_channel *pchan = pcnxt->channels + ch;
|
||||||
int32_t csample = *sample;
|
int32_t csample = *sample;
|
||||||
int depth = num_samples - 1, nibble;
|
int depth = num_samples - 1, nibble;
|
||||||
uint16_t step = step_table[pchan->index];
|
uint16_t step = step_table[pchan->index];
|
||||||
uint16_t trial_delta = (step >> 3);
|
uint16_t trial_delta = (step >> 3);
|
||||||
|
|
||||||
if (pcnxt->noise_shaping == NOISE_SHAPING_DYNAMIC) {
|
if (pcnxt->noise_shaping == NOISE_SHAPING_DYNAMIC) {
|
||||||
int32_t sam = (3 * pchan->history [0] - pchan->history [1]) >> 1;
|
int32_t sam = (3 * pchan->history [0] - pchan->history [1]) >> 1;
|
||||||
int32_t temp = csample - (((pchan->weight * sam) + 512) >> 10);
|
int32_t temp = csample - (((pchan->weight * sam) + 512) >> 10);
|
||||||
int32_t shaping_weight;
|
int32_t shaping_weight;
|
||||||
|
|
||||||
if (sam && temp) pchan->weight -= (((sam ^ temp) >> 29) & 4) - 2;
|
if (sam && temp) pchan->weight -= (((sam ^ temp) >> 29) & 4) - 2;
|
||||||
pchan->history [1] = pchan->history [0];
|
pchan->history [1] = pchan->history [0];
|
||||||
pchan->history [0] = csample;
|
pchan->history [0] = csample;
|
||||||
|
|
||||||
shaping_weight = (pchan->weight < 256) ? 1024 : 1536 - (pchan->weight * 2);
|
shaping_weight = (pchan->weight < 256) ? 1024 : 1536 - (pchan->weight * 2);
|
||||||
temp = -((shaping_weight * pchan->error + 512) >> 10);
|
temp = -((shaping_weight * pchan->error + 512) >> 10);
|
||||||
|
|
||||||
if (shaping_weight < 0 && temp) {
|
if (shaping_weight < 0 && temp) {
|
||||||
if (temp == pchan->error)
|
if (temp == pchan->error)
|
||||||
temp = (temp < 0) ? temp + 1 : temp - 1;
|
temp = (temp < 0) ? temp + 1 : temp - 1;
|
||||||
|
|
||||||
pchan->error = -csample;
|
pchan->error = -csample;
|
||||||
csample += temp;
|
csample += temp;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
pchan->error = -(csample += temp);
|
pchan->error = -(csample += temp);
|
||||||
}
|
}
|
||||||
else if (pcnxt->noise_shaping == NOISE_SHAPING_STATIC)
|
else if (pcnxt->noise_shaping == NOISE_SHAPING_STATIC)
|
||||||
pchan->error = -(csample -= pchan->error);
|
pchan->error = -(csample -= pchan->error);
|
||||||
|
|
||||||
if (depth > pcnxt->lookahead)
|
if (depth > pcnxt->lookahead)
|
||||||
depth = pcnxt->lookahead;
|
depth = pcnxt->lookahead;
|
||||||
|
|
||||||
minimum_error (pchan, pcnxt->num_channels, csample, sample, depth, &nibble);
|
minimum_error (pchan, pcnxt->num_channels, csample, sample, depth, &nibble);
|
||||||
|
|
||||||
if (nibble & 1) trial_delta += (step >> 2);
|
if (nibble & 1) trial_delta += (step >> 2);
|
||||||
if (nibble & 2) trial_delta += (step >> 1);
|
if (nibble & 2) trial_delta += (step >> 1);
|
||||||
if (nibble & 4) trial_delta += step;
|
if (nibble & 4) trial_delta += step;
|
||||||
|
|
||||||
if (nibble & 8)
|
if (nibble & 8)
|
||||||
pchan->pcmdata -= trial_delta;
|
pchan->pcmdata -= trial_delta;
|
||||||
else
|
else
|
||||||
pchan->pcmdata += trial_delta;
|
pchan->pcmdata += trial_delta;
|
||||||
|
|
||||||
pchan->index += index_table[nibble & 0x07];
|
pchan->index += index_table[nibble & 0x07];
|
||||||
CLIP(pchan->index, 0, 88);
|
CLIP(pchan->index, 0, 88);
|
||||||
CLIP(pchan->pcmdata, -32768, 32767);
|
CLIP(pchan->pcmdata, -32768, 32767);
|
||||||
|
|
||||||
if (pcnxt->noise_shaping)
|
if (pcnxt->noise_shaping)
|
||||||
pchan->error += pchan->pcmdata;
|
pchan->error += pchan->pcmdata;
|
||||||
|
|
||||||
return nibble;
|
return nibble;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void encode_chunks (struct adpcm_context *pcnxt, uint8_t **outbuf, size_t *outbufsize, const int16_t **inbuf, int inbufcount)
|
static void encode_chunks (struct adpcm_context *pcnxt, uint8_t **outbuf, size_t *outbufsize, const int16_t **inbuf, int inbufcount)
|
||||||
{
|
{
|
||||||
const int16_t *pcmbuf;
|
const int16_t *pcmbuf;
|
||||||
int chunks, ch, i;
|
int chunks, ch, i;
|
||||||
|
|
||||||
chunks = (inbufcount - 1) / 8;
|
chunks = (inbufcount - 1) / 8;
|
||||||
*outbufsize += (chunks * 4) * pcnxt->num_channels;
|
*outbufsize += (chunks * 4) * pcnxt->num_channels;
|
||||||
|
|
||||||
while (chunks--)
|
while (chunks--)
|
||||||
{
|
{
|
||||||
for (ch = 0; ch < pcnxt->num_channels; ch++)
|
for (ch = 0; ch < pcnxt->num_channels; ch++)
|
||||||
{
|
{
|
||||||
pcmbuf = *inbuf + ch;
|
pcmbuf = *inbuf + ch;
|
||||||
|
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
**outbuf = encode_sample (pcnxt, ch, pcmbuf, chunks * 8 + (3 - i) * 2 + 2);
|
**outbuf = encode_sample (pcnxt, ch, pcmbuf, chunks * 8 + (3 - i) * 2 + 2);
|
||||||
pcmbuf += pcnxt->num_channels;
|
pcmbuf += pcnxt->num_channels;
|
||||||
**outbuf |= encode_sample (pcnxt, ch, pcmbuf, chunks * 8 + (3 - i) * 2 + 1) << 4;
|
**outbuf |= encode_sample (pcnxt, ch, pcmbuf, chunks * 8 + (3 - i) * 2 + 1) << 4;
|
||||||
pcmbuf += pcnxt->num_channels;
|
pcmbuf += pcnxt->num_channels;
|
||||||
(*outbuf)++;
|
(*outbuf)++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*inbuf += 8 * pcnxt->num_channels;
|
*inbuf += 8 * pcnxt->num_channels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Encode a block of 16-bit PCM data into 4-bit ADPCM.
|
/* Encode a block of 16-bit PCM data into 4-bit ADPCM.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* p the context returned by adpcm_begin()
|
* p the context returned by adpcm_begin()
|
||||||
* outbuf destination buffer
|
* outbuf destination buffer
|
||||||
* outbufsize pointer to variable where the number of bytes written
|
* outbufsize pointer to variable where the number of bytes written
|
||||||
* will be stored
|
* will be stored
|
||||||
* inbuf source PCM samples
|
* inbuf source PCM samples
|
||||||
* inbufcount number of composite PCM samples provided (note: this is
|
* inbufcount number of composite PCM samples provided (note: this is
|
||||||
* the total number of 16-bit samples divided by the number
|
* the total number of 16-bit samples divided by the number
|
||||||
* of channels)
|
* of channels)
|
||||||
*
|
*
|
||||||
* Returns 1 (for success as there is no error checking)
|
* Returns 1 (for success as there is no error checking)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int adpcm_encode_block (void *p, uint8_t *outbuf, size_t *outbufsize, const int16_t *inbuf, int inbufcount)
|
int adpcm_encode_block (void *p, uint8_t *outbuf, size_t *outbufsize, const int16_t *inbuf, int inbufcount)
|
||||||
{
|
{
|
||||||
struct adpcm_context *pcnxt = (struct adpcm_context *) p;
|
struct adpcm_context *pcnxt = (struct adpcm_context *) p;
|
||||||
int32_t init_pcmdata[2];
|
int32_t init_pcmdata[2];
|
||||||
int8_t init_index[2];
|
int8_t init_index[2];
|
||||||
int ch;
|
int ch;
|
||||||
|
|
||||||
*outbufsize = 0;
|
*outbufsize = 0;
|
||||||
|
|
||||||
if (!inbufcount)
|
if (!inbufcount)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
get_decode_parameters(pcnxt, init_pcmdata, init_index);
|
get_decode_parameters(pcnxt, init_pcmdata, init_index);
|
||||||
|
|
||||||
for (ch = 0; ch < pcnxt->num_channels; ch++) {
|
for (ch = 0; ch < pcnxt->num_channels; ch++) {
|
||||||
init_pcmdata[ch] = *inbuf++;
|
init_pcmdata[ch] = *inbuf++;
|
||||||
outbuf[0] = init_pcmdata[ch];
|
outbuf[0] = init_pcmdata[ch];
|
||||||
outbuf[1] = init_pcmdata[ch] >> 8;
|
outbuf[1] = init_pcmdata[ch] >> 8;
|
||||||
outbuf[2] = init_index[ch];
|
outbuf[2] = init_index[ch];
|
||||||
outbuf[3] = 0;
|
outbuf[3] = 0;
|
||||||
|
|
||||||
outbuf += 4;
|
outbuf += 4;
|
||||||
*outbufsize += 4;
|
*outbufsize += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_decode_parameters(pcnxt, init_pcmdata, init_index);
|
set_decode_parameters(pcnxt, init_pcmdata, init_index);
|
||||||
encode_chunks (pcnxt, &outbuf, outbufsize, &inbuf, inbufcount);
|
encode_chunks (pcnxt, &outbuf, outbufsize, &inbuf, inbufcount);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************* 4-bit ADPCM decoder ********************************/
|
/********************************* 4-bit ADPCM decoder ********************************/
|
||||||
|
|
||||||
/* Decode the block of ADPCM data into PCM. This requires no context because ADPCM blocks
|
/* Decode the block of ADPCM data into PCM. This requires no context because ADPCM blocks
|
||||||
* are indeppendently decodable. This assumes that a single entire block is always decoded;
|
* are indeppendently decodable. This assumes that a single entire block is always decoded;
|
||||||
* it must be called multiple times for multiple blocks and cannot resume in the middle of a
|
* it must be called multiple times for multiple blocks and cannot resume in the middle of a
|
||||||
* block.
|
* block.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* outbuf destination for interleaved PCM samples
|
* outbuf destination for interleaved PCM samples
|
||||||
* inbuf source ADPCM block
|
* inbuf source ADPCM block
|
||||||
* inbufsize size of source ADPCM block
|
* inbufsize size of source ADPCM block
|
||||||
* channels number of channels in block (must be determined from other context)
|
* channels number of channels in block (must be determined from other context)
|
||||||
*
|
*
|
||||||
* Returns number of converted composite samples (total samples divided by number of channels)
|
* Returns number of converted composite samples (total samples divided by number of channels)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int adpcm_decode_block (int16_t *outbuf, const uint8_t *inbuf, size_t inbufsize, size_t outbufsize, int channels)
|
int adpcm_decode_block (int16_t *outbuf, const uint8_t *inbuf, size_t inbufsize, size_t outbufsize)
|
||||||
{
|
{
|
||||||
int ch, samples = 1, chunks;
|
int samples = 1, chunks;
|
||||||
int32_t pcmdata[2];
|
int32_t pcmdata[2];
|
||||||
int8_t index[2];
|
int8_t index[2];
|
||||||
|
|
||||||
if (inbufsize < (uint32_t) channels * 4)
|
if (inbufsize < 4)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (ch = 0; ch < channels; ch++) {
|
*outbuf++ = pcmdata[0] = (int16_t) (inbuf [0] | (inbuf [1] << 8));
|
||||||
*outbuf++ = pcmdata[ch] = (int16_t) (inbuf [0] | (inbuf [1] << 8));
|
index[0] = inbuf [2];
|
||||||
index[ch] = inbuf [2];
|
|
||||||
|
if (index [0] < 0 || index [0] > 88 || inbuf [3]) // sanitize the input a little...
|
||||||
if (index [ch] < 0 || index [ch] > 88 || inbuf [3]) // sanitize the input a little...
|
return 0;
|
||||||
return 0;
|
|
||||||
|
inbufsize -= 4;
|
||||||
inbufsize -= 4;
|
inbuf += 4;
|
||||||
inbuf += 4;
|
|
||||||
}
|
chunks = inbufsize / 4;
|
||||||
|
samples += chunks * 8;
|
||||||
chunks = inbufsize / (channels * 4);
|
|
||||||
samples += chunks * 8;
|
while (chunks--) {
|
||||||
|
int i;
|
||||||
while (chunks--) {
|
|
||||||
int ch, i;
|
for (i = 0; i < 4; ++i) {
|
||||||
|
uint16_t step = step_table [index [0]], delta = step >> 3;
|
||||||
for (ch = 0; ch < channels; ++ch) {
|
|
||||||
|
if (*inbuf & 1) delta += (step >> 2);
|
||||||
for (i = 0; i < 4; ++i) {
|
if (*inbuf & 2) delta += (step >> 1);
|
||||||
uint16_t step = step_table [index [ch]], delta = step >> 3;
|
if (*inbuf & 4) delta += step;
|
||||||
|
|
||||||
if (*inbuf & 1) delta += (step >> 2);
|
if (*inbuf & 8)
|
||||||
if (*inbuf & 2) delta += (step >> 1);
|
pcmdata[0] -= delta;
|
||||||
if (*inbuf & 4) delta += step;
|
else
|
||||||
|
pcmdata[0] += delta;
|
||||||
if (*inbuf & 8)
|
|
||||||
pcmdata[ch] -= delta;
|
index[0] += index_table [*inbuf & 0x7];
|
||||||
else
|
CLIP(index[0], 0, 88);
|
||||||
pcmdata[ch] += delta;
|
CLIP(pcmdata[0], -32768, 32767);
|
||||||
|
outbuf [i * 2] = pcmdata[0];
|
||||||
index[ch] += index_table [*inbuf & 0x7];
|
|
||||||
CLIP(index[ch], 0, 88);
|
step = step_table [index [0]]; delta = step >> 3;
|
||||||
CLIP(pcmdata[ch], -32768, 32767);
|
|
||||||
outbuf [i * 2 * channels] = pcmdata[ch];
|
if (*inbuf & 0x10) delta += (step >> 2);
|
||||||
|
if (*inbuf & 0x20) delta += (step >> 1);
|
||||||
step = step_table [index [ch]]; delta = step >> 3;
|
if (*inbuf & 0x40) delta += step;
|
||||||
|
|
||||||
if (*inbuf & 0x10) delta += (step >> 2);
|
if (*inbuf & 0x80)
|
||||||
if (*inbuf & 0x20) delta += (step >> 1);
|
pcmdata[0] -= delta;
|
||||||
if (*inbuf & 0x40) delta += step;
|
else
|
||||||
|
pcmdata[0] += delta;
|
||||||
if (*inbuf & 0x80)
|
|
||||||
pcmdata[ch] -= delta;
|
index[0] += index_table [(*inbuf >> 4) & 0x7];
|
||||||
else
|
CLIP(index[0], 0, 88);
|
||||||
pcmdata[ch] += delta;
|
CLIP(pcmdata[0], -32768, 32767);
|
||||||
|
outbuf [(i * 2 + 1)] = pcmdata[0];
|
||||||
index[ch] += index_table [(*inbuf >> 4) & 0x7];
|
|
||||||
CLIP(index[ch], 0, 88);
|
inbuf++;
|
||||||
CLIP(pcmdata[ch], -32768, 32767);
|
}
|
||||||
outbuf [(i * 2 + 1) * channels] = pcmdata[ch];
|
|
||||||
|
outbuf += 8;
|
||||||
inbuf++;
|
}
|
||||||
}
|
|
||||||
|
return samples;
|
||||||
outbuf++;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
outbuf += channels * 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
return samples;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
88
extern/adpcm-xq-s/adpcm-lib.h
vendored
88
extern/adpcm-xq-s/adpcm-lib.h
vendored
|
@ -1,44 +1,44 @@
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// **** ADPCM-XQ **** //
|
// **** ADPCM-XQ **** //
|
||||||
// Xtreme Quality ADPCM Encoder/Decoder //
|
// Xtreme Quality ADPCM Encoder/Decoder //
|
||||||
// Copyright (c) 2015 David Bryant. //
|
// Copyright (c) 2015 David Bryant. //
|
||||||
// All Rights Reserved. //
|
// All Rights Reserved. //
|
||||||
// Distributed under the BSD Software License (see license.txt) //
|
// Distributed under the BSD Software License (see license.txt) //
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef ADPCMLIB_H_
|
#ifndef ADPCMLIB_H_
|
||||||
#define ADPCMLIB_H_
|
#define ADPCMLIB_H_
|
||||||
|
|
||||||
#define NOISE_SHAPING_OFF 0 // flat noise (no shaping)
|
#define NOISE_SHAPING_OFF 0 // flat noise (no shaping)
|
||||||
#define NOISE_SHAPING_STATIC 1 // first-order highpass shaping
|
#define NOISE_SHAPING_STATIC 1 // first-order highpass shaping
|
||||||
#define NOISE_SHAPING_DYNAMIC 2 // dynamically tilted noise based on signal
|
#define NOISE_SHAPING_DYNAMIC 2 // dynamically tilted noise based on signal
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1600
|
#if defined(_MSC_VER) && _MSC_VER < 1600
|
||||||
typedef unsigned __int64 uint64_t;
|
typedef unsigned __int64 uint64_t;
|
||||||
typedef unsigned __int32 uint32_t;
|
typedef unsigned __int32 uint32_t;
|
||||||
typedef unsigned __int16 uint16_t;
|
typedef unsigned __int16 uint16_t;
|
||||||
typedef unsigned __int8 uint8_t;
|
typedef unsigned __int8 uint8_t;
|
||||||
typedef __int64 int64_t;
|
typedef __int64 int64_t;
|
||||||
typedef __int32 int32_t;
|
typedef __int32 int32_t;
|
||||||
typedef __int16 int16_t;
|
typedef __int16 int16_t;
|
||||||
typedef __int8 int8_t;
|
typedef __int8 int8_t;
|
||||||
#else
|
#else
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void *adpcm_create_context (int num_channels, int lookahead, int noise_shaping, int32_t initial_deltas [2]);
|
void *adpcm_create_context (int num_channels, int lookahead, int noise_shaping, int32_t initial_deltas [2]);
|
||||||
int adpcm_encode_block (void *p, uint8_t *outbuf, size_t *outbufsize, const int16_t *inbuf, int inbufcount);
|
int adpcm_encode_block (void *p, uint8_t *outbuf, size_t *outbufsize, const int16_t *inbuf, int inbufcount);
|
||||||
int adpcm_decode_block (int16_t *outbuf, const uint8_t *inbuf, size_t inbufsize, size_t outbufsize, int channels);
|
int adpcm_decode_block (int16_t *outbuf, const uint8_t *inbuf, size_t inbufsize, size_t outbufsize);
|
||||||
void adpcm_free_context (void *p);
|
void adpcm_free_context (void *p);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif /* ADPCMLIB_H_ */
|
#endif /* ADPCMLIB_H_ */
|
||||||
|
|
|
@ -1289,7 +1289,7 @@ void DivSample::render(unsigned int formatMask) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIV_SAMPLE_DEPTH_IMA_ADPCM: // IMA ADPCM
|
case DIV_SAMPLE_DEPTH_IMA_ADPCM: // IMA ADPCM
|
||||||
if (adpcm_decode_block(data16,dataIMA,lengthIMA,samples,1)==0) logE("oh crap!");
|
if (adpcm_decode_block(data16,dataIMA,lengthIMA,samples)==0) logE("oh crap!");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in a new issue