diff --git a/higan/audio/audio.hpp b/higan/audio/audio.hpp index d589974f..3a390491 100644 --- a/higan/audio/audio.hpp +++ b/higan/audio/audio.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -7,6 +8,7 @@ namespace Emulator { struct Interface; struct Audio; +struct Filter; struct Stream; struct Audio { @@ -37,11 +39,19 @@ private: friend class Stream; }; +struct Filter { + enum class Order : uint { First, Second }; + enum class Type : uint { LowPass, HighPass }; + + Order order; + DSP::IIR::OnePole onePole; //first-order + DSP::IIR::Biquad biquad; //second-order +}; + struct Stream { auto reset(uint channels, double inputFrequency, double outputFrequency) -> void; - auto addLowPassFilter(double cutoffFrequency, uint passes = 1) -> void; - auto addHighPassFilter(double cutoffFrequency, uint passes = 1) -> void; + auto addFilter(Filter::Order order, Filter::Type type, double cutoffFrequency, uint passes = 1) -> void; auto pending() const -> bool; auto read(double* samples) -> uint; @@ -54,7 +64,7 @@ struct Stream { private: struct Channel { - vector filters; + vector filters; DSP::Resampler::Cubic resampler; }; vector channels; diff --git a/higan/audio/stream.cpp b/higan/audio/stream.cpp index 8f16a32d..a84f23bf 100644 --- a/higan/audio/stream.cpp +++ b/higan/audio/stream.cpp @@ -11,22 +11,27 @@ auto Stream::reset(uint channels_, double inputFrequency, double outputFrequency } } -auto Stream::addLowPassFilter(double cutoffFrequency, uint passes) -> void { +auto Stream::addFilter(Filter::Order order, Filter::Type type, double cutoffFrequency, uint passes) -> void { for(auto& channel : channels) { for(auto pass : range(passes)) { - double q = DSP::IIR::Biquad::butterworth(passes * 2, pass); - channel.filters.append(DSP::IIR::Biquad{}); - channel.filters.right().reset(DSP::IIR::Biquad::Type::LowPass, cutoffFrequency, inputFrequency, q); - } - } -} + Filter filter{order}; -auto Stream::addHighPassFilter(double cutoffFrequency, uint passes) -> void { - for(auto& channel : channels) { - for(auto pass : range(passes)) { - double q = DSP::IIR::Biquad::butterworth(passes * 2, pass); - channel.filters.append(DSP::IIR::Biquad{}); - channel.filters.right().reset(DSP::IIR::Biquad::Type::HighPass, cutoffFrequency, inputFrequency, q); + if(order == Filter::Order::First) { + DSP::IIR::OnePole::Type _type; + if(type == Filter::Type::LowPass) _type = DSP::IIR::OnePole::Type::LowPass; + if(type == Filter::Type::HighPass) _type = DSP::IIR::OnePole::Type::HighPass; + filter.onePole.reset(_type, cutoffFrequency, inputFrequency); + } + + if(order == Filter::Order::Second) { + DSP::IIR::Biquad::Type _type; + if(type == Filter::Type::LowPass) _type = DSP::IIR::Biquad::Type::LowPass; + if(type == Filter::Type::HighPass) _type = DSP::IIR::Biquad::Type::HighPass; + double q = DSP::IIR::Biquad::butterworth(passes * 2, pass); + filter.biquad.reset(_type, cutoffFrequency, inputFrequency, q); + } + + channel.filters.append(filter); } } } @@ -43,7 +48,12 @@ auto Stream::read(double* samples) -> uint { auto Stream::write(const double* samples) -> void { for(auto c : range(channels)) { double sample = samples[c] + 1e-25; //constant offset used to suppress denormals - for(auto& filter : channels[c].filters) sample = filter.process(sample); + for(auto& filter : channels[c].filters) { + switch(filter.order) { + case Filter::Order::First: sample = filter.onePole.process(sample); break; + case Filter::Order::Second: sample = filter.biquad.process(sample); break; + } + } channels[c].resampler.write(sample); } diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index a458a549..f5ae48cd 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -12,7 +12,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "103"; + static const string Version = "103.01"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/fc/apu/apu.cpp b/higan/fc/apu/apu.cpp index ec05ea37..8a99c3e1 100644 --- a/higan/fc/apu/apu.cpp +++ b/higan/fc/apu/apu.cpp @@ -74,8 +74,10 @@ auto APU::setSample(int16 sample) -> void { auto APU::power() -> void { create(APU::Enter, system.frequency()); stream = Emulator::audio.createStream(1, frequency() / rate()); - stream->addLowPassFilter(20000.0, 3); - stream->addHighPassFilter(20.0, 3); + stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 90.0); + stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 440.0); + stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::LowPass, 14000.0); + stream->addFilter(Emulator::Filter::Order::Second, Emulator::Filter::Type::LowPass, 20000.0, 3); pulse[0].power(); pulse[1].power(); diff --git a/higan/fc/apu/apu.hpp b/higan/fc/apu/apu.hpp index 0aa7ac31..420dc0e4 100644 --- a/higan/fc/apu/apu.hpp +++ b/higan/fc/apu/apu.hpp @@ -1,7 +1,7 @@ struct APU : Thread { shared_pointer stream; - inline auto rate() const -> uint { return Region::NTSC() ? 12 : 16; } + inline auto rate() const -> uint { return Region::PAL() ? 16 : 12; } //apu.cpp APU(); diff --git a/higan/fc/apu/dmc.cpp b/higan/fc/apu/dmc.cpp index 8ebf3622..b007f346 100644 --- a/higan/fc/apu/dmc.cpp +++ b/higan/fc/apu/dmc.cpp @@ -57,7 +57,7 @@ auto APU::DMC::clock() -> uint8 { } } - periodCounter = Region::NTSC() ? dmcPeriodTableNTSC[period] : dmcPeriodTablePAL[period]; + periodCounter = Region::PAL() ? dmcPeriodTablePAL[period] : dmcPeriodTableNTSC[period]; } if(lengthCounter > 0 && !dmaBufferValid && dmaDelayCounter == 0) { @@ -73,7 +73,7 @@ auto APU::DMC::power() -> void { irqPending = 0; period = 0; - periodCounter = Region::NTSC() ? dmcPeriodTableNTSC[0] : dmcPeriodTablePAL[0]; + periodCounter = Region::PAL() ? dmcPeriodTablePAL[0] : dmcPeriodTableNTSC[0]; irqEnable = 0; loopMode = 0; dacLatch = 0; diff --git a/higan/fc/apu/noise.cpp b/higan/fc/apu/noise.cpp index 54e27c37..356280b2 100644 --- a/higan/fc/apu/noise.cpp +++ b/higan/fc/apu/noise.cpp @@ -19,7 +19,7 @@ auto APU::Noise::clock() -> uint8 { } lfsr = (lfsr >> 1) | (feedback << 14); - periodCounter = Region::NTSC() ? apu.noisePeriodTableNTSC[period] : apu.noisePeriodTablePAL[period]; + periodCounter = Region::PAL() ? apu.noisePeriodTablePAL[period] : apu.noisePeriodTableNTSC[period]; } return result; diff --git a/higan/fc/cartridge/cartridge.cpp b/higan/fc/cartridge/cartridge.cpp index a8e65158..663c3255 100644 --- a/higan/fc/cartridge/cartridge.cpp +++ b/higan/fc/cartridge/cartridge.cpp @@ -16,7 +16,7 @@ auto Cartridge::main() -> void { } auto Cartridge::load() -> bool { - if(auto loaded = platform->load(ID::Famicom, "Famicom", "fc", {"NTSC", "PAL"})) { + if(auto loaded = platform->load(ID::Famicom, "Famicom", "fc", {"NTSC-J", "NTSC-U", "PAL"})) { information.pathID = loaded.pathID(); information.region = loaded.option(); } else return false; diff --git a/higan/fc/cartridge/cartridge.hpp b/higan/fc/cartridge/cartridge.hpp index fbb7f6cc..50e6a8ca 100644 --- a/higan/fc/cartridge/cartridge.hpp +++ b/higan/fc/cartridge/cartridge.hpp @@ -2,7 +2,7 @@ #include "board/board.hpp" struct Cartridge : Thread { - inline auto rate() const -> uint { return Region::NTSC() ? 12 : 16; } + inline auto rate() const -> uint { return Region::PAL() ? 16 : 12; } //cartridge.cpp static auto Enter() -> void; diff --git a/higan/fc/cpu/cpu.hpp b/higan/fc/cpu/cpu.hpp index b9ef2481..978e5372 100644 --- a/higan/fc/cpu/cpu.hpp +++ b/higan/fc/cpu/cpu.hpp @@ -1,5 +1,5 @@ struct CPU : Processor::MOS6502, Thread { - inline auto rate() const -> uint { return Region::NTSC() ? 12 : 16; } + inline auto rate() const -> uint { return Region::PAL() ? 16 : 12; } //cpu.cpp static auto Enter() -> void; diff --git a/higan/fc/fc.hpp b/higan/fc/fc.hpp index 598da789..912590c4 100644 --- a/higan/fc/fc.hpp +++ b/higan/fc/fc.hpp @@ -30,7 +30,8 @@ namespace Famicom { }; struct Region { - static inline auto NTSC() -> bool; + static inline auto NTSCJ() -> bool; + static inline auto NTSCU() -> bool; static inline auto PAL() -> bool; }; diff --git a/higan/fc/ppu/ppu.hpp b/higan/fc/ppu/ppu.hpp index 856fdffe..52efb8fa 100644 --- a/higan/fc/ppu/ppu.hpp +++ b/higan/fc/ppu/ppu.hpp @@ -1,6 +1,6 @@ struct PPU : Thread { - inline auto rate() const -> uint { return Region::NTSC() ? 4 : 5; } - inline auto vlines() const -> uint { return Region::NTSC() ? 262 : 312; } + inline auto rate() const -> uint { return Region::PAL() ? 5 : 4; } + inline auto vlines() const -> uint { return Region::PAL() ? 312 : 262; } //ppu.cpp static auto Enter() -> void; diff --git a/higan/fc/system/system.cpp b/higan/fc/system/system.cpp index 0f533604..18350906 100644 --- a/higan/fc/system/system.cpp +++ b/higan/fc/system/system.cpp @@ -32,8 +32,12 @@ auto System::load(Emulator::Interface* interface) -> bool { auto document = BML::unserialize(information.manifest); if(!cartridge.load()) return false; - if(cartridge.region() == "NTSC") { - information.region = Region::NTSC; + if(cartridge.region() == "NTSC-J") { + information.region = Region::NTSCJ; + information.frequency = Emulator::Constants::Colorburst::NTSC * 6.0; + } + if(cartridge.region() == "NTSC-U") { + information.region = Region::NTSCU; information.frequency = Emulator::Constants::Colorburst::NTSC * 6.0; } if(cartridge.region() == "PAL") { diff --git a/higan/fc/system/system.hpp b/higan/fc/system/system.hpp index 7725a6fb..a72375d9 100644 --- a/higan/fc/system/system.hpp +++ b/higan/fc/system/system.hpp @@ -1,5 +1,5 @@ struct System { - enum class Region : uint { NTSC, PAL }; + enum class Region : uint { NTSCJ, NTSCU, PAL }; auto loaded() const -> bool { return information.loaded; } auto region() const -> Region { return information.region; } @@ -33,7 +33,7 @@ private: struct Information { bool loaded = false; - Region region = Region::NTSC; + Region region = Region::NTSCJ; double frequency = Emulator::Constants::Colorburst::NTSC * 6.0; string manifest; } information; @@ -53,5 +53,6 @@ struct Peripherals { extern System system; extern Peripherals peripherals; -auto Region::NTSC() -> bool { return system.region() == System::Region::NTSC; } +auto Region::NTSCJ() -> bool { return system.region() == System::Region::NTSCJ; } +auto Region::NTSCU() -> bool { return system.region() == System::Region::NTSCU; } auto Region::PAL() -> bool { return system.region() == System::Region::PAL; } diff --git a/higan/gb/apu/apu.cpp b/higan/gb/apu/apu.cpp index 240d86a3..b9f7498d 100644 --- a/higan/gb/apu/apu.cpp +++ b/higan/gb/apu/apu.cpp @@ -55,8 +55,8 @@ auto APU::power() -> void { create(Enter, 2 * 1024 * 1024); if(!Model::SuperGameBoy()) { stream = Emulator::audio.createStream(2, frequency()); - stream->addLowPassFilter(20000.0, 3); - stream->addHighPassFilter(20.0, 3); + stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0); + stream->addFilter(Emulator::Filter::Order::Second, Emulator::Filter::Type::LowPass, 20000.0, 3); } for(uint n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this; diff --git a/higan/gba/apu/apu.cpp b/higan/gba/apu/apu.cpp index 33e5982f..8b944813 100644 --- a/higan/gba/apu/apu.cpp +++ b/higan/gba/apu/apu.cpp @@ -77,8 +77,8 @@ auto APU::step(uint clocks) -> void { auto APU::power() -> void { create(APU::Enter, 16'777'216); stream = Emulator::audio.createStream(2, frequency() / 64.0); - stream->addLowPassFilter(20000.0, 3); - stream->addHighPassFilter(20.0, 3); + stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0); + stream->addFilter(Emulator::Filter::Order::Second, Emulator::Filter::Type::LowPass, 20000.0, 3); clock = 0; square1.power(); diff --git a/higan/gba/apu/apu.hpp b/higan/gba/apu/apu.hpp index f2d958df..ecc3b117 100644 --- a/higan/gba/apu/apu.hpp +++ b/higan/gba/apu/apu.hpp @@ -1,8 +1,6 @@ struct APU : Thread, IO { shared_pointer stream; - #include "registers.hpp" - static auto Enter() -> void; auto main() -> void; auto step(uint clocks) -> void; @@ -16,6 +14,165 @@ struct APU : Thread, IO { auto serialize(serializer&) -> void; uint clock; + + struct Registers { + struct SoundBias { + uint10 level; + uint2 amplitude; + } bias; + } regs; + + struct Sweep { + uint3 shift; + uint1 direction; + uint3 frequency; + + uint1 enable; + uint1 negate; + uint3 period; + }; + + struct Envelope { + uint3 frequency; + uint1 direction; + uint4 volume; + + uint3 period; + + auto dacEnable() const -> bool { return volume || direction; } + }; + + struct Square { + Envelope envelope; + uint1 enable; + uint6 length; + uint2 duty; + uint11 frequency; + uint1 counter; + uint1 initialize; + + int shadowfrequency; + uint1 signal; + uint4 output; + uint period; + uint3 phase; + uint4 volume; + + auto run() -> void; + auto clocklength() -> void; + auto clockenvelope() -> void; + }; + + struct Square1 : Square { + Sweep sweep; + + auto runsweep(bool update) -> void; + auto clocksweep() -> void; + auto read(uint addr) const -> uint8; + auto write(uint addr, uint8 byte) -> void; + auto power() -> void; + } square1; + + struct Square2 : Square { + auto read(uint addr) const -> uint8; + auto write(uint addr, uint8 byte) -> void; + auto power() -> void; + } square2; + + struct Wave { + uint1 mode; + uint1 bank; + uint1 dacenable; + uint8 length; + uint3 volume; + uint11 frequency; + uint1 counter; + uint1 initialize; + uint4 pattern[2 * 32]; + + uint1 enable; + uint4 output; + uint5 patternaddr; + uint1 patternbank; + uint4 patternsample; + uint period; + + auto run() -> void; + auto clocklength() -> void; + auto read(uint addr) const -> uint8; + auto write(uint addr, uint8 byte) -> void; + auto readram(uint addr) const -> uint8; + auto writeram(uint addr, uint8 byte) -> void; + auto power() -> void; + } wave; + + struct Noise { + Envelope envelope; + uint6 length; + uint3 divisor; + uint1 narrowlfsr; + uint4 frequency; + uint1 counter; + uint1 initialize; + + uint1 enable; + uint15 lfsr; + uint4 output; + uint period; + uint4 volume; + + auto divider() const -> uint; + auto run() -> void; + auto clocklength() -> void; + auto clockenvelope() -> void; + auto read(uint addr) const -> uint8; + auto write(uint addr, uint8 byte) -> void; + auto power() -> void; + } noise; + + struct Sequencer { + uint2 volume; + uint3 lvolume; + uint3 rvolume; + uint1 lenable[4]; + uint1 renable[4]; + uint1 masterenable; + + uint12 base; + uint3 step; + int16 lsample; + int16 rsample; + + uint10 loutput; + uint10 routput; + + auto sample() -> void; + + auto read(uint addr) const -> uint8; + auto write(uint addr, uint8 byte) -> void; + auto power() -> void; + } sequencer; + + struct FIFO { + int8 samples[32]; + int8 active; + int8 output; + + uint5 rdoffset; + uint5 wroffset; + uint6 size; + + uint1 volume; //0 = 50%, 1 = 100% + uint1 lenable; + uint1 renable; + uint1 timer; + + auto sample() -> void; + auto read() -> void; + auto write(int8 byte) -> void; + auto reset() -> void; + auto power() -> void; + } fifo[2]; }; extern APU apu; diff --git a/higan/gba/apu/registers.hpp b/higan/gba/apu/registers.hpp deleted file mode 100644 index 1e574369..00000000 --- a/higan/gba/apu/registers.hpp +++ /dev/null @@ -1,158 +0,0 @@ -struct Registers { - struct SoundBias { - uint10 level; - uint2 amplitude; - } bias; -} regs; - -struct Sweep { - uint3 shift; - uint1 direction; - uint3 frequency; - - uint1 enable; - uint1 negate; - uint3 period; -}; - -struct Envelope { - uint3 frequency; - uint1 direction; - uint4 volume; - - uint3 period; - - auto dacEnable() const -> bool { return volume || direction; } -}; - -struct Square { - Envelope envelope; - uint1 enable; - uint6 length; - uint2 duty; - uint11 frequency; - uint1 counter; - uint1 initialize; - - int shadowfrequency; - uint1 signal; - uint4 output; - uint period; - uint3 phase; - uint4 volume; - - auto run() -> void; - auto clocklength() -> void; - auto clockenvelope() -> void; -}; - -struct Square1 : Square { - Sweep sweep; - - auto runsweep(bool update) -> void; - auto clocksweep() -> void; - auto read(uint addr) const -> uint8; - auto write(uint addr, uint8 byte) -> void; - auto power() -> void; -} square1; - -struct Square2 : Square { - auto read(uint addr) const -> uint8; - auto write(uint addr, uint8 byte) -> void; - auto power() -> void; -} square2; - -struct Wave { - uint1 mode; - uint1 bank; - uint1 dacenable; - uint8 length; - uint3 volume; - uint11 frequency; - uint1 counter; - uint1 initialize; - uint4 pattern[32]; - - uint1 enable; - uint4 output; - uint4 patternaddr; - uint1 patternbank; - uint4 patternsample; - uint period; - - auto run() -> void; - auto clocklength() -> void; - auto read(uint addr) const -> uint8; - auto write(uint addr, uint8 byte) -> void; - auto readram(uint addr) const -> uint8; - auto writeram(uint addr, uint8 byte) -> void; - auto power() -> void; -} wave; - -struct Noise { - Envelope envelope; - uint6 length; - uint3 divisor; - uint1 narrowlfsr; - uint4 frequency; - uint1 counter; - uint1 initialize; - - uint1 enable; - uint15 lfsr; - uint4 output; - uint period; - uint4 volume; - - auto divider() const -> uint; - auto run() -> void; - auto clocklength() -> void; - auto clockenvelope() -> void; - auto read(uint addr) const -> uint8; - auto write(uint addr, uint8 byte) -> void; - auto power() -> void; -} noise; - -struct Sequencer { - uint2 volume; - uint3 lvolume; - uint3 rvolume; - uint1 lenable[4]; - uint1 renable[4]; - uint1 masterenable; - - uint12 base; - uint3 step; - int16 lsample; - int16 rsample; - - uint10 loutput; - uint10 routput; - - auto sample() -> void; - - auto read(uint addr) const -> uint8; - auto write(uint addr, uint8 byte) -> void; - auto power() -> void; -} sequencer; - -struct FIFO { - int8 samples[32]; - int8 active; - int8 output; - - uint5 rdoffset; - uint5 wroffset; - uint6 size; - - uint1 volume; //0 = 50%, 1 = 100% - uint1 lenable; - uint1 renable; - uint1 timer; - - auto sample() -> void; - auto read() -> void; - auto write(int8 byte) -> void; - auto reset() -> void; - auto power() -> void; -} fifo[2]; diff --git a/higan/gba/apu/wave.cpp b/higan/gba/apu/wave.cpp index 647fc140..ebfcb223 100644 --- a/higan/gba/apu/wave.cpp +++ b/higan/gba/apu/wave.cpp @@ -1,7 +1,7 @@ auto APU::Wave::run() -> void { if(period && --period == 0) { period = 1 * (2048 - frequency); - patternsample = pattern[patternbank * 16 + patternaddr++]; + patternsample = pattern[patternbank << 5 | patternaddr++]; if(patternaddr == 0) patternbank ^= mode; } @@ -66,14 +66,14 @@ auto APU::Wave::write(uint addr, uint8 byte) -> void { auto APU::Wave::readram(uint addr) const -> uint8 { uint8 byte = 0; - byte |= pattern[addr * 2 + 0] << 0; - byte |= pattern[addr * 2 + 1] << 4; + byte |= pattern[!bank << 5 | addr << 1 | 0] << 0; + byte |= pattern[!bank << 5 | addr << 1 | 1] << 4; return byte; } auto APU::Wave::writeram(uint addr, uint8 byte) -> void { - pattern[addr * 2 + 0] = byte >> 0; - pattern[addr * 2 + 1] = byte >> 4; + pattern[!bank << 5 | addr << 1 | 0] = byte >> 0; + pattern[!bank << 5 | addr << 1 | 1] = byte >> 4; } auto APU::Wave::power() -> void { diff --git a/higan/md/psg/psg.cpp b/higan/md/psg/psg.cpp index f32e8105..b02527fb 100644 --- a/higan/md/psg/psg.cpp +++ b/higan/md/psg/psg.cpp @@ -37,12 +37,13 @@ auto PSG::step(uint clocks) -> void { auto PSG::power() -> void { create(PSG::Enter, system.colorburst() / 16.0); stream = Emulator::audio.createStream(1, frequency()); - stream->addLowPassFilter(20000.0, 3); - stream->addHighPassFilter(20.0, 3); + stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0); + stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::LowPass, 2840.0); + stream->addFilter(Emulator::Filter::Order::Second, Emulator::Filter::Type::LowPass, 20000.0, 3); select = 0; for(auto n : range(15)) { - levels[n] = 0x2000 * pow(2, n * -2.0 / 6.0) + 0.5; + levels[n] = 0x1400 * pow(2, n * -2.0 / 6.0) + 0.5; } levels[15] = 0; diff --git a/higan/md/psg/serialization.cpp b/higan/md/psg/serialization.cpp index 42a04120..121179d9 100644 --- a/higan/md/psg/serialization.cpp +++ b/higan/md/psg/serialization.cpp @@ -7,7 +7,6 @@ auto PSG::serialize(serializer& s) -> void { noise.serialize(s); s.integer(select); - s.array(levels); } auto PSG::Tone::serialize(serializer& s) -> void { diff --git a/higan/md/vdp/io.cpp b/higan/md/vdp/io.cpp index 8c723998..bcb26dab 100644 --- a/higan/md/vdp/io.cpp +++ b/higan/md/vdp/io.cpp @@ -116,8 +116,9 @@ auto VDP::readControlPort() -> uint16 { uint16 result = 0b0011'0100'0000'0000; result |= 1 << 9; //FIFO empty result |= (state.vcounter >= screenHeight()) << 3; //vertical blank - result |= (state.vcounter >= screenHeight() || state.hcounter >= 1280) << 2; //horizontal blank + result |= (state.hcounter >= 1280) << 2; //horizontal blank result |= io.command.bit(5) << 1; //DMA active + result |= Region::PAL() << 0; return result; } diff --git a/higan/md/vdp/vdp.cpp b/higan/md/vdp/vdp.cpp index 8c349263..9b0b75bd 100644 --- a/higan/md/vdp/vdp.cpp +++ b/higan/md/vdp/vdp.cpp @@ -30,6 +30,7 @@ auto VDP::main() -> void { if(io.verticalBlankInterruptEnable) { cpu.raise(CPU::Interrupt::VerticalBlank); } + //todo: should only stay high for ~2573/2 clocks apu.setINT(true); } diff --git a/higan/md/ym2612/ym2612.cpp b/higan/md/ym2612/ym2612.cpp index da9ee4de..28f9775d 100644 --- a/higan/md/ym2612/ym2612.cpp +++ b/higan/md/ym2612/ym2612.cpp @@ -157,6 +157,9 @@ auto YM2612::step(uint clocks) -> void { auto YM2612::power() -> void { create(YM2612::Enter, system.colorburst() * 15.0 / 7.0); stream = Emulator::audio.createStream(2, frequency() / 144.0); + stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0); + stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::LowPass, 2840.0); + stream->addFilter(Emulator::Filter::Order::Second, Emulator::Filter::Type::LowPass, 20000.0, 3); io = {}; lfo = {}; diff --git a/higan/ms/psg/psg.cpp b/higan/ms/psg/psg.cpp index c3face17..4c7248d6 100644 --- a/higan/ms/psg/psg.cpp +++ b/higan/ms/psg/psg.cpp @@ -44,8 +44,8 @@ auto PSG::power() -> void { //use stereo mode for both; output same sample to both channels for Master System create(PSG::Enter, system.colorburst() / 16.0); stream = Emulator::audio.createStream(2, frequency()); - stream->addLowPassFilter(20000.0, 3); - stream->addHighPassFilter(20.0, 3); + stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0); + stream->addFilter(Emulator::Filter::Order::Second, Emulator::Filter::Type::LowPass, 20000.0, 3); select = 0; for(auto n : range(15)) { diff --git a/higan/ms/psg/serialization.cpp b/higan/ms/psg/serialization.cpp index 1fa33c8a..cad1b1ba 100644 --- a/higan/ms/psg/serialization.cpp +++ b/higan/ms/psg/serialization.cpp @@ -7,7 +7,6 @@ auto PSG::serialize(serializer& s) -> void { noise.serialize(s); s.integer(select); - s.array(levels); } auto PSG::Tone::serialize(serializer& s) -> void { diff --git a/higan/pce/psg/psg.cpp b/higan/pce/psg/psg.cpp index bebca9a5..57c0cfec 100644 --- a/higan/pce/psg/psg.cpp +++ b/higan/pce/psg/psg.cpp @@ -52,8 +52,8 @@ auto PSG::step(uint clocks) -> void { auto PSG::power() -> void { create(PSG::Enter, system.colorburst()); stream = Emulator::audio.createStream(2, frequency()); - stream->addLowPassFilter(20000.0, 3); - stream->addHighPassFilter(20.0, 3); + stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0); + stream->addFilter(Emulator::Filter::Order::Second, Emulator::Filter::Type::LowPass, 20000.0, 3); memory::fill(&io, sizeof(IO)); for(auto C : range(6)) channel[C].power(C); diff --git a/higan/sfc/coprocessor/icd2/icd2.cpp b/higan/sfc/coprocessor/icd2/icd2.cpp index b177a8bd..ca5bc401 100644 --- a/higan/sfc/coprocessor/icd2/icd2.cpp +++ b/higan/sfc/coprocessor/icd2/icd2.cpp @@ -48,8 +48,8 @@ auto ICD2::unload() -> void { auto ICD2::power() -> void { create(ICD2::Enter, system.colorburst() * 6.0 / 5.0); stream = Emulator::audio.createStream(2, frequency() / 2.0); - stream->addLowPassFilter(20000.0, 3); - stream->addHighPassFilter(20.0, 3); + stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0); + stream->addFilter(Emulator::Filter::Order::Second, Emulator::Filter::Type::LowPass, 20000.0, 3); r6003 = 0x00; r6004 = 0xff; diff --git a/higan/ws/apu/apu.cpp b/higan/ws/apu/apu.cpp index ff62eddf..d7dd6e59 100644 --- a/higan/ws/apu/apu.cpp +++ b/higan/ws/apu/apu.cpp @@ -67,8 +67,8 @@ auto APU::step(uint clocks) -> void { auto APU::power() -> void { create(APU::Enter, 3'072'000); stream = Emulator::audio.createStream(2, frequency()); - stream->addLowPassFilter(20000.0, 3); - stream->addHighPassFilter(20.0, 3); + stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0); + stream->addFilter(Emulator::Filter::Order::Second, Emulator::Filter::Type::LowPass, 20000.0, 3); bus.map(this, 0x004a, 0x004c); bus.map(this, 0x004e, 0x0050); diff --git a/nall/dsp/iir/one-pole.hpp b/nall/dsp/iir/one-pole.hpp index c644b9aa..e678c999 100644 --- a/nall/dsp/iir/one-pole.hpp +++ b/nall/dsp/iir/one-pole.hpp @@ -26,20 +26,19 @@ auto OnePole::reset(Type type, double cutoffFrequency, double samplingFrequency) this->cutoffFrequency = cutoffFrequency; this->samplingFrequency = samplingFrequency; - b1 = exp(-2.0 * Math::Pi * cutoffFrequency / samplingFrequency); - a0 = 1.0 - b1; - z1 = 0.0; -} - -auto OnePole::process(double in) -> double { - z1 = in * a0 + z1 * b1; - - switch(type) { - case Type::LowPass: return z1; - case Type::HighPass: return in - z1; - default: return 0.0; + double x = cos(2.0 * Math::Pi * cutoffFrequency / samplingFrequency); + if(type == Type::LowPass) { + b1 = +2.0 - x - sqrt((+2.0 - x) * (+2.0 - x) - 1); + a0 = 1.0 - b1; + } else { + b1 = -2.0 - x + sqrt((-2.0 - x) * (-2.0 - x) - 1); + a0 = 1.0 + b1; } } +auto OnePole::process(double in) -> double { + return z1 = in * a0 + z1 * b1; +} + }}}