2015-10-10 02:16:12 +00:00
|
|
|
inline auto DSP::voiceOutput(Voice& v, bool channel) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
//apply left/right volume
|
2016-03-29 09:15:01 +00:00
|
|
|
int amp = (state._output * (int8)VREG(VOLL + channel)) >> 7;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
//add to output total
|
2015-10-10 02:16:12 +00:00
|
|
|
state._mainOut[channel] += amp;
|
|
|
|
state._mainOut[channel] = sclamp<16>(state._mainOut[channel]);
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
//optionally add to echo total
|
2015-10-10 02:16:12 +00:00
|
|
|
if(state._eon & v.vbit) {
|
|
|
|
state._echoOut[channel] += amp;
|
|
|
|
state._echoOut[channel] = sclamp<16>(state._echoOut[channel]);
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-10 02:16:12 +00:00
|
|
|
auto DSP::voice1(Voice& v) -> void {
|
|
|
|
state._dirAddress = (state._dir << 8) + (state._srcn << 2);
|
|
|
|
state._srcn = VREG(SRCN);
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-10 02:16:12 +00:00
|
|
|
auto DSP::voice2(Voice& v) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
//read sample pointer (ignored if not needed)
|
2015-10-10 02:16:12 +00:00
|
|
|
uint16 addr = state._dirAddress;
|
|
|
|
if(!v.konDelay) addr += 2;
|
Update to v103r05 release.
byuu says:
Changelog:
- fc/controller: added ControllerPort class; removed Peripherals class
- md/controller/gamepad: removed X,Y,Z buttons since this isn't a
6-button controller
- ms/controller: added ControllerPort class (not used in Game Gear
mode); removed Peripherals class
- pce/controller: added ControllerPort class; removed Peripherals
class
- processor/spc700: idle(address) is part of SMP class again, contains
flag to detect mov (x)+ edge case
- sfc/controller/super-scope,justifier: use CPU frequency instead of
hard-coding NTSC frequency
- sfc/cpu: move 4x8-bit SMP ports to SMP class
- sfc/smp: move APU RAM to DSP class
- sfc/smp: improved emulation of TEST registers bits 4-7 [information
from nocash]
- d4,d5 is RAM wait states (1,2,5,10)
- d6,d7 is ROM/IO wait states (1,2,5,10)
- sfc/smp: code cleanup to new style (order from lowest to highest
bits; use .bit(s) functions)
- sfc/smp: $00f8,$00f9 are P4/P5 auxiliary ports; named the registers
better
2017-07-01 06:15:27 +00:00
|
|
|
uint8 lo = apuram[(uint16)(addr + 0)];
|
|
|
|
uint8 hi = apuram[(uint16)(addr + 1)];
|
2015-10-10 02:16:12 +00:00
|
|
|
state._brrNextAddress = ((hi << 8) + lo);
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2015-10-10 02:16:12 +00:00
|
|
|
state._adsr0 = VREG(ADSR0);
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
//read pitch, spread over two clocks
|
2015-10-10 02:16:12 +00:00
|
|
|
state._pitch = VREG(PITCHL);
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-10 02:16:12 +00:00
|
|
|
auto DSP::voice3(Voice& v) -> void {
|
|
|
|
voice3a(v);
|
|
|
|
voice3b(v);
|
|
|
|
voice3c(v);
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-10 02:16:12 +00:00
|
|
|
auto DSP::voice3a(Voice& v) -> void {
|
|
|
|
state._pitch += (VREG(PITCHH) & 0x3f) << 8;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-10 02:16:12 +00:00
|
|
|
auto DSP::voice3b(Voice& v) -> void {
|
Update to v103r05 release.
byuu says:
Changelog:
- fc/controller: added ControllerPort class; removed Peripherals class
- md/controller/gamepad: removed X,Y,Z buttons since this isn't a
6-button controller
- ms/controller: added ControllerPort class (not used in Game Gear
mode); removed Peripherals class
- pce/controller: added ControllerPort class; removed Peripherals
class
- processor/spc700: idle(address) is part of SMP class again, contains
flag to detect mov (x)+ edge case
- sfc/controller/super-scope,justifier: use CPU frequency instead of
hard-coding NTSC frequency
- sfc/cpu: move 4x8-bit SMP ports to SMP class
- sfc/smp: move APU RAM to DSP class
- sfc/smp: improved emulation of TEST registers bits 4-7 [information
from nocash]
- d4,d5 is RAM wait states (1,2,5,10)
- d6,d7 is ROM/IO wait states (1,2,5,10)
- sfc/smp: code cleanup to new style (order from lowest to highest
bits; use .bit(s) functions)
- sfc/smp: $00f8,$00f9 are P4/P5 auxiliary ports; named the registers
better
2017-07-01 06:15:27 +00:00
|
|
|
state._brrByte = apuram[(uint16)(v.brrAddress + v.brrOffset)];
|
|
|
|
state._brrHeader = apuram[(uint16)(v.brrAddress)];
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-10 02:16:12 +00:00
|
|
|
auto DSP::voice3c(Voice& v) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
//pitch modulation using previous voice's output
|
|
|
|
|
2015-10-10 02:16:12 +00:00
|
|
|
if(state._pmon & v.vbit) {
|
|
|
|
state._pitch += ((state._output >> 5) * state._pitch) >> 10;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-10 02:16:12 +00:00
|
|
|
if(v.konDelay) {
|
2010-08-09 13:28:56 +00:00
|
|
|
//get ready to start BRR decoding on next sample
|
2015-10-10 02:16:12 +00:00
|
|
|
if(v.konDelay == 5) {
|
|
|
|
v.brrAddress = state._brrNextAddress;
|
|
|
|
v.brrOffset = 1;
|
|
|
|
v.bufferOffset = 0;
|
|
|
|
state._brrHeader = 0; //header is ignored on this sample
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//envelope is never run during KON
|
2015-10-10 02:16:12 +00:00
|
|
|
v.envelope = 0;
|
|
|
|
v.hiddenEnvelope = 0;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
//disable BRR decoding until last three samples
|
2015-10-10 02:16:12 +00:00
|
|
|
v.gaussianOffset = 0;
|
|
|
|
v.konDelay--;
|
|
|
|
if(v.konDelay & 3) v.gaussianOffset = 0x4000;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
//pitch is never added during KON
|
2015-10-10 02:16:12 +00:00
|
|
|
state._pitch = 0;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//gaussian interpolation
|
2016-03-29 09:15:01 +00:00
|
|
|
int output = gaussianInterpolate(v);
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
//noise
|
2015-10-10 02:16:12 +00:00
|
|
|
if(state._non & v.vbit) {
|
2010-08-09 13:28:56 +00:00
|
|
|
output = (int16)(state.noise << 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
//apply envelope
|
2015-10-10 02:16:12 +00:00
|
|
|
state._output = ((output * v.envelope) >> 11) & ~1;
|
|
|
|
v._envxOut = v.envelope >> 4;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
//immediate silence due to end of sample or soft reset
|
2015-10-10 02:16:12 +00:00
|
|
|
if(REG(FLG) & 0x80 || (state._brrHeader & 3) == 1) {
|
|
|
|
v.envelopeMode = EnvelopeRelease;
|
|
|
|
v.envelope = 0;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-10 02:16:12 +00:00
|
|
|
if(state.everyOtherSample) {
|
2010-08-09 13:28:56 +00:00
|
|
|
//KOFF
|
2015-10-10 02:16:12 +00:00
|
|
|
if(state._koff & v.vbit) {
|
|
|
|
v.envelopeMode = EnvelopeRelease;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//KON
|
|
|
|
if(state.kon & v.vbit) {
|
2015-10-10 02:16:12 +00:00
|
|
|
v.konDelay = 5;
|
|
|
|
v.envelopeMode = EnvelopeAttack;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//run envelope for next sample
|
2015-10-10 02:16:12 +00:00
|
|
|
if(!v.konDelay) envelopeRun(v);
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-10 02:16:12 +00:00
|
|
|
auto DSP::voice4(Voice& v) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
//decode BRR
|
2015-10-10 02:16:12 +00:00
|
|
|
state._looped = 0;
|
|
|
|
if(v.gaussianOffset >= 0x4000) {
|
|
|
|
brrDecode(v);
|
|
|
|
v.brrOffset += 2;
|
|
|
|
if(v.brrOffset >= 9) {
|
2010-08-09 13:28:56 +00:00
|
|
|
//start decoding next BRR block
|
2015-10-10 02:16:12 +00:00
|
|
|
v.brrAddress = (uint16)(v.brrAddress + 9);
|
|
|
|
if(state._brrHeader & 1) {
|
|
|
|
v.brrAddress = state._brrNextAddress;
|
|
|
|
state._looped = v.vbit;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
2015-10-10 02:16:12 +00:00
|
|
|
v.brrOffset = 1;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//apply pitch
|
2015-10-10 02:16:12 +00:00
|
|
|
v.gaussianOffset = (v.gaussianOffset & 0x3fff) + state._pitch;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
//keep from getting too far ahead (when using pitch modulation)
|
2015-10-10 02:16:12 +00:00
|
|
|
if(v.gaussianOffset > 0x7fff) v.gaussianOffset = 0x7fff;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
//output left
|
2015-10-10 02:16:12 +00:00
|
|
|
voiceOutput(v, 0);
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-10 02:16:12 +00:00
|
|
|
auto DSP::voice5(Voice& v) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
//output right
|
2015-10-10 02:16:12 +00:00
|
|
|
voiceOutput(v, 1);
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
//ENDX, OUTX and ENVX won't update if you wrote to them 1-2 clocks earlier
|
2015-10-10 02:16:12 +00:00
|
|
|
state.endxBuffer = REG(ENDX) | state._looped;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
//clear bit in ENDX if KON just began
|
2015-10-10 02:16:12 +00:00
|
|
|
if(v.konDelay == 5) state.endxBuffer &= ~v.vbit;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-10 02:16:12 +00:00
|
|
|
auto DSP::voice6(Voice& v) -> void {
|
|
|
|
state.outxBuffer = state._output >> 8;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-10 02:16:12 +00:00
|
|
|
auto DSP::voice7(Voice& v) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
//update ENDX
|
2015-10-10 02:16:12 +00:00
|
|
|
REG(ENDX) = (uint8)state.endxBuffer;
|
|
|
|
state.envxBuffer = v._envxOut;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-10 02:16:12 +00:00
|
|
|
auto DSP::voice8(Voice& v) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
//update OUTX
|
2015-10-10 02:16:12 +00:00
|
|
|
VREG(OUTX) = (uint8)state.outxBuffer;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-10 02:16:12 +00:00
|
|
|
auto DSP::voice9(Voice& v) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
//update ENVX
|
2015-10-10 02:16:12 +00:00
|
|
|
VREG(ENVX) = (uint8)state.envxBuffer;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|