Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/HW/SasAudio.cpp
3186 views
1
// Copyright (c) 2012- 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 <algorithm>
19
20
#include "Common/Profiler/Profiler.h"
21
22
#include "Common/Serialize/SerializeFuncs.h"
23
#include "Core/MemMapHelpers.h"
24
#include "Core/HLE/sceAtrac.h"
25
#include "Core/Config.h"
26
#include "Core/Reporting.h"
27
#include "Core/Util/AudioFormat.h"
28
#include "Core/System.h"
29
#include "SasAudio.h"
30
31
static const u8 f[16][2] = {
32
{ 0, 0 },
33
{ 60, 0 },
34
{ 115, 52 },
35
{ 98, 55 },
36
{ 122, 60 },
37
// TODO: The below values could use more testing, but match initial tests.
38
// Not sure if they are used by games, found by tests.
39
{ 0, 0 },
40
{ 0, 0 },
41
{ 52, 0 },
42
{ 55, 2 },
43
{ 60, 125 },
44
{ 0, 0 },
45
{ 0, 91 },
46
{ 0, 0 },
47
{ 2, 216 },
48
{ 125, 6 },
49
{ 0, 151 },
50
};
51
52
void VagDecoder::Start(u32 data, u32 vagSize, bool loopEnabled) {
53
loopEnabled_ = loopEnabled;
54
loopAtNextBlock_ = false;
55
loopStartBlock_ = -1;
56
numBlocks_ = vagSize / 16;
57
end_ = false;
58
data_ = data;
59
read_ = data;
60
curSample = 28;
61
curBlock_ = -1;
62
s_1 = 0; // per block?
63
s_2 = 0;
64
}
65
66
void VagDecoder::DecodeBlock(const u8 *&read_pointer) {
67
if (curBlock_ == numBlocks_ - 1) {
68
end_ = true;
69
return;
70
}
71
72
_dbg_assert_(curBlock_ < numBlocks_);
73
74
const u8 *readp = read_pointer;
75
int predict_nr = *readp++;
76
int shift_factor = predict_nr & 0xf;
77
predict_nr >>= 4;
78
int flags = *readp++;
79
if (flags == 7) {
80
VERBOSE_LOG(Log::SasMix, "VAG ending block at %d", curBlock_);
81
end_ = true;
82
return;
83
}
84
else if (flags == 6) {
85
loopStartBlock_ = curBlock_;
86
}
87
else if (flags == 3) {
88
if (loopEnabled_) {
89
loopAtNextBlock_ = true;
90
}
91
}
92
93
// Keep state in locals to avoid bouncing to memory.
94
int s1 = s_1;
95
int s2 = s_2;
96
97
int coef1 = f[predict_nr][0];
98
int coef2 = -f[predict_nr][1];
99
100
// TODO: Unroll once more and interleave the unpacking with the decoding more?
101
for (int i = 0; i < 28; i += 2) {
102
u8 d = *readp++;
103
int sample1 = (short)((d & 0xf) << 12) >> shift_factor;
104
int sample2 = (short)((d & 0xf0) << 8) >> shift_factor;
105
s2 = clamp_s16(sample1 + ((s1 * coef1 + s2 * coef2) >> 6));
106
s1 = clamp_s16(sample2 + ((s2 * coef1 + s1 * coef2) >> 6));
107
samples[i] = s2;
108
samples[i + 1] = s1;
109
}
110
111
s_1 = s1;
112
s_2 = s2;
113
curSample = 0;
114
curBlock_++;
115
116
read_pointer = readp;
117
}
118
119
void VagDecoder::GetSamples(s16 *outSamples, int numSamples) {
120
if (end_) {
121
memset(outSamples, 0, numSamples * sizeof(s16));
122
return;
123
}
124
if (!Memory::IsValidRange(read_, numBlocks_ * 16)) {
125
WARN_LOG_REPORT(Log::SasMix, "Bad VAG samples address? %08x / %d", read_, numBlocks_);
126
return;
127
}
128
129
const u8 *readp = Memory::GetPointerUnchecked(read_);
130
const u8 *origp = readp;
131
132
for (int i = 0; i < numSamples; i++) {
133
if (curSample == 28) {
134
if (loopAtNextBlock_) {
135
VERBOSE_LOG(Log::SasMix, "Looping VAG from block %d/%d to %d", curBlock_, numBlocks_, loopStartBlock_);
136
// data_ starts at curBlock = -1.
137
read_ = data_ + 16 * loopStartBlock_ + 16;
138
readp = Memory::GetPointerUnchecked(read_);
139
origp = readp;
140
curBlock_ = loopStartBlock_;
141
loopAtNextBlock_ = false;
142
}
143
DecodeBlock(readp);
144
if (end_) {
145
// Clear the rest of the buffer and return.
146
memset(&outSamples[i], 0, (numSamples - i) * sizeof(s16));
147
return;
148
}
149
}
150
_dbg_assert_(curSample < 28);
151
outSamples[i] = samples[curSample++];
152
}
153
154
if (readp > origp) {
155
if (MemBlockInfoDetailed())
156
NotifyMemInfo(MemBlockFlags::READ, read_, readp - origp, "SasVagDecoder");
157
read_ += readp - origp;
158
}
159
}
160
161
void VagDecoder::DoState(PointerWrap &p) {
162
auto s = p.Section("VagDecoder", 1, 2);
163
if (!s)
164
return;
165
166
if (s >= 2) {
167
DoArray(p, samples, ARRAY_SIZE(samples));
168
} else {
169
int samplesOld[ARRAY_SIZE(samples)];
170
DoArray(p, samplesOld, ARRAY_SIZE(samples));
171
for (size_t i = 0; i < ARRAY_SIZE(samples); ++i) {
172
samples[i] = samplesOld[i];
173
}
174
}
175
Do(p, curSample);
176
177
Do(p, data_);
178
Do(p, read_);
179
Do(p, curBlock_);
180
Do(p, loopStartBlock_);
181
Do(p, numBlocks_);
182
183
Do(p, s_1);
184
Do(p, s_2);
185
186
Do(p, loopEnabled_);
187
Do(p, loopAtNextBlock_);
188
Do(p, end_);
189
}
190
191
int SasAtrac3::SetContext(u32 contextAddr) {
192
contextAddr_ = contextAddr;
193
// Note: On hardware, atracID_ is also stored in the loopNum member of the context.
194
// But we don't actually mirror our struct to memory, so it doesn't really matter.
195
atracID_ = AtracSasBindContextAndGetID(contextAddr);
196
if (!sampleQueue_)
197
sampleQueue_ = new BufferQueue();
198
sampleQueue_->clear();
199
end_ = false;
200
return 0;
201
}
202
203
void SasAtrac3::GetNextSamples(s16 *outbuf, int wantedSamples) {
204
if (atracID_ < 0) {
205
end_ = true;
206
return;
207
}
208
209
if (!buf_) {
210
buf_ = new s16[0x800];
211
}
212
213
int finish = 0;
214
int wantedbytes = wantedSamples * sizeof(s16);
215
while (!finish && sampleQueue_->getQueueSize() < wantedbytes) {
216
int numSamples = 0;
217
AtracSasDecodeData(atracID_, (u8*)buf_, &numSamples, &finish);
218
if (numSamples > 0)
219
sampleQueue_->push((u8*)buf_, numSamples * sizeof(s16));
220
else
221
finish = 1;
222
}
223
sampleQueue_->pop_front((u8*)outbuf, wantedbytes);
224
end_ = finish == 1;
225
}
226
227
int SasAtrac3::Concatenate(u32 bufPtr, u32 addbytes) {
228
if (atracID_ >= 0) {
229
AtracSasAddStreamData(atracID_, bufPtr, addbytes);
230
}
231
return 0;
232
}
233
234
void SasAtrac3::DoState(PointerWrap &p) {
235
auto s = p.Section("SasAtrac3", 1, 2);
236
if (!s)
237
return;
238
239
Do(p, contextAddr_);
240
Do(p, atracID_);
241
if (p.mode == p.MODE_READ && atracID_ >= 0 && !sampleQueue_) {
242
sampleQueue_ = new BufferQueue();
243
}
244
if (s >= 2) {
245
Do(p, end_);
246
}
247
}
248
249
// http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/sceSasCore.java
250
251
static int simpleRate(int n) {
252
n &= 0x7F;
253
if (n == 0x7F) {
254
return 0;
255
}
256
int rate = ((7 - (n & 0x3)) << 26) >> (n >> 2);
257
if (rate == 0) {
258
return 1;
259
}
260
return rate;
261
}
262
263
static int exponentRate(int n) {
264
n &= 0x7F;
265
if (n == 0x7F) {
266
return 0;
267
}
268
int rate = ((7 - (n & 0x3)) << 24) >> (n >> 2);
269
if (rate == 0) {
270
return 1;
271
}
272
return rate;
273
}
274
275
static int getAttackRate(int bitfield1) {
276
return simpleRate(bitfield1 >> 8);
277
}
278
279
static int getAttackType(int bitfield1) {
280
return (bitfield1 & 0x8000) == 0 ? PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE : PSP_SAS_ADSR_CURVE_MODE_LINEAR_BENT;
281
}
282
283
static int getDecayRate(int bitfield1) {
284
int n = (bitfield1 >> 4) & 0x000F;
285
if (n == 0)
286
return 0x7FFFFFFF;
287
return 0x80000000 >> n;
288
}
289
290
static int getSustainType(int bitfield2) {
291
return (bitfield2 >> 14) & 3;
292
}
293
294
static int getSustainRate(int bitfield2) {
295
if (getSustainType(bitfield2) == PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE) {
296
return exponentRate(bitfield2 >> 6);
297
} else {
298
return simpleRate(bitfield2 >> 6);
299
}
300
}
301
302
static int getReleaseType(int bitfield2) {
303
return (bitfield2 & 0x0020) == 0 ? PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE : PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE;
304
}
305
306
static int getReleaseRate(int bitfield2) {
307
int n = bitfield2 & 0x001F;
308
if (n == 31) {
309
return 0;
310
}
311
if (getReleaseType(bitfield2) == PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE) {
312
if (n == 30) {
313
return 0x40000000;
314
} else if (n == 29) {
315
return 1;
316
}
317
return 0x10000000 >> n;
318
}
319
if (n == 0)
320
return 0x7FFFFFFF;
321
return 0x80000000 >> n;
322
}
323
324
static int getSustainLevel(int bitfield1) {
325
return ((bitfield1 & 0x000F) + 1) << 26;
326
}
327
328
void ADSREnvelope::SetEnvelope(int flag, int a, int d, int s, int r) {
329
if ((flag & 0x1) != 0)
330
attackType = (SasADSRCurveMode)a;
331
if ((flag & 0x2) != 0)
332
decayType = (SasADSRCurveMode)d;
333
if ((flag & 0x4) != 0)
334
sustainType = (SasADSRCurveMode)s;
335
if ((flag & 0x8) != 0)
336
releaseType = (SasADSRCurveMode)r;
337
338
if (PSP_CoreParameter().compat.flags().RockmanDash2SoundFix && sustainType == PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE) {
339
sustainType = PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE;
340
}
341
}
342
343
void ADSREnvelope::SetRate(int flag, int a, int d, int s, int r) {
344
if ((flag & 0x1) != 0)
345
attackRate = a;
346
if ((flag & 0x2) != 0)
347
decayRate = d;
348
if ((flag & 0x4) != 0)
349
sustainRate = s;
350
if ((flag & 0x8) != 0)
351
releaseRate = r;
352
}
353
354
void ADSREnvelope::SetSimpleEnvelope(u32 ADSREnv1, u32 ADSREnv2) {
355
attackRate = getAttackRate(ADSREnv1);
356
attackType = (SasADSRCurveMode)getAttackType(ADSREnv1);
357
decayRate = getDecayRate(ADSREnv1);
358
decayType = PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE;
359
sustainRate = getSustainRate(ADSREnv2);
360
sustainType = (SasADSRCurveMode)getSustainType(ADSREnv2);
361
releaseRate = getReleaseRate(ADSREnv2);
362
releaseType = (SasADSRCurveMode)getReleaseType(ADSREnv2);
363
sustainLevel = getSustainLevel(ADSREnv1);
364
365
if (PSP_CoreParameter().compat.flags().RockmanDash2SoundFix && sustainType == PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE) {
366
sustainType = PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE;
367
}
368
369
if (attackRate < 0 || decayRate < 0 || sustainRate < 0 || releaseRate < 0) {
370
ERROR_LOG_REPORT(Log::SasMix, "Simple ADSR resulted in invalid rates: %04x, %04x", ADSREnv1, ADSREnv2);
371
}
372
}
373
374
SasInstance::SasInstance() {
375
memset(&waveformEffect, 0, sizeof(waveformEffect));
376
waveformEffect.type = PSP_SAS_EFFECT_TYPE_OFF;
377
waveformEffect.isDryOn = 1;
378
memset(mixTemp_, 0, sizeof(mixTemp_)); // just to avoid a static analysis warning.
379
}
380
381
SasInstance::~SasInstance() {
382
ClearGrainSize();
383
}
384
385
void SasInstance::GetDebugText(char *text, size_t bufsize) {
386
char voiceBuf[4096];
387
voiceBuf[0] = '\0';
388
char *p = voiceBuf;
389
for (int i = 0; i < maxVoices; i++) {
390
if (voices[i].playing) {
391
uint32_t readAddr = voices[i].GetReadAddress();
392
const char *indicator = "";
393
switch (voices[i].type) {
394
case VOICETYPE_VAG:
395
if (readAddr < voices[i].vagAddr || readAddr > voices[i].vagAddr + voices[i].vagSize) {
396
indicator = " (BAD!)";
397
}
398
break;
399
default:
400
break;
401
}
402
p += snprintf(p, sizeof(voiceBuf) - (p - voiceBuf), " %d: Pitch %04x L/R,FX: %d,%d|%d,%d VAG: %08x:%d:%08x%s Height:%d%%\n", i,
403
voices[i].pitch, voices[i].volumeLeft, voices[i].volumeRight, voices[i].effectLeft, voices[i].effectRight,
404
voices[i].vagAddr, voices[i].vagSize, voices[i].GetReadAddress(), indicator, (int)((int64_t)voices[i].envelope.GetHeight() * 100 / PSP_SAS_ENVELOPE_HEIGHT_MAX));
405
p += snprintf(p, sizeof(voiceBuf) - (p - voiceBuf), " - ADSR: %s/%s/%s/%s\n",
406
ADSRCurveModeAsString(voices[i].envelope.attackType),
407
ADSRCurveModeAsString(voices[i].envelope.decayType),
408
ADSRCurveModeAsString(voices[i].envelope.sustainType),
409
ADSRCurveModeAsString(voices[i].envelope.releaseType)
410
);
411
}
412
}
413
414
snprintf(text, bufsize,
415
"SR: %d Mode: %s Grain: %d\n"
416
"Effect: Type: %d Dry: %d Wet: %d L: %d R: %d Delay: %d Feedback: %d\n"
417
"\n%s\n",
418
sampleRate, outputMode == PSP_SAS_OUTPUTMODE_RAW ? "Raw" : "Mixed", grainSize,
419
waveformEffect.type, waveformEffect.isDryOn, waveformEffect.isWetOn, waveformEffect.leftVol, waveformEffect.rightVol, waveformEffect.delay, waveformEffect.feedback,
420
voiceBuf);
421
422
}
423
424
void SasInstance::ClearGrainSize() {
425
delete[] mixBuffer;
426
delete[] sendBuffer;
427
delete[] sendBufferDownsampled;
428
delete[] sendBufferProcessed;
429
mixBuffer = nullptr;
430
sendBuffer = nullptr;
431
sendBufferDownsampled = nullptr;
432
sendBufferProcessed = nullptr;
433
}
434
435
void SasInstance::SetGrainSize(int newGrainSize) {
436
grainSize = newGrainSize;
437
438
// If you change the sizes here, don't forget DoState().
439
delete[] mixBuffer;
440
delete[] sendBuffer;
441
delete[] sendBufferDownsampled;
442
delete[] sendBufferProcessed;
443
444
mixBuffer = new s32[grainSize * 2];
445
sendBuffer = new s32[grainSize * 2];
446
sendBufferDownsampled = new s16[grainSize];
447
sendBufferProcessed = new s16[grainSize * 2];
448
memset(mixBuffer, 0, sizeof(int) * grainSize * 2);
449
memset(sendBuffer, 0, sizeof(int) * grainSize * 2);
450
memset(sendBufferDownsampled, 0, sizeof(s16) * grainSize);
451
memset(sendBufferProcessed, 0, sizeof(s16) * grainSize * 2);
452
}
453
454
int SasInstance::EstimateMixUs() {
455
int voicesPlayingCount = 0;
456
457
for (int v = 0; v < PSP_SAS_VOICES_MAX; v++) {
458
SasVoice &voice = voices[v];
459
if (!voice.playing || voice.paused)
460
continue;
461
voicesPlayingCount++;
462
}
463
464
// Each voice costs extra time, and each byte of grain costs extra time.
465
int cycles = 20 + voicesPlayingCount * 68 + (grainSize * 60) / 100;
466
// Cap to 1200 to fix FFT, see issue #9956.
467
return std::min(cycles, 1200);
468
}
469
470
void SasVoice::ReadSamples(s16 *output, int numSamples) {
471
// Read N samples into the resample buffer. Could do either PCM or VAG here.
472
switch (type) {
473
case VOICETYPE_VAG:
474
vag.GetSamples(output, numSamples);
475
break;
476
case VOICETYPE_PCM:
477
{
478
int needed = numSamples;
479
s16 *out = output;
480
while (needed > 0) {
481
u32 size = std::min(pcmSize - pcmIndex, needed);
482
if (!on) {
483
pcmIndex = 0;
484
break;
485
}
486
Memory::Memcpy(out, pcmAddr + pcmIndex * sizeof(s16), size * sizeof(s16), "SasVoicePCM");
487
pcmIndex += size;
488
needed -= size;
489
out += size;
490
if (pcmIndex >= pcmSize) {
491
if (!loop) {
492
// All out, quit. We'll end in HaveSamplesEnded().
493
break;
494
}
495
pcmIndex = pcmLoopPos;
496
}
497
}
498
if (needed > 0) {
499
memset(out, 0, needed * sizeof(s16));
500
}
501
}
502
break;
503
case VOICETYPE_ATRAC3:
504
atrac3.GetNextSamples(output, numSamples);
505
break;
506
default:
507
memset(output, 0, numSamples * sizeof(s16));
508
break;
509
}
510
}
511
512
bool SasVoice::HaveSamplesEnded() const {
513
switch (type) {
514
case VOICETYPE_VAG:
515
return vag.End();
516
517
case VOICETYPE_PCM:
518
return pcmIndex >= pcmSize;
519
520
case VOICETYPE_ATRAC3:
521
return atrac3.End();
522
523
default:
524
return false;
525
}
526
}
527
528
void SasInstance::MixVoice(SasVoice &voice) {
529
switch (voice.type) {
530
case VOICETYPE_VAG:
531
if (voice.type == VOICETYPE_VAG && !voice.vagAddr)
532
break;
533
// else fallthrough! Don't change the check above.
534
[[fallthrough]];
535
case VOICETYPE_PCM:
536
if (voice.type == VOICETYPE_PCM && !voice.pcmAddr)
537
break;
538
// else fallthrough! Don't change the check above.
539
[[fallthrough]];
540
default:
541
// This feels a bit hacky. The first 32 samples after a keyon are 0s.
542
int delay = 0;
543
if (voice.envelope.NeedsKeyOn()) {
544
const bool ignorePitch = voice.type == VOICETYPE_PCM && voice.pitch > PSP_SAS_PITCH_BASE;
545
delay = ignorePitch ? 32 : (32 * (u32)voice.pitch) >> PSP_SAS_PITCH_BASE_SHIFT;
546
// VAG seems to have an extra sample delay (not shared by PCM.)
547
if (voice.type == VOICETYPE_VAG)
548
++delay;
549
}
550
551
// Resample to the correct pitch, writing exactly "grainSize" samples. We need a buffer that can
552
// fit 4x that, as the max pitch is 0x4000.
553
// TODO: Special case no-resample case (and 2x and 0.5x) for speed, it's not uncommon
554
555
// Two passes: First read, then resample.
556
mixTemp_[0] = voice.resampleHist[0];
557
mixTemp_[1] = voice.resampleHist[1];
558
559
int voicePitch = voice.pitch;
560
u32 sampleFrac = voice.sampleFrac;
561
int samplesToRead = (sampleFrac + voicePitch * std::max(0, grainSize - delay)) >> PSP_SAS_PITCH_BASE_SHIFT;
562
if (samplesToRead > ARRAY_SIZE(mixTemp_) - 2) {
563
ERROR_LOG(Log::sceSas, "Too many samples to read (%d)! This shouldn't happen.", samplesToRead);
564
samplesToRead = ARRAY_SIZE(mixTemp_) - 2;
565
}
566
int readPos = 2;
567
if (voice.envelope.NeedsKeyOn()) {
568
readPos = 0;
569
samplesToRead += 2;
570
}
571
voice.ReadSamples(&mixTemp_[readPos], samplesToRead);
572
int tempPos = readPos + samplesToRead;
573
574
for (int i = 0; i < delay; ++i) {
575
// Walk the curve. This means we'll reach ATTACK already, likely.
576
// This matches the results of tests (but maybe we can just remove the STATE_KEYON_STEP hack.)
577
voice.envelope.Step();
578
}
579
580
const bool needsInterp = voicePitch != PSP_SAS_PITCH_BASE || (sampleFrac & PSP_SAS_PITCH_MASK) != 0;
581
for (int i = delay; i < grainSize; i++) {
582
const int16_t *s = mixTemp_ + (sampleFrac >> PSP_SAS_PITCH_BASE_SHIFT);
583
584
// Linear interpolation. Good enough. Need to make resampleHist bigger if we want more.
585
int sample = s[0];
586
if (needsInterp) {
587
int f = sampleFrac & PSP_SAS_PITCH_MASK;
588
sample = (s[0] * (PSP_SAS_PITCH_MASK - f) + s[1] * f) >> PSP_SAS_PITCH_BASE_SHIFT;
589
}
590
sampleFrac += voicePitch;
591
592
// The maximum envelope height (PSP_SAS_ENVELOPE_HEIGHT_MAX) is (1 << 30) - 1.
593
// Reduce it to 14 bits, by shifting off 15. Round up by adding (1 << 14) first.
594
int envelopeValue = voice.envelope.GetHeight();
595
voice.envelope.Step();
596
envelopeValue = (envelopeValue + (1 << 14)) >> 15;
597
598
// We just scale by the envelope before we scale by volumes.
599
// Again, we round up by adding (1 << 14) first (*after* multiplying.)
600
sample = ((sample * envelopeValue) + (1 << 14)) >> 15;
601
602
// We mix into this 32-bit temp buffer and clip in a second loop
603
// Ideally, the shift right should be there too but for now I'm concerned about
604
// not overflowing.
605
mixBuffer[i * 2] += (sample * voice.volumeLeft) >> 12;
606
mixBuffer[i * 2 + 1] += (sample * voice.volumeRight) >> 12;
607
sendBuffer[i * 2] += sample * voice.effectLeft >> 12;
608
sendBuffer[i * 2 + 1] += sample * voice.effectRight >> 12;
609
}
610
611
voice.resampleHist[0] = mixTemp_[tempPos - 2];
612
voice.resampleHist[1] = mixTemp_[tempPos - 1];
613
614
voice.sampleFrac = sampleFrac - (tempPos - 2) * PSP_SAS_PITCH_BASE;
615
616
if (voice.HaveSamplesEnded())
617
voice.envelope.End();
618
if (voice.envelope.HasEnded()) {
619
// NOTICE_LOG(Log::SasMix, "Hit end of envelope");
620
voice.playing = false;
621
voice.on = false;
622
}
623
}
624
}
625
626
void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol, bool mute) {
627
for (int v = 0; v < PSP_SAS_VOICES_MAX; v++) {
628
SasVoice &voice = voices[v];
629
if (!voice.playing || voice.paused)
630
continue;
631
MixVoice(voice);
632
}
633
634
// Apply mute if needed (note: we try to keep everything else identical to the non-muted case).
635
if (mute) {
636
memset(mixBuffer, 0, grainSize * sizeof(int) * 2);
637
memset(sendBuffer, 0, grainSize * sizeof(int) * 2);
638
}
639
640
// Then mix the send buffer in with the rest.
641
642
// Alright, all voices mixed. Let's convert and clip, and at the same time, wipe mixBuffer for next time. Could also dither.
643
s16 *outp = (s16 *)Memory::GetPointerWriteRange(outAddr, 4 * grainSize);
644
const s16 *inp = inAddr ? (const s16 *)Memory::GetPointerRange(inAddr, 4 * grainSize) : 0;
645
if (!outp) {
646
WARN_LOG_REPORT(Log::sceSas, "Bad SAS Mix output address: %08x, grain=%d", outAddr, grainSize);
647
} else if (outputMode == PSP_SAS_OUTPUTMODE_MIXED) {
648
// Okay, apply effects processing to the Send buffer.
649
WriteMixedOutput(outp, inp, leftVol, rightVol);
650
if (MemBlockInfoDetailed()) {
651
if (inp)
652
NotifyMemInfo(MemBlockFlags::READ, inAddr, grainSize * sizeof(u16) * 2, "SasMix");
653
NotifyMemInfo(MemBlockFlags::WRITE, outAddr, grainSize * sizeof(u16) * 2, "SasMix");
654
}
655
} else {
656
s16 *outpL = outp + grainSize * 0;
657
s16 *outpR = outp + grainSize * 1;
658
s16 *outpSendL = outp + grainSize * 2;
659
s16 *outpSendR = outp + grainSize * 3;
660
WARN_LOG_REPORT_ONCE(sasraw, Log::SasMix, "sceSasCore: raw outputMode");
661
for (int i = 0; i < grainSize * 2; i += 2) {
662
*outpL++ = clamp_s16(mixBuffer[i + 0]);
663
*outpR++ = clamp_s16(mixBuffer[i + 1]);
664
*outpSendL++ = clamp_s16(sendBuffer[i + 0]);
665
*outpSendR++ = clamp_s16(sendBuffer[i + 1]);
666
}
667
NotifyMemInfo(MemBlockFlags::WRITE, outAddr, grainSize * sizeof(u16) * 4, "SasMix");
668
}
669
memset(mixBuffer, 0, grainSize * sizeof(int) * 2);
670
memset(sendBuffer, 0, grainSize * sizeof(int) * 2);
671
}
672
673
// Note: leftVol/rightVol here are how much to scale the inp content by, not the mixBuffer.
674
void SasInstance::WriteMixedOutput(s16 *outp, const s16 *inp, int leftVol, int rightVol) {
675
const bool dry = waveformEffect.isDryOn != 0;
676
const bool wet = waveformEffect.isWetOn != 0;
677
if (wet) {
678
ApplyWaveformEffect();
679
}
680
681
if (inp) {
682
for (int i = 0; i < grainSize * 2; i += 2) {
683
int sampleL = ((*inp++) * leftVol >> 12);
684
int sampleR = ((*inp++) * rightVol >> 12);
685
if (dry) {
686
sampleL += mixBuffer[i + 0];
687
sampleR += mixBuffer[i + 1];
688
}
689
if (wet) {
690
sampleL += sendBufferProcessed[i + 0];
691
sampleR += sendBufferProcessed[i + 1];
692
}
693
*outp++ = clamp_s16(sampleL);
694
*outp++ = clamp_s16(sampleR);
695
}
696
} else {
697
// These are the optimal cases.
698
if (dry && wet) {
699
for (int i = 0; i < grainSize * 2; i += 2) {
700
*outp++ = clamp_s16(mixBuffer[i + 0] + sendBufferProcessed[i + 0]);
701
*outp++ = clamp_s16(mixBuffer[i + 1] + sendBufferProcessed[i + 1]);
702
}
703
} else if (dry) {
704
for (int i = 0; i < grainSize * 2; i += 2) {
705
*outp++ = clamp_s16(mixBuffer[i + 0]);
706
*outp++ = clamp_s16(mixBuffer[i + 1]);
707
}
708
} else {
709
// This is another uncommon case, dry must be off but let's keep it for clarity.
710
for (int i = 0; i < grainSize * 2; i += 2) {
711
int sampleL = 0;
712
int sampleR = 0;
713
if (dry) {
714
sampleL += mixBuffer[i + 0];
715
sampleR += mixBuffer[i + 1];
716
}
717
if (wet) {
718
sampleL += sendBufferProcessed[i + 0];
719
sampleR += sendBufferProcessed[i + 1];
720
}
721
*outp++ = clamp_s16(sampleL);
722
*outp++ = clamp_s16(sampleR);
723
}
724
}
725
}
726
}
727
728
void SasInstance::SetWaveformEffectType(int type) {
729
if (type != waveformEffect.type) {
730
waveformEffect.type = type;
731
reverb_.SetPreset(type);
732
}
733
}
734
735
// http://psx.rules.org/spu.txt has some information about setting up the delay time by modifying the delay preset.
736
// See http://report.ppsspp.org/logs/kind/772 for a list of games that use different types. Maybe can help us figure out
737
// which is which.
738
void SasInstance::ApplyWaveformEffect() {
739
// First, downsample the send buffer to 22khz. We do this naively for now.
740
for (int i = 0; i < grainSize / 2; i++) {
741
sendBufferDownsampled[i * 2] = clamp_s16(sendBuffer[i * 4]);
742
sendBufferDownsampled[i * 2 + 1] = clamp_s16(sendBuffer[i * 4 + 1]);
743
}
744
745
// Volume max is 0x1000, while our factor is up to 0x8000. Shifting left by 3 fixes that.
746
reverb_.ProcessReverb(sendBufferProcessed, sendBufferDownsampled, grainSize / 2, (uint16_t)(waveformEffect.leftVol << 3), (uint16_t)(waveformEffect.rightVol << 3));
747
}
748
749
void SasInstance::DoState(PointerWrap &p) {
750
auto s = p.Section("SasInstance", 1);
751
if (!s)
752
return;
753
754
Do(p, grainSize);
755
if (p.mode == p.MODE_READ) {
756
if (grainSize > 0) {
757
SetGrainSize(grainSize);
758
} else {
759
ClearGrainSize();
760
}
761
}
762
763
Do(p, maxVoices);
764
Do(p, sampleRate);
765
Do(p, outputMode);
766
767
// SetGrainSize() / ClearGrainSize() should've made our buffers match.
768
if (mixBuffer != NULL && grainSize > 0) {
769
DoArray(p, mixBuffer, grainSize * 2);
770
}
771
if (sendBuffer != NULL && grainSize > 0) {
772
DoArray(p, sendBuffer, grainSize * 2);
773
}
774
if (sendBuffer != NULL && grainSize > 0) {
775
// Backwards compat
776
int16_t *resampleBuf = new int16_t[grainSize * 4 + 3]();
777
DoArray(p, resampleBuf, grainSize * 4 + 3);
778
delete[] resampleBuf;
779
}
780
781
int n = PSP_SAS_VOICES_MAX;
782
Do(p, n);
783
if (n != PSP_SAS_VOICES_MAX) {
784
ERROR_LOG(Log::SaveState, "Wrong number of SAS voices");
785
return;
786
}
787
DoArray(p, voices, ARRAY_SIZE(voices));
788
Do(p, waveformEffect);
789
if (p.mode == p.MODE_READ) {
790
reverb_.SetPreset(waveformEffect.type);
791
}
792
}
793
794
void SasVoice::Reset() {
795
resampleHist[0] = 0;
796
resampleHist[1] = 0;
797
}
798
799
void SasVoice::KeyOn() {
800
envelope.KeyOn();
801
switch (type) {
802
case VOICETYPE_VAG:
803
if (Memory::IsValidAddress(vagAddr)) {
804
vag.Start(vagAddr, vagSize, loop);
805
} else {
806
ERROR_LOG(Log::SasMix, "Invalid VAG address %08x", vagAddr);
807
return;
808
}
809
break;
810
default:
811
break;
812
}
813
playing = true;
814
on = true;
815
paused = false;
816
sampleFrac = 0;
817
}
818
819
void SasVoice::KeyOff() {
820
on = false;
821
envelope.KeyOff();
822
}
823
824
void SasVoice::DoState(PointerWrap &p) {
825
auto s = p.Section("SasVoice", 1, 3);
826
if (!s)
827
return;
828
829
Do(p, playing);
830
Do(p, paused);
831
Do(p, on);
832
833
Do(p, type);
834
835
Do(p, vagAddr);
836
Do(p, vagSize);
837
Do(p, pcmAddr);
838
Do(p, pcmSize);
839
Do(p, pcmIndex);
840
if (s >= 2) {
841
Do(p, pcmLoopPos);
842
} else {
843
pcmLoopPos = 0;
844
}
845
Do(p, sampleRate);
846
847
Do(p, sampleFrac);
848
Do(p, pitch);
849
Do(p, loop);
850
if (s < 2 && type == VOICETYPE_PCM) {
851
// We set loop incorrectly before, and always looped.
852
// Let's keep always looping, since it's usually right.
853
loop = true;
854
}
855
856
Do(p, noiseFreq);
857
858
Do(p, volumeLeft);
859
Do(p, volumeRight);
860
if (s < 3) {
861
// There were extra variables here that were for the same purpose.
862
Do(p, effectLeft);
863
Do(p, effectRight);
864
}
865
Do(p, effectLeft);
866
Do(p, effectRight);
867
DoArray(p, resampleHist, ARRAY_SIZE(resampleHist));
868
869
envelope.DoState(p);
870
vag.DoState(p);
871
atrac3.DoState(p);
872
}
873
874
void ADSREnvelope::WalkCurve(int type, int rate) {
875
s64 expDelta;
876
switch (type) {
877
case PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE:
878
height_ += rate;
879
break;
880
881
case PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE:
882
height_ -= rate;
883
break;
884
885
case PSP_SAS_ADSR_CURVE_MODE_LINEAR_BENT:
886
if (height_ <= (s64)PSP_SAS_ENVELOPE_HEIGHT_MAX * 3 / 4) {
887
height_ += rate;
888
} else {
889
height_ += rate / 4;
890
}
891
break;
892
893
case PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE:
894
expDelta = height_ - PSP_SAS_ENVELOPE_HEIGHT_MAX;
895
// Flipping the sign so that we can shift in the top bits.
896
expDelta += (-expDelta * rate) >> 32;
897
height_ = expDelta + PSP_SAS_ENVELOPE_HEIGHT_MAX - (rate + 3UL) / 4UL;
898
break;
899
900
case PSP_SAS_ADSR_CURVE_MODE_EXPONENT_INCREASE:
901
expDelta = height_ - PSP_SAS_ENVELOPE_HEIGHT_MAX;
902
// Flipping the sign so that we can shift in the top bits.
903
expDelta += (-expDelta * rate) >> 32;
904
height_ = expDelta + 0x4000 + PSP_SAS_ENVELOPE_HEIGHT_MAX;
905
break;
906
907
case PSP_SAS_ADSR_CURVE_MODE_DIRECT:
908
height_ = rate; // Simple :)
909
break;
910
}
911
}
912
913
void ADSREnvelope::SetState(ADSRState state) {
914
if (height_ > PSP_SAS_ENVELOPE_HEIGHT_MAX) {
915
height_ = PSP_SAS_ENVELOPE_HEIGHT_MAX;
916
}
917
// TODO: Also check for height_ < 0 and set to 0?
918
state_ = state;
919
}
920
921
inline void ADSREnvelope::Step() {
922
switch (state_) {
923
case STATE_ATTACK:
924
WalkCurve(attackType, attackRate);
925
if (height_ >= PSP_SAS_ENVELOPE_HEIGHT_MAX || height_ < 0)
926
SetState(STATE_DECAY);
927
break;
928
case STATE_DECAY:
929
WalkCurve(decayType, decayRate);
930
if (height_ < sustainLevel)
931
SetState(STATE_SUSTAIN);
932
break;
933
case STATE_SUSTAIN:
934
WalkCurve(sustainType, sustainRate);
935
if (height_ <= 0) {
936
height_ = 0;
937
SetState(STATE_RELEASE);
938
}
939
break;
940
case STATE_RELEASE:
941
WalkCurve(releaseType, releaseRate);
942
if (height_ <= 0) {
943
height_ = 0;
944
SetState(STATE_OFF);
945
}
946
break;
947
case STATE_OFF:
948
// Do nothing
949
break;
950
951
case STATE_KEYON:
952
height_ = 0;
953
SetState(STATE_KEYON_STEP);
954
break;
955
case STATE_KEYON_STEP:
956
// This entire state is pretty much a hack to reproduce PSP behavior.
957
// The STATE_KEYON state is a real state, but not sure how it switches.
958
// It takes 32 steps at 0 for keyon to "kick in", 31 should shift to 0 anyway.
959
height_++;
960
if (height_ >= 31) {
961
height_ = 0;
962
SetState(STATE_ATTACK);
963
}
964
break;
965
}
966
}
967
968
void ADSREnvelope::KeyOn() {
969
SetState(STATE_KEYON);
970
}
971
972
void ADSREnvelope::KeyOff() {
973
SetState(STATE_RELEASE);
974
}
975
976
void ADSREnvelope::End() {
977
SetState(STATE_OFF);
978
height_ = 0;
979
}
980
981
void ADSREnvelope::DoState(PointerWrap &p) {
982
auto s = p.Section("ADSREnvelope", 1, 2);
983
if (!s) {
984
return;
985
}
986
987
Do(p, attackRate);
988
Do(p, decayRate);
989
Do(p, sustainRate);
990
Do(p, releaseRate);
991
Do(p, attackType);
992
Do(p, decayType);
993
Do(p, sustainType);
994
Do(p, sustainLevel);
995
Do(p, releaseType);
996
if (s < 2) {
997
Do(p, state_);
998
if (state_ == 4) {
999
state_ = STATE_OFF;
1000
}
1001
int stepsLegacy;
1002
Do(p, stepsLegacy);
1003
} else {
1004
Do(p, state_);
1005
}
1006
Do(p, height_);
1007
}
1008
1009
const char *ADSRCurveModeAsString(SasADSRCurveMode mode) {
1010
switch (mode) {
1011
case PSP_SAS_ADSR_CURVE_MODE_DIRECT: return "D";
1012
case PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE: return "L+";
1013
case PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE: return "L-";
1014
case PSP_SAS_ADSR_CURVE_MODE_LINEAR_BENT: return "LB";
1015
case PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE: return "E-";
1016
case PSP_SAS_ADSR_CURVE_MODE_EXPONENT_INCREASE: return "E+";
1017
default: return "N/A";
1018
}
1019
}
1020
1021