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);
159 p
.DoArray(samples
, ARRAY_SIZE(samples
));
165 p
.Do(loopStartBlock_
);
172 p
.Do(loopAtNextBlock_
);
176 int SasAtrac3::setContext(u32 context
) {
177 contextAddr
= context
;
178 atracID
= _AtracGetIDByContext(context
);
180 sampleQueue
= new BufferQueue();
181 sampleQueue
->clear();
185 int SasAtrac3::getNextSamples(s16
* outbuf
, int wantedSamples
) {
189 int wantedbytes
= wantedSamples
* sizeof(s16
);
190 while (!finish
&& sampleQueue
->getQueueSize() < wantedbytes
) {
193 static s16 buf
[0x800];
194 _AtracDecodeData(atracID
, (u8
*)buf
, 0, &numSamples
, &finish
, &remains
);
196 sampleQueue
->push((u8
*)buf
, numSamples
* sizeof(s16
));
200 sampleQueue
->pop_front((u8
*)outbuf
, wantedbytes
);
204 int SasAtrac3::addStreamData(u32 bufPtr
, u32 addbytes
) {
206 _AtracAddStreamData(atracID
, bufPtr
, addbytes
);
211 void SasAtrac3::DoState(PointerWrap
&p
) {
212 auto s
= p
.Section("SasAtrac3", 1);
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
) {
230 int rate
= ((7 - (n
& 0x3)) << 26) >> (n
>> 2);
237 static int exponentRate(int n
) {
242 int rate
= ((7 - (n
& 0x3)) << 24) >> (n
>> 2);
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;
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);
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;
285 if (getReleaseType(bitfield2
) == PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE
) {
288 } else if (n
== 29) {
291 return 0x10000000 >> n
;
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
),
321 outputMode(PSP_SAS_OUTPUTMODE_MIXED
),
327 audioDump
= fopen("D:\\audio.raw", "wb");
329 memset(&waveformEffect
, 0, sizeof(waveformEffect
));
330 waveformEffect
.type
= PSP_SAS_EFFECT_TYPE_OFF
;
331 waveformEffect
.isDryOn
= 1;
334 SasInstance::~SasInstance() {
338 void SasInstance::ClearGrainSize() {
342 delete [] sendBuffer
;
344 delete [] resampleBuffer
;
347 resampleBuffer
= NULL
;
350 void SasInstance::SetGrainSize(int newGrainSize
) {
351 grainSize
= newGrainSize
;
353 // If you change the sizes here, don't forget DoState().
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);
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.
374 vag
.GetSamples(output
, numSamples
);
378 int needed
= numSamples
;
381 u32 size
= std::min(pcmSize
- pcmIndex
, needed
);
386 Memory::Memcpy(out
, pcmAddr
+ pcmIndex
* sizeof(s16
), size
* sizeof(s16
));
390 if (pcmIndex
>= pcmSize
) {
392 // All out, quit. We'll end in HaveSamplesEnded().
395 pcmIndex
= pcmLoopPos
;
399 memset(out
, 0, needed
* sizeof(s16
));
403 case VOICETYPE_ATRAC3
:
405 int ret
= atrac3
.getNextSamples(output
, numSamples
);
407 // Hit atrac3 voice end
416 memset(output
, 0, numSamples
* sizeof(s16
));
422 bool SasVoice::HaveSamplesEnded() const {
428 return pcmIndex
>= pcmSize
;
430 case VOICETYPE_ATRAC3
:
431 // TODO: Is it here, or before the samples are processed?
439 void SasInstance::MixVoice(SasVoice
&voice
) {
440 switch (voice
.type
) {
442 if (voice
.type
== VOICETYPE_VAG
&& !voice
.vagAddr
)
444 // else fallthrough! Don't change the check above.
446 if (voice
.type
== VOICETYPE_PCM
&& !voice
.pcmAddr
)
448 // else fallthrough! Don't change the check above.
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
)
471 voice
.ReadSamples(resampleBuffer
+ 2 + delay
, numSamples
- delay
);
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
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;
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
)
538 voicesPlayingCount
++;
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)
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?
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
);
562 for (int i
= 0; i
< grainSize
* 2; i
+= 2) {
563 *outp
++ = clamp_s16(mixBuffer
[i
+ 0]);
564 *outp
++ = clamp_s16(mixBuffer
[i
+ 1]);
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);
584 fwrite(Memory::GetPointer(outAddr
), 1, grainSize
* 2 * 2, audioDump
);
588 void SasInstance::ApplyReverb() {
589 // for (int i = 0; i < grainSize * 2; i += 2) {
594 void SasInstance::DoState(PointerWrap
&p
) {
595 auto s
= p
.Section("SasInstance", 1);
600 if (p
.mode
== p
.MODE_READ
) {
602 SetGrainSize(grainSize
);
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
;
625 if (n
!= PSP_SAS_VOICES_MAX
)
627 ERROR_LOG(HLE
, "Savestate failure: wrong number of SAS voices");
630 p
.DoArray(voices
, ARRAY_SIZE(voices
));
631 p
.Do(waveformEffect
);
634 void SasVoice::Reset() {
639 void SasVoice::KeyOn() {
643 if (Memory::IsValidAddress(vagAddr
)) {
644 vag
.Start(vagAddr
, vagSize
, loop
);
646 ERROR_LOG(SASMIX
, "Invalid VAG address %08x", vagAddr
);
659 void SasVoice::KeyOff() {
664 void SasVoice::ChangedParams(bool changedVag
) {
665 if (!playing
&& on
) {
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);
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.
711 // There were extra variables here that were for the same purpose.
717 p
.DoArray(resampleHist
, ARRAY_SIZE(resampleHist
));
724 ADSREnvelope::ADSREnvelope()
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
),
733 releaseType(PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE
),
738 void ADSREnvelope::WalkCurve(int type
, int rate
) {
741 case PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE
:
745 case PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE
:
749 case PSP_SAS_ADSR_CURVE_MODE_LINEAR_BENT
:
750 if (height_
<= (s64
)PSP_SAS_ENVELOPE_HEIGHT_MAX
* 3 / 4) {
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;
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
;
771 case PSP_SAS_ADSR_CURVE_MODE_DIRECT
:
772 height_
= rate
; // Simple :)
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?
785 inline void ADSREnvelope::Step() {
788 WalkCurve(attackType
, attackRate
);
789 if (height_
>= PSP_SAS_ENVELOPE_HEIGHT_MAX
|| height_
< 0)
790 SetState(STATE_DECAY
);
793 WalkCurve(decayType
, decayRate
);
794 if (height_
< sustainLevel
)
795 SetState(STATE_SUSTAIN
);
798 WalkCurve(sustainType
, sustainRate
);
801 SetState(STATE_RELEASE
);
805 WalkCurve(releaseType
, releaseRate
);
817 SetState(STATE_KEYON_STEP
);
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.
826 SetState(STATE_ATTACK
);
832 void ADSREnvelope::KeyOn() {
833 SetState(STATE_KEYON
);
836 void ADSREnvelope::KeyOff() {
837 SetState(STATE_RELEASE
);
840 void ADSREnvelope::End() {
845 void ADSREnvelope::DoState(PointerWrap
&p
) {
846 auto s
= p
.Section("ADSREnvelope", 1, 2);