Merge pull request #90 from gizmo98/patch-2
[libretro-ppsspp.git] / Core / HW / SasAudio.cpp
blob15598c1c5bcbceb4f53ae3c8374e70433a8956ff
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"
21 #include "Globals.h"
22 #include "Core/MemMapHelpers.h"
23 #include "Core/HLE/sceAtrac.h"
24 #include "Core/Config.h"
25 #include "Core/Reporting.h"
26 #include "SasAudio.h"
28 #include <algorithm>
30 // #define AUDIO_TO_FILE
32 static const u8 f[16][2] = {
33 { 0, 0 },
34 { 60, 0 },
35 { 115, 52 },
36 { 98, 55 },
37 { 122, 60 },
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.
40 { 0, 0 },
41 { 0, 0 },
42 { 52, 0 },
43 { 55, 2 },
44 { 60, 125 },
45 { 0, 0 },
46 { 0, 91 },
47 { 0, 0 },
48 { 2, 216 },
49 { 125, 6 },
50 { 0, 151 },
53 void VagDecoder::Start(u32 data, u32 vagSize, bool loopEnabled) {
54 loopEnabled_ = loopEnabled;
55 loopAtNextBlock_ = false;
56 loopStartBlock_ = -1;
57 numBlocks_ = vagSize / 16;
58 end_ = false;
59 data_ = data;
60 read_ = data;
61 curSample = 28;
62 curBlock_ = -1;
63 s_1 = 0; // per block?
64 s_2 = 0;
67 void VagDecoder::DecodeBlock(u8 *&read_pointer) {
68 u8 *readp = read_pointer;
69 int predict_nr = *readp++;
70 int shift_factor = predict_nr & 0xf;
71 predict_nr >>= 4;
72 int flags = *readp++;
73 if (flags == 7) {
74 VERBOSE_LOG(SASMIX, "VAG ending block at %d", curBlock_);
75 end_ = true;
76 return;
78 else if (flags == 6) {
79 loopStartBlock_ = curBlock_;
81 else if (flags == 3) {
82 if (loopEnabled_) {
83 loopAtNextBlock_ = true;
87 // Keep state in locals to avoid bouncing to memory.
88 int s1 = s_1;
89 int s2 = s_2;
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) {
96 u8 d = *readp++;
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));
101 samples[i] = s2;
102 samples[i + 1] = s1;
105 s_1 = s1;
106 s_2 = s2;
107 curSample = 0;
108 curBlock_++;
109 if (curBlock_ == numBlocks_) {
110 end_ = true;
113 read_pointer = readp;
116 void VagDecoder::GetSamples(s16 *outSamples, int numSamples) {
117 if (end_) {
118 memset(outSamples, 0, numSamples * sizeof(s16));
119 return;
121 if (!Memory::IsValidAddress(read_)) {
122 WARN_LOG(SASMIX, "Bad VAG samples address?");
123 return;
125 u8 *readp = Memory::GetPointerUnchecked(read_);
126 u8 *origp = readp;
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_);
135 origp = readp;
136 curBlock_ = loopStartBlock_;
137 loopAtNextBlock_ = false;
139 DecodeBlock(readp);
140 if (end_) {
141 // Clear the rest of the buffer and return.
142 memset(&outSamples[i], 0, (numSamples - i) * sizeof(s16));
143 return;
146 outSamples[i] = samples[curSample++];
149 if (readp > origp) {
150 read_ += readp - origp;
154 void VagDecoder::DoState(PointerWrap &p) {
155 auto s = p.Section("VagDecoder", 1);
156 if (!s)
157 return;
159 p.DoArray(samples, ARRAY_SIZE(samples));
160 p.Do(curSample);
162 p.Do(data_);
163 p.Do(read_);
164 p.Do(curBlock_);
165 p.Do(loopStartBlock_);
166 p.Do(numBlocks_);
168 p.Do(s_1);
169 p.Do(s_2);
171 p.Do(loopEnabled_);
172 p.Do(loopAtNextBlock_);
173 p.Do(end_);
176 int SasAtrac3::setContext(u32 context) {
177 contextAddr = context;
178 atracID = _AtracGetIDByContext(context);
179 if (!sampleQueue)
180 sampleQueue = new BufferQueue();
181 sampleQueue->clear();
182 return 0;
185 int SasAtrac3::getNextSamples(s16* outbuf, int wantedSamples) {
186 if (atracID < 0)
187 return -1;
188 u32 finish = 0;
189 int wantedbytes = wantedSamples * sizeof(s16);
190 while (!finish && sampleQueue->getQueueSize() < wantedbytes) {
191 u32 numSamples = 0;
192 int remains = 0;
193 static s16 buf[0x800];
194 _AtracDecodeData(atracID, (u8*)buf, 0, &numSamples, &finish, &remains);
195 if (numSamples > 0)
196 sampleQueue->push((u8*)buf, numSamples * sizeof(s16));
197 else
198 finish = 1;
200 sampleQueue->pop_front((u8*)outbuf, wantedbytes);
201 return finish;
204 int SasAtrac3::addStreamData(u32 bufPtr, u32 addbytes) {
205 if (atracID > 0) {
206 _AtracAddStreamData(atracID, bufPtr, addbytes);
208 return 0;
211 void SasAtrac3::DoState(PointerWrap &p) {
212 auto s = p.Section("SasAtrac3", 1);
213 if (!s)
214 return;
216 p.Do(contextAddr);
217 p.Do(atracID);
218 if (p.mode == p.MODE_READ && atracID >= 0 && !sampleQueue) {
219 sampleQueue = new BufferQueue();
223 // http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/sceSasCore.java
225 static int simpleRate(int n) {
226 n &= 0x7F;
227 if (n == 0x7F) {
228 return 0;
230 int rate = ((7 - (n & 0x3)) << 26) >> (n >> 2);
231 if (rate == 0) {
232 return 1;
234 return rate;
237 static int exponentRate(int n) {
238 n &= 0x7F;
239 if (n == 0x7F) {
240 return 0;
242 int rate = ((7 - (n & 0x3)) << 24) >> (n >> 2);
243 if (rate == 0) {
244 return 1;
246 return rate;
249 static int getAttackRate(int bitfield1) {
250 return simpleRate(bitfield1 >> 8);
253 static int getAttackType(int bitfield1) {
254 return (bitfield1 & 0x8000) == 0 ? PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE : PSP_SAS_ADSR_CURVE_MODE_LINEAR_BENT;
257 static int getDecayRate(int bitfield1) {
258 int n = (bitfield1 >> 4) & 0x000F;
259 if (n == 0)
260 return 0x7FFFFFFF;
261 return 0x80000000 >> n;
264 static int getSustainType(int bitfield2) {
265 return (bitfield2 >> 14) & 3;
268 static int getSustainRate(int bitfield2) {
269 if (getSustainType(bitfield2) == PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE) {
270 return exponentRate(bitfield2 >> 6);
271 } else {
272 return simpleRate(bitfield2 >> 6);
276 static int getReleaseType(int bitfield2) {
277 return (bitfield2 & 0x0020) == 0 ? PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE : PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE;
280 static int getReleaseRate(int bitfield2) {
281 int n = bitfield2 & 0x001F;
282 if (n == 31) {
283 return 0;
285 if (getReleaseType(bitfield2) == PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE) {
286 if (n == 30) {
287 return 0x40000000;
288 } else if (n == 29) {
289 return 1;
291 return 0x10000000 >> n;
293 if (n == 0)
294 return 0x7FFFFFFF;
295 return 0x80000000 >> n;
298 static int getSustainLevel(int bitfield1) {
299 return ((bitfield1 & 0x000F) + 1) << 26;
302 void ADSREnvelope::SetSimpleEnvelope(u32 ADSREnv1, u32 ADSREnv2) {
303 attackRate = getAttackRate(ADSREnv1);
304 attackType = getAttackType(ADSREnv1);
305 decayRate = getDecayRate(ADSREnv1);
306 decayType = PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE;
307 sustainRate = getSustainRate(ADSREnv2);
308 sustainType = getSustainType(ADSREnv2);
309 releaseRate = getReleaseRate(ADSREnv2);
310 releaseType = getReleaseType(ADSREnv2);
311 sustainLevel = getSustainLevel(ADSREnv1);
313 if (attackRate < 0 || decayRate < 0 || sustainRate < 0 || releaseRate < 0) {
314 ERROR_LOG_REPORT(SCESAS, "Simple ADSR resulted in invalid rates: %04x, %04x", ADSREnv1, ADSREnv2);
318 SasInstance::SasInstance()
319 : maxVoices(PSP_SAS_VOICES_MAX),
320 sampleRate(44100),
321 outputMode(PSP_SAS_OUTPUTMODE_MIXED),
322 mixBuffer(0),
323 sendBuffer(0),
324 resampleBuffer(0),
325 grainSize(0) {
326 #ifdef AUDIO_TO_FILE
327 audioDump = fopen("D:\\audio.raw", "wb");
328 #endif
329 memset(&waveformEffect, 0, sizeof(waveformEffect));
330 waveformEffect.type = PSP_SAS_EFFECT_TYPE_OFF;
331 waveformEffect.isDryOn = 1;
334 SasInstance::~SasInstance() {
335 ClearGrainSize();
338 void SasInstance::ClearGrainSize() {
339 if (mixBuffer)
340 delete [] mixBuffer;
341 if (sendBuffer)
342 delete [] sendBuffer;
343 if (resampleBuffer)
344 delete [] resampleBuffer;
345 mixBuffer = NULL;
346 sendBuffer = NULL;
347 resampleBuffer = NULL;
350 void SasInstance::SetGrainSize(int newGrainSize) {
351 grainSize = newGrainSize;
353 // If you change the sizes here, don't forget DoState().
354 if (mixBuffer)
355 delete [] mixBuffer;
356 if (sendBuffer)
357 delete [] sendBuffer;
358 mixBuffer = new s32[grainSize * 2];
359 sendBuffer = new s32[grainSize * 2];
360 memset(mixBuffer, 0, sizeof(int) * grainSize * 2);
361 memset(sendBuffer, 0, sizeof(int) * grainSize * 2);
362 if (resampleBuffer)
363 delete [] resampleBuffer;
365 // 2 samples padding at the start, that's where we copy the two last samples from the channel
366 // so that we can do bicubic resampling if necessary. Plus 1 for smoothness hackery.
367 resampleBuffer = new s16[grainSize * 4 + 3];
370 void SasVoice::ReadSamples(s16 *output, int numSamples) {
371 // Read N samples into the resample buffer. Could do either PCM or VAG here.
372 switch (type) {
373 case VOICETYPE_VAG:
374 vag.GetSamples(output, numSamples);
375 break;
376 case VOICETYPE_PCM:
378 int needed = numSamples;
379 s16 *out = output;
380 while (needed > 0) {
381 u32 size = std::min(pcmSize - pcmIndex, needed);
382 if (!on) {
383 pcmIndex = 0;
384 break;
386 Memory::Memcpy(out, pcmAddr + pcmIndex * sizeof(s16), size * sizeof(s16));
387 pcmIndex += size;
388 needed -= size;
389 out += size;
390 if (pcmIndex >= pcmSize) {
391 if (!loop) {
392 // All out, quit. We'll end in HaveSamplesEnded().
393 break;
395 pcmIndex = pcmLoopPos;
398 if (needed > 0) {
399 memset(out, 0, needed * sizeof(s16));
402 break;
403 case VOICETYPE_ATRAC3:
405 int ret = atrac3.getNextSamples(output, numSamples);
406 if (ret) {
407 // Hit atrac3 voice end
408 playing = false;
409 on = false; // ??
410 envelope.End();
413 break;
414 default:
416 memset(output, 0, numSamples * sizeof(s16));
418 break;
422 bool SasVoice::HaveSamplesEnded() const {
423 switch (type) {
424 case VOICETYPE_VAG:
425 return vag.End();
427 case VOICETYPE_PCM:
428 return pcmIndex >= pcmSize;
430 case VOICETYPE_ATRAC3:
431 // TODO: Is it here, or before the samples are processed?
432 return false;
434 default:
435 return false;
439 void SasInstance::MixVoice(SasVoice &voice) {
440 switch (voice.type) {
441 case VOICETYPE_VAG:
442 if (voice.type == VOICETYPE_VAG && !voice.vagAddr)
443 break;
444 // else fallthrough! Don't change the check above.
445 case VOICETYPE_PCM:
446 if (voice.type == VOICETYPE_PCM && !voice.pcmAddr)
447 break;
448 // else fallthrough! Don't change the check above.
449 default:
450 // Load resample history (so we can use a wide filter)
451 resampleBuffer[0] = voice.resampleHist[0];
452 resampleBuffer[1] = voice.resampleHist[1];
454 // Figure out number of samples to read.
455 // Actually this is not entirely correct - we need to get one extra sample, and store it
456 // for the next time around. A little complicated...
457 // But for now, see Smoothness HACKERY below :P
458 u32 numSamples = ((u32)voice.sampleFrac + (u32)grainSize * (u32)voice.pitch) >> PSP_SAS_PITCH_BASE_SHIFT;
459 if ((int)numSamples > grainSize * 4) {
460 ERROR_LOG(SASMIX, "numSamples too large, clamping: %i vs %i", numSamples, grainSize * 4);
461 numSamples = grainSize * 4;
464 // This feels a bit hacky. The first 32 samples after a keyon are 0s.
465 const bool ignorePitch = voice.type == VOICETYPE_PCM && voice.pitch > PSP_SAS_PITCH_BASE;
466 if (voice.envelope.NeedsKeyOn()) {
467 int delay = ignorePitch ? 32 : (32 * (u32)voice.pitch) >> PSP_SAS_PITCH_BASE_SHIFT;
468 // VAG seems to have an extra sample delay (not shared by PCM.)
469 if (voice.type == VOICETYPE_VAG)
470 ++delay;
471 voice.ReadSamples(resampleBuffer + 2 + delay, numSamples - delay);
472 } else {
473 voice.ReadSamples(resampleBuffer + 2, numSamples);
476 // Smoothness HACKERY
477 resampleBuffer[2 + numSamples] = resampleBuffer[2 + numSamples - 1];
479 // Save resample history
480 voice.resampleHist[0] = resampleBuffer[2 + numSamples - 2];
481 voice.resampleHist[1] = resampleBuffer[2 + numSamples - 1];
483 // Resample to the correct pitch, writing exactly "grainSize" samples.
484 // This is a HORRIBLE resampler by the way.
485 // TODO: Special case no-resample case (and 2x and 0.5x) for speed, it's not uncommon
487 u32 sampleFrac = voice.sampleFrac;
488 // We need to shift by 12 anyway, so combine that with the volume shift.
489 for (int i = 0; i < grainSize; i++) {
490 // For now: nearest neighbour, not even using the resample history at all.
491 int sample = resampleBuffer[sampleFrac / PSP_SAS_PITCH_BASE + 2];
492 sampleFrac += voice.pitch;
494 // The maximum envelope height (PSP_SAS_ENVELOPE_HEIGHT_MAX) is (1 << 30) - 1.
495 // Reduce it to 14 bits, by shifting off 15. Round up by adding (1 << 14) first.
496 int envelopeValue = voice.envelope.GetHeight();
497 voice.envelope.Step();
498 envelopeValue = (envelopeValue + (1 << 14)) >> 15;
500 // We just scale by the envelope before we scale by volumes.
501 // Again, we round up by adding (1 << 14) first (*after* multiplying.)
502 sample = ((sample * envelopeValue) + (1 << 14)) >> 15;
504 // We mix into this 32-bit temp buffer and clip in a second loop
505 // Ideally, the shift right should be there too but for now I'm concerned about
506 // not overflowing.
507 mixBuffer[i * 2] += (sample * voice.volumeLeft ) >> 12;
508 mixBuffer[i * 2 + 1] += (sample * voice.volumeRight) >> 12;
509 sendBuffer[i * 2] += sample * voice.effectLeft >> 12;
510 sendBuffer[i * 2 + 1] += sample * voice.effectRight >> 12;
513 voice.sampleFrac = sampleFrac;
514 // Let's hope grainSize is a power of 2.
515 //voice.sampleFrac &= grainSize * PSP_SAS_PITCH_BASE - 1;
516 voice.sampleFrac -= numSamples * PSP_SAS_PITCH_BASE;
518 if (voice.HaveSamplesEnded())
519 voice.envelope.End();
520 if (voice.envelope.HasEnded())
522 // NOTICE_LOG(SCESAS, "Hit end of envelope");
523 voice.playing = false;
524 voice.on = false;
529 void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol) {
530 PROFILE_THIS_SCOPE("mixer");
532 int voicesPlayingCount = 0;
534 for (int v = 0; v < PSP_SAS_VOICES_MAX; v++) {
535 SasVoice &voice = voices[v];
536 if (!voice.playing || voice.paused)
537 continue;
538 voicesPlayingCount++;
539 MixVoice(voice);
542 // Okay, apply effects processing to the Send buffer.
543 // TODO: Is this only done in PSP_SAS_OUTPUTMODE_MIXED?
544 //if (waveformEffect.type != PSP_SAS_EFFECT_TYPE_OFF)
545 // ApplyReverb();
547 // Then mix the send buffer in with the rest.
549 // Alright, all voices mixed. Let's convert and clip, and at the same time, wipe mixBuffer for next time. Could also dither.
550 s16 *outp = (s16 *)Memory::GetPointer(outAddr);
551 const s16 *inp = inAddr ? (s16*)Memory::GetPointer(inAddr) : 0;
552 if (outputMode == PSP_SAS_OUTPUTMODE_MIXED) {
553 // TODO: Mix send when it has proper values, probably based on dry/wet?
554 if (inp) {
555 for (int i = 0; i < grainSize * 2; i += 2) {
556 int sampleL = mixBuffer[i + 0] + ((*inp++) * leftVol >> 12);
557 int sampleR = mixBuffer[i + 1] + ((*inp++) * rightVol >> 12);
558 *outp++ = clamp_s16(sampleL);
559 *outp++ = clamp_s16(sampleR);
561 } else {
562 for (int i = 0; i < grainSize * 2; i += 2) {
563 *outp++ = clamp_s16(mixBuffer[i + 0]);
564 *outp++ = clamp_s16(mixBuffer[i + 1]);
567 } else {
568 s16 *outpL = outp + grainSize * 0;
569 s16 *outpR = outp + grainSize * 1;
570 s16 *outpSendL = outp + grainSize * 2;
571 s16 *outpSendR = outp + grainSize * 3;
572 WARN_LOG_REPORT_ONCE(sasraw, SCESAS, "sceSasCore: raw outputMode");
573 for (int i = 0; i < grainSize * 2; i += 2) {
574 *outpL++ = clamp_s16(mixBuffer[i + 0]);
575 *outpR++ = clamp_s16(mixBuffer[i + 1]);
576 *outpSendL++ = clamp_s16(sendBuffer[i + 0]);
577 *outpSendR++ = clamp_s16(sendBuffer[i + 1]);
580 memset(mixBuffer, 0, grainSize * sizeof(int) * 2);
581 memset(sendBuffer, 0, grainSize * sizeof(int) * 2);
583 #ifdef AUDIO_TO_FILE
584 fwrite(Memory::GetPointer(outAddr), 1, grainSize * 2 * 2, audioDump);
585 #endif
588 void SasInstance::ApplyReverb() {
589 // for (int i = 0; i < grainSize * 2; i += 2) {
590 // modify sendBuffer
591 // }
594 void SasInstance::DoState(PointerWrap &p) {
595 auto s = p.Section("SasInstance", 1);
596 if (!s)
597 return;
599 p.Do(grainSize);
600 if (p.mode == p.MODE_READ) {
601 if (grainSize > 0) {
602 SetGrainSize(grainSize);
603 } else {
604 ClearGrainSize();
608 p.Do(maxVoices);
609 p.Do(sampleRate);
610 p.Do(outputMode);
612 // SetGrainSize() / ClearGrainSize() should've made our buffers match.
613 if (mixBuffer != NULL && grainSize > 0) {
614 p.DoArray(mixBuffer, grainSize * 2);
616 if (sendBuffer != NULL && grainSize > 0) {
617 p.DoArray(sendBuffer, grainSize * 2);
619 if (resampleBuffer != NULL && grainSize > 0) {
620 p.DoArray(resampleBuffer, grainSize * 4 + 3);
623 int n = PSP_SAS_VOICES_MAX;
624 p.Do(n);
625 if (n != PSP_SAS_VOICES_MAX)
627 ERROR_LOG(HLE, "Savestate failure: wrong number of SAS voices");
628 return;
630 p.DoArray(voices, ARRAY_SIZE(voices));
631 p.Do(waveformEffect);
634 void SasVoice::Reset() {
635 resampleHist[0] = 0;
636 resampleHist[1] = 0;
639 void SasVoice::KeyOn() {
640 envelope.KeyOn();
641 switch (type) {
642 case VOICETYPE_VAG:
643 if (Memory::IsValidAddress(vagAddr)) {
644 vag.Start(vagAddr, vagSize, loop);
645 } else {
646 ERROR_LOG(SASMIX, "Invalid VAG address %08x", vagAddr);
647 return;
649 break;
650 default:
651 break;
653 playing = true;
654 on = true;
655 paused = false;
656 sampleFrac = 0;
659 void SasVoice::KeyOff() {
660 on = false;
661 envelope.KeyOff();
664 void SasVoice::ChangedParams(bool changedVag) {
665 if (!playing && on) {
666 playing = true;
667 if (changedVag)
668 vag.Start(vagAddr, vagSize, loop);
670 // TODO: restart VAG somehow
673 void SasVoice::DoState(PointerWrap &p)
675 auto s = p.Section("SasVoice", 1, 3);
676 if (!s)
677 return;
679 p.Do(playing);
680 p.Do(paused);
681 p.Do(on);
683 p.Do(type);
685 p.Do(vagAddr);
686 p.Do(vagSize);
687 p.Do(pcmAddr);
688 p.Do(pcmSize);
689 p.Do(pcmIndex);
690 if (s >= 2) {
691 p.Do(pcmLoopPos);
692 } else {
693 pcmLoopPos = 0;
695 p.Do(sampleRate);
697 p.Do(sampleFrac);
698 p.Do(pitch);
699 p.Do(loop);
700 if (s < 2 && type == VOICETYPE_PCM) {
701 // We set loop incorrectly before, and always looped.
702 // Let's keep always looping, since it's usually right.
703 loop = true;
706 p.Do(noiseFreq);
708 p.Do(volumeLeft);
709 p.Do(volumeRight);
710 if (s < 3) {
711 // There were extra variables here that were for the same purpose.
712 p.Do(effectLeft);
713 p.Do(effectRight);
715 p.Do(effectLeft);
716 p.Do(effectRight);
717 p.DoArray(resampleHist, ARRAY_SIZE(resampleHist));
719 envelope.DoState(p);
720 vag.DoState(p);
721 atrac3.DoState(p);
724 ADSREnvelope::ADSREnvelope()
725 : attackRate(0),
726 decayRate(0),
727 sustainRate(0),
728 releaseRate(0),
729 attackType(PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE),
730 decayType(PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE),
731 sustainType(PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE),
732 sustainLevel(0),
733 releaseType(PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE),
734 state_(STATE_OFF),
735 height_(0) {
738 void ADSREnvelope::WalkCurve(int type, int rate) {
739 s64 expDelta;
740 switch (type) {
741 case PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE:
742 height_ += rate;
743 break;
745 case PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE:
746 height_ -= rate;
747 break;
749 case PSP_SAS_ADSR_CURVE_MODE_LINEAR_BENT:
750 if (height_ <= (s64)PSP_SAS_ENVELOPE_HEIGHT_MAX * 3 / 4) {
751 height_ += rate;
752 } else {
753 height_ += rate / 4;
755 break;
757 case PSP_SAS_ADSR_CURVE_MODE_EXPONENT_DECREASE:
758 expDelta = height_ - PSP_SAS_ENVELOPE_HEIGHT_MAX;
759 // Flipping the sign so that we can shift in the top bits.
760 expDelta += (-expDelta * rate) >> 32;
761 height_ = expDelta + PSP_SAS_ENVELOPE_HEIGHT_MAX - (rate + 3UL) / 4UL;
762 break;
764 case PSP_SAS_ADSR_CURVE_MODE_EXPONENT_INCREASE:
765 expDelta = height_ - PSP_SAS_ENVELOPE_HEIGHT_MAX;
766 // Flipping the sign so that we can shift in the top bits.
767 expDelta += (-expDelta * rate) >> 32;
768 height_ = expDelta + 0x4000 + PSP_SAS_ENVELOPE_HEIGHT_MAX;
769 break;
771 case PSP_SAS_ADSR_CURVE_MODE_DIRECT:
772 height_ = rate; // Simple :)
773 break;
777 void ADSREnvelope::SetState(ADSRState state) {
778 if (height_ > PSP_SAS_ENVELOPE_HEIGHT_MAX) {
779 height_ = PSP_SAS_ENVELOPE_HEIGHT_MAX;
781 // TODO: Also check for height_ < 0 and set to 0?
782 state_ = state;
785 inline void ADSREnvelope::Step() {
786 switch (state_) {
787 case STATE_ATTACK:
788 WalkCurve(attackType, attackRate);
789 if (height_ >= PSP_SAS_ENVELOPE_HEIGHT_MAX || height_ < 0)
790 SetState(STATE_DECAY);
791 break;
792 case STATE_DECAY:
793 WalkCurve(decayType, decayRate);
794 if (height_ < sustainLevel)
795 SetState(STATE_SUSTAIN);
796 break;
797 case STATE_SUSTAIN:
798 WalkCurve(sustainType, sustainRate);
799 if (height_ <= 0) {
800 height_ = 0;
801 SetState(STATE_RELEASE);
803 break;
804 case STATE_RELEASE:
805 WalkCurve(releaseType, releaseRate);
806 if (height_ <= 0) {
807 height_ = 0;
808 SetState(STATE_OFF);
810 break;
811 case STATE_OFF:
812 // Do nothing
813 break;
815 case STATE_KEYON:
816 height_ = 0;
817 SetState(STATE_KEYON_STEP);
818 break;
819 case STATE_KEYON_STEP:
820 // This entire state is pretty much a hack to reproduce PSP behavior.
821 // The STATE_KEYON state is a real state, but not sure how it switches.
822 // It takes 32 steps at 0 for keyon to "kick in", 31 should shift to 0 anyway.
823 height_++;
824 if (height_ >= 31) {
825 height_ = 0;
826 SetState(STATE_ATTACK);
828 break;
832 void ADSREnvelope::KeyOn() {
833 SetState(STATE_KEYON);
836 void ADSREnvelope::KeyOff() {
837 SetState(STATE_RELEASE);
840 void ADSREnvelope::End() {
841 SetState(STATE_OFF);
842 height_ = 0;
845 void ADSREnvelope::DoState(PointerWrap &p) {
846 auto s = p.Section("ADSREnvelope", 1, 2);
847 if (!s) {
848 return;
851 p.Do(attackRate);
852 p.Do(decayRate);
853 p.Do(sustainRate);
854 p.Do(releaseRate);
855 p.Do(attackType);
856 p.Do(decayType);
857 p.Do(sustainType);
858 p.Do(sustainLevel);
859 p.Do(releaseType);
860 if (s < 2) {
861 p.Do(state_);
862 if (state_ == 4) {
863 state_ = STATE_OFF;
865 int stepsLegacy;
866 p.Do(stepsLegacy);
867 } else {
868 p.Do(state_);
870 p.Do(height_);