pureikyubu/SRC/DSP/DspAdpcm.cpp
2020-08-08 20:10:33 +03:00

72 lines
1.5 KiB
C++

// DSP PCM/ADPCM Decoder
#include "pch.h"
using namespace Debug;
#define my_max(a,b) (((a) > (b)) ? (a) : (b))
#define my_min(a,b) (((a) < (b)) ? (a) : (b))
namespace DSP
{
uint16_t Dsp16::DecodeAdpcm(uint16_t in)
{
int64_t yn = 0;
int64_t out = 0;
int outputMode = (Accel.Fmt >> 4) & 3;
switch ((Accel.Fmt >> 2) & 3)
{
case 0:
{
int pred = (Accel.AdpcmPds >> 4) & 7;
int scale = Accel.AdpcmPds & 0xf;
int16_t gain = 1 << scale;
if (scale > 0xc)
scale = 0xc;
int16_t xn = in << 11;
if (xn & 0x4000)
xn |= 0x8000;
yn = (int64_t)(int32_t)(int16_t)Accel.AdpcmYn1 * (int64_t)(int32_t)(int16_t)Accel.AdpcmCoef[2 * pred]
+ (int64_t)(int32_t)(int16_t)Accel.AdpcmYn2 * (int64_t)(int32_t)(int16_t)Accel.AdpcmCoef[2 * pred + 1] +
(int64_t)(int32_t)xn * gain;
Accel.AdpcmYn2 = Accel.AdpcmYn1;
Accel.AdpcmYn1 = (uint16_t)(yn >> 11);
break;
}
case 1:
yn = (int64_t)(int32_t)((int16_t)(in << 8)) * Accel.AdpcmGan;
break;
case 2:
yn = (int64_t)(int32_t)(int16_t)in * Accel.AdpcmGan;
break;
}
switch (outputMode)
{
case 0:
out = yn >> 11;
out = my_max(-0x8000, my_min(out, 0x7FFF));
break;
case 1:
out = yn & 0xffff;
break;
case 2:
out = (yn >> 16);
break;
case 3:
Halt("DSP: Unsupported Decoder output mode\n");
break;
}
//Report(Channel::DSP, "0x%08X = 0x%04X\n", (Accel.CurrAddress.addr & 0x07FF'FFFF) - 1, (uint16_t)out);
return (uint16_t)out;
}
}