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

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
Copyright (c) 2017 Alex Barney
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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
SOFTWARE.
MIT License
Copyright (c) 2017 Alex Barney
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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
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
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#define BYTES_PER_FRAME 8
#define SAMPLES_PER_FRAME 14
#define NIBBLES_PER_FRAME 16
#ifdef COMPILING_DLL
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT __declspec(dllimport)
#endif
typedef struct
{
int16_t coef[16];
uint16_t gain;
uint16_t pred_scale;
int16_t yn1;
int16_t yn2;
uint16_t loop_pred_scale;
int16_t loop_yn1;
int16_t loop_yn2;
} ADPCMINFO;
DLLEXPORT void encode(int16_t* src, uint8_t* dst, ADPCMINFO* cxt, uint32_t samples);
DLLEXPORT void decode(uint8_t* src, int16_t* dst, ADPCMINFO* cxt, uint32_t samples);
DLLEXPORT void getLoopContext(uint8_t* src, ADPCMINFO* cxt, uint32_t samples);
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);
DLLEXPORT uint32_t getBytesForAdpcmBuffer(uint32_t samples);
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
#ifndef DSPTOOL_H
#define DSPTOOL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#define BYTES_PER_FRAME 8
#define SAMPLES_PER_FRAME 14
#define NIBBLES_PER_FRAME 16
#if defined( _WIN32 ) || defined( __CYGWIN__ )
# ifdef BUILD_SHARED
# define DLLEXPORT __declspec(dllexport)
# 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
{
int16_t coef[16];
uint16_t gain;
uint16_t pred_scale;
int16_t yn1;
int16_t yn2;
uint16_t loop_pred_scale;
int16_t loop_yn1;
int16_t loop_yn2;
} ADPCMINFO;
DLLEXPORT void encode(int16_t* src, uint8_t* dst, ADPCMINFO* cxt, uint32_t samples);
DLLEXPORT void decode(uint8_t* src, int16_t* dst, ADPCMINFO* cxt, uint32_t samples);
DLLEXPORT void getLoopContext(uint8_t* src, ADPCMINFO* cxt, uint32_t samples);
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);
DLLEXPORT uint32_t getBytesForAdpcmBuffer(uint32_t samples);
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"
uint32_t getBytesForAdpcmBuffer(uint32_t samples)
{
uint32_t frames = samples / SAMPLES_PER_FRAME;
if (samples % SAMPLES_PER_FRAME)
frames++;
return frames * BYTES_PER_FRAME;
}
uint32_t getBytesForAdpcmInfo()
{
return sizeof(ADPCMINFO);
}
uint32_t getBytesForAdpcmSamples(uint32_t samples)
{
uint32_t extraBytes = 0;
uint32_t frames = samples / SAMPLES_PER_FRAME;
uint32_t extraSamples = samples % SAMPLES_PER_FRAME;
if (extraSamples)
{
extraBytes = (extraSamples / 2) + (extraSamples % 2) + 1;
}
return BYTES_PER_FRAME * frames + extraBytes;
}
uint32_t getBytesForPcmBuffer(uint32_t samples)
{
uint32_t frames = samples / SAMPLES_PER_FRAME;
if (samples % SAMPLES_PER_FRAME)
frames++;
return frames * SAMPLES_PER_FRAME * sizeof(int16_t);
}
uint32_t getBytesForPcmSamples(uint32_t samples)
{
return samples * sizeof(int16_t);
}
uint32_t getNibbleAddress(uint32_t samples)
{
int frames = samples / SAMPLES_PER_FRAME;
int extraSamples = samples % SAMPLES_PER_FRAME;
return NIBBLES_PER_FRAME * frames + extraSamples + 2;
}
uint32_t getNibblesForNSamples(uint32_t samples)
{
uint32_t frames = samples / SAMPLES_PER_FRAME;
uint32_t extraSamples = samples % SAMPLES_PER_FRAME;
uint32_t extraNibbles = extraSamples == 0 ? 0 : extraSamples + 2;
return NIBBLES_PER_FRAME * frames + extraNibbles;
}
uint32_t getSampleForAdpcmNibble(uint32_t nibble)
{
uint32_t frames = nibble / NIBBLES_PER_FRAME;
uint32_t extraNibbles = nibble % NIBBLES_PER_FRAME;
uint32_t samples = SAMPLES_PER_FRAME * frames;
return samples + extraNibbles - 2;
}
/* (c) 2017 Alex Barney (MIT) */
#include "dsptool.h"
uint32_t getBytesForAdpcmBuffer(uint32_t samples)
{
uint32_t frames = samples / SAMPLES_PER_FRAME;
if (samples % SAMPLES_PER_FRAME)
frames++;
return frames * BYTES_PER_FRAME;
}
uint32_t getBytesForAdpcmInfo(void)
{
return sizeof(ADPCMINFO);
}
uint32_t getBytesForAdpcmSamples(uint32_t samples)
{
uint32_t extraBytes = 0;
uint32_t frames = samples / SAMPLES_PER_FRAME;
uint32_t extraSamples = samples % SAMPLES_PER_FRAME;
if (extraSamples)
extraBytes = (extraSamples / 2) + (extraSamples % 2) + 1;
return BYTES_PER_FRAME * frames + extraBytes;
}
uint32_t getBytesForPcmBuffer(uint32_t samples)
{
uint32_t frames = samples / SAMPLES_PER_FRAME;
if (samples % SAMPLES_PER_FRAME)
frames++;
return frames * SAMPLES_PER_FRAME * sizeof(int16_t);
}
uint32_t getBytesForPcmSamples(uint32_t samples)
{
return samples * sizeof(int16_t);
}
uint32_t getNibbleAddress(uint32_t samples)
{
uint32_t frames = samples / SAMPLES_PER_FRAME;
uint32_t extraSamples = samples - (frames * SAMPLES_PER_FRAME);
return NIBBLES_PER_FRAME * frames + extraSamples + 2;
}
uint32_t getNibblesForNSamples(uint32_t samples)
{
uint32_t frames = 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;
}
uint32_t getSampleForAdpcmNibble(uint32_t nibble)
{
uint32_t frames = nibble / NIBBLES_PER_FRAME;
uint32_t extraNibbles = nibble - (frames * NIBBLES_PER_FRAME);
uint32_t samples = SAMPLES_PER_FRAME * frames;
return samples + extraNibbles - 2;
}