mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-05 04:37:50 +02:00
first version, sounds wrong :)
This commit is contained in:
194
src/sound.h
194
src/sound.h
@@ -49,6 +49,66 @@ namespace Sound {
|
||||
{ 0, -0x0005, +0x0011, -0x0023, +0x0046, -0x0017, -0x0044, +0x015B, -0x0347, +0x080E, -0x1249, +0x3C07, +0x53E0, -0x16FA, +0x0AFA, -0x0548, +0x027B, -0x00EB, +0x001A, +0x002B, -0x0023, +0x0010, -0x0008, +0x0002, 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
// https://problemkaputt.de/psx-spx.htm#spureverbformula
|
||||
struct ReverbPreset {
|
||||
uint16 size;
|
||||
int16 dAPF1, dAPF2, vIIR, vCOMB1, vCOMB2, vCOMB3, vCOMB4, vWALL;
|
||||
int16 vAPF1, vAPF2, mLSAME, mRSAME, mLCOMB1, mRCOMB1, mLCOMB2, mRCOMB2;
|
||||
int16 dLSAME, dRSAME, mLDIFF, mRDIFF, mLCOMB3, mRCOMB3, mLCOMB4, mRCOMB4;
|
||||
int16 dLDIFF, dRDIFF, mLAPF1, mRAPF1, mLAPF2, mRAPF2, vLIN, vRIN;
|
||||
};
|
||||
|
||||
static const uint16 SPU_REVERB[8][sizeof(ReverbPreset) / 2] = {
|
||||
// Room
|
||||
{ 0x26C0 / 2,
|
||||
0x007D, 0x005B, 0x6D80, 0x54B8, 0xBED0, 0x0000, 0x0000, 0xBA80,
|
||||
0x5800, 0x5300, 0x04D6, 0x0333, 0x03F0, 0x0227, 0x0374, 0x01EF,
|
||||
0x0334, 0x01B5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x01B4, 0x0136, 0x00B8, 0x005C, 0x8000, 0x8000 },
|
||||
// Studio Small
|
||||
{ 0x1F40 / 2,
|
||||
0x0033, 0x0025, 0x70F0, 0x4FA8, 0xBCE0, 0x4410, 0xC0F0, 0x9C00,
|
||||
0x5280, 0x4EC0, 0x03E4, 0x031B, 0x03A4, 0x02AF, 0x0372, 0x0266,
|
||||
0x031C, 0x025D, 0x025C, 0x018E, 0x022F, 0x0135, 0x01D2, 0x00B7,
|
||||
0x018F, 0x00B5, 0x00B4, 0x0080, 0x004C, 0x0026, 0x8000, 0x8000 },
|
||||
// Studio Medium
|
||||
{ 0x4840 / 2,
|
||||
0x00B1, 0x007F, 0x70F0, 0x4FA8, 0xBCE0, 0x4510, 0xBEF0, 0xB4C0,
|
||||
0x5280, 0x4EC0, 0x0904, 0x076B, 0x0824, 0x065F, 0x07A2, 0x0616,
|
||||
0x076C, 0x05ED, 0x05EC, 0x042E, 0x050F, 0x0305, 0x0462, 0x02B7,
|
||||
0x042F, 0x0265, 0x0264, 0x01B2, 0x0100, 0x0080, 0x8000, 0x8000 },
|
||||
// Studio Large
|
||||
{ 0x6FE0 / 2,
|
||||
0x00E3, 0x00A9, 0x6F60, 0x4FA8, 0xBCE0, 0x4510, 0xBEF0, 0xA680,
|
||||
0x5680, 0x52C0, 0x0DFB, 0x0B58, 0x0D09, 0x0A3C, 0x0BD9, 0x0973,
|
||||
0x0B59, 0x08DA, 0x08D9, 0x05E9, 0x07EC, 0x04B0, 0x06EF, 0x03D2,
|
||||
0x05EA, 0x031D, 0x031C, 0x0238, 0x0154, 0x00AA, 0x8000, 0x8000 },
|
||||
// Hall
|
||||
{ 0xADE0 / 2,
|
||||
0x01A5, 0x0139, 0x6000, 0x5000, 0x4C00, 0xB800, 0xBC00, 0xC000,
|
||||
0x6000, 0x5C00, 0x15BA, 0x11BB, 0x14C2, 0x10BD, 0x11BC, 0x0DC1,
|
||||
0x11C0, 0x0DC3, 0x0DC0, 0x09C1, 0x0BC4, 0x07C1, 0x0A00, 0x06CD,
|
||||
0x09C2, 0x05C1, 0x05C0, 0x041A, 0x0274, 0x013A, 0x8000, 0x8000 },
|
||||
// Half Echo
|
||||
{ 0x3C00 / 2,
|
||||
0x0017, 0x0013, 0x70F0, 0x4FA8, 0xBCE0, 0x4510, 0xBEF0, 0x8500,
|
||||
0x5F80, 0x54C0, 0x0371, 0x02AF, 0x02E5, 0x01DF, 0x02B0, 0x01D7,
|
||||
0x0358, 0x026A, 0x01D6, 0x011E, 0x012D, 0x00B1, 0x011F, 0x0059,
|
||||
0x01A0, 0x00E3, 0x0058, 0x0040, 0x0028, 0x0014, 0x8000, 0x8000 },
|
||||
// Space Echo
|
||||
{ 0xF6C0 / 2,
|
||||
0x033D, 0x0231, 0x7E00, 0x5000, 0xB400, 0xB000, 0x4C00, 0xB000,
|
||||
0x6000, 0x5400, 0x1ED6, 0x1A31, 0x1D14, 0x183B, 0x1BC2, 0x16B2,
|
||||
0x1A32, 0x15EF, 0x15EE, 0x1055, 0x1334, 0x0F2D, 0x11F6, 0x0C5D,
|
||||
0x1056, 0x0AE1, 0x0AE0, 0x07A2, 0x0464, 0x0232, 0x8000, 0x8000 },
|
||||
// Reverb off
|
||||
{ 0x0010 / 2,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||
0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||
0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0000 }
|
||||
};
|
||||
|
||||
struct Frame {
|
||||
int16 L, R;
|
||||
};
|
||||
@@ -65,34 +125,10 @@ namespace Sound {
|
||||
} stats;
|
||||
|
||||
namespace Filter {
|
||||
#define MAX_FDN 16
|
||||
#define MAX_DELAY 954
|
||||
|
||||
#define DSP_SCALE_BIT 8
|
||||
#define DSP_SCALE (1 << DSP_SCALE_BIT)
|
||||
|
||||
static const int16 FDN[MAX_FDN] = { 281, 331, 373, 419, 461, 503, 547, 593, 641, 683, 727, 769, 811, 853, 907, 953 };
|
||||
|
||||
struct Delay {
|
||||
int index;
|
||||
int16 out[MAX_DELAY];
|
||||
|
||||
void process(int16 &x, int16 delay) {
|
||||
index = (index + 1) % delay;
|
||||
int16 y = out[index];
|
||||
out[index] = x;
|
||||
x = y;
|
||||
}
|
||||
};
|
||||
|
||||
struct Absorption {
|
||||
int16 out;
|
||||
|
||||
void process(int16 &x, int32 gain, int32 damping) {
|
||||
x = out = (out * damping + ((x * gain * (DSP_SCALE - damping)) >> DSP_SCALE_BIT)) >> DSP_SCALE_BIT;
|
||||
}
|
||||
};
|
||||
|
||||
struct LowPass {
|
||||
float buffer[2][4];
|
||||
|
||||
@@ -117,88 +153,80 @@ namespace Sound {
|
||||
};
|
||||
|
||||
struct Reverberation {
|
||||
Delay df[MAX_FDN];
|
||||
Absorption af[MAX_FDN];
|
||||
int32 pos;
|
||||
int16 buffer[0x8000];
|
||||
|
||||
int32 output[MAX_FDN];
|
||||
int16 buffer[MAX_FDN];
|
||||
int16 panCoeff[MAX_FDN][2];
|
||||
int32 absCoeff[MAX_FDN][2]; // absorption gain & damping
|
||||
ReverbPreset preset;
|
||||
|
||||
Reverberation() {
|
||||
for (int i = 0; i < MAX_FDN; i++) {
|
||||
panCoeff[i][0] = (i % 2) ? -1 : 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_FDN; i += 2) {
|
||||
if ((i / 2) % 2)
|
||||
panCoeff[i][1] = panCoeff[i + 1][1] = -1;
|
||||
else
|
||||
panCoeff[i][1] = panCoeff[i + 1][1] = 1;
|
||||
}
|
||||
|
||||
memcpy(&preset, SPU_REVERB + 0, sizeof(preset));
|
||||
clear();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
memset(output, 0, sizeof(output));
|
||||
memset(df, 0, sizeof(df));
|
||||
memset(af, 0, sizeof(af));
|
||||
|
||||
// TODO
|
||||
setRoomSize(vec3(1.0f));
|
||||
}
|
||||
|
||||
void setRoomSize(const vec3 &size) {
|
||||
float S = (size.x * size.z + size.x * size.y + size.z * size.y) * 2;
|
||||
float V = size.x * size.y * size.z;
|
||||
float f = 0.1f; // absorption factor
|
||||
float rt60 = 0.161f * (V / (S * f));
|
||||
float k = -10.0f / (44100.0f * rt60);
|
||||
|
||||
for (int i = 0; i < MAX_FDN; i++) {
|
||||
float v = powf(10.0f, FDN[i] * k);
|
||||
absCoeff[i][0] = int32(v * DSP_SCALE);
|
||||
absCoeff[i][1] = int32((1.0f - (2.0f / (1.0f + powf(v, 1.0f - 1.0f / 0.15f)))) * DSP_SCALE);
|
||||
}
|
||||
// TODO
|
||||
};
|
||||
|
||||
int16& value(int index) {
|
||||
index += pos;
|
||||
if (index >= preset.size) index -= preset.size;
|
||||
if (index < 0) index += preset.size;
|
||||
return buffer[index];
|
||||
}
|
||||
|
||||
#define R(x) int32(preset.##x)
|
||||
#define V(x) value(R(x))
|
||||
#define D(a,b) value(preset.##a - preset.##b)
|
||||
|
||||
void process(FrameHI *frames, int count) {
|
||||
PROFILE_CPU_TIMING(stats.reverb);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
FrameHI &frame = frames[i];
|
||||
int32 in = (frame.L + frame.R) / 2;
|
||||
int32 out = 0;
|
||||
int32 L = 0;
|
||||
int32 R = 0;
|
||||
|
||||
// apply delay & absorption filters
|
||||
for (int j = 0; j < MAX_FDN; j++) {
|
||||
int16 k = clamp(in + output[j], -0x7FFF, 0x7FFF);
|
||||
df[j].process(k, FDN[j]);
|
||||
af[j].process(k, absCoeff[j][0], absCoeff[j][1]);
|
||||
buffer[j] = k;
|
||||
out += k;
|
||||
int32 Lin = frame.L;
|
||||
int32 Rin = frame.R;
|
||||
|
||||
// Same Side Reflection (left-to-left and right-to-right)
|
||||
V(mLSAME) = ((Lin + (V(dLSAME) * R(vWALL) >> 15) - V(mLSAME - 1)) * R(vIIR) >> 15) + V(mLSAME - 1);
|
||||
V(mRSAME) = ((Rin + (V(dRSAME) * R(vWALL) >> 15) - V(mRSAME - 1)) * R(vIIR) >> 15) + V(mRSAME - 1);
|
||||
|
||||
// Different Side Reflection (left-to-right and right-to-left)
|
||||
V(mLDIFF) = ((Lin + (V(dRDIFF) * R(vWALL) >> 15) - V(mLDIFF - 1)) * R(vIIR) >> 15) + V(mLDIFF - 1);
|
||||
V(mRDIFF) = ((Rin + (V(dLDIFF) * R(vWALL) >> 15) - V(mRDIFF - 1)) * R(vIIR) >> 15) + V(mRDIFF - 1);
|
||||
|
||||
// Early Echo (Comb Filter, with input from buffer)
|
||||
int32 Lout = (R(vCOMB1) * V(mLCOMB1) + R(vCOMB2) * V(mLCOMB2) + R(vCOMB3) * V(mLCOMB3) + R(vCOMB4) * V(mLCOMB4)) >> 15;
|
||||
int32 Rout = (R(vCOMB1) * V(mRCOMB1) + R(vCOMB2) * V(mRCOMB2) + R(vCOMB3) * V(mRCOMB3) + R(vCOMB4) * V(mRCOMB4)) >> 15;
|
||||
|
||||
// Late Reverb APF1 (All Pass Filter 1, with input from COMB)
|
||||
Lout = Lout - (R(vAPF1) * D(mLAPF1, dAPF1) >> 15); V(mLAPF1) = Lout; Lout = (Lout * R(vAPF1) >> 15) + D(mLAPF1, dAPF1);
|
||||
Rout = Rout - (R(vAPF1) * D(mRAPF1, dAPF1) >> 15); V(mRAPF1) = Rout; Rout = (Rout * R(vAPF1) >> 15) + D(mRAPF1, dAPF1);
|
||||
|
||||
// Late Reverb APF2 (All Pass Filter 2, with input from APF1)
|
||||
Lout = Lout - (R(vAPF2) * D(mLAPF2, dAPF2) >> 15); V(mLAPF2) = Lout; Lout = (Lout * R(vAPF2) >> 15) + D(mLAPF2, dAPF2);
|
||||
Rout = Rout - (R(vAPF2) * D(mRAPF2, dAPF2) >> 15); V(mRAPF2) = Rout; Rout = (Rout * R(vAPF2) >> 15) + D(mRAPF2, dAPF2);
|
||||
|
||||
// Output to Mixer (Output volume multiplied with input from APF2)
|
||||
frame.L = Lout;
|
||||
frame.R = Rout;
|
||||
|
||||
pos++;
|
||||
if (pos >= preset.size) {
|
||||
pos -= preset.size;
|
||||
}
|
||||
out = out * 2 / MAX_FDN;
|
||||
|
||||
// apply pan
|
||||
int16 buf = buffer[MAX_FDN - 1];
|
||||
for (int j = 0; j < MAX_FDN; j++) {
|
||||
output[j] = max(0, out - buf);
|
||||
buf = buffer[j];
|
||||
L += buf ^ panCoeff[j][0];
|
||||
R += buf ^ panCoeff[j][1];
|
||||
}
|
||||
|
||||
frame.L += L / MAX_FDN;
|
||||
frame.R += R / MAX_FDN;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#undef MAX_FDN
|
||||
#undef MAX_DELAY
|
||||
#undef R
|
||||
#undef V
|
||||
#undef D
|
||||
};
|
||||
};
|
||||
|
||||
struct Decoder {
|
||||
|
Reference in New Issue
Block a user