Skip to content

Commit

Permalink
pce: reduce per-iteration conditional statements in psg
Browse files Browse the repository at this point in the history
This also significantly increases performance
  • Loading branch information
LukeUsher committed Jan 31, 2025
1 parent 69c2071 commit 6cc9f5a
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 33 deletions.
35 changes: 15 additions & 20 deletions ares/pce/psg/channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,22 @@ auto PSG::Channel::power(u32 id) -> void {
io = {};
}

auto PSG::Channel::run() -> void {
if(!io.enable) return sample(0);
template<int index, int step> auto PSG::Channel::run() -> n5 {
for(u32 n : range(step)) {
if(!io.direct && --io.wavePeriod == 0) {
io.wavePeriod = io.waveFrequency;
io.waveOffset++;
io.waveSample = io.waveBuffer[io.waveOffset];
}

if(!io.direct && --io.wavePeriod == 0) {
io.wavePeriod = io.waveFrequency;
io.waveOffset++;
io.waveSample = io.waveBuffer[io.waveOffset];
//Only channels 4-5 support noise
if(index >= 4 && io.noiseEnable) {
if(--io.noisePeriod == 0) {
io.noisePeriod = ~io.noiseFrequency << 7;
io.noiseSample = nall::random() & 1 ? ~0 : 0;
}
}
}

if(!io.noiseEnable) {
return sample(io.waveSample);
}

if(--io.noisePeriod == 0) {
io.noisePeriod = ~io.noiseFrequency << 7;
io.noiseSample = nall::random() & 1 ? ~0 : 0;
}

return sample(io.noiseSample);
}

auto PSG::Channel::sample(n5 sample) -> void {
io.output = sample;
return index >= 4 && io.noiseEnable ? io.noiseSample : io.waveSample;
}
19 changes: 13 additions & 6 deletions ares/pce/psg/psg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,21 @@ auto PSG::main() -> void {
i16 outputRight;

#if defined(PROFILE_ACCURACY)
frame(outputLeft, outputRight);
frame<1>(outputLeft, outputRight);
stream->frame(sclamp<16>(outputLeft) / 32768.0, sclamp<16>(outputRight) / 32768.0);
step(1);
#endif

#if defined(PROFILE_PERFORMANCE)
//3.57MHz stereo audio through a 6th-order biquad IIR filter is very demanding.
//decimate the audio to ~56KHz, which is still well above the range of human hearing.
for(u32 n : range(64)) frame(outputLeft, outputRight);
frame<64>(outputLeft, outputRight);
stream->frame(sclamp<16>(outputLeft) / 32768.0, sclamp<16>(outputRight) / 32768.0);
step(64);
#endif
}

auto PSG::frame(i16& outputLeft, i16& outputRight) -> void {
template<int step> auto PSG::frame(i16& outputLeft, i16& outputRight) -> void {
static const n5 volumeScale[16] = {
0x00, 0x03, 0x05, 0x07, 0x09, 0x0b, 0x0d, 0x0f,
0x10, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d, 0x1f,
Expand All @@ -58,6 +58,14 @@ auto PSG::frame(i16& outputLeft, i16& outputRight) -> void {
n5 lmal = volumeScale[io.volumeLeft];
n5 rmal = volumeScale[io.volumeRight];

n5 output[6];
if(channel[0].io.enable) output[0] = channel[0].run<0, step>();
if(channel[1].io.enable) output[1] = channel[1].run<1, step>();
if(channel[2].io.enable) output[2] = channel[2].run<2, step>();
if(channel[3].io.enable) output[3] = channel[3].run<3, step>();
if(channel[4].io.enable) output[4] = channel[4].run<4, step>();
if(channel[5].io.enable) output[5] = channel[5].run<5, step>();

for(u32 C : range(6)) {
n5 al = channel[C].io.volume;
n5 lal = volumeScale[channel[C].io.volumeLeft];
Expand All @@ -66,12 +74,11 @@ auto PSG::frame(i16& outputLeft, i16& outputRight) -> void {
n5 volumeLeft = min(0x1f, (0x1f - lmal) + (0x1f - lal) + (0x1f - al));
n5 volumeRight = min(0x1f, (0x1f - rmal) + (0x1f - ral) + (0x1f - al));

channel[C].run();
if(C == 1 && io.lfoEnable) {
//todo: frequency modulation of channel 0 using channel 1's output
} else {
outputLeft += channel[C].io.output * volumeScalar[volumeLeft];
outputRight += channel[C].io.output * volumeScalar[volumeRight];
outputLeft += output[C] * volumeScalar[volumeLeft];
outputRight += output[C] * volumeScalar[volumeRight];
}
}
}
Expand Down
7 changes: 2 additions & 5 deletions ares/pce/psg/psg.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ struct PSG : Thread {
auto unload() -> void;

auto main() -> void;
auto frame(i16&, i16&) -> void;
template<int step> auto frame(i16&, i16&) -> void;
auto step(u32 clocks) -> void;

auto power() -> void;
Expand All @@ -33,8 +33,7 @@ struct PSG : Thread {
struct Channel {
//channel.cpp
auto power(u32 id) -> void;
auto run() -> void;
auto sample(n5 sample) -> void;
template<int channel, int step> auto run() -> n5;

//io.cpp
auto write(n4 address, n8 data) -> void;
Expand All @@ -55,8 +54,6 @@ struct PSG : Thread {
n5 waveOffset;
n12 noisePeriod;
n5 noiseSample;

n5 output;
} io;

u32 id;
Expand Down
1 change: 0 additions & 1 deletion ares/pce/psg/serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,5 @@ auto PSG::serialize(serializer& s) -> void {
s(c.io.waveOffset);
s(c.io.noisePeriod);
s(c.io.noiseSample);
s(c.io.output);
}
}
2 changes: 1 addition & 1 deletion ares/pce/system/serialization.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
static const string SerializerVersion = "v132";
static const string SerializerVersion = "v133";

auto System::serialize(bool synchronize) -> serializer {
if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);
Expand Down

0 comments on commit 6cc9f5a

Please sign in to comment.