~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to Core/HW/SasReverb.cpp

  • Committer: Sérgio Benjamim
  • Date: 2017-01-02 00:12:05 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20170102001205-cxbta9za203nmjwm
1.3.0 source (from ppsspp_1.3.0-r160.p5.l1762.a165.t83~56~ubuntu16.04.1.tar.xz).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) 2015- PPSSPP Project.
 
2
 
 
3
// This program is free software: you can redistribute it and/or modify
 
4
// it under the terms of the GNU General Public License as published by
 
5
// the Free Software Foundation, version 2.0 or later versions.
 
6
 
 
7
// This program is distributed in the hope that it will be useful,
 
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
// GNU General Public License 2.0 for more details.
 
11
 
 
12
// A copy of the GPL 2.0 should have been included with the program.
 
13
// If not, see http://www.gnu.org/licenses/
 
14
 
 
15
// Official git repository and contact information can be found at
 
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
 
17
 
 
18
#include <stdint.h>
 
19
 
 
20
#include "base/basictypes.h"
 
21
#include "Globals.h"
 
22
#include "Core/HW/SasReverb.h"
 
23
 
 
24
 
 
25
// This is under the assumption that the reverb used in Sas is the same as the PSX SPU reverb.
 
26
 
 
27
// Source: http://problemkaputt.de/psx-spx.htm#spureverbformula
 
28
 
 
29
struct SasReverbData {
 
30
        const char *name;
 
31
        int32_t size;
 
32
 
 
33
        int16_t dAPF1;
 
34
        int16_t dAPF2;
 
35
        int16_t vIIR;
 
36
        int16_t vCOMB1;
 
37
        int16_t vCOMB2;
 
38
        int16_t vCOMB3;
 
39
        int16_t vCOMB4;
 
40
        int16_t vWALL;
 
41
 
 
42
        int16_t vAPF1;
 
43
        int16_t vAPF2;
 
44
        int16_t mLSAME;
 
45
        int16_t mRSAME;
 
46
        int16_t mLCOMB1;
 
47
        int16_t mRCOMB1;
 
48
        int16_t mLCOMB2;
 
49
        int16_t mRCOMB2;
 
50
 
 
51
        int16_t dLSAME;
 
52
        int16_t dRSAME;
 
53
        int16_t mLDIFF;
 
54
        int16_t mRDIFF;
 
55
        int16_t mLCOMB3;
 
56
        int16_t mRCOMB3;
 
57
        int16_t mLCOMB4;
 
58
        int16_t mRCOMB4;
 
59
 
 
60
        int16_t dLDIFF;
 
61
        int16_t dRDIFF;
 
62
        int16_t mLAPF1;
 
63
        int16_t mRAPF1;
 
64
        int16_t mLAPF2;
 
65
        int16_t mRAPF2;
 
66
 
 
67
        // These aren't used for anything else than 1.0 in any of the presets so let's drop them.
 
68
        // int16_t vLIN;
 
69
        // int16_t vRIN;
 
70
};
 
71
 
 
72
static const SasReverbData presets[10] = {
 
73
        {
 
74
                "Room",
 
75
                0x26C0,
 
76
                0x007D,0x005B,0x6D80,0x54B8,(int16_t)0xBED0,0x0000,0x0000,(int16_t)0xBA80,
 
77
                0x5800,0x5300,0x04D6,0x0333,0x03F0,0x0227,0x0374,0x01EF,
 
78
                0x0334,0x01B5,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 
79
                0x0000,0x0000,0x01B4,0x0136,0x00B8,0x005C, //(int16_t)0x8000,(int16_t)0x8000,
 
80
        },
 
81
        {
 
82
                "Studio Small",
 
83
                0x1F40,
 
84
                0x0033,0x0025,0x70F0,0x4FA8,(int16_t)0xBCE0,0x4410,(int16_t)0xC0F0,(int16_t)0x9C00,
 
85
                0x5280,0x4EC0,0x03E4,0x031B,0x03A4,0x02AF,0x0372,0x0266,
 
86
                0x031C,0x025D,0x025C,0x018E,0x022F,0x0135,0x01D2,0x00B7,
 
87
                0x018F,0x00B5,0x00B4,0x0080,0x004C,0x0026, //(int16_t)0x8000,(int16_t)0x8000,
 
88
        },
 
89
 
 
90
        {
 
91
                "Studio Medium",
 
92
                0x4840,
 
93
                0x00B1,0x007F,0x70F0,0x4FA8,(int16_t)0xBCE0,0x4510,(int16_t)0xBEF0,(int16_t)0xB4C0,
 
94
                0x5280,0x4EC0,0x0904,0x076B,0x0824,0x065F,0x07A2,0x0616,
 
95
                0x076C,0x05ED,0x05EC,0x042E,0x050F,0x0305,0x0462,0x02B7,
 
96
                0x042F,0x0265,0x0264,0x01B2,0x0100,0x0080, //(int16_t)0x8000,(int16_t)0x8000,
 
97
        },
 
98
 
 
99
        // Studio Large(size = 6FE0h bytes)
 
100
        {
 
101
                "Studio Large",
 
102
                0x6FE0,
 
103
                0x00E3,0x00A9,0x6F60,0x4FA8,(int16_t)0xBCE0,0x4510,(int16_t)0xBEF0,(int16_t)0xA680,
 
104
                0x5680,0x52C0,0x0DFB,0x0B58,0x0D09,0x0A3C,0x0BD9,0x0973,
 
105
                0x0B59,0x08DA,0x08D9,0x05E9,0x07EC,0x04B0,0x06EF,0x03D2,
 
106
                0x05EA,0x031D,0x031C,0x0238,0x0154,0x00AA, //(int16_t)0x8000,(int16_t)0x8000,
 
107
        },
 
108
 
 
109
        {
 
110
                "Hall",
 
111
                0xADE0,
 
112
                0x01A5,0x0139,0x6000,0x5000,0x4C00,(int16_t)0xB800,(int16_t)0xBC00,(int16_t)0xC000,
 
113
                0x6000,0x5C00,0x15BA,0x11BB,0x14C2,0x10BD,0x11BC,0x0DC1,
 
114
                0x11C0,0x0DC3,0x0DC0,0x09C1,0x0BC4,0x07C1,0x0A00,0x06CD,
 
115
                0x09C2,0x05C1,0x05C0,0x041A,0x0274,0x013A, //(int16_t)0x8000,(int16_t)0x8000,
 
116
        },
 
117
 
 
118
        {
 
119
                "Space Echo",
 
120
                0xF6C0,
 
121
                0x033D,0x0231,0x7E00,0x5000,(int16_t)0xB400,(int16_t)0xB000,0x4C00,(int16_t)0xB000,
 
122
                0x6000,0x5400,0x1ED6,0x1A31,0x1D14,0x183B,0x1BC2,0x16B2,
 
123
                0x1A32,0x15EF,0x15EE,0x1055,0x1334,0x0F2D,0x11F6,0x0C5D,
 
124
                0x1056,0x0AE1,0x0AE0,0x07A2,0x0464,0x0232, //(int16_t)0x8000,(int16_t)0x8000,
 
125
        },
 
126
 
 
127
        {
 
128
                "Echo (almost infinite)",
 
129
                0x18040,
 
130
                0x0001,0x0001,0x7FFF,0x7FFF,0x0000,0x0000,0x0000,(int16_t)0xC080,
 
131
                0x0000,0x0000,0x1FFF,0x0FFF,0x1005,0x0005,0x0000,0x0000,
 
132
                0x1005,0x0005,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 
133
                0x0000,0x0000,0x1004,0x1002,0x0004,0x0002, //(int16_t)0x8000,(int16_t)0x8000,
 
134
        },
 
135
 
 
136
        {
 
137
                "Delay (one - shot echo)",
 
138
                0x18040,
 
139
                0x0001,0x0001,0x7FFF,0x7FFF,0x0000,0x0000,0x0000,0x0000,
 
140
                0x0000,0x0000,0x1FFF,0x0FFF,0x1005,0x0005,0x0000,0x0000,
 
141
                0x1005,0x0005,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
 
142
                0x0000,0x0000,0x1004,0x1002,0x0004,0x0002, //(int16_t)0x8000,(int16_t)0x8000,
 
143
        },
 
144
 
 
145
        {
 
146
                "Half Echo",
 
147
                0x3C00,
 
148
                0x0017,0x0013,0x70F0,0x4FA8,(int16_t)0xBCE0,0x4510,(int16_t)0xBEF0,(int16_t)0x8500,
 
149
                0x5F80,0x54C0,0x0371,0x02AF,0x02E5,0x01DF,0x02B0,0x01D7,
 
150
                0x0358,0x026A,0x01D6,0x011E,0x012D,0x00B1,0x011F,0x0059,
 
151
                0x01A0,0x00E3,0x0058,0x0040,0x0028,0x0014, //(int16_t)0x8000,(int16_t)0x8000,
 
152
        },
 
153
};
 
154
 
 
155
SasReverb::SasReverb() : preset_(-1), pos_(0) {
 
156
        workspace_ = new int16_t[BUFSIZE];
 
157
}
 
158
 
 
159
SasReverb::~SasReverb() {
 
160
        delete[] workspace_;
 
161
}
 
162
 
 
163
const char *SasReverb::GetPresetName(int preset) {
 
164
        if (preset == -1) {
 
165
                return "Off";
 
166
        }
 
167
        return presets[preset].name;
 
168
}
 
169
 
 
170
void SasReverb::SetPreset(int preset) {
 
171
        if (preset < (int)ARRAY_SIZE(presets))
 
172
                preset_ = preset;
 
173
        if (preset_ != -1) {
 
174
                pos_ = BUFSIZE - presets[preset_].size;
 
175
                memset(workspace_, 0, sizeof(int16_t) * BUFSIZE);
 
176
        } else {
 
177
                pos_ = 0;
 
178
        }
 
179
}
 
180
 
 
181
// Wraps around the upper part of a buffer.
 
182
template<int bufsize>
 
183
class BufferWrapper {
 
184
public:
 
185
        BufferWrapper(int16_t *buffer, int position, int usedSize) : buf_(buffer), pos_(position), end_(bufsize), base_(bufsize - usedSize), size_(usedSize) {}
 
186
        int16_t &operator [](int index) {
 
187
                int addr = pos_ + index;
 
188
                if (addr >= end_) { addr -= size_; }
 
189
                if (addr < base_) { addr += size_; }
 
190
                return buf_[addr];
 
191
        }
 
192
 
 
193
        int GetPosition() { return pos_; }
 
194
        void Next() {
 
195
                pos_++;
 
196
                if (pos_ >= end_) {
 
197
                        pos_ -= size_;
 
198
                }
 
199
        }
 
200
 
 
201
private:
 
202
        int16_t *buf_;
 
203
        int pos_;
 
204
        int end_;
 
205
        int base_;
 
206
        int size_;
 
207
};
 
208
 
 
209
void SasReverb::ProcessReverb(int16_t *output, const int16_t *input, size_t inputSize, uint16_t volLeft, uint16_t volRight) {
 
210
        // This means replicate the input signal in the processed buffer.
 
211
        // Can also be used to verify that the error is in here...
 
212
        if (preset_ == -1) {
 
213
                // Strangely, OFF is not filled with zeroes every other.  Seems special cased.
 
214
                for (size_t i = 0; i < inputSize; ++i) {
 
215
                        output[i * 4 + 0] = clamp_s16((int)input[i * 2 + 0] * volLeft >> 15);
 
216
                        output[i * 4 + 1] = clamp_s16((int)input[i * 2 + 1] * volRight >> 15);
 
217
                        output[i * 4 + 2] = clamp_s16((int)input[i * 2 + 0] * volLeft >> 15);
 
218
                        output[i * 4 + 3] = clamp_s16((int)input[i * 2 + 1] * volRight >> 15);
 
219
                }
 
220
                return;
 
221
        }
 
222
 
 
223
        const SasReverbData &d = presets[preset_];
 
224
 
 
225
        // We put this on the stack instead of in the object to let the compiler optimize better (avoid mem r/w).
 
226
        BufferWrapper<BUFSIZE> b(workspace_, pos_, d.size);
 
227
 
 
228
        // This runs at 22khz.
 
229
        // Very unoptimized, straight from the description. Can probably be reformulated into something way more efficient.
 
230
        // Or we could actually template the whole thing with the parameters as template arguments, as the presets are fixed.
 
231
        for (size_t i = 0; i < inputSize; i++) {
 
232
                // Dividing by two here is an incorrect hack. Some multiplication factor is needed to prevent the reverb from getting too loud, though.
 
233
                int16_t LeftInput = input[i * 2] >> 1;
 
234
                int16_t RightInput = input[i * 2 + 1] >> 1;
 
235
 
 
236
                int16_t Lin = LeftInput; //  (d.vLIN * LeftInput) >> 15;
 
237
                int16_t Rin = RightInput; // (d.vRIN * RightInput) >> 15;
 
238
 
 
239
                // ____Same Side Reflection(left - to - left and right - to - right)___________________
 
240
                b[d.mLSAME] = clamp_s16(Lin + (b[d.dLSAME] * d.vWALL >> 15) - (b[d.mLSAME - 1]*d.vIIR >> 15) + b[d.mLSAME - 1]); // L - to - L
 
241
                b[d.mRSAME] = clamp_s16(Rin + (b[d.dRSAME] * d.vWALL >> 15) - (b[d.mRSAME - 1]*d.vIIR >> 15) + b[d.mRSAME - 1]); // R - to - R
 
242
                // ___Different Side Reflection(left - to - right and right - to - left)_______________
 
243
                b[d.mLDIFF] = clamp_s16(Lin + (b[d.dRDIFF] * d.vWALL >> 15) - (b[d.mLDIFF - 1]*d.vIIR >> 15) + b[d.mLDIFF - 1]); // R - to - L
 
244
                b[d.mRDIFF] = clamp_s16(Rin + (b[d.dLDIFF] * d.vWALL >> 15) - (b[d.mRDIFF - 1]*d.vIIR >> 15) + b[d.mRDIFF - 1]); // L - to - R
 
245
                // ___Early Echo(Comb Filter, with input from buffer)__________________________
 
246
                int32_t Lout = ((d.vCOMB1*b[d.mLCOMB1] + d.vCOMB2*b[d.mLCOMB2] + d.vCOMB3*b[d.mLCOMB3] + d.vCOMB4*b[d.mLCOMB4]) >> 15);
 
247
                int32_t Rout = ((d.vCOMB1*b[d.mRCOMB1] + d.vCOMB2*b[d.mRCOMB2] + d.vCOMB3*b[d.mRCOMB3] + d.vCOMB4*b[d.mRCOMB4]) >> 15);
 
248
                // ___Late Reverb APF1(All Pass Filter 1, with input from COMB)________________
 
249
                b[d.mLAPF1] = clamp_s16(Lout - (d.vAPF1*b[(d.mLAPF1 - d.dAPF1)] >> 15));
 
250
                Lout = b[(d.mLAPF1 - d.dAPF1)] + (b[d.mLAPF1] * d.vAPF1 >> 15);
 
251
                b[d.mRAPF1] = clamp_s16(Rout - (d.vAPF1*b[(d.mRAPF1 - d.dAPF1)] >> 15));
 
252
                Rout = b[(d.mRAPF1 - d.dAPF1)] + (b[d.mRAPF1] * d.vAPF1 >> 15);
 
253
                // ___Late Reverb APF2(All Pass Filter 2, with input from APF1)________________
 
254
                b[d.mLAPF2] = clamp_s16(Lout - (d.vAPF2*b[(d.mLAPF2 - d.dAPF2)] >> 15));
 
255
                Lout = b[(d.mLAPF2 - d.dAPF2)] + (b[d.mLAPF2] * d.vAPF2 >> 15);
 
256
                b[d.mRAPF2] = clamp_s16(Rout - (d.vAPF2*b[(d.mRAPF2 - d.dAPF2)] >> 15));
 
257
                Rout = b[(d.mRAPF2 - d.dAPF2)] + (b[d.mRAPF2] * d.vAPF2 >> 15);
 
258
                // ___Output to Mixer(Output volume multiplied with input from APF2)___________
 
259
                output[i * 4 + 0] = clamp_s16(Lout * volLeft >> 15);
 
260
                output[i * 4 + 1] = clamp_s16(Rout * volRight >> 15);
 
261
                output[i * 4 + 2] = 0;
 
262
                output[i * 4 + 3] = 0;
 
263
 
 
264
                b.Next();
 
265
        }
 
266
 
 
267
        // Save the state in the object.
 
268
        pos_ = b.GetPosition();
 
269
}
 
270