1
// Copyright (c) 2012- PPSSPP Project.
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.
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.
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
18
#include "base/basictypes.h"
19
#include "profiler/profiler.h"
22
#include "Core/MemMapHelpers.h"
23
#include "Core/HLE/sceAtrac.h"
24
#include "Core/Config.h"
25
#include "Core/Reporting.h"
30
// #define AUDIO_TO_FILE
32
static const u8 f[16][2] = {
38
// TODO: The below values could use more testing, but match initial tests.
39
// Not sure if they are used by games, found by tests.
53
void VagDecoder::Start(u32 data, u32 vagSize, bool loopEnabled) {
54
loopEnabled_ = loopEnabled;
55
loopAtNextBlock_ = false;
57
numBlocks_ = vagSize / 16;
63
s_1 = 0; // per block?
67
void VagDecoder::DecodeBlock(u8 *&read_pointer) {
68
u8 *readp = read_pointer;
69
int predict_nr = *readp++;
70
int shift_factor = predict_nr & 0xf;
74
VERBOSE_LOG(SASMIX, "VAG ending block at %d", curBlock_);
78
else if (flags == 6) {
79
loopStartBlock_ = curBlock_;
81
else if (flags == 3) {
83
loopAtNextBlock_ = true;
87
// Keep state in locals to avoid bouncing to memory.
91
int coef1 = f[predict_nr][0];
92
int coef2 = -f[predict_nr][1];
94
// TODO: Unroll once more and interleave the unpacking with the decoding more?
95
for (int i = 0; i < 28; i += 2) {
97
int sample1 = (short)((d & 0xf) << 12) >> shift_factor;
98
int sample2 = (short)((d & 0xf0) << 8) >> shift_factor;
99
s2 = clamp_s16(sample1 + ((s1 * coef1 + s2 * coef2) >> 6));
100
s1 = clamp_s16(sample2 + ((s2 * coef1 + s1 * coef2) >> 6));
109
if (curBlock_ == numBlocks_) {
113
read_pointer = readp;
116
void VagDecoder::GetSamples(s16 *outSamples, int numSamples) {
118
memset(outSamples, 0, numSamples * sizeof(s16));
121
if (!Memory::IsValidAddress(read_)) {
122
WARN_LOG(SASMIX, "Bad VAG samples address?");
125
u8 *readp = Memory::GetPointerUnchecked(read_);
128
for (int i = 0; i < numSamples; i++) {
129
if (curSample == 28) {
130
if (loopAtNextBlock_) {
131
VERBOSE_LOG(SASMIX, "Looping VAG from block %d/%d to %d", curBlock_, numBlocks_, loopStartBlock_);
132
// data_ starts at curBlock = -1.
133
read_ = data_ + 16 * loopStartBlock_ + 16;
134
readp = Memory::GetPointerUnchecked(read_);
136
curBlock_ = loopStartBlock_;
137
loopAtNextBlock_ = false;
141
// Clear the rest of the buffer and return.
142
memset(&outSamples[i], 0, (numSamples - i) * sizeof(s16));
146
outSamples[i] = samples[curSample++];
150
read_ += readp - origp;
154
void VagDecoder::DoState(PointerWrap &p) {
155
auto s = p.Section("VagDecoder", 1, 2);
160
p.DoArray(samples, ARRAY_SIZE(samples));
162
int samplesOld[ARRAY_SIZE(samples)];
163
p.DoArray(samplesOld, ARRAY_SIZE(samples));
164
for (size_t i = 0; i < ARRAY_SIZE(samples); ++i) {
165
samples[i] = samplesOld[i];
173
p.Do(loopStartBlock_);
180
p.Do(loopAtNextBlock_);
184
int SasAtrac3::setContext(u32 context) {
185
contextAddr_ = context;
186
atracID_ = _AtracGetIDByContext(context);
188
sampleQueue_ = new BufferQueue();
189
sampleQueue_->clear();
194
void SasAtrac3::getNextSamples(s16 *outbuf, int wantedSamples) {
200
int wantedbytes = wantedSamples * sizeof(s16);
201
while (!finish && sampleQueue_->getQueueSize() < wantedbytes) {
204
static s16 buf[0x800];
205
_AtracDecodeData(atracID_, (u8*)buf, 0, &numSamples, &finish, &remains);
207
sampleQueue_->push((u8*)buf, numSamples * sizeof(s16));
211
sampleQueue_->pop_front((u8*)outbuf, wantedbytes);
215
int SasAtrac3::addStreamData(u32 bufPtr, u32 addbytes) {
217
_AtracAddStreamData(atracID_, bufPtr, addbytes);
222
void SasAtrac3::DoState(PointerWrap &p) {
223
auto s = p.Section("SasAtrac3", 1, 2);
229
if (p.mode == p.MODE_READ && atracID_ >= 0 && !sampleQueue_) {
230
sampleQueue_ = new BufferQueue();
237
// http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/sceSasCore.java
239
static int simpleRate(int n) {
244
int rate = ((7 - (n & 0x3)) << 26) >> (n >> 2);
251
static int exponentRate(int n) {
256
int rate = ((7 - (n & 0x3)) << 24) >> (n >> 2);
263
static int getAttackRate(int bitfield1) {
264
return simpleRate(bitfield1 >> 8);
267
static int getAttackType(int bitfield1) {
268
return (bitfield1 & 0x8000) == 0 ? PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE : PSP_SAS_ADSR_CURVE_MODE_LINEAR_BENT;
271
static int getDecayRate(int bitfield1) {
272
int n = (bitfield1 >> 4) & 0x000F;
275
return 0x80000000 >> n;
278
static int getSustainType(int bitfield2) {
279
return (bitfield2 >> 14) & 3;
282
static int getSustainRate(int bitfield2) {
283
if (getSustainType(bitfield2) == PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE) {
284
return exponentRate(bitfield2 >> 6);
286
return simpleRate(bitfield2 >> 6);
290
static int getReleaseType(int bitfield2) {
291
return (bitfield2 & 0x0020) == 0 ? PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE : PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE;
294
static int getReleaseRate(int bitfield2) {
295
int n = bitfield2 & 0x001F;
299
if (getReleaseType(bitfield2) == PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE) {
302
} else if (n == 29) {
305
return 0x10000000 >> n;
309
return 0x80000000 >> n;
312
static int getSustainLevel(int bitfield1) {
313
return ((bitfield1 & 0x000F) + 1) << 26;
316
void ADSREnvelope::SetSimpleEnvelope(u32 ADSREnv1, u32 ADSREnv2) {
317
attackRate = getAttackRate(ADSREnv1);
318
attackType = getAttackType(ADSREnv1);
319
decayRate = getDecayRate(ADSREnv1);
320
decayType = PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE;
321
sustainRate = getSustainRate(ADSREnv2);
322
sustainType = getSustainType(ADSREnv2);
323
releaseRate = getReleaseRate(ADSREnv2);
324
releaseType = getReleaseType(ADSREnv2);
325
sustainLevel = getSustainLevel(ADSREnv1);
327
if (attackRate < 0 || decayRate < 0 || sustainRate < 0 || releaseRate < 0) {
328
ERROR_LOG_REPORT(SCESAS, "Simple ADSR resulted in invalid rates: %04x, %04x", ADSREnv1, ADSREnv2);
332
SasInstance::SasInstance()
333
: maxVoices(PSP_SAS_VOICES_MAX),
335
outputMode(PSP_SAS_OUTPUTMODE_MIXED),
338
sendBufferDownsampled(0),
339
sendBufferProcessed(0),
343
audioDump = fopen("D:\\audio.raw", "wb");
345
memset(&waveformEffect, 0, sizeof(waveformEffect));
346
waveformEffect.type = PSP_SAS_EFFECT_TYPE_OFF;
347
waveformEffect.isDryOn = 1;
350
SasInstance::~SasInstance() {
354
void SasInstance::GetDebugText(char *text, size_t bufsize) {
358
for (int i = 0; i < maxVoices; i++) {
359
if (voices[i].playing) {
360
p += snprintf(p, sizeof(voiceBuf) - (p - voiceBuf), " %d: Pitch %d L/R,FX: %d,%d|%d,%d VAG: %08x:%d:%08x Height:%d%%\n", i, voices[i].pitch, voices[i].volumeLeft, voices[i].volumeRight, voices[i].effectLeft, voices[i].effectRight, voices[i].vagAddr, voices[i].vagSize, voices[i].vag.GetReadPtr(), (int)((int64_t)voices[i].envelope.GetHeight() * 100 / PSP_SAS_ENVELOPE_HEIGHT_MAX));
364
snprintf(text, bufsize,
365
"SR: %d Mode: %s Grain: %d\n"
366
"Effect: Type: %d Dry: %d Wet: %d L: %d R: %d Delay: %d Feedback: %d\n"
368
sampleRate, outputMode == PSP_SAS_OUTPUTMODE_RAW ? "Raw" : "Mixed", grainSize,
369
waveformEffect.type, waveformEffect.isDryOn, waveformEffect.isWetOn, waveformEffect.leftVol, waveformEffect.rightVol, waveformEffect.delay, waveformEffect.feedback,
374
void SasInstance::ClearGrainSize() {
377
delete[] sendBufferDownsampled;
378
delete[] sendBufferProcessed;
379
delete[] resampleBuffer;
381
sendBuffer = nullptr;
382
resampleBuffer = nullptr;
383
sendBufferDownsampled = nullptr;
384
sendBufferProcessed = nullptr;
387
void SasInstance::SetGrainSize(int newGrainSize) {
388
grainSize = newGrainSize;
390
// If you change the sizes here, don't forget DoState().
393
delete[] sendBufferDownsampled;
394
delete[] sendBufferProcessed;
395
delete[] resampleBuffer;
397
mixBuffer = new s32[grainSize * 2];
398
sendBuffer = new s32[grainSize * 2];
399
sendBufferDownsampled = new s16[grainSize];
400
sendBufferProcessed = new s16[grainSize * 2];
401
memset(mixBuffer, 0, sizeof(int) * grainSize * 2);
402
memset(sendBuffer, 0, sizeof(int) * grainSize * 2);
403
memset(sendBufferDownsampled, 0, sizeof(s16) * grainSize);
404
memset(sendBufferProcessed, 0, sizeof(s16) * grainSize * 2);
406
// 2 samples padding at the start, that's where we copy the two last samples from the channel
407
// so that we can do bicubic resampling if necessary. Plus 1 for smoothness hackery.
408
resampleBuffer = new s16[grainSize * 4 + 3];
411
int SasInstance::EstimateMixUs() {
412
int voicesPlayingCount = 0;
414
for (int v = 0; v < PSP_SAS_VOICES_MAX; v++) {
415
SasVoice &voice = voices[v];
416
if (!voice.playing || voice.paused)
418
voicesPlayingCount++;
421
// Each voice costs extra time, and each byte of grain costs extra time.
422
return 20 + voicesPlayingCount * 68 + (grainSize * 60) / 100;
425
void SasVoice::ReadSamples(s16 *output, int numSamples) {
426
// Read N samples into the resample buffer. Could do either PCM or VAG here.
429
vag.GetSamples(output, numSamples);
433
int needed = numSamples;
436
u32 size = std::min(pcmSize - pcmIndex, needed);
441
Memory::Memcpy(out, pcmAddr + pcmIndex * sizeof(s16), size * sizeof(s16));
445
if (pcmIndex >= pcmSize) {
447
// All out, quit. We'll end in HaveSamplesEnded().
450
pcmIndex = pcmLoopPos;
454
memset(out, 0, needed * sizeof(s16));
458
case VOICETYPE_ATRAC3:
459
atrac3.getNextSamples(output, numSamples);
463
memset(output, 0, numSamples * sizeof(s16));
469
bool SasVoice::HaveSamplesEnded() const {
475
return pcmIndex >= pcmSize;
477
case VOICETYPE_ATRAC3:
485
void SasInstance::MixVoice(SasVoice &voice) {
486
switch (voice.type) {
488
if (voice.type == VOICETYPE_VAG && !voice.vagAddr)
490
// else fallthrough! Don't change the check above.
492
if (voice.type == VOICETYPE_PCM && !voice.pcmAddr)
494
// else fallthrough! Don't change the check above.
496
// Load resample history (so we can use a wide filter)
497
resampleBuffer[0] = voice.resampleHist[0];
498
resampleBuffer[1] = voice.resampleHist[1];
500
// Figure out number of samples to read.
501
// Actually this is not entirely correct - we need to get one extra sample, and store it
502
// for the next time around. A little complicated...
503
// But for now, see Smoothness HACKERY below :P
504
u32 numSamples = ((u32)voice.sampleFrac + (u32)grainSize * (u32)voice.pitch) >> PSP_SAS_PITCH_BASE_SHIFT;
505
if ((int)numSamples > grainSize * 4) {
506
ERROR_LOG(SASMIX, "numSamples too large, clamping: %i vs %i", numSamples, grainSize * 4);
507
numSamples = grainSize * 4;
510
// This feels a bit hacky. The first 32 samples after a keyon are 0s.
511
const bool ignorePitch = voice.type == VOICETYPE_PCM && voice.pitch > PSP_SAS_PITCH_BASE;
512
if (voice.envelope.NeedsKeyOn()) {
513
int delay = ignorePitch ? 32 : (32 * (u32)voice.pitch) >> PSP_SAS_PITCH_BASE_SHIFT;
514
// VAG seems to have an extra sample delay (not shared by PCM.)
515
if (voice.type == VOICETYPE_VAG)
517
voice.ReadSamples(resampleBuffer + 2 + delay, numSamples - delay);
519
voice.ReadSamples(resampleBuffer + 2, numSamples);
522
// Smoothness HACKERY
523
resampleBuffer[2 + numSamples] = resampleBuffer[2 + numSamples - 1];
525
// Save resample history
526
voice.resampleHist[0] = resampleBuffer[2 + numSamples - 2];
527
voice.resampleHist[1] = resampleBuffer[2 + numSamples - 1];
529
// Resample to the correct pitch, writing exactly "grainSize" samples.
530
// This is a HORRIBLE resampler by the way.
531
// TODO: Special case no-resample case (and 2x and 0.5x) for speed, it's not uncommon
533
u32 sampleFrac = voice.sampleFrac;
534
for (int i = 0; i < grainSize; i++) {
535
// For now: nearest neighbour, not even using the resample history at all.
536
int sample = resampleBuffer[sampleFrac / PSP_SAS_PITCH_BASE + 2];
537
sampleFrac += voice.pitch;
539
// The maximum envelope height (PSP_SAS_ENVELOPE_HEIGHT_MAX) is (1 << 30) - 1.
540
// Reduce it to 14 bits, by shifting off 15. Round up by adding (1 << 14) first.
541
int envelopeValue = voice.envelope.GetHeight();
542
voice.envelope.Step();
543
envelopeValue = (envelopeValue + (1 << 14)) >> 15;
545
// We just scale by the envelope before we scale by volumes.
546
// Again, we round up by adding (1 << 14) first (*after* multiplying.)
547
sample = ((sample * envelopeValue) + (1 << 14)) >> 15;
549
// We mix into this 32-bit temp buffer and clip in a second loop
550
// Ideally, the shift right should be there too but for now I'm concerned about
552
mixBuffer[i * 2] += (sample * voice.volumeLeft ) >> 12;
553
mixBuffer[i * 2 + 1] += (sample * voice.volumeRight) >> 12;
554
sendBuffer[i * 2] += sample * voice.effectLeft >> 12;
555
sendBuffer[i * 2 + 1] += sample * voice.effectRight >> 12;
558
voice.sampleFrac = sampleFrac;
559
// Let's hope grainSize is a power of 2.
560
//voice.sampleFrac &= grainSize * PSP_SAS_PITCH_BASE - 1;
561
voice.sampleFrac -= numSamples * PSP_SAS_PITCH_BASE;
563
if (voice.HaveSamplesEnded())
564
voice.envelope.End();
565
if (voice.envelope.HasEnded())
567
// NOTICE_LOG(SCESAS, "Hit end of envelope");
568
voice.playing = false;
574
void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol) {
575
int voicesPlayingCount = 0;
577
for (int v = 0; v < PSP_SAS_VOICES_MAX; v++) {
578
SasVoice &voice = voices[v];
579
if (!voice.playing || voice.paused)
581
voicesPlayingCount++;
585
// Then mix the send buffer in with the rest.
587
// Alright, all voices mixed. Let's convert and clip, and at the same time, wipe mixBuffer for next time. Could also dither.
588
s16 *outp = (s16 *)Memory::GetPointer(outAddr);
589
const s16 *inp = inAddr ? (s16*)Memory::GetPointer(inAddr) : 0;
590
if (outputMode == PSP_SAS_OUTPUTMODE_MIXED) {
591
// Okay, apply effects processing to the Send buffer.
592
WriteMixedOutput(outp, inp, leftVol, rightVol);
594
s16 *outpL = outp + grainSize * 0;
595
s16 *outpR = outp + grainSize * 1;
596
s16 *outpSendL = outp + grainSize * 2;
597
s16 *outpSendR = outp + grainSize * 3;
598
WARN_LOG_REPORT_ONCE(sasraw, SCESAS, "sceSasCore: raw outputMode");
599
for (int i = 0; i < grainSize * 2; i += 2) {
600
*outpL++ = clamp_s16(mixBuffer[i + 0]);
601
*outpR++ = clamp_s16(mixBuffer[i + 1]);
602
*outpSendL++ = clamp_s16(sendBuffer[i + 0]);
603
*outpSendR++ = clamp_s16(sendBuffer[i + 1]);
606
memset(mixBuffer, 0, grainSize * sizeof(int) * 2);
607
memset(sendBuffer, 0, grainSize * sizeof(int) * 2);
610
fwrite(Memory::GetPointer(outAddr), 1, grainSize * 2 * 2, audioDump);
614
void SasInstance::WriteMixedOutput(s16 *outp, const s16 *inp, int leftVol, int rightVol) {
615
const bool dry = waveformEffect.isDryOn != 0;
616
const bool wet = waveformEffect.isWetOn != 0;
618
ApplyWaveformEffect();
622
for (int i = 0; i < grainSize * 2; i += 2) {
623
int sampleL = ((*inp++) * leftVol >> 12);
624
int sampleR = ((*inp++) * rightVol >> 12);
626
sampleL += mixBuffer[i + 0];
627
sampleR += mixBuffer[i + 1];
630
sampleL += sendBufferProcessed[i + 0];
631
sampleR += sendBufferProcessed[i + 1];
633
*outp++ = clamp_s16(sampleL);
634
*outp++ = clamp_s16(sampleR);
637
// These are the optimal cases.
639
for (int i = 0; i < grainSize * 2; i += 2) {
640
*outp++ = clamp_s16(mixBuffer[i + 0] + sendBufferProcessed[i + 0]);
641
*outp++ = clamp_s16(mixBuffer[i + 1] + sendBufferProcessed[i + 1]);
644
for (int i = 0; i < grainSize * 2; i += 2) {
645
*outp++ = clamp_s16(mixBuffer[i + 0]);
646
*outp++ = clamp_s16(mixBuffer[i + 1]);
649
// This is another uncommon case, dry must be off but let's keep it for clarity.
650
for (int i = 0; i < grainSize * 2; i += 2) {
654
sampleL += mixBuffer[i + 0];
655
sampleR += mixBuffer[i + 1];
658
sampleL += sendBufferProcessed[i + 0];
659
sampleR += sendBufferProcessed[i + 1];
661
*outp++ = clamp_s16(sampleL);
662
*outp++ = clamp_s16(sampleR);
668
void SasInstance::SetWaveformEffectType(int type) {
669
if (type != waveformEffect.type) {
670
waveformEffect.type = type;
671
reverb_.SetPreset(type);
675
// http://psx.rules.org/spu.txt has some information about setting up the delay time by modifying the delay preset.
676
// See http://report.ppsspp.org/logs/kind/772 for a list of games that use different types. Maybe can help us figure out
678
void SasInstance::ApplyWaveformEffect() {
679
// First, downsample the send buffer to 22khz. We do this naively for now.
680
for (int i = 0; i < grainSize / 2; i++) {
681
sendBufferDownsampled[i * 2] = clamp_s16(sendBuffer[i * 4]);
682
sendBufferDownsampled[i * 2 + 1] = clamp_s16(sendBuffer[i * 4 + 1]);
685
// Volume max is 0x1000, while our factor is up to 0x8000. Shifting right by 3 fixes that.
686
reverb_.ProcessReverb(sendBufferProcessed, sendBufferDownsampled, grainSize / 2, waveformEffect.leftVol << 3, waveformEffect.rightVol << 3);
689
void SasInstance::DoState(PointerWrap &p) {
690
auto s = p.Section("SasInstance", 1);
695
if (p.mode == p.MODE_READ) {
697
SetGrainSize(grainSize);
707
// SetGrainSize() / ClearGrainSize() should've made our buffers match.
708
if (mixBuffer != NULL && grainSize > 0) {
709
p.DoArray(mixBuffer, grainSize * 2);
711
if (sendBuffer != NULL && grainSize > 0) {
712
p.DoArray(sendBuffer, grainSize * 2);
714
if (resampleBuffer != NULL && grainSize > 0) {
715
p.DoArray(resampleBuffer, grainSize * 4 + 3);
718
int n = PSP_SAS_VOICES_MAX;
720
if (n != PSP_SAS_VOICES_MAX) {
721
ERROR_LOG(HLE, "Savestate failure: wrong number of SAS voices");
724
p.DoArray(voices, ARRAY_SIZE(voices));
725
p.Do(waveformEffect);
726
if (p.mode == p.MODE_READ) {
727
reverb_.SetPreset(waveformEffect.type);
731
void SasVoice::Reset() {
736
void SasVoice::KeyOn() {
740
if (Memory::IsValidAddress(vagAddr)) {
741
vag.Start(vagAddr, vagSize, loop);
743
ERROR_LOG(SASMIX, "Invalid VAG address %08x", vagAddr);
756
void SasVoice::KeyOff() {
761
void SasVoice::ChangedParams(bool changedVag) {
762
if (!playing && on) {
765
vag.Start(vagAddr, vagSize, loop);
767
// TODO: restart VAG somehow
770
void SasVoice::DoState(PointerWrap &p) {
771
auto s = p.Section("SasVoice", 1, 3);
796
if (s < 2 && type == VOICETYPE_PCM) {
797
// We set loop incorrectly before, and always looped.
798
// Let's keep always looping, since it's usually right.
807
// There were extra variables here that were for the same purpose.
813
p.DoArray(resampleHist, ARRAY_SIZE(resampleHist));
820
ADSREnvelope::ADSREnvelope()
825
attackType(PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE),
826
decayType(PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE),
827
sustainType(PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE),
829
releaseType(PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE),
834
void ADSREnvelope::WalkCurve(int type, int rate) {
837
case PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE:
841
case PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE:
845
case PSP_SAS_ADSR_CURVE_MODE_LINEAR_BENT:
846
if (height_ <= (s64)PSP_SAS_ENVELOPE_HEIGHT_MAX * 3 / 4) {
853
case PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE:
854
expDelta = height_ - PSP_SAS_ENVELOPE_HEIGHT_MAX;
855
// Flipping the sign so that we can shift in the top bits.
856
expDelta += (-expDelta * rate) >> 32;
857
height_ = expDelta + PSP_SAS_ENVELOPE_HEIGHT_MAX - (rate + 3UL) / 4UL;
860
case PSP_SAS_ADSR_CURVE_MODE_EXPONENT_INCREASE:
861
expDelta = height_ - PSP_SAS_ENVELOPE_HEIGHT_MAX;
862
// Flipping the sign so that we can shift in the top bits.
863
expDelta += (-expDelta * rate) >> 32;
864
height_ = expDelta + 0x4000 + PSP_SAS_ENVELOPE_HEIGHT_MAX;
867
case PSP_SAS_ADSR_CURVE_MODE_DIRECT:
868
height_ = rate; // Simple :)
873
void ADSREnvelope::SetState(ADSRState state) {
874
if (height_ > PSP_SAS_ENVELOPE_HEIGHT_MAX) {
875
height_ = PSP_SAS_ENVELOPE_HEIGHT_MAX;
877
// TODO: Also check for height_ < 0 and set to 0?
881
inline void ADSREnvelope::Step() {
884
WalkCurve(attackType, attackRate);
885
if (height_ >= PSP_SAS_ENVELOPE_HEIGHT_MAX || height_ < 0)
886
SetState(STATE_DECAY);
889
WalkCurve(decayType, decayRate);
890
if (height_ < sustainLevel)
891
SetState(STATE_SUSTAIN);
894
WalkCurve(sustainType, sustainRate);
897
SetState(STATE_RELEASE);
901
WalkCurve(releaseType, releaseRate);
913
SetState(STATE_KEYON_STEP);
915
case STATE_KEYON_STEP:
916
// This entire state is pretty much a hack to reproduce PSP behavior.
917
// The STATE_KEYON state is a real state, but not sure how it switches.
918
// It takes 32 steps at 0 for keyon to "kick in", 31 should shift to 0 anyway.
922
SetState(STATE_ATTACK);
928
void ADSREnvelope::KeyOn() {
929
SetState(STATE_KEYON);
932
void ADSREnvelope::KeyOff() {
933
SetState(STATE_RELEASE);
936
void ADSREnvelope::End() {
941
void ADSREnvelope::DoState(PointerWrap &p) {
942
auto s = p.Section("ADSREnvelope", 1, 2);