desubmodulize adpcm-xq

This commit is contained in:
tildearrow 2024-04-05 14:45:41 -05:00
parent 849f0efc33
commit 0bf0d57738
12 changed files with 1396 additions and 6 deletions

3
.gitmodules vendored
View file

@ -15,6 +15,3 @@
[submodule "extern/portaudio"] [submodule "extern/portaudio"]
path = extern/portaudio path = extern/portaudio
url = https://github.com/PortAudio/portaudio.git url = https://github.com/PortAudio/portaudio.git
[submodule "extern/adpcm-xq"]
path = extern/adpcm-xq
url = https://github.com/dbry/adpcm-xq.git

View file

@ -486,7 +486,7 @@ extern/adpcm/yma_codec.c
extern/adpcm/ymb_codec.c extern/adpcm/ymb_codec.c
extern/adpcm/ymz_codec.c extern/adpcm/ymz_codec.c
extern/adpcm-xq/adpcm-lib.c extern/adpcm-xq-s/adpcm-lib.c
extern/opn/ym3438.c extern/opn/ym3438.c
extern/Nuked-PSG/ympsg.c extern/Nuked-PSG/ympsg.c

1
extern/adpcm-xq vendored

@ -1 +0,0 @@
Subproject commit 6220fed7655e86a29702b45dbc641a028ed5a4bf

1
extern/adpcm-xq-s/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
build/

18
extern/adpcm-xq-s/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.16)
# set the project name
project(adpcm-xq)
# lots of warnings and all warnings as errors
# add_compile_options(-Wall -Wextra )
# define as library
add_library (adpcm-xq adpcm-xq.c)
# build executable
add_executable (adpcm-xq-exe adpcm-lib.c adpcm-xq.c)
set_property(TARGET adpcm-xq-exe PROPERTY OUTPUT_NAME adpcm-xq)
# define location for header files
target_include_directories(adpcm-xq PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} )

63
extern/adpcm-xq-s/README vendored Normal file
View file

@ -0,0 +1,63 @@
# MODIFIED
this is a modified version of adpcm-xq which fixes memory safety issues.
////////////////////////////////////////////////////////////////////////////
// **** ADPCM-XQ **** //
// Xtreme Quality ADPCM Encoder/Decoder //
// Copyright (c) 2022 David Bryant. //
// All Rights Reserved. //
// Distributed under the BSD Software License (see license.txt) //
////////////////////////////////////////////////////////////////////////////
While very popular at the end of the last century, ADPCM is no longer a
common audio encoding format, and is certainly not recommended as a general
purpose encoder. However, it requires minimal CPU resources for decoding,
and so still is ideally suited for certain embedded games and applications
that contain canned audio samples.
This encoder combines two different techniques to achieve higher quality
than existing ADPCM encoders while remaining fully compatible with standard
decoders. The first is dynamic noise shaping, which shifts the quantization
noise up or down in frequency based on the spectrum of the source signal.
This technique is identical to the algorithm used in WavPack's lossy mode
and can make any audible quantization noise much less annoying (or, in some
cases, inaudible).
The other technique is "lookahead" in which the encoder exhaustively
searches ahead to find the optimum coding sequence based on future samples.
This process can reduce the quantization noise from about 1 to 6 dB (depending
on the source) and also reduces or eliminates the harmonic content in the
noise that sometimes plagues ADPCM. Unfortunately, at its maximum settings
this can be very slow, but this should be relatively irrelevant if the
encoder is being used to generate canned samples.
Adpcm-xq consists of two standard C files and builds with a single command
on most platforms. It has been designed with maximum portability in mind
and should work correctly even on 16-bit and big-endian architectures
(WAV files are of course always little-endian).
Linux:
% gcc -O2 *.c -o adpcm-xq
Darwin/Mac:
% clang -O2 *.c -o adpcm-xq
MS Visual Studio:
cl -O2 adpcm-xq.c adpcm-lib.c
Bugs:
1. Unknown RIFF chunk types are correctly parsed on input files, but are not
passed to the output file.
2. The lookahead feature does not work for the last samples in an ADPCM
block (i.e. it doesn't utilize samples in the _next_ block).
3. In some situations the lookahead can get very slow or seem to be stuck
because it needs improved trellis pruning. However the default level 3
should always be fine and then the user can simply try increasing levels
until the time becomes untenable.
4. Pipes are not yet supported.

415
extern/adpcm-xq-s/adpcm-lib.c vendored Normal file
View file

@ -0,0 +1,415 @@
////////////////////////////////////////////////////////////////////////////
// **** ADPCM-XQ **** //
// Xtreme Quality ADPCM Encoder/Decoder //
// Copyright (c) 2022 David Bryant. //
// All Rights Reserved. //
// Distributed under the BSD Software License (see license.txt) //
////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <string.h>
#include "adpcm-lib.h"
/* 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
* 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
* multiple channels are present, they are interleaved in the data with an 8-sample
* interval.
*/
/********************************* 4-bit ADPCM encoder ********************************/
#define CLIP(data, min, max) \
if ((data) > (max)) data = max; \
else if ((data) < (min)) data = min;
/* step table */
static const uint16_t step_table[89] = {
7, 8, 9, 10, 11, 12, 13, 14,
16, 17, 19, 21, 23, 25, 28, 31,
34, 37, 41, 45, 50, 55, 60, 66,
73, 80, 88, 97, 107, 118, 130, 143,
157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658,
724, 796, 876, 963, 1060, 1166, 1282, 1411,
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
32767
};
/* step index tables */
static const int index_table[] = {
/* adpcm data size is 4 */
-1, -1, -1, -1, 2, 4, 6, 8
};
struct adpcm_channel {
int32_t pcmdata; // current PCM value
int32_t error, weight, history [2]; // for noise shaping
int8_t index; // current index into step size table
};
struct adpcm_context {
struct adpcm_channel channels [2];
int num_channels, lookahead, noise_shaping;
};
/* Create ADPCM encoder context with given number of channels.
* The returned pointer is used for subsequent calls. Note that
* even though an ADPCM encoder could be set up to encode frames
* independently, we use a context so that we can use previous
* data to improve quality (this encoder might not be optimal
* for encoding independent frames).
*/
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));
int ch, i;
memset (pcnxt, 0, sizeof (struct adpcm_context));
pcnxt->noise_shaping = noise_shaping;
pcnxt->num_channels = num_channels;
pcnxt->lookahead = lookahead;
// given the supplied initial deltas, search for and store the closest index
for (ch = 0; ch < num_channels; ++ch)
for (i = 0; i <= 88; i++)
if (i == 88 || initial_deltas [ch] < ((int32_t) step_table [i] + step_table [i+1]) / 2) {
pcnxt->channels [ch].index = i;
break;
}
return pcnxt;
}
/* Free the ADPCM encoder context.
*/
void adpcm_free_context (void *p)
{
struct adpcm_context *pcnxt = (struct adpcm_context *) p;
free (pcnxt);
}
static void set_decode_parameters (struct adpcm_context *pcnxt, int32_t *init_pcmdata, int8_t *init_index)
{
int ch;
for (ch = 0; ch < pcnxt->num_channels; ch++) {
pcnxt->channels[ch].pcmdata = init_pcmdata[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)
{
int ch;
for (ch = 0; ch < pcnxt->num_channels; ch++) {
init_pcmdata[ch] = pcnxt->channels[ch].pcmdata;
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)
{
int32_t delta = csample - pchan->pcmdata;
struct adpcm_channel chan = *pchan;
uint16_t step = step_table[chan.index];
uint16_t trial_delta = (step >> 3);
int nibble, nibble2;
double min_error;
if (delta < 0) {
int mag = (-delta << 2) / step;
nibble = 0x8 | (mag > 7 ? 7 : mag);
}
else {
int mag = (delta << 2) / step;
nibble = mag > 7 ? 7 : mag;
}
if (nibble & 1) trial_delta += (step >> 2);
if (nibble & 2) trial_delta += (step >> 1);
if (nibble & 4) trial_delta += step;
if (nibble & 8)
chan.pcmdata -= trial_delta;
else
chan.pcmdata += trial_delta;
CLIP(chan.pcmdata, -32768, 32767);
if (best_nibble) *best_nibble = nibble;
min_error = (double) (chan.pcmdata - csample) * (chan.pcmdata - csample);
if (depth) {
chan.index += index_table[nibble & 0x07];
CLIP(chan.index, 0, 88);
min_error += minimum_error (&chan, nch, sample [nch], sample + nch, depth - 1, NULL);
}
else
return min_error;
for (nibble2 = 0; nibble2 <= 0xF; ++nibble2) {
double error;
if (nibble2 == nibble)
continue;
chan = *pchan;
trial_delta = (step >> 3);
if (nibble2 & 1) trial_delta += (step >> 2);
if (nibble2 & 2) trial_delta += (step >> 1);
if (nibble2 & 4) trial_delta += step;
if (nibble2 & 8)
chan.pcmdata -= trial_delta;
else
chan.pcmdata += trial_delta;
CLIP(chan.pcmdata, -32768, 32767);
error = (double) (chan.pcmdata - csample) * (chan.pcmdata - csample);
if (error < min_error) {
chan.index += index_table[nibble2 & 0x07];
CLIP(chan.index, 0, 88);
error += minimum_error (&chan, nch, sample [nch], sample + nch, depth - 1, NULL);
if (error < min_error) {
if (best_nibble) *best_nibble = nibble2;
min_error = error;
}
}
}
return min_error;
}
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;
int32_t csample = *sample;
int depth = num_samples - 1, nibble;
uint16_t step = step_table[pchan->index];
uint16_t trial_delta = (step >> 3);
if (pcnxt->noise_shaping == NOISE_SHAPING_DYNAMIC) {
int32_t sam = (3 * pchan->history [0] - pchan->history [1]) >> 1;
int32_t temp = csample - (((pchan->weight * sam) + 512) >> 10);
int32_t shaping_weight;
if (sam && temp) pchan->weight -= (((sam ^ temp) >> 29) & 4) - 2;
pchan->history [1] = pchan->history [0];
pchan->history [0] = csample;
shaping_weight = (pchan->weight < 256) ? 1024 : 1536 - (pchan->weight * 2);
temp = -((shaping_weight * pchan->error + 512) >> 10);
if (shaping_weight < 0 && temp) {
if (temp == pchan->error)
temp = (temp < 0) ? temp + 1 : temp - 1;
pchan->error = -csample;
csample += temp;
}
else
pchan->error = -(csample += temp);
}
else if (pcnxt->noise_shaping == NOISE_SHAPING_STATIC)
pchan->error = -(csample -= pchan->error);
if (depth > pcnxt->lookahead)
depth = pcnxt->lookahead;
minimum_error (pchan, pcnxt->num_channels, csample, sample, depth, &nibble);
if (nibble & 1) trial_delta += (step >> 2);
if (nibble & 2) trial_delta += (step >> 1);
if (nibble & 4) trial_delta += step;
if (nibble & 8)
pchan->pcmdata -= trial_delta;
else
pchan->pcmdata += trial_delta;
pchan->index += index_table[nibble & 0x07];
CLIP(pchan->index, 0, 88);
CLIP(pchan->pcmdata, -32768, 32767);
if (pcnxt->noise_shaping)
pchan->error += pchan->pcmdata;
return nibble;
}
static void encode_chunks (struct adpcm_context *pcnxt, uint8_t **outbuf, size_t *outbufsize, const int16_t **inbuf, int inbufcount)
{
const int16_t *pcmbuf;
int chunks, ch, i;
chunks = (inbufcount - 1) / 8;
*outbufsize += (chunks * 4) * pcnxt->num_channels;
while (chunks--)
{
for (ch = 0; ch < pcnxt->num_channels; ch++)
{
pcmbuf = *inbuf + ch;
for (i = 0; i < 4; i++) {
**outbuf = encode_sample (pcnxt, ch, pcmbuf, chunks * 8 + (3 - i) * 2 + 2);
pcmbuf += pcnxt->num_channels;
**outbuf |= encode_sample (pcnxt, ch, pcmbuf, chunks * 8 + (3 - i) * 2 + 1) << 4;
pcmbuf += pcnxt->num_channels;
(*outbuf)++;
}
}
*inbuf += 8 * pcnxt->num_channels;
}
}
/* Encode a block of 16-bit PCM data into 4-bit ADPCM.
*
* Parameters:
* p the context returned by adpcm_begin()
* outbuf destination buffer
* outbufsize pointer to variable where the number of bytes written
* will be stored
* inbuf source PCM samples
* inbufcount number of composite PCM samples provided (note: this is
* the total number of 16-bit samples divided by the number
* of channels)
*
* 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)
{
struct adpcm_context *pcnxt = (struct adpcm_context *) p;
int32_t init_pcmdata[2];
int8_t init_index[2];
int ch;
*outbufsize = 0;
if (!inbufcount)
return 1;
get_decode_parameters(pcnxt, init_pcmdata, init_index);
for (ch = 0; ch < pcnxt->num_channels; ch++) {
init_pcmdata[ch] = *inbuf++;
outbuf[0] = init_pcmdata[ch];
outbuf[1] = init_pcmdata[ch] >> 8;
outbuf[2] = init_index[ch];
outbuf[3] = 0;
outbuf += 4;
*outbufsize += 4;
}
set_decode_parameters(pcnxt, init_pcmdata, init_index);
encode_chunks (pcnxt, &outbuf, outbufsize, &inbuf, inbufcount);
return 1;
}
/********************************* 4-bit ADPCM decoder ********************************/
/* 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;
* it must be called multiple times for multiple blocks and cannot resume in the middle of a
* block.
*
* Parameters:
* outbuf destination for interleaved PCM samples
* inbuf source ADPCM block
* inbufsize size of source ADPCM block
* 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)
*/
int adpcm_decode_block (int16_t *outbuf, const uint8_t *inbuf, size_t inbufsize, int channels)
{
int ch, samples = 1, chunks;
int32_t pcmdata[2];
int8_t index[2];
if (inbufsize < (uint32_t) channels * 4)
return 0;
for (ch = 0; ch < channels; ch++) {
*outbuf++ = pcmdata[ch] = (int16_t) (inbuf [0] | (inbuf [1] << 8));
index[ch] = inbuf [2];
if (index [ch] < 0 || index [ch] > 88 || inbuf [3]) // sanitize the input a little...
return 0;
inbufsize -= 4;
inbuf += 4;
}
chunks = inbufsize / (channels * 4);
samples += chunks * 8;
while (chunks--) {
int ch, i;
for (ch = 0; ch < channels; ++ch) {
for (i = 0; i < 4; ++i) {
uint16_t step = step_table [index [ch]], delta = step >> 3;
if (*inbuf & 1) delta += (step >> 2);
if (*inbuf & 2) delta += (step >> 1);
if (*inbuf & 4) delta += step;
if (*inbuf & 8)
pcmdata[ch] -= delta;
else
pcmdata[ch] += delta;
index[ch] += index_table [*inbuf & 0x7];
CLIP(index[ch], 0, 88);
CLIP(pcmdata[ch], -32768, 32767);
outbuf [i * 2 * channels] = pcmdata[ch];
step = step_table [index [ch]]; delta = step >> 3;
if (*inbuf & 0x10) delta += (step >> 2);
if (*inbuf & 0x20) delta += (step >> 1);
if (*inbuf & 0x40) delta += step;
if (*inbuf & 0x80)
pcmdata[ch] -= delta;
else
pcmdata[ch] += delta;
index[ch] += index_table [(*inbuf >> 4) & 0x7];
CLIP(index[ch], 0, 88);
CLIP(pcmdata[ch], -32768, 32767);
outbuf [(i * 2 + 1) * channels] = pcmdata[ch];
inbuf++;
}
outbuf++;
}
outbuf += channels * 7;
}
return samples;
}

44
extern/adpcm-xq-s/adpcm-lib.h vendored Normal file
View file

@ -0,0 +1,44 @@
////////////////////////////////////////////////////////////////////////////
// **** ADPCM-XQ **** //
// Xtreme Quality ADPCM Encoder/Decoder //
// Copyright (c) 2015 David Bryant. //
// All Rights Reserved. //
// Distributed under the BSD Software License (see license.txt) //
////////////////////////////////////////////////////////////////////////////
#ifndef ADPCMLIB_H_
#define ADPCMLIB_H_
#define NOISE_SHAPING_OFF 0 // flat noise (no shaping)
#define NOISE_SHAPING_STATIC 1 // first-order highpass shaping
#define NOISE_SHAPING_DYNAMIC 2 // dynamically tilted noise based on signal
#if defined(_MSC_VER) && _MSC_VER < 1600
typedef unsigned __int64 uint64_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int8 uint8_t;
typedef __int64 int64_t;
typedef __int32 int32_t;
typedef __int16 int16_t;
typedef __int8 int8_t;
#else
#include <stdint.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
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_decode_block (int16_t *outbuf, const uint8_t *inbuf, size_t inbufsize, int channels);
void adpcm_free_context (void *p);
#ifdef __cplusplus
}
#endif
#endif /* ADPCMLIB_H_ */

819
extern/adpcm-xq-s/adpcm-xq.c vendored Normal file
View file

@ -0,0 +1,819 @@
#ifndef ARDUINO
////////////////////////////////////////////////////////////////////////////
// **** ADPCM-XQ **** //
// Xtreme Quality ADPCM Encoder/Decoder //
// Copyright (c) 2022 David Bryant. //
// All Rights Reserved. //
// Distributed under the BSD Software License (see license.txt) //
////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "adpcm-lib.h"
// This runtime macro is not strictly needed because the code is endian-safe,
// but including it improves performance on little-endian systems because we
// can avoid a couple loops through the audio.
#define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x0100)
static const char *sign_on = "\n"
" ADPCM-XQ Xtreme Quality IMA-ADPCM WAV Encoder / Decoder Version 0.4\n"
" Copyright (c) 2022 David Bryant. All Rights Reserved.\n\n";
static const char *usage =
" Usage: ADPCM-XQ [-options] infile.wav outfile.wav\n\n"
" Operation: conversion is performed based on the type of the infile\n"
" (either encode 16-bit PCM to 4-bit IMA-ADPCM or decode back)\n\n"
" Options: -[0-8] = encode lookahead samples (default = 3)\n"
" -bn = override auto block size, 2^n bytes (n = 8-15)\n"
" -d = decode only (fail on WAV file already PCM)\n"
" -e = encode only (fail on WAV file already ADPCM)\n"
" -f = encode flat noise (no dynamic noise shaping)\n"
" -h = display this help message\n"
" -q = quiet mode (display errors only)\n"
" -r = raw output (little-endian, no WAV header written)\n"
" -v = verbose (display lots of info)\n"
" -y = overwrite outfile if it exists\n\n"
" Web: Visit www.github.com/dbry/adpcm-xq for latest version and info\n\n";
#define ADPCM_FLAG_NOISE_SHAPING 0x1
#define ADPCM_FLAG_RAW_OUTPUT 0x2
static int adpcm_converter (char *infilename, char *outfilename, int flags, int blocksize_pow2, int lookahead);
static int verbosity = 0, decode_only = 0, encode_only = 0;
int main (argc, argv) int argc; char **argv;
{
int lookahead = 3, flags = ADPCM_FLAG_NOISE_SHAPING, blocksize_pow2 = 0, overwrite = 0, asked_help = 0;
char *infilename = NULL, *outfilename = NULL;
FILE *outfile;
// if the name of the executable ends in "encoder" or "decoder", just do that function
encode_only = argc && strstr (argv [0], "encoder") && strlen (strstr (argv [0], "encoder")) == strlen ("encoder");
decode_only = argc && strstr (argv [0], "decoder") && strlen (strstr (argv [0], "decoder")) == strlen ("decoder");
// loop through command-line arguments
while (--argc) {
#if defined (_WIN32)
if ((**++argv == '-' || **argv == '/') && (*argv)[1])
#else
if ((**++argv == '-') && (*argv)[1])
#endif
while (*++*argv)
switch (**argv) {
case '0': case '1': case '2':
case '3': case '4': case '5':
case '6': case '7': case '8':
lookahead = **argv - '0';
break;
case 'B': case 'b':
blocksize_pow2 = strtol (++*argv, argv, 10);
if (blocksize_pow2 < 8 || blocksize_pow2 > 15) {
fprintf (stderr, "\nblock size power must be 8 to 15!\n");
return -1;
}
--*argv;
break;
case 'D': case 'd':
decode_only = 1;
break;
case 'E': case 'e':
encode_only = 1;
break;
case 'F': case 'f':
flags &= ~ADPCM_FLAG_NOISE_SHAPING;
break;
case 'H': case 'h':
asked_help = 0;
break;
case 'Q': case 'q':
verbosity = -1;
break;
case 'R': case 'r':
flags |= ADPCM_FLAG_RAW_OUTPUT;
break;
case 'V': case 'v':
verbosity = 1;
break;
case 'Y': case 'y':
overwrite = 1;
break;
default:
fprintf (stderr, "\nillegal option: %c !\n", **argv);
return 1;
}
else if (!infilename) {
infilename = malloc (strlen (*argv) + 10);
strcpy (infilename, *argv);
}
else if (!outfilename) {
outfilename = malloc (strlen (*argv) + 10);
strcpy (outfilename, *argv);
}
else {
fprintf (stderr, "\nextra unknown argument: %s !\n", *argv);
return 1;
}
}
if (verbosity >= 0)
fprintf (stderr, "%s", sign_on);
if (!outfilename || asked_help) {
printf ("%s", usage);
return 0;
}
if (!strcmp (infilename, outfilename)) {
fprintf (stderr, "can't overwrite input file (specify different/new output file name)\n");
return -1;
}
if (!overwrite && (outfile = fopen (outfilename, "r"))) {
fclose (outfile);
fprintf (stderr, "output file \"%s\" exists (use -y to overwrite)\n", outfilename);
return -1;
}
return adpcm_converter (infilename, outfilename, flags, blocksize_pow2, lookahead);
}
typedef struct {
char ckID [4];
uint32_t ckSize;
char formType [4];
} RiffChunkHeader;
typedef struct {
char ckID [4];
uint32_t ckSize;
} ChunkHeader;
#define ChunkHeaderFormat "4L"
typedef struct {
uint16_t FormatTag, NumChannels;
uint32_t SampleRate, BytesPerSecond;
uint16_t BlockAlign, BitsPerSample;
uint16_t cbSize;
union {
uint16_t ValidBitsPerSample;
uint16_t SamplesPerBlock;
uint16_t Reserved;
} Samples;
int32_t ChannelMask;
uint16_t SubFormat;
char GUID [14];
} WaveHeader;
#define WaveHeaderFormat "SSLLSSSSLS"
typedef struct {
char ckID [4];
uint32_t ckSize;
uint32_t TotalSamples;
} FactHeader;
#define FactHeaderFormat "4LL"
#define WAVE_FORMAT_PCM 0x1
#define WAVE_FORMAT_IMA_ADPCM 0x11
#define WAVE_FORMAT_EXTENSIBLE 0xfffe
static int write_pcm_wav_header (FILE *outfile, int num_channels, uint32_t num_samples, uint32_t sample_rate);
static int write_adpcm_wav_header (FILE *outfile, int num_channels, uint32_t num_samples, uint32_t sample_rate, int samples_per_block);
static int adpcm_decode_data (FILE *infile, FILE *outfile, int num_channels, uint32_t num_samples, int block_size);
static int adpcm_encode_data (FILE *infile, FILE *outfile, int num_channels, uint32_t num_samples, int samples_per_block, int lookahead, int noise_shaping);
static void little_endian_to_native (void *data, char *format);
static void native_to_little_endian (void *data, char *format);
static int adpcm_converter (char *infilename, char *outfilename, int flags, int blocksize_pow2, int lookahead)
{
int format = 0, res = 0, bits_per_sample, num_channels;
uint32_t fact_samples = 0, num_samples = 0, sample_rate;
FILE *infile, *outfile;
RiffChunkHeader riff_chunk_header;
ChunkHeader chunk_header;
WaveHeader WaveHeader;
if (!(infile = fopen (infilename, "rb"))) {
fprintf (stderr, "can't open file \"%s\" for reading!\n", infilename);
return -1;
}
// read initial RIFF form header
if (!fread (&riff_chunk_header, sizeof (RiffChunkHeader), 1, infile) ||
strncmp (riff_chunk_header.ckID, "RIFF", 4) ||
strncmp (riff_chunk_header.formType, "WAVE", 4)) {
fprintf (stderr, "\"%s\" is not a valid .WAV file!\n", infilename);
return -1;
}
// loop through all elements of the RIFF wav header (until the data chuck)
while (1) {
if (!fread (&chunk_header, sizeof (ChunkHeader), 1, infile)) {
fprintf (stderr, "\"%s\" is not a valid .WAV file!\n", infilename);
return -1;
}
little_endian_to_native (&chunk_header, ChunkHeaderFormat);
// if it's the format chunk, we want to get some info out of there and
// make sure it's a .wav file we can handle
if (!strncmp (chunk_header.ckID, "fmt ", 4)) {
int supported = 1;
if (chunk_header.ckSize < 16 || chunk_header.ckSize > sizeof (WaveHeader) ||
!fread (&WaveHeader, chunk_header.ckSize, 1, infile)) {
fprintf (stderr, "\"%s\" is not a valid .WAV file!\n", infilename);
return -1;
}
little_endian_to_native (&WaveHeader, WaveHeaderFormat);
format = (WaveHeader.FormatTag == WAVE_FORMAT_EXTENSIBLE && chunk_header.ckSize == 40) ?
WaveHeader.SubFormat : WaveHeader.FormatTag;
bits_per_sample = (chunk_header.ckSize == 40 && WaveHeader.Samples.ValidBitsPerSample) ?
WaveHeader.Samples.ValidBitsPerSample : WaveHeader.BitsPerSample;
if (WaveHeader.NumChannels < 1 || WaveHeader.NumChannels > 2)
supported = 0;
else if (format == WAVE_FORMAT_PCM) {
if (decode_only) {
fprintf (stderr, "\"%s\" is PCM .WAV file, invalid in decode-only mode!\n", infilename);
return -1;
}
if (bits_per_sample < 9 || bits_per_sample > 16)
supported = 0;
if (WaveHeader.BlockAlign != WaveHeader.NumChannels * 2)
supported = 0;
}
else if (format == WAVE_FORMAT_IMA_ADPCM) {
if (encode_only) {
fprintf (stderr, "\"%s\" is ADPCM .WAV file, invalid in encode-only mode!\n", infilename);
return -1;
}
if (bits_per_sample != 4)
supported = 0;
if (WaveHeader.Samples.SamplesPerBlock != (WaveHeader.BlockAlign - WaveHeader.NumChannels * 4) * (WaveHeader.NumChannels ^ 3) + 1) {
fprintf (stderr, "\"%s\" is not a valid .WAV file!\n", infilename);
return -1;
}
}
else
supported = 0;
if (!supported) {
fprintf (stderr, "\"%s\" is an unsupported .WAV format!\n", infilename);
return -1;
}
if (verbosity > 0) {
fprintf (stderr, "format tag size = %d\n", chunk_header.ckSize);
fprintf (stderr, "FormatTag = 0x%x, NumChannels = %u, BitsPerSample = %u\n",
WaveHeader.FormatTag, WaveHeader.NumChannels, WaveHeader.BitsPerSample);
fprintf (stderr, "BlockAlign = %u, SampleRate = %lu, BytesPerSecond = %lu\n",
WaveHeader.BlockAlign, (unsigned long) WaveHeader.SampleRate, (unsigned long) WaveHeader.BytesPerSecond);
if (chunk_header.ckSize > 16) {
if (format == WAVE_FORMAT_PCM)
fprintf (stderr, "cbSize = %d, ValidBitsPerSample = %d\n", WaveHeader.cbSize,
WaveHeader.Samples.ValidBitsPerSample);
else if (format == WAVE_FORMAT_IMA_ADPCM)
fprintf (stderr, "cbSize = %d, SamplesPerBlock = %d\n", WaveHeader.cbSize,
WaveHeader.Samples.SamplesPerBlock);
}
if (chunk_header.ckSize > 20)
fprintf (stderr, "ChannelMask = %x, SubFormat = %d\n",
WaveHeader.ChannelMask, WaveHeader.SubFormat);
}
}
else if (!strncmp (chunk_header.ckID, "fact", 4)) {
if (chunk_header.ckSize < 4 || !fread (&fact_samples, sizeof (fact_samples), 1, infile)) {
fprintf (stderr, "\"%s\" is not a valid .WAV file!\n", infilename);
return -1;
}
little_endian_to_native (&fact_samples, "L");
if (chunk_header.ckSize > 4) {
int bytes_to_skip = chunk_header.ckSize - 4;
char dummy;
while (bytes_to_skip--)
if (!fread (&dummy, 1, 1, infile)) {
fprintf (stderr, "\"%s\" is not a valid .WAV file!\n", infilename);
return -1;
}
}
}
else if (!strncmp (chunk_header.ckID, "data", 4)) {
// on the data chunk, get size and exit parsing loop
if (!WaveHeader.NumChannels) { // make sure we saw a "fmt" chunk...
fprintf (stderr, "\"%s\" is not a valid .WAV file!\n", infilename);
return -1;
}
if (!chunk_header.ckSize) {
fprintf (stderr, "this .WAV file has no audio samples, probably is corrupt!\n");
return -1;
}
if (format == WAVE_FORMAT_PCM) {
if (chunk_header.ckSize % WaveHeader.BlockAlign) {
fprintf (stderr, "\"%s\" is not a valid .WAV file!\n", infilename);
return -1;
}
num_samples = chunk_header.ckSize / WaveHeader.BlockAlign;
}
else {
uint32_t complete_blocks = chunk_header.ckSize / WaveHeader.BlockAlign;
int leftover_bytes = chunk_header.ckSize % WaveHeader.BlockAlign;
int samples_last_block;
num_samples = complete_blocks * WaveHeader.Samples.SamplesPerBlock;
if (leftover_bytes) {
if (leftover_bytes % (WaveHeader.NumChannels * 4)) {
fprintf (stderr, "\"%s\" is not a valid .WAV file!\n", infilename);
return -1;
}
if (verbosity > 0) fprintf (stderr, "data chunk has %d bytes left over for final ADPCM block\n", leftover_bytes);
samples_last_block = (leftover_bytes - (WaveHeader.NumChannels * 4)) * (WaveHeader.NumChannels ^ 3) + 1;
num_samples += samples_last_block;
}
else
samples_last_block = WaveHeader.Samples.SamplesPerBlock;
if (fact_samples) {
if (fact_samples < num_samples && fact_samples > num_samples - samples_last_block) {
if (verbosity > 0) fprintf (stderr, "total samples reduced %lu by FACT chunk\n", (unsigned long) (num_samples - fact_samples));
num_samples = fact_samples;
}
else if (WaveHeader.NumChannels == 2 && (fact_samples >>= 1) < num_samples && fact_samples > num_samples - samples_last_block) {
if (verbosity > 0) fprintf (stderr, "num samples reduced %lu by [incorrect] FACT chunk\n", (unsigned long) (num_samples - fact_samples));
num_samples = fact_samples;
}
}
}
if (!num_samples) {
fprintf (stderr, "this .WAV file has no audio samples, probably is corrupt!\n");
return -1;
}
if (verbosity > 0)
fprintf (stderr, "num samples = %lu\n", (unsigned long) num_samples);
num_channels = WaveHeader.NumChannels;
sample_rate = WaveHeader.SampleRate;
break;
}
else { // just ignore unknown chunks
int bytes_to_eat = (chunk_header.ckSize + 1) & ~1L;
char dummy;
if (verbosity > 0)
fprintf (stderr, "extra unknown chunk \"%c%c%c%c\" of %d bytes\n",
chunk_header.ckID [0], chunk_header.ckID [1], chunk_header.ckID [2],
chunk_header.ckID [3], chunk_header.ckSize);
while (bytes_to_eat--)
if (!fread (&dummy, 1, 1, infile)) {
fprintf (stderr, "\"%s\" is not a valid .WAV file!\n", infilename);
return -1;
}
}
}
if (!(outfile = fopen (outfilename, "wb"))) {
fprintf (stderr, "can't open file \"%s\" for writing!\n", outfilename);
return -1;
}
if (format == WAVE_FORMAT_PCM) {
int block_size, samples_per_block;
if (blocksize_pow2)
block_size = 1 << blocksize_pow2;
else
block_size = 256 * num_channels * (sample_rate < 11000 ? 1 : sample_rate / 11000);
samples_per_block = (block_size - num_channels * 4) * (num_channels ^ 3) + 1;
if (verbosity > 0)
fprintf (stderr, "each %d byte ADPCM block will contain %d samples * %d channels\n",
block_size, samples_per_block, num_channels);
if (!(flags & ADPCM_FLAG_RAW_OUTPUT) && !write_adpcm_wav_header (outfile, num_channels, num_samples, sample_rate, samples_per_block)) {
fprintf (stderr, "can't write header to file \"%s\" !\n", outfilename);
return -1;
}
if (verbosity >= 0) fprintf (stderr, "encoding PCM file \"%s\" to%sADPCM file \"%s\"...\n",
infilename, (flags & ADPCM_FLAG_RAW_OUTPUT) ? " raw " : " ", outfilename);
res = adpcm_encode_data (infile, outfile, num_channels, num_samples, samples_per_block, lookahead,
(flags & ADPCM_FLAG_NOISE_SHAPING) ? (sample_rate > 64000 ? NOISE_SHAPING_STATIC : NOISE_SHAPING_DYNAMIC) : NOISE_SHAPING_OFF);
}
else if (format == WAVE_FORMAT_IMA_ADPCM) {
if (!(flags & ADPCM_FLAG_RAW_OUTPUT) && !write_pcm_wav_header (outfile, num_channels, num_samples, sample_rate)) {
fprintf (stderr, "can't write header to file \"%s\" !\n", outfilename);
return -1;
}
if (verbosity >= 0) fprintf (stderr, "decoding ADPCM file \"%s\" to%sPCM file \"%s\"...\n",
infilename, (flags & ADPCM_FLAG_RAW_OUTPUT) ? " raw " : " ", outfilename);
res = adpcm_decode_data (infile, outfile, num_channels, num_samples, WaveHeader.BlockAlign);
}
fclose (outfile);
fclose (infile);
return res;
}
static int write_pcm_wav_header (FILE *outfile, int num_channels, uint32_t num_samples, uint32_t sample_rate)
{
RiffChunkHeader riffhdr;
ChunkHeader datahdr, fmthdr;
WaveHeader wavhdr;
int wavhdrsize = 16;
int bytes_per_sample = 2;
uint32_t total_data_bytes = num_samples * bytes_per_sample * num_channels;
memset (&wavhdr, 0, sizeof (wavhdr));
wavhdr.FormatTag = WAVE_FORMAT_PCM;
wavhdr.NumChannels = num_channels;
wavhdr.SampleRate = sample_rate;
wavhdr.BytesPerSecond = sample_rate * num_channels * bytes_per_sample;
wavhdr.BlockAlign = bytes_per_sample * num_channels;
wavhdr.BitsPerSample = 16;
strncpy (riffhdr.ckID, "RIFF", sizeof (riffhdr.ckID));
strncpy (riffhdr.formType, "WAVE", sizeof (riffhdr.formType));
riffhdr.ckSize = sizeof (riffhdr) + wavhdrsize + sizeof (datahdr) + total_data_bytes;
strncpy (fmthdr.ckID, "fmt ", sizeof (fmthdr.ckID));
fmthdr.ckSize = wavhdrsize;
strncpy (datahdr.ckID, "data", sizeof (datahdr.ckID));
datahdr.ckSize = total_data_bytes;
// write the RIFF chunks up to just before the data starts
native_to_little_endian (&riffhdr, ChunkHeaderFormat);
native_to_little_endian (&fmthdr, ChunkHeaderFormat);
native_to_little_endian (&wavhdr, WaveHeaderFormat);
native_to_little_endian (&datahdr, ChunkHeaderFormat);
return fwrite (&riffhdr, sizeof (riffhdr), 1, outfile) &&
fwrite (&fmthdr, sizeof (fmthdr), 1, outfile) &&
fwrite (&wavhdr, wavhdrsize, 1, outfile) &&
fwrite (&datahdr, sizeof (datahdr), 1, outfile);
}
static int write_adpcm_wav_header (FILE *outfile, int num_channels, uint32_t num_samples, uint32_t sample_rate, int samples_per_block)
{
RiffChunkHeader riffhdr;
ChunkHeader datahdr, fmthdr;
WaveHeader wavhdr;
FactHeader facthdr;
int wavhdrsize = 20;
int block_size = (samples_per_block - 1) / (num_channels ^ 3) + (num_channels * 4);
uint32_t num_blocks = num_samples / samples_per_block;
int leftover_samples = num_samples % samples_per_block;
uint32_t total_data_bytes = num_blocks * block_size;
if (leftover_samples) {
int last_block_samples = ((leftover_samples + 6) & ~7) + 1;
int last_block_size = (last_block_samples - 1) / (num_channels ^ 3) + (num_channels * 4);
total_data_bytes += last_block_size;
}
memset (&wavhdr, 0, sizeof (wavhdr));
wavhdr.FormatTag = WAVE_FORMAT_IMA_ADPCM;
wavhdr.NumChannels = num_channels;
wavhdr.SampleRate = sample_rate;
wavhdr.BytesPerSecond = sample_rate * block_size / samples_per_block;
wavhdr.BlockAlign = block_size;
wavhdr.BitsPerSample = 4;
wavhdr.cbSize = 2;
wavhdr.Samples.SamplesPerBlock = samples_per_block;
strncpy (riffhdr.ckID, "RIFF", sizeof (riffhdr.ckID));
strncpy (riffhdr.formType, "WAVE", sizeof (riffhdr.formType));
riffhdr.ckSize = sizeof (riffhdr) + wavhdrsize + sizeof (facthdr) + sizeof (datahdr) + total_data_bytes;
strncpy (fmthdr.ckID, "fmt ", sizeof (fmthdr.ckID));
fmthdr.ckSize = wavhdrsize;
strncpy (facthdr.ckID, "fact", sizeof (facthdr.ckID));
facthdr.TotalSamples = num_samples;
facthdr.ckSize = 4;
strncpy (datahdr.ckID, "data", sizeof (datahdr.ckID));
datahdr.ckSize = total_data_bytes;
// write the RIFF chunks up to just before the data starts
native_to_little_endian (&riffhdr, ChunkHeaderFormat);
native_to_little_endian (&fmthdr, ChunkHeaderFormat);
native_to_little_endian (&wavhdr, WaveHeaderFormat);
native_to_little_endian (&facthdr, FactHeaderFormat);
native_to_little_endian (&datahdr, ChunkHeaderFormat);
return fwrite (&riffhdr, sizeof (riffhdr), 1, outfile) &&
fwrite (&fmthdr, sizeof (fmthdr), 1, outfile) &&
fwrite (&wavhdr, wavhdrsize, 1, outfile) &&
fwrite (&facthdr, sizeof (facthdr), 1, outfile) &&
fwrite (&datahdr, sizeof (datahdr), 1, outfile);
}
static int adpcm_decode_data (FILE *infile, FILE *outfile, int num_channels, uint32_t num_samples, int block_size)
{
int samples_per_block = (block_size - num_channels * 4) * (num_channels ^ 3) + 1, percent;
void *pcm_block = malloc (samples_per_block * num_channels * 2);
void *adpcm_block = malloc (block_size);
uint32_t progress_divider = 0;
if (!pcm_block || !adpcm_block) {
fprintf (stderr, "could not allocate memory for buffers!\n");
return -1;
}
if (verbosity >= 0 && num_samples > 1000) {
progress_divider = (num_samples + 50) / 100;
fprintf (stderr, "\rprogress: %d%% ", percent = 0);
fflush (stderr);
}
while (num_samples) {
int this_block_adpcm_samples = samples_per_block;
int this_block_pcm_samples = samples_per_block;
if (this_block_adpcm_samples > num_samples) {
this_block_adpcm_samples = ((num_samples + 6) & ~7) + 1;
block_size = (this_block_adpcm_samples - 1) / (num_channels ^ 3) + (num_channels * 4);
this_block_pcm_samples = num_samples;
}
if (!fread (adpcm_block, block_size, 1, infile)) {
fprintf (stderr, "could not read all audio data from input file!\n");
return -1;
}
if (adpcm_decode_block (pcm_block, adpcm_block, block_size, num_channels) != this_block_adpcm_samples) {
fprintf (stderr, "adpcm_decode_block() did not return expected value!\n");
return -1;
}
if (IS_BIG_ENDIAN) {
int scount = this_block_pcm_samples * num_channels;
unsigned char *cp = (unsigned char *) pcm_block;
while (scount--) {
int16_t temp = * (int16_t *) cp;
*cp++ = (unsigned char) temp;
*cp++ = (unsigned char) (temp >> 8);
}
}
if (!fwrite (pcm_block, this_block_pcm_samples * num_channels * 2, 1, outfile)) {
fprintf (stderr, "could not write all audio data to output file!\n");
return -1;
}
num_samples -= this_block_pcm_samples;
if (progress_divider) {
int new_percent = 100 - num_samples / progress_divider;
if (new_percent != percent) {
fprintf (stderr, "\rprogress: %d%% ", percent = new_percent);
fflush (stderr);
}
}
}
if (verbosity >= 0)
fprintf (stderr, "\r...completed successfully\n");
free (adpcm_block);
free (pcm_block);
return 0;
}
static int adpcm_encode_data (FILE *infile, FILE *outfile, int num_channels, uint32_t num_samples, int samples_per_block, int lookahead, int noise_shaping)
{
int block_size = (samples_per_block - 1) / (num_channels ^ 3) + (num_channels * 4), percent;
int16_t *pcm_block = malloc (samples_per_block * num_channels * 2);
void *adpcm_block = malloc (block_size);
uint32_t progress_divider = 0;
void *adpcm_cnxt = NULL;
if (!pcm_block || !adpcm_block) {
fprintf (stderr, "could not allocate memory for buffers!\n");
return -1;
}
if (verbosity >= 0 && num_samples > 1000) {
progress_divider = (num_samples + 50) / 100;
fprintf (stderr, "\rprogress: %d%% ", percent = 0);
fflush (stderr);
}
while (num_samples) {
int this_block_adpcm_samples = samples_per_block;
int this_block_pcm_samples = samples_per_block;
size_t num_bytes;
if (this_block_pcm_samples > num_samples) {
this_block_adpcm_samples = ((num_samples + 6) & ~7) + 1;
block_size = (this_block_adpcm_samples - 1) / (num_channels ^ 3) + (num_channels * 4);
this_block_pcm_samples = num_samples;
}
if (!fread (pcm_block, this_block_pcm_samples * num_channels * 2, 1, infile)) {
fprintf (stderr, "\rcould not read all audio data from input file!\n");
return -1;
}
if (IS_BIG_ENDIAN) {
int scount = this_block_pcm_samples * num_channels;
unsigned char *cp = (unsigned char *) pcm_block;
while (scount--) {
int16_t temp = cp [0] + (cp [1] << 8);
* (int16_t *) cp = temp;
cp += 2;
}
}
// if this is the last block and it's not full, duplicate the last sample(s) so we don't
// create problems for the lookahead
if (this_block_adpcm_samples > this_block_pcm_samples) {
int16_t *dst = pcm_block + this_block_pcm_samples * num_channels, *src = dst - num_channels;
int dups = (this_block_adpcm_samples - this_block_pcm_samples) * num_channels;
while (dups--)
*dst++ = *src++;
}
// if this is the first block, compute a decaying average (in reverse) so that we can let the
// encoder know what kind of initial deltas to expect (helps initializing index)
if (!adpcm_cnxt) {
int32_t average_deltas [2];
int i;
average_deltas [0] = average_deltas [1] = 0;
for (i = this_block_adpcm_samples * num_channels; i -= num_channels;) {
average_deltas [0] -= average_deltas [0] >> 3;
average_deltas [0] += abs ((int32_t) pcm_block [i] - pcm_block [i - num_channels]);
if (num_channels == 2) {
average_deltas [1] -= average_deltas [1] >> 3;
average_deltas [1] += abs ((int32_t) pcm_block [i-1] - pcm_block [i+1]);
}
}
average_deltas [0] >>= 3;
average_deltas [1] >>= 3;
adpcm_cnxt = adpcm_create_context (num_channels, lookahead, noise_shaping, average_deltas);
}
adpcm_encode_block (adpcm_cnxt, adpcm_block, &num_bytes, pcm_block, this_block_adpcm_samples);
if (num_bytes != block_size) {
fprintf (stderr, "\radpcm_encode_block() did not return expected value (expected %d, got %d)!\n", block_size, (int) num_bytes);
return -1;
}
if (!fwrite (adpcm_block, block_size, 1, outfile)) {
fprintf (stderr, "\rcould not write all audio data to output file!\n");
return -1;
}
num_samples -= this_block_pcm_samples;
if (progress_divider) {
int new_percent = 100 - num_samples / progress_divider;
if (new_percent != percent) {
fprintf (stderr, "\rprogress: %d%% ", percent = new_percent);
fflush (stderr);
}
}
}
if (verbosity >= 0)
fprintf (stderr, "\r...completed successfully\n");
if (adpcm_cnxt)
adpcm_free_context (adpcm_cnxt);
free (adpcm_block);
free (pcm_block);
return 0;
}
static void little_endian_to_native (void *data, char *format)
{
unsigned char *cp = (unsigned char *) data;
int32_t temp;
while (*format) {
switch (*format) {
case 'L':
temp = cp [0] + ((int32_t) cp [1] << 8) + ((int32_t) cp [2] << 16) + ((int32_t) cp [3] << 24);
* (int32_t *) cp = temp;
cp += 4;
break;
case 'S':
temp = cp [0] + (cp [1] << 8);
* (short *) cp = (short) temp;
cp += 2;
break;
default:
if (isdigit ((unsigned char) *format))
cp += *format - '0';
break;
}
format++;
}
}
static void native_to_little_endian (void *data, char *format)
{
unsigned char *cp = (unsigned char *) data;
int32_t temp;
while (*format) {
switch (*format) {
case 'L':
temp = * (int32_t *) cp;
*cp++ = (unsigned char) temp;
*cp++ = (unsigned char) (temp >> 8);
*cp++ = (unsigned char) (temp >> 16);
*cp++ = (unsigned char) (temp >> 24);
break;
case 'S':
temp = * (short *) cp;
*cp++ = (unsigned char) temp;
*cp++ = (unsigned char) (temp >> 8);
break;
default:
if (isdigit ((unsigned char) *format))
cp += *format - '0';
break;
}
format++;
}
}
#endif

9
extern/adpcm-xq-s/library.properties vendored Normal file
View file

@ -0,0 +1,9 @@
name=adpcm-xq
version=0.3.0
author=David Bryant
maintainer=David Bryant
sentence=ADPCM Codec
paragraph=Encoding and decoding of IMA ADPCM
category=Signal Input/Output
url=https://github.com/drby/adpcm-xq
architectures=*

25
extern/adpcm-xq-s/license.txt vendored Normal file
View file

@ -0,0 +1,25 @@
Copyright (c) David Bryant
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Conifer Software nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -35,7 +35,7 @@ extern "C" {
#include "../../extern/adpcm/ymb_codec.h" #include "../../extern/adpcm/ymb_codec.h"
#include "../../extern/adpcm/ymz_codec.h" #include "../../extern/adpcm/ymz_codec.h"
} }
#include "../../extern/adpcm-xq/adpcm-lib.h" #include "../../extern/adpcm-xq-s/adpcm-lib.h"
#include "brrUtils.h" #include "brrUtils.h"
DivSampleHistory::~DivSampleHistory() { DivSampleHistory::~DivSampleHistory() {