1
0
mirror of https://github.com/ScrelliCopter/VGM-Tools synced 2025-02-21 04:09:25 +11:00

dsptool: refactor

This commit is contained in:
2023-03-19 09:58:26 +11:00
parent ac89564669
commit 99bf061438
9 changed files with 848 additions and 804 deletions

View File

@@ -1,9 +1,18 @@
cmake_minimum_required(VERSION 3.1 FATAL_ERROR) cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
project(DspTool LANGUAGES C) 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) set(SOURCES math.c decode.c encode.c)
add_library(DspTool ${HEADERS} ${SOURCES}) 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>)

View File

@@ -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;
}

View 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>)

View File

@@ -1,21 +1,21 @@
MIT License MIT License
Copyright (c) 2017 Alex Barney Copyright (c) 2017 Alex Barney
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.

View 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

View 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;
}

View File

@@ -1,49 +1,61 @@
#pragma once #ifndef DSPTOOL_H
#ifdef __cplusplus #define DSPTOOL_H
extern "C" {
#endif #ifdef __cplusplus
extern "C" {
#include <stdint.h> #endif
#define BYTES_PER_FRAME 8 #include <stdint.h>
#define SAMPLES_PER_FRAME 14
#define NIBBLES_PER_FRAME 16 #define BYTES_PER_FRAME 8
#define SAMPLES_PER_FRAME 14
#ifdef COMPILING_DLL #define NIBBLES_PER_FRAME 16
#define DLLEXPORT __declspec(dllexport)
#else #if defined( _WIN32 ) || defined( __CYGWIN__ )
#define DLLEXPORT __declspec(dllimport) # ifdef BUILD_SHARED
#endif # define DLLEXPORT __declspec(dllexport)
# elif defined( WHY_ARE_YOU_USING_THIS_AS_A_DLL )
typedef struct # define DLLEXPORT __declspec(dllimport)
{ # else
int16_t coef[16]; # define DLLEXPORT
uint16_t gain; # endif
uint16_t pred_scale; #elif __GNUC__ >= 4
int16_t yn1; # define DLLEXPORT __attribute__((visibility("default")))
int16_t yn2; #else
# define DLLEXPORT
uint16_t loop_pred_scale; #endif
int16_t loop_yn1;
int16_t loop_yn2; typedef struct
} ADPCMINFO; {
int16_t coef[16];
DLLEXPORT void encode(int16_t* src, uint8_t* dst, ADPCMINFO* cxt, uint32_t samples); uint16_t gain;
DLLEXPORT void decode(uint8_t* src, int16_t* dst, ADPCMINFO* cxt, uint32_t samples); uint16_t pred_scale;
DLLEXPORT void getLoopContext(uint8_t* src, ADPCMINFO* cxt, uint32_t samples); int16_t yn1;
int16_t yn2;
DLLEXPORT void encodeFrame(int16_t* src, uint8_t* dst, int16_t* coefs, uint8_t one);
DLLEXPORT void correlateCoefs(int16_t* src, uint32_t samples, int16_t* coefsOut); uint16_t loop_pred_scale;
int16_t loop_yn1;
DLLEXPORT uint32_t getBytesForAdpcmBuffer(uint32_t samples); int16_t loop_yn2;
DLLEXPORT uint32_t getBytesForAdpcmSamples(uint32_t samples); } ADPCMINFO;
DLLEXPORT uint32_t getBytesForPcmBuffer(uint32_t samples);
DLLEXPORT uint32_t getBytesForPcmSamples(uint32_t samples); DLLEXPORT void encode(int16_t* src, uint8_t* dst, ADPCMINFO* cxt, uint32_t samples);
DLLEXPORT uint32_t getNibbleAddress(uint32_t samples); DLLEXPORT void decode(uint8_t* src, int16_t* dst, ADPCMINFO* cxt, uint32_t samples);
DLLEXPORT uint32_t getNibblesForNSamples(uint32_t samples); DLLEXPORT void getLoopContext(uint8_t* src, ADPCMINFO* cxt, uint32_t samples);
DLLEXPORT uint32_t getSampleForAdpcmNibble(uint32_t nibble);
DLLEXPORT uint32_t getBytesForAdpcmInfo(void); DLLEXPORT void encodeFrame(int16_t* src, uint8_t* dst, int16_t* coefs, uint8_t one);
DLLEXPORT void correlateCoefs(int16_t* src, uint32_t samples, int16_t* coefsOut);
#ifdef __cplusplus
} DLLEXPORT uint32_t getBytesForAdpcmBuffer(uint32_t samples);
#endif DLLEXPORT uint32_t getBytesForAdpcmSamples(uint32_t samples);
DLLEXPORT uint32_t getBytesForPcmBuffer(uint32_t samples);
DLLEXPORT uint32_t getBytesForPcmSamples(uint32_t samples);
DLLEXPORT uint32_t getNibbleAddress(uint32_t samples);
DLLEXPORT uint32_t getNibblesForNSamples(uint32_t samples);
DLLEXPORT uint32_t getSampleForAdpcmNibble(uint32_t nibble);
DLLEXPORT uint32_t getBytesForAdpcmInfo(void);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,69 +1,69 @@
#include "dsptool.h" /* (c) 2017 Alex Barney (MIT) */
uint32_t getBytesForAdpcmBuffer(uint32_t samples) #include "dsptool.h"
{
uint32_t frames = samples / SAMPLES_PER_FRAME; uint32_t getBytesForAdpcmBuffer(uint32_t samples)
if (samples % SAMPLES_PER_FRAME) {
frames++; uint32_t frames = samples / SAMPLES_PER_FRAME;
if (samples % SAMPLES_PER_FRAME)
return frames * BYTES_PER_FRAME; frames++;
}
return frames * BYTES_PER_FRAME;
uint32_t getBytesForAdpcmInfo() }
{
return sizeof(ADPCMINFO); uint32_t getBytesForAdpcmInfo(void)
} {
return sizeof(ADPCMINFO);
uint32_t getBytesForAdpcmSamples(uint32_t samples) }
{
uint32_t extraBytes = 0; uint32_t getBytesForAdpcmSamples(uint32_t samples)
uint32_t frames = samples / SAMPLES_PER_FRAME; {
uint32_t extraSamples = samples % SAMPLES_PER_FRAME; uint32_t extraBytes = 0;
uint32_t frames = samples / SAMPLES_PER_FRAME;
if (extraSamples) uint32_t extraSamples = samples % SAMPLES_PER_FRAME;
{
extraBytes = (extraSamples / 2) + (extraSamples % 2) + 1; if (extraSamples)
} extraBytes = (extraSamples / 2) + (extraSamples % 2) + 1;
return BYTES_PER_FRAME * frames + extraBytes; return BYTES_PER_FRAME * frames + extraBytes;
} }
uint32_t getBytesForPcmBuffer(uint32_t samples) uint32_t getBytesForPcmBuffer(uint32_t samples)
{ {
uint32_t frames = samples / SAMPLES_PER_FRAME; uint32_t frames = samples / SAMPLES_PER_FRAME;
if (samples % SAMPLES_PER_FRAME) if (samples % SAMPLES_PER_FRAME)
frames++; frames++;
return frames * SAMPLES_PER_FRAME * sizeof(int16_t); return frames * SAMPLES_PER_FRAME * sizeof(int16_t);
} }
uint32_t getBytesForPcmSamples(uint32_t samples) uint32_t getBytesForPcmSamples(uint32_t samples)
{ {
return samples * sizeof(int16_t); return samples * sizeof(int16_t);
} }
uint32_t getNibbleAddress(uint32_t samples) uint32_t getNibbleAddress(uint32_t samples)
{ {
int frames = samples / SAMPLES_PER_FRAME; uint32_t frames = samples / SAMPLES_PER_FRAME;
int extraSamples = samples % SAMPLES_PER_FRAME; uint32_t extraSamples = samples - (frames * SAMPLES_PER_FRAME);
return NIBBLES_PER_FRAME * frames + extraSamples + 2; return NIBBLES_PER_FRAME * frames + extraSamples + 2;
} }
uint32_t getNibblesForNSamples(uint32_t samples) uint32_t getNibblesForNSamples(uint32_t samples)
{ {
uint32_t frames = samples / SAMPLES_PER_FRAME; 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; uint32_t extraNibbles = extraSamples == 0 ? 0 : extraSamples + 2;
return NIBBLES_PER_FRAME * frames + extraNibbles; return NIBBLES_PER_FRAME * frames + extraNibbles;
} }
uint32_t getSampleForAdpcmNibble(uint32_t nibble) uint32_t getSampleForAdpcmNibble(uint32_t nibble)
{ {
uint32_t frames = nibble / NIBBLES_PER_FRAME; 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; uint32_t samples = SAMPLES_PER_FRAME * frames;
return samples + extraNibbles - 2; return samples + extraNibbles - 2;
} }