mirror of
https://github.com/XProger/OpenLara.git
synced 2025-01-17 04:48:57 +01:00
GBA: Fix ADPCM encoding issues (#474)
* ADPCM: Add 8bit debugging, fix limit cycles * ADPCM: Increase output gain
This commit is contained in:
parent
d2e363db88
commit
931079c49b
@ -1,10 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
//! Uncommenting this line writes the output to Debug.sb as 8bit signed PCM
|
||||
//#define DEBUG_OUTPUT
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct AD4State_t {
|
||||
int32_t zM1, zM2;
|
||||
int32_t Tap;
|
||||
int32_t Quant;
|
||||
int32_t Output;
|
||||
uint32_t MaxOutputLevel;
|
||||
@ -13,7 +16,6 @@ struct AD4State_t {
|
||||
void AD4_Init(struct AD4State_t *State) {
|
||||
State->zM1 = 0;
|
||||
State->zM2 = 0;
|
||||
State->Tap = 0;
|
||||
State->Quant = 0x0800;
|
||||
State->Output = 0;
|
||||
State->MaxOutputLevel = 0;
|
||||
@ -28,39 +30,58 @@ uint32_t AD4_EncodeFrame(struct AD4State_t *State, const int16_t *Data) {
|
||||
uint8_t n;
|
||||
int32_t zM1 = State->zM1;
|
||||
int32_t zM2 = State->zM2;
|
||||
int32_t Tap = State->Tap;
|
||||
int32_t Quant = State->Quant;
|
||||
int32_t Output = State->Output;
|
||||
uint32_t MaxOutputLevel = State->MaxOutputLevel;
|
||||
uint32_t FrameData = 0;
|
||||
#ifdef DEBUG_OUTPUT
|
||||
static FILE *DebugFile = NULL;
|
||||
if(!DebugFile) DebugFile = fopen("Debug.sb", "ab");
|
||||
#endif
|
||||
for(n=0;n<8;n++) {
|
||||
//! Get input, compute prediction, and quantize residue
|
||||
//! Note that we minimize error of Output rather than Y, which implies
|
||||
//! applying the post-filter in the analysis equation to get the residue.
|
||||
int32_t X = Data[n];
|
||||
int32_t P = zM1 - zM2;
|
||||
int32_t R = X - (P + (Tap - (Tap >> 3))); {
|
||||
int32_t R = X - (P + Output - (Output >> 3)); {
|
||||
#if 0 //! Lower RMSE, but sounds noisier
|
||||
R = (2*R + ((R < 0) ? (-Quant) : (+Quant))) / (2*Quant); //! (R + Sign[R]*(Quant/2)) / Quant
|
||||
#else
|
||||
R /= Quant;
|
||||
//! Round positive residues up, and negative residues towards 0.
|
||||
//! I have no idea why, but this fixes limit cycles.
|
||||
if(R > 0) R = (R + (Quant-1)) / Quant;
|
||||
else R = (R + 0) / Quant;
|
||||
#endif
|
||||
if(R < -8) R = -8;
|
||||
if(R > +7) R = +7;
|
||||
}
|
||||
int32_t Y = P + R*Quant;
|
||||
|
||||
//! Calculate output value and update maximum level
|
||||
//! Calculate output value and apply limiting
|
||||
//! Post-filter: Hpost(z) = 1 / Hpre(z) = 1 / (1 - (7/8)z^-1)
|
||||
Output = Y + Output - (Output >> 3);
|
||||
int32_t Y;
|
||||
Output = Output - (Output >> 3);
|
||||
for(;;) {
|
||||
Y = P + R*Quant;
|
||||
if(Output+Y < -32768) {
|
||||
if(R < +7) R++;
|
||||
else break;
|
||||
} else if(Output+Y > +32767) {
|
||||
if(R > -8) R--;
|
||||
else break;
|
||||
} else break;
|
||||
}
|
||||
Output += Y;
|
||||
|
||||
//! Update maximum level after attempted clipping
|
||||
uint32_t Level = (uint32_t)((Output < 0) ? (-Output) : (+Output));
|
||||
if(Level > MaxOutputLevel) MaxOutputLevel = Level;
|
||||
|
||||
//! Do the same, but for the encoding tap. This is needed to
|
||||
//! avoid a limit oscillation on silence from round-off error.
|
||||
//! Technically, it does mean a different output, but it should
|
||||
//! be close enough to what we want that it shouldn't matter.
|
||||
Tap = Y + Tap - ((Tap + 4 - (Tap < 0)) >> 3); //! Y + Round[Tap*7/8]
|
||||
//! Write debug output
|
||||
#ifdef DEBUG_OUTPUT
|
||||
int8_t DebugSample = Output >> 8;
|
||||
fwrite(&DebugSample, sizeof(int8_t), 1, DebugFile);
|
||||
#endif
|
||||
|
||||
//! Update taps and push residue to frame
|
||||
zM2 = zM1;
|
||||
@ -73,7 +94,6 @@ uint32_t AD4_EncodeFrame(struct AD4State_t *State, const int16_t *Data) {
|
||||
}
|
||||
State->zM1 = zM1;
|
||||
State->zM2 = zM2;
|
||||
State->Tap = Tap;
|
||||
State->Quant = Quant;
|
||||
State->Output = Output;
|
||||
State->MaxOutputLevel = MaxOutputLevel;
|
||||
|
@ -6,7 +6,7 @@ set DEMO_FOLDER=conv_demo\
|
||||
|
||||
for /r %IN_FOLDER% %%i in (*.wav) do (
|
||||
ffmpeg -v panic -y -i %%i -ar 10512 -f s16le -acodec pcm_s16le temp.raw
|
||||
ad4 temp.raw %OUT_FOLDER%%%~ni.ad4 -0.8
|
||||
ad4 temp.raw %OUT_FOLDER%%%~ni.ad4 -0.5
|
||||
)
|
||||
del /f temp.raw
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user