mirror of
https://github.com/ScrelliCopter/VGM-Tools
synced 2025-02-21 04:09:25 +11:00
dsptool: refactor
This commit is contained in:
@@ -1,9 +1,18 @@
|
||||
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
|
||||
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
|
||||
project(DspTool LANGUAGES C)
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
option(BUILD_SHARED_LIBS "Build as a Shared Object or DLL" ON)
|
||||
|
||||
set(HEADERS dsptool.h)
|
||||
set(HEADERS common.h dsptool.h)
|
||||
set(SOURCES math.c decode.c encode.c)
|
||||
|
||||
add_library(DspTool ${HEADERS} ${SOURCES})
|
||||
set_property(TARGET DspTool PROPERTY C_STANDARD 99)
|
||||
if (BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(DspTool PRIVATE BUILD_SHARED)
|
||||
else()
|
||||
target_compile_definitions(DspTool PRIVATE BUILD_STATIC)
|
||||
endif()
|
||||
target_compile_options(DspTool PRIVATE
|
||||
$<$<C_COMPILER_ID:AppleClang,Clang,GNU>:-Wall -Wextra -pedantic -Wno-unused-parameter>
|
||||
$<$<C_COMPILER_ID:MSVC>:/Wall /wd4100>)
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include "dsptool.h"
|
||||
#include <limits.h>
|
||||
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
|
||||
inline int DivideByRoundUp(int dividend, int divisor)
|
||||
{
|
||||
return (dividend + divisor - 1) / divisor;
|
||||
}
|
||||
|
||||
inline char GetHighNibble(char value)
|
||||
{
|
||||
return value >> 4 & 0xF;
|
||||
}
|
||||
|
||||
inline char GetLowNibble(char value)
|
||||
{
|
||||
return value & 0xF;
|
||||
}
|
||||
|
||||
inline short Clamp16(int value)
|
||||
{
|
||||
if (value > SHRT_MAX)
|
||||
return SHRT_MAX;
|
||||
if (value < SHRT_MIN)
|
||||
return SHRT_MIN;
|
||||
return value;
|
||||
}
|
||||
|
||||
void decode(uint8_t* src, int16_t* dst, ADPCMINFO* cxt, uint32_t samples)
|
||||
{
|
||||
short hist1 = cxt->yn1;
|
||||
short hist2 = cxt->yn2;
|
||||
short* coefs = cxt->coef;
|
||||
int frameCount = DivideByRoundUp(samples, SAMPLES_PER_FRAME);
|
||||
int samplesRemaining = samples;
|
||||
|
||||
for (int i = 0; i < frameCount; i++)
|
||||
{
|
||||
int predictor = GetHighNibble(*src);
|
||||
int scale = 1 << GetLowNibble(*src++);
|
||||
short coef1 = coefs[predictor * 2];
|
||||
short coef2 = coefs[predictor * 2 + 1];
|
||||
|
||||
int samplesToRead = MIN(SAMPLES_PER_FRAME, samplesRemaining);
|
||||
|
||||
for (int s = 0; s < samplesToRead; s++)
|
||||
{
|
||||
int sample = s % 2 == 0 ? GetHighNibble(*src) : GetLowNibble(*src++);
|
||||
sample = sample >= 8 ? sample - 16 : sample;
|
||||
sample = (((scale * sample) << 11) + 1024 + (coef1 * hist1 + coef2 * hist2)) >> 11;
|
||||
short finalSample = Clamp16(sample);
|
||||
|
||||
hist2 = hist1;
|
||||
hist1 = finalSample;
|
||||
|
||||
*dst++ = finalSample;
|
||||
}
|
||||
|
||||
samplesRemaining -= samplesToRead;
|
||||
}
|
||||
}
|
||||
|
||||
void getLoopContext(uint8_t* src, ADPCMINFO* cxt, uint32_t samples)
|
||||
{
|
||||
short hist1 = cxt->yn1;
|
||||
short hist2 = cxt->yn2;
|
||||
short* coefs = cxt->coef;
|
||||
char ps = 0;
|
||||
int frameCount = DivideByRoundUp(samples, SAMPLES_PER_FRAME);
|
||||
int samplesRemaining = samples;
|
||||
|
||||
for (int i = 0; i < frameCount; i++)
|
||||
{
|
||||
ps = *src;
|
||||
int predictor = GetHighNibble(*src);
|
||||
int scale = 1 << GetLowNibble(*src++);
|
||||
short coef1 = coefs[predictor * 2];
|
||||
short coef2 = coefs[predictor * 2 + 1];
|
||||
|
||||
int samplesToRead = MIN(SAMPLES_PER_FRAME, samplesRemaining);
|
||||
|
||||
for (int s = 0; s < samplesToRead; s++)
|
||||
{
|
||||
int sample = s % 2 == 0 ? GetHighNibble(*src) : GetLowNibble(*src++);
|
||||
sample = sample >= 8 ? sample - 16 : sample;
|
||||
sample = (((scale * sample) << 11) + 1024 + (coef1 * hist1 + coef2 * hist2)) >> 11;
|
||||
short finalSample = Clamp16(sample);
|
||||
|
||||
hist2 = hist1;
|
||||
hist1 = finalSample;
|
||||
}
|
||||
samplesRemaining -= samplesToRead;
|
||||
}
|
||||
|
||||
cxt->loop_pred_scale = ps;
|
||||
cxt->loop_yn1 = hist1;
|
||||
cxt->loop_yn2 = hist2;
|
||||
}
|
||||
19
dsptools/libdsptool/CMakeLists.txt
Normal file
19
dsptools/libdsptool/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
|
||||
project(DspTool LANGUAGES C)
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build as a Shared Object or DLL" OFF)
|
||||
|
||||
set(HEADERS common.h dsptool.h)
|
||||
set(SOURCES math.c decode.c encode.c)
|
||||
|
||||
add_library(DspTool ${HEADERS} ${SOURCES})
|
||||
add_library(DspTool::DspTool ALIAS DspTool)
|
||||
|
||||
target_include_directories(DspTool PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set_property(TARGET DspTool PROPERTY C_STANDARD 99)
|
||||
if (BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(DspTool PRIVATE BUILD_SHARED)
|
||||
endif()
|
||||
target_compile_options(DspTool PRIVATE
|
||||
$<$<C_COMPILER_ID:AppleClang,Clang,GNU>:-Wall -Wextra -pedantic -Wno-unused-parameter>
|
||||
$<$<C_COMPILER_ID:MSVC>:/Wall /wd4100>)
|
||||
7
dsptools/libdsptool/common.h
Normal file
7
dsptools/libdsptool/common.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
|
||||
#endif//COMMON_H
|
||||
101
dsptools/libdsptool/decode.c
Normal file
101
dsptools/libdsptool/decode.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/* (c) 2017 Alex Barney (MIT) */
|
||||
|
||||
#include <stdint.h>
|
||||
#include "common.h"
|
||||
#include "dsptool.h"
|
||||
|
||||
static inline uint8_t GetHighNibble(uint8_t value)
|
||||
{
|
||||
return value >> 4 & 0xF;
|
||||
}
|
||||
|
||||
static inline uint8_t GetLowNibble(uint8_t value)
|
||||
{
|
||||
return value & 0xF;
|
||||
}
|
||||
|
||||
static inline int16_t Clamp16(int value)
|
||||
{
|
||||
if (value > INT16_MAX)
|
||||
return INT16_MAX;
|
||||
if (value < INT16_MIN)
|
||||
return INT16_MIN;
|
||||
return (int16_t)value;
|
||||
}
|
||||
|
||||
void decode(uint8_t* src, int16_t* dst, ADPCMINFO* cxt, uint32_t samples)
|
||||
{
|
||||
short hist1 = cxt->yn1;
|
||||
short hist2 = cxt->yn2;
|
||||
short* coefs = cxt->coef;
|
||||
uint32_t frameCount = (samples + SAMPLES_PER_FRAME - 1) / SAMPLES_PER_FRAME;
|
||||
uint32_t samplesRemaining = samples;
|
||||
|
||||
for (uint32_t i = 0; i < frameCount; i++)
|
||||
{
|
||||
int predictor = GetHighNibble(*src);
|
||||
int scale = 1 << GetLowNibble(*src++);
|
||||
short coef1 = coefs[predictor * 2];
|
||||
short coef2 = coefs[predictor * 2 + 1];
|
||||
|
||||
uint32_t samplesToRead = MIN(SAMPLES_PER_FRAME, samplesRemaining);
|
||||
|
||||
for (uint32_t s = 0; s < samplesToRead; s++)
|
||||
{
|
||||
int sample = (s & 0x1)
|
||||
? GetLowNibble(*src++)
|
||||
: GetHighNibble(*src);
|
||||
sample = sample >= 8 ? sample - 16 : sample;
|
||||
sample = (scale * sample) << 11;
|
||||
sample = (sample + 1024 + (coef1 * hist1 + coef2 * hist2)) >> 11;
|
||||
short finalSample = Clamp16(sample);
|
||||
|
||||
hist2 = hist1;
|
||||
hist1 = finalSample;
|
||||
|
||||
*dst++ = finalSample;
|
||||
}
|
||||
|
||||
samplesRemaining -= samplesToRead;
|
||||
}
|
||||
}
|
||||
|
||||
void getLoopContext(uint8_t* src, ADPCMINFO* cxt, uint32_t samples)
|
||||
{
|
||||
short hist1 = cxt->yn1;
|
||||
short hist2 = cxt->yn2;
|
||||
short* coefs = cxt->coef;
|
||||
uint8_t ps = 0;
|
||||
int frameCount = (int)((samples + SAMPLES_PER_FRAME - 1) / SAMPLES_PER_FRAME);
|
||||
uint32_t samplesRemaining = samples;
|
||||
|
||||
for (int i = 0; i < frameCount; i++)
|
||||
{
|
||||
ps = *src;
|
||||
int predictor = GetHighNibble(*src);
|
||||
int scale = 1 << GetLowNibble(*src++);
|
||||
short coef1 = coefs[predictor * 2];
|
||||
short coef2 = coefs[predictor * 2 + 1];
|
||||
|
||||
uint32_t samplesToRead = MIN(SAMPLES_PER_FRAME, samplesRemaining);
|
||||
|
||||
for (uint32_t s = 0; s < samplesToRead; s++)
|
||||
{
|
||||
int sample = (s & 0x1)
|
||||
? GetLowNibble(*src++)
|
||||
: GetHighNibble(*src);
|
||||
sample = sample >= 8 ? sample - 16 : sample;
|
||||
sample = (scale * sample) << 11;
|
||||
sample = (sample + 1024 + (coef1 * hist1 + coef2 * hist2)) >> 11;
|
||||
short finalSample = Clamp16(sample);
|
||||
|
||||
hist2 = hist1;
|
||||
hist1 = finalSample;
|
||||
}
|
||||
samplesRemaining -= samplesToRead;
|
||||
}
|
||||
|
||||
cxt->loop_pred_scale = ps;
|
||||
cxt->loop_yn1 = hist1;
|
||||
cxt->loop_yn2 = hist2;
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
#pragma once
|
||||
#ifndef DSPTOOL_H
|
||||
#define DSPTOOL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -9,10 +11,18 @@ extern "C" {
|
||||
#define SAMPLES_PER_FRAME 14
|
||||
#define NIBBLES_PER_FRAME 16
|
||||
|
||||
#ifdef COMPILING_DLL
|
||||
#if defined( _WIN32 ) || defined( __CYGWIN__ )
|
||||
# ifdef BUILD_SHARED
|
||||
# define DLLEXPORT __declspec(dllexport)
|
||||
#else
|
||||
# elif defined( WHY_ARE_YOU_USING_THIS_AS_A_DLL )
|
||||
# define DLLEXPORT __declspec(dllimport)
|
||||
# else
|
||||
# define DLLEXPORT
|
||||
# endif
|
||||
#elif __GNUC__ >= 4
|
||||
# define DLLEXPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
# define DLLEXPORT
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
@@ -47,3 +57,5 @@ DLLEXPORT uint32_t getBytesForAdpcmInfo(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,41 +1,40 @@
|
||||
/* (c) 2017 Alex Barney (MIT) */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <string.h>
|
||||
#include "common.h"
|
||||
#include "dsptool.h"
|
||||
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
|
||||
/* Temporal Vector
|
||||
* A contiguous history of 3 samples starting with
|
||||
* 'current' and going 2 backwards
|
||||
*/
|
||||
typedef double tvec[3];
|
||||
void correlateCoefs(int16_t* source, uint32_t samples, int16_t* coefsOut);
|
||||
void DSPEncodeFrame(short pcmInOut[16], int sampleCount, unsigned char adpcmOut[8], const short coefsIn[8][2]);
|
||||
static void DSPEncodeFrame(short pcmInOut[16], int sampleCount, unsigned char adpcmOut[8], const short coefsIn[8][2]);
|
||||
|
||||
void encode(int16_t* src, uint8_t* dst, ADPCMINFO* cxt, uint32_t samples)
|
||||
{
|
||||
int16_t* coefs = cxt->coef;
|
||||
correlateCoefs(src, samples, coefs);
|
||||
|
||||
int32_t frameCount = samples / SAMPLES_PER_FRAME + (samples % SAMPLES_PER_FRAME != 0);
|
||||
uint32_t frameCount = samples / SAMPLES_PER_FRAME + (samples % SAMPLES_PER_FRAME != 0);
|
||||
|
||||
int16_t* pcm = src;
|
||||
uint8_t* adpcm = dst;
|
||||
int16_t pcmFrame[SAMPLES_PER_FRAME + 2] = { 0 };
|
||||
uint8_t adpcmFrame[BYTES_PER_FRAME] = { 0 };
|
||||
|
||||
for (int i = 0; i < frameCount; ++i, pcm += SAMPLES_PER_FRAME, adpcm += BYTES_PER_FRAME)
|
||||
for (uint32_t i = 0; i < frameCount; ++i, pcm += SAMPLES_PER_FRAME, adpcm += BYTES_PER_FRAME)
|
||||
{
|
||||
int32_t sampleCount = MIN(samples - i * SAMPLES_PER_FRAME, SAMPLES_PER_FRAME);
|
||||
uint32_t sampleCount = MIN(samples - i * SAMPLES_PER_FRAME, SAMPLES_PER_FRAME);
|
||||
memset(pcmFrame + 2, 0, SAMPLES_PER_FRAME * sizeof(int16_t));
|
||||
memcpy(pcmFrame + 2, pcm, sampleCount * sizeof(int16_t));
|
||||
|
||||
DSPEncodeFrame(pcmFrame, SAMPLES_PER_FRAME, adpcmFrame, (short(*)[2])&coefs[0]);
|
||||
DSPEncodeFrame(pcmFrame, SAMPLES_PER_FRAME, adpcmFrame, (const short(*)[2])&coefs[0]);
|
||||
|
||||
pcmFrame[0] = pcmFrame[14];
|
||||
pcmFrame[1] = pcmFrame[15];
|
||||
@@ -49,7 +48,7 @@ void encode(int16_t* src, uint8_t* dst, ADPCMINFO* cxt, uint32_t samples)
|
||||
cxt->yn2 = 0;
|
||||
}
|
||||
|
||||
void InnerProductMerge(tvec vecOut, short pcmBuf[14])
|
||||
static void InnerProductMerge(tvec vecOut, const short pcmBuf[14])
|
||||
{
|
||||
for (int i = 0; i <= 2; i++)
|
||||
{
|
||||
@@ -59,7 +58,7 @@ void InnerProductMerge(tvec vecOut, short pcmBuf[14])
|
||||
}
|
||||
}
|
||||
|
||||
void OuterProductMerge(tvec mtxOut[3], short pcmBuf[14])
|
||||
static void OuterProductMerge(tvec mtxOut[3], const short pcmBuf[14])
|
||||
{
|
||||
for (int x = 1; x <= 2; x++)
|
||||
for (int y = 1; y <= 2; y++)
|
||||
@@ -70,12 +69,12 @@ void OuterProductMerge(tvec mtxOut[3], short pcmBuf[14])
|
||||
}
|
||||
}
|
||||
|
||||
bool AnalyzeRanges(tvec mtx[3], int* vecIdxsOut)
|
||||
static bool AnalyzeRanges(tvec mtx[3], int* vecIdxsOut)
|
||||
{
|
||||
double recips[3];
|
||||
double val, tmp, min, max;
|
||||
|
||||
/* Get greatest distance from zero */
|
||||
// Get greatest distance from zero
|
||||
for (int x = 1; x <= 2; x++)
|
||||
{
|
||||
val = MAX(fabs(mtx[x][1]), fabs(mtx[x][2]));
|
||||
@@ -136,7 +135,7 @@ bool AnalyzeRanges(tvec mtx[3], int* vecIdxsOut)
|
||||
}
|
||||
}
|
||||
|
||||
/* Get range */
|
||||
// Get range
|
||||
min = 1.0e10;
|
||||
max = 0.0;
|
||||
for (int i = 1; i <= 2; i++)
|
||||
@@ -154,7 +153,7 @@ bool AnalyzeRanges(tvec mtx[3], int* vecIdxsOut)
|
||||
return false;
|
||||
}
|
||||
|
||||
void BidirectionalFilter(tvec mtx[3], int* vecIdxs, tvec vecOut)
|
||||
static void BidirectionalFilter(tvec mtx[3], const int* vecIdxs, tvec vecOut)
|
||||
{
|
||||
double tmp;
|
||||
|
||||
@@ -182,7 +181,7 @@ void BidirectionalFilter(tvec mtx[3], int* vecIdxs, tvec vecOut)
|
||||
vecOut[0] = 1.0;
|
||||
}
|
||||
|
||||
bool QuadraticMerge(tvec inOutVec)
|
||||
static bool QuadraticMerge(tvec inOutVec)
|
||||
{
|
||||
double v0, v1, v2 = inOutVec[2];
|
||||
double tmp = 1.0 - (v2 * v2);
|
||||
@@ -199,7 +198,7 @@ bool QuadraticMerge(tvec inOutVec)
|
||||
return fabs(v1) > 1.0;
|
||||
}
|
||||
|
||||
void FinishRecord(tvec in, tvec out)
|
||||
static void FinishRecord(tvec in, tvec out)
|
||||
{
|
||||
for (int z = 1; z <= 2; z++)
|
||||
{
|
||||
@@ -213,7 +212,7 @@ void FinishRecord(tvec in, tvec out)
|
||||
out[2] = in[2];
|
||||
}
|
||||
|
||||
void MatrixFilter(tvec src, tvec dst)
|
||||
static void MatrixFilter(const tvec src, tvec dst)
|
||||
{
|
||||
tvec mtx[3];
|
||||
|
||||
@@ -237,7 +236,7 @@ void MatrixFilter(tvec src, tvec dst)
|
||||
}
|
||||
}
|
||||
|
||||
void MergeFinishRecord(tvec src, tvec dst)
|
||||
static void MergeFinishRecord(const tvec src, tvec dst)
|
||||
{
|
||||
tvec tmp;
|
||||
double val = src[0];
|
||||
@@ -265,7 +264,7 @@ void MergeFinishRecord(tvec src, tvec dst)
|
||||
FinishRecord(tmp, dst);
|
||||
}
|
||||
|
||||
double ContrastVectors(tvec source1, tvec source2)
|
||||
static double ContrastVectors(const tvec source1, const tvec source2)
|
||||
{
|
||||
double val = (source2[2] * source2[1] + -source2[1]) / (1.0 - source2[2] * source2[2]);
|
||||
double val1 = (source1[0] * source1[0]) + (source1[1] * source1[1]) + (source1[2] * source1[2]);
|
||||
@@ -274,7 +273,7 @@ double ContrastVectors(tvec source1, tvec source2)
|
||||
return val1 + (2.0 * val * val2) + (2.0 * (-source2[1] * val + -source2[2]) * val3);
|
||||
}
|
||||
|
||||
void FilterRecords(tvec vecBest[8], int exp, tvec records[], int recordCount)
|
||||
static void FilterRecords(tvec vecBest[8], int exp, tvec records[], int recordCount)
|
||||
{
|
||||
tvec bufferList[8];
|
||||
|
||||
@@ -323,8 +322,8 @@ void FilterRecords(tvec vecBest[8], int exp, tvec records[], int recordCount)
|
||||
|
||||
void correlateCoefs(int16_t* source, uint32_t samples, int16_t* coefsOut)
|
||||
{
|
||||
int numFrames = (samples + 13) / 14;
|
||||
int frameSamples;
|
||||
uint32_t numFrames = (samples + 13) / 14;
|
||||
uint32_t frameSamples;
|
||||
|
||||
short* blockBuffer = (short*)calloc(sizeof(short), 0x3800);
|
||||
short pcmHistBuffer[2][14] = { 0 };
|
||||
@@ -340,29 +339,29 @@ void correlateCoefs(int16_t* source, uint32_t samples, int16_t* coefsOut)
|
||||
|
||||
tvec vecBest[8];
|
||||
|
||||
/* Iterate though 1024-block frames */
|
||||
for (int x = samples; x > 0;)
|
||||
// Iterate though 1024-block frames
|
||||
for (uint32_t x = samples; x > 0;)
|
||||
{
|
||||
if (x > 0x3800) /* Full 1024-block frame */
|
||||
if (x > 0x3800) // Full 1024-block frame
|
||||
{
|
||||
frameSamples = 0x3800;
|
||||
x -= 0x3800;
|
||||
}
|
||||
else /* Partial frame */
|
||||
else // Partial frame
|
||||
{
|
||||
/* Zero lingering block samples */
|
||||
// Zero lingering block samples
|
||||
frameSamples = x;
|
||||
for (int z = 0; z < 14 && z + frameSamples < 0x3800; z++)
|
||||
blockBuffer[frameSamples + z] = 0;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
/* Copy (potentially non-frame-aligned PCM samples into aligned buffer) */
|
||||
// Copy (potentially non-frame-aligned PCM samples into aligned buffer)
|
||||
memcpy(blockBuffer, source, frameSamples * sizeof(short));
|
||||
source += frameSamples;
|
||||
|
||||
|
||||
for (int i = 0; i < frameSamples;)
|
||||
for (uint32_t i = 0; i < frameSamples;)
|
||||
{
|
||||
for (int z = 0; z < 14; z++)
|
||||
pcmHistBuffer[0][z] = pcmHistBuffer[1][z];
|
||||
@@ -416,7 +415,7 @@ void correlateCoefs(int16_t* source, uint32_t samples, int16_t* coefsOut)
|
||||
FilterRecords(vecBest, exp, records, recordCount);
|
||||
}
|
||||
|
||||
/* Write output */
|
||||
// Write output
|
||||
for (int z = 0; z < 8; z++)
|
||||
{
|
||||
double d;
|
||||
@@ -433,12 +432,12 @@ void correlateCoefs(int16_t* source, uint32_t samples, int16_t* coefsOut)
|
||||
coefsOut[z * 2 + 1] = (d < -32768.0) ? (short)-32768 : (short)lround(d);
|
||||
}
|
||||
|
||||
/* Free memory */
|
||||
// Free memory
|
||||
free(records);
|
||||
free(blockBuffer);
|
||||
}
|
||||
|
||||
/* Make sure source includes the yn values (16 samples total) */
|
||||
// Make sure source includes the yn values (16 samples total)
|
||||
void DSPEncodeFrame(short pcmInOut[16], int sampleCount, unsigned char adpcmOut[8], const short coefsIn[8][2])
|
||||
{
|
||||
int inSamples[8][16];
|
||||
@@ -449,32 +448,32 @@ void DSPEncodeFrame(short pcmInOut[16], int sampleCount, unsigned char adpcmOut[
|
||||
int scale[8];
|
||||
double distAccum[8];
|
||||
|
||||
/* Iterate through each coef set, finding the set with the smallest error */
|
||||
// Iterate through each coef set, finding the set with the smallest error
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
int v1, v2, v3;
|
||||
int distance, index;
|
||||
|
||||
/* Set yn values */
|
||||
// Set yn values
|
||||
inSamples[i][0] = pcmInOut[0];
|
||||
inSamples[i][1] = pcmInOut[1];
|
||||
|
||||
/* Round and clamp samples for this coef set */
|
||||
// Round and clamp samples for this coef set
|
||||
distance = 0;
|
||||
for (int s = 0; s < sampleCount; s++)
|
||||
{
|
||||
/* Multiply previous samples by coefs */
|
||||
// Multiply previous samples by coefs
|
||||
inSamples[i][s + 2] = v1 = ((pcmInOut[s] * coefsIn[i][1]) + (pcmInOut[s + 1] * coefsIn[i][0])) / 2048;
|
||||
/* Subtract from current sample */
|
||||
// Subtract from current sample
|
||||
v2 = pcmInOut[s + 2] - v1;
|
||||
/* Clamp */
|
||||
// Clamp
|
||||
v3 = (v2 >= 32767) ? 32767 : (v2 <= -32768) ? -32768 : v2;
|
||||
/* Compare distance */
|
||||
// Compare distance
|
||||
if (abs(v3) > abs(distance))
|
||||
distance = v3;
|
||||
}
|
||||
|
||||
/* Set initial scale */
|
||||
// Set initial scale
|
||||
for (scale[i] = 0; (scale[i] <= 12) && ((distance > 7) || (distance < -8)); scale[i]++, distance /= 2)
|
||||
{
|
||||
}
|
||||
@@ -488,14 +487,14 @@ void DSPEncodeFrame(short pcmInOut[16], int sampleCount, unsigned char adpcmOut[
|
||||
|
||||
for (int s = 0; s < sampleCount; s++)
|
||||
{
|
||||
/* Multiply previous */
|
||||
// Multiply previous
|
||||
v1 = ((inSamples[i][s] * coefsIn[i][1]) + (inSamples[i][s + 1] * coefsIn[i][0]));
|
||||
/* Evaluate from real sample */
|
||||
// Evaluate from real sample
|
||||
v2 = (pcmInOut[s + 2] << 11) - v1;
|
||||
/* Round to nearest sample */
|
||||
// Round to nearest sample
|
||||
v3 = (v2 > 0) ? (int)((double)v2 / (1 << scale[i]) / 2048 + 0.4999999f) : (int)((double)v2 / (1 << scale[i]) / 2048 - 0.4999999f);
|
||||
|
||||
/* Clamp sample and set index */
|
||||
// Clamp sample and set index
|
||||
if (v3 < -8)
|
||||
{
|
||||
if (index < (v3 = -8 - v3))
|
||||
@@ -509,14 +508,14 @@ void DSPEncodeFrame(short pcmInOut[16], int sampleCount, unsigned char adpcmOut[
|
||||
v3 = 7;
|
||||
}
|
||||
|
||||
/* Store result */
|
||||
// Store result
|
||||
outSamples[i][s] = v3;
|
||||
|
||||
/* Round and expand */
|
||||
// Round and expand
|
||||
v1 = (v1 + ((v3 * (1 << scale[i])) << 11) + 1024) >> 11;
|
||||
/* Clamp and store */
|
||||
// Clamp and store
|
||||
inSamples[i][s + 2] = v2 = (v1 >= 32767) ? 32767 : (v1 <= -32768) ? -32768 : v1;
|
||||
/* Accumulate distance */
|
||||
// Accumulate distance
|
||||
v3 = pcmInOut[s + 2] - v2;
|
||||
distAccum[i] += v3 * (double)v3;
|
||||
}
|
||||
@@ -537,25 +536,23 @@ void DSPEncodeFrame(short pcmInOut[16], int sampleCount, unsigned char adpcmOut[
|
||||
}
|
||||
}
|
||||
|
||||
/* Write converted samples */
|
||||
// Write converted samples
|
||||
for (int s = 0; s < sampleCount; s++)
|
||||
pcmInOut[s + 2] = inSamples[bestIndex][s + 2];
|
||||
pcmInOut[s + 2] = (short)inSamples[bestIndex][s + 2];
|
||||
|
||||
/* Write ps */
|
||||
// Write ps
|
||||
adpcmOut[0] = (char)((bestIndex << 4) | (scale[bestIndex] & 0xF));
|
||||
|
||||
/* Zero remaining samples */
|
||||
// Zero remaining samples
|
||||
for (int s = sampleCount; s < 14; s++)
|
||||
outSamples[bestIndex][s] = 0;
|
||||
|
||||
/* Write output samples */
|
||||
// Write output samples
|
||||
for (int y = 0; y < 7; y++)
|
||||
{
|
||||
adpcmOut[y + 1] = (char)((outSamples[bestIndex][y * 2] << 4) | (outSamples[bestIndex][y * 2 + 1] & 0xF));
|
||||
}
|
||||
}
|
||||
|
||||
void encodeFrame(int16_t* src, uint8_t* dst, int16_t* coefs, uint8_t one)
|
||||
{
|
||||
DSPEncodeFrame(src, 14, dst, (short(*)[2])&coefs[0]);
|
||||
DSPEncodeFrame(src, 14, dst, (const short(*)[2])&coefs[0]);
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
/* (c) 2017 Alex Barney (MIT) */
|
||||
|
||||
#include "dsptool.h"
|
||||
|
||||
uint32_t getBytesForAdpcmBuffer(uint32_t samples)
|
||||
@@ -9,7 +11,7 @@ uint32_t getBytesForAdpcmBuffer(uint32_t samples)
|
||||
return frames * BYTES_PER_FRAME;
|
||||
}
|
||||
|
||||
uint32_t getBytesForAdpcmInfo()
|
||||
uint32_t getBytesForAdpcmInfo(void)
|
||||
{
|
||||
return sizeof(ADPCMINFO);
|
||||
}
|
||||
@@ -21,9 +23,7 @@ uint32_t getBytesForAdpcmSamples(uint32_t samples)
|
||||
uint32_t extraSamples = samples % SAMPLES_PER_FRAME;
|
||||
|
||||
if (extraSamples)
|
||||
{
|
||||
extraBytes = (extraSamples / 2) + (extraSamples % 2) + 1;
|
||||
}
|
||||
|
||||
return BYTES_PER_FRAME * frames + extraBytes;
|
||||
}
|
||||
@@ -44,8 +44,8 @@ uint32_t getBytesForPcmSamples(uint32_t samples)
|
||||
|
||||
uint32_t getNibbleAddress(uint32_t samples)
|
||||
{
|
||||
int frames = samples / SAMPLES_PER_FRAME;
|
||||
int extraSamples = samples % SAMPLES_PER_FRAME;
|
||||
uint32_t frames = samples / SAMPLES_PER_FRAME;
|
||||
uint32_t extraSamples = samples - (frames * SAMPLES_PER_FRAME);
|
||||
|
||||
return NIBBLES_PER_FRAME * frames + extraSamples + 2;
|
||||
}
|
||||
@@ -53,7 +53,7 @@ uint32_t getNibbleAddress(uint32_t samples)
|
||||
uint32_t getNibblesForNSamples(uint32_t samples)
|
||||
{
|
||||
uint32_t frames = samples / SAMPLES_PER_FRAME;
|
||||
uint32_t extraSamples = samples % SAMPLES_PER_FRAME;
|
||||
uint32_t extraSamples = samples - (frames * SAMPLES_PER_FRAME);
|
||||
uint32_t extraNibbles = extraSamples == 0 ? 0 : extraSamples + 2;
|
||||
|
||||
return NIBBLES_PER_FRAME * frames + extraNibbles;
|
||||
@@ -62,7 +62,7 @@ uint32_t getNibblesForNSamples(uint32_t samples)
|
||||
uint32_t getSampleForAdpcmNibble(uint32_t nibble)
|
||||
{
|
||||
uint32_t frames = nibble / NIBBLES_PER_FRAME;
|
||||
uint32_t extraNibbles = nibble % NIBBLES_PER_FRAME;
|
||||
uint32_t extraNibbles = nibble - (frames * NIBBLES_PER_FRAME);
|
||||
uint32_t samples = SAMPLES_PER_FRAME * frames;
|
||||
|
||||
return samples + extraNibbles - 2;
|
||||
Reference in New Issue
Block a user