CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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