From 6cc9f5a416ec9b0077fc0f50912b1af96987cdf5 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Fri, 31 Jan 2025 14:40:27 +0000 Subject: [PATCH] pce: reduce per-iteration conditional statements in psg This also significantly increases performance --- ares/pce/psg/channel.cpp | 35 +++++++++++++------------------ ares/pce/psg/psg.cpp | 19 +++++++++++------ ares/pce/psg/psg.hpp | 7 ++----- ares/pce/psg/serialization.cpp | 1 - ares/pce/system/serialization.cpp | 2 +- 5 files changed, 31 insertions(+), 33 deletions(-) diff --git a/ares/pce/psg/channel.cpp b/ares/pce/psg/channel.cpp index 05ed5b801c..0ffbdafbfc 100644 --- a/ares/pce/psg/channel.cpp +++ b/ares/pce/psg/channel.cpp @@ -3,27 +3,22 @@ auto PSG::Channel::power(u32 id) -> void { io = {}; } -auto PSG::Channel::run() -> void { - if(!io.enable) return sample(0); +template 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; } diff --git a/ares/pce/psg/psg.cpp b/ares/pce/psg/psg.cpp index 8248f6804d..f12e4b4d80 100644 --- a/ares/pce/psg/psg.cpp +++ b/ares/pce/psg/psg.cpp @@ -32,7 +32,7 @@ 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 @@ -40,13 +40,13 @@ auto PSG::main() -> void { #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 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, @@ -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]; @@ -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]; } } } diff --git a/ares/pce/psg/psg.hpp b/ares/pce/psg/psg.hpp index cc7cf64f21..d041f65af5 100644 --- a/ares/pce/psg/psg.hpp +++ b/ares/pce/psg/psg.hpp @@ -9,7 +9,7 @@ struct PSG : Thread { auto unload() -> void; auto main() -> void; - auto frame(i16&, i16&) -> void; + template auto frame(i16&, i16&) -> void; auto step(u32 clocks) -> void; auto power() -> void; @@ -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 auto run() -> n5; //io.cpp auto write(n4 address, n8 data) -> void; @@ -55,8 +54,6 @@ struct PSG : Thread { n5 waveOffset; n12 noisePeriod; n5 noiseSample; - - n5 output; } io; u32 id; diff --git a/ares/pce/psg/serialization.cpp b/ares/pce/psg/serialization.cpp index a77b713b98..7681d74f16 100644 --- a/ares/pce/psg/serialization.cpp +++ b/ares/pce/psg/serialization.cpp @@ -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); } } diff --git a/ares/pce/system/serialization.cpp b/ares/pce/system/serialization.cpp index 8ef77f4135..75fba9f353 100644 --- a/ares/pce/system/serialization.cpp +++ b/ares/pce/system/serialization.cpp @@ -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);