mirror of https://github.com/bsnes-emu/bsnes.git
Update to v106r50 release.
byuu says: Changelog: - emulator/video,audio: various cleanups - emulator/audio: removed reverb effect (it breaks very badly on high-frequency systems) - emulator/audio: the Nyquist anti-aliasing lowpass filter is now generated automatically instead of set per-core - at 44.1KHz output, it's set to 22KHz; at 48KHz, it's set to 22KHz; at 96KHz, it's set to 25KHz - this filter now takes the bsnes emulation speed setting into account - all system/video.cpp files removed; inlined in System::power() and Interface::set() instead - sfc/cpu: pre-compute `HTIME` as `HTIME+1<<2` for faster comparisons of HIRQs - sfc/cpu: re-add check to block IRQs on the last dot of each frame (minor speed hit) - hiro/gtk3: fixed headers for Linux compilation finally - hiro/gtk,qt: fixed settings.cpp logic so initial values are used when no settings.bml file exists - hiro/gtk: started a minor experiment to specify theming information in settings.bml files - nall/dsp: allow the precision type (double) to be overridden (to float) - nall: add some helpers for generating pre-compiled headers - it was a failure to try using them for higan, however ... - nall: add some helpers for reading fallback values from empty `Markup::Node[search]` statements Todo: - CRITICAL: a lot of my IRQ/NMI/HDMA timing tests are failing with the fast PPU ... need to figure out why - space between Emulator::video functions and Emulator::audio functions in gb/system/system.cpp - remove Audio/Reverb/Enable from settings.bml in target-bsnes
This commit is contained in:
parent
65a3e6c676
commit
35ff15f83e
|
@ -47,5 +47,5 @@ include $(ui)/GNUmakefile
|
||||||
-include obj/*.d
|
-include obj/*.d
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(call delete,out/*)
|
|
||||||
$(call delete,obj/*)
|
$(call delete,obj/*)
|
||||||
|
$(call delete,out/*)
|
||||||
|
|
|
@ -5,30 +5,14 @@ namespace Emulator {
|
||||||
#include "stream.cpp"
|
#include "stream.cpp"
|
||||||
Audio audio;
|
Audio audio;
|
||||||
|
|
||||||
auto Audio::reset(maybe<uint> channels_, maybe<double> frequency_) -> void {
|
Audio::~Audio() {
|
||||||
interface = nullptr;
|
reset(nullptr);
|
||||||
|
|
||||||
if(channels_) channels = channels_();
|
|
||||||
if(frequency_) frequency = frequency_();
|
|
||||||
|
|
||||||
streams.reset();
|
|
||||||
reverb.reset();
|
|
||||||
|
|
||||||
reverb.resize(channels);
|
|
||||||
for(auto c : range(channels)) {
|
|
||||||
reverb[c].resize(7);
|
|
||||||
reverb[c][0].resize(1229);
|
|
||||||
reverb[c][1].resize(1559);
|
|
||||||
reverb[c][2].resize(1907);
|
|
||||||
reverb[c][3].resize(4057);
|
|
||||||
reverb[c][4].resize(8117);
|
|
||||||
reverb[c][5].resize(8311);
|
|
||||||
reverb[c][6].resize(9931);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Audio::setInterface(Interface* interface) -> void {
|
auto Audio::reset(Interface* interface) -> void {
|
||||||
this->interface = interface;
|
this->interface = interface;
|
||||||
|
streams.reset();
|
||||||
|
channels = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Audio::setFrequency(double frequency) -> void {
|
auto Audio::setFrequency(double frequency) -> void {
|
||||||
|
@ -46,11 +30,8 @@ auto Audio::setBalance(double balance) -> void {
|
||||||
this->balance = balance;
|
this->balance = balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Audio::setReverb(bool enabled) -> void {
|
|
||||||
this->reverbEnable = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Audio::createStream(uint channels, double frequency) -> shared_pointer<Stream> {
|
auto Audio::createStream(uint channels, double frequency) -> shared_pointer<Stream> {
|
||||||
|
this->channels = max(this->channels, channels);
|
||||||
shared_pointer<Stream> stream = new Stream;
|
shared_pointer<Stream> stream = new Stream;
|
||||||
stream->reset(channels, frequency, this->frequency);
|
stream->reset(channels, frequency, this->frequency);
|
||||||
streams.append(stream);
|
streams.append(stream);
|
||||||
|
@ -67,7 +48,7 @@ auto Audio::process() -> void {
|
||||||
for(auto& sample : samples) sample = 0.0;
|
for(auto& sample : samples) sample = 0.0;
|
||||||
|
|
||||||
for(auto& stream : streams) {
|
for(auto& stream : streams) {
|
||||||
double buffer[16];
|
double buffer[channels];
|
||||||
uint length = stream->read(buffer), offset = 0;
|
uint length = stream->read(buffer), offset = 0;
|
||||||
|
|
||||||
for(auto& sample : samples) {
|
for(auto& sample : samples) {
|
||||||
|
@ -78,13 +59,6 @@ auto Audio::process() -> void {
|
||||||
|
|
||||||
for(auto c : range(channels)) {
|
for(auto c : range(channels)) {
|
||||||
samples[c] = max(-1.0, min(+1.0, samples[c] * volume));
|
samples[c] = max(-1.0, min(+1.0, samples[c] * volume));
|
||||||
|
|
||||||
if(reverbEnable) {
|
|
||||||
samples[c] *= 0.125;
|
|
||||||
for(auto n : range(7)) samples[c] += 0.125 * reverb[c][n].last();
|
|
||||||
for(auto n : range(7)) reverb[c][n].write(samples[c]);
|
|
||||||
samples[c] *= 8.000;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(channels == 2) {
|
if(channels == 2) {
|
||||||
|
|
|
@ -12,13 +12,12 @@ struct Filter;
|
||||||
struct Stream;
|
struct Stream;
|
||||||
|
|
||||||
struct Audio {
|
struct Audio {
|
||||||
auto reset(maybe<uint> channels = nothing, maybe<double> frequency = nothing) -> void;
|
~Audio();
|
||||||
auto setInterface(Interface* interface) -> void;
|
auto reset(Interface* interface) -> void;
|
||||||
|
|
||||||
auto setFrequency(double frequency) -> void;
|
auto setFrequency(double frequency) -> void;
|
||||||
auto setVolume(double volume) -> void;
|
auto setVolume(double volume) -> void;
|
||||||
auto setBalance(double balance) -> void;
|
auto setBalance(double balance) -> void;
|
||||||
auto setReverb(bool enabled) -> void;
|
|
||||||
|
|
||||||
auto createStream(uint channels, double frequency) -> shared_pointer<Stream>;
|
auto createStream(uint channels, double frequency) -> shared_pointer<Stream>;
|
||||||
|
|
||||||
|
@ -29,14 +28,11 @@ private:
|
||||||
vector<shared_pointer<Stream>> streams;
|
vector<shared_pointer<Stream>> streams;
|
||||||
|
|
||||||
uint channels = 0;
|
uint channels = 0;
|
||||||
double frequency = 0.0;
|
double frequency = 48000.0;
|
||||||
|
|
||||||
double volume = 1.0;
|
double volume = 1.0;
|
||||||
double balance = 0.0;
|
double balance = 0.0;
|
||||||
|
|
||||||
bool reverbEnable = false;
|
|
||||||
vector<vector<queue<double>>> reverb;
|
|
||||||
|
|
||||||
friend class Stream;
|
friend class Stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -68,6 +64,7 @@ struct Stream {
|
||||||
private:
|
private:
|
||||||
struct Channel {
|
struct Channel {
|
||||||
vector<Filter> filters;
|
vector<Filter> filters;
|
||||||
|
vector<DSP::IIR::Biquad> nyquist;
|
||||||
DSP::Resampler::Cubic resampler;
|
DSP::Resampler::Cubic resampler;
|
||||||
};
|
};
|
||||||
vector<Channel> channels;
|
vector<Channel> channels;
|
||||||
|
|
|
@ -16,13 +16,28 @@ auto Stream::setFrequency(double inputFrequency, maybe<double> outputFrequency)
|
||||||
if(outputFrequency) this->outputFrequency = outputFrequency();
|
if(outputFrequency) this->outputFrequency = outputFrequency();
|
||||||
|
|
||||||
for(auto& channel : channels) {
|
for(auto& channel : channels) {
|
||||||
|
channel.nyquist.reset();
|
||||||
channel.resampler.reset(this->inputFrequency, this->outputFrequency);
|
channel.resampler.reset(this->inputFrequency, this->outputFrequency);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(this->inputFrequency >= this->outputFrequency * 2) {
|
||||||
|
//add a low-pass filter to prevent aliasing during resampling
|
||||||
|
double cutoffFrequency = min(25000.0, this->outputFrequency / 2.0 - 2000.0);
|
||||||
|
for(auto& channel : channels) {
|
||||||
|
uint passes = 3;
|
||||||
|
for(uint pass : range(passes)) {
|
||||||
|
DSP::IIR::Biquad filter;
|
||||||
|
double q = DSP::IIR::Biquad::butterworth(passes * 2, pass);
|
||||||
|
filter.reset(DSP::IIR::Biquad::Type::LowPass, cutoffFrequency, this->inputFrequency, q);
|
||||||
|
channel.nyquist.append(filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Stream::addFilter(Filter::Order order, Filter::Type type, 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& channel : channels) {
|
||||||
for(auto pass : range(passes)) {
|
for(uint pass : range(passes)) {
|
||||||
Filter filter{order};
|
Filter filter{order};
|
||||||
|
|
||||||
if(order == Filter::Order::First) {
|
if(order == Filter::Order::First) {
|
||||||
|
@ -63,6 +78,9 @@ auto Stream::write(const double samples[]) -> void {
|
||||||
case Filter::Order::Second: sample = filter.biquad.process(sample); break;
|
case Filter::Order::Second: sample = filter.biquad.process(sample); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for(auto& filter : channels[c].nyquist) {
|
||||||
|
sample = filter.process(sample);
|
||||||
|
}
|
||||||
channels[c].resampler.write(sample);
|
channels[c].resampler.write(sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "106.49";
|
static const string Version = "106.50";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "https://byuu.org/";
|
static const string Website = "https://byuu.org/";
|
||||||
|
|
|
@ -77,7 +77,6 @@ auto APU::power(bool reset) -> void {
|
||||||
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 90.0);
|
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::HighPass, 440.0);
|
||||||
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::LowPass, 14000.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[0].power();
|
||||||
pulse[1].power();
|
pulse[1].power();
|
||||||
|
|
|
@ -177,7 +177,7 @@ auto Interface::get(const string& name) -> any {
|
||||||
auto Interface::set(const string& name, const any& value) -> bool {
|
auto Interface::set(const string& name, const any& value) -> bool {
|
||||||
if(name == "Color Emulation" && value.is<bool>()) {
|
if(name == "Color Emulation" && value.is<bool>()) {
|
||||||
settings.colorEmulation = value.get<bool>();
|
settings.colorEmulation = value.get<bool>();
|
||||||
system.configureVideoPalette();
|
Emulator::video.setPalette();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(name == "Scanline Emulation" && value.is<bool>()) return settings.scanlineEmulation = value.get<bool>(), true;
|
if(name == "Scanline Emulation" && value.is<bool>()) return settings.scanlineEmulation = value.get<bool>(), true;
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
namespace Famicom {
|
namespace Famicom {
|
||||||
|
|
||||||
#include "video.cpp"
|
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
System system;
|
System system;
|
||||||
Scheduler scheduler;
|
Scheduler scheduler;
|
||||||
|
@ -63,13 +62,10 @@ auto System::unload() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::power(bool reset) -> void {
|
auto System::power(bool reset) -> void {
|
||||||
Emulator::video.reset();
|
Emulator::video.reset(interface);
|
||||||
Emulator::video.setInterface(interface);
|
Emulator::video.setPalette();
|
||||||
configureVideoPalette();
|
|
||||||
configureVideoEffects();
|
|
||||||
|
|
||||||
Emulator::audio.reset();
|
Emulator::audio.reset(interface);
|
||||||
Emulator::audio.setInterface(interface);
|
|
||||||
|
|
||||||
scheduler.reset();
|
scheduler.reset();
|
||||||
cartridge.power();
|
cartridge.power();
|
||||||
|
|
|
@ -16,10 +16,6 @@ struct System {
|
||||||
auto init() -> void;
|
auto init() -> void;
|
||||||
auto term() -> void;
|
auto term() -> void;
|
||||||
|
|
||||||
//video.cpp
|
|
||||||
auto configureVideoPalette() -> void;
|
|
||||||
auto configureVideoEffects() -> void;
|
|
||||||
|
|
||||||
//serialization.cpp
|
//serialization.cpp
|
||||||
auto serialize() -> serializer;
|
auto serialize() -> serializer;
|
||||||
auto unserialize(serializer&) -> bool;
|
auto unserialize(serializer&) -> bool;
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
auto System::configureVideoPalette() -> void {
|
|
||||||
Emulator::video.setPalette();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto System::configureVideoEffects() -> void {
|
|
||||||
}
|
|
|
@ -56,7 +56,6 @@ auto APU::power() -> void {
|
||||||
if(!Model::SuperGameBoy()) {
|
if(!Model::SuperGameBoy()) {
|
||||||
stream = Emulator::audio.createStream(2, frequency());
|
stream = Emulator::audio.createStream(2, frequency());
|
||||||
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0);
|
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;
|
for(uint n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this;
|
||||||
|
|
||||||
|
|
|
@ -100,13 +100,15 @@ auto Interface::get(const string& name) -> any {
|
||||||
auto Interface::set(const string& name, const any& value) -> bool {
|
auto Interface::set(const string& name, const any& value) -> bool {
|
||||||
if(name == "Blur Emulation" && value.is<bool>()) {
|
if(name == "Blur Emulation" && value.is<bool>()) {
|
||||||
settings.blurEmulation = value.get<bool>();
|
settings.blurEmulation = value.get<bool>();
|
||||||
system.configureVideoEffects();
|
if(Model::SuperGameBoy()) return true;
|
||||||
|
Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(name == "Color Emulation" && value.is<bool>()) {
|
if(name == "Color Emulation" && value.is<bool>()) {
|
||||||
settings.colorEmulation = value.get<bool>();
|
settings.colorEmulation = value.get<bool>();
|
||||||
system.configureVideoPalette();
|
if(Model::SuperGameBoy()) return true;
|
||||||
|
Emulator::video.setPalette();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
namespace GameBoy {
|
namespace GameBoy {
|
||||||
|
|
||||||
#include "video.cpp"
|
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
System system;
|
System system;
|
||||||
Scheduler scheduler;
|
Scheduler scheduler;
|
||||||
|
@ -83,13 +82,10 @@ auto System::unload() -> void {
|
||||||
|
|
||||||
auto System::power() -> void {
|
auto System::power() -> void {
|
||||||
if(model() != Model::SuperGameBoy) {
|
if(model() != Model::SuperGameBoy) {
|
||||||
Emulator::video.reset();
|
Emulator::video.reset(interface);
|
||||||
Emulator::video.setInterface(interface);
|
Emulator::video.setPalette();
|
||||||
configureVideoPalette();
|
Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation);
|
||||||
configureVideoEffects();
|
Emulator::audio.reset(interface);
|
||||||
|
|
||||||
Emulator::audio.reset();
|
|
||||||
Emulator::audio.setInterface(interface);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduler.reset();
|
scheduler.reset();
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
auto System::configureVideoPalette() -> void {
|
|
||||||
if(model() == Model::SuperGameBoy) return;
|
|
||||||
Emulator::video.setPalette();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto System::configureVideoEffects() -> void {
|
|
||||||
if(model() == Model::SuperGameBoy) return;
|
|
||||||
Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation);
|
|
||||||
}
|
|
|
@ -78,7 +78,6 @@ auto APU::power() -> void {
|
||||||
create(APU::Enter, system.frequency());
|
create(APU::Enter, system.frequency());
|
||||||
stream = Emulator::audio.createStream(2, frequency() / 64.0);
|
stream = Emulator::audio.createStream(2, frequency() / 64.0);
|
||||||
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0);
|
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;
|
clock = 0;
|
||||||
square1.power();
|
square1.power();
|
||||||
|
|
|
@ -131,19 +131,19 @@ auto Interface::get(const string& name) -> any {
|
||||||
auto Interface::set(const string& name, const any& value) -> bool {
|
auto Interface::set(const string& name, const any& value) -> bool {
|
||||||
if(name == "Blur Emulation" && value.is<bool>()) {
|
if(name == "Blur Emulation" && value.is<bool>()) {
|
||||||
settings.blurEmulation = value.get<bool>();
|
settings.blurEmulation = value.get<bool>();
|
||||||
system.configureVideoEffects();
|
Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(name == "Color Emulation" && value.is<bool>()) {
|
if(name == "Color Emulation" && value.is<bool>()) {
|
||||||
settings.colorEmulation = value.get<bool>();
|
settings.colorEmulation = value.get<bool>();
|
||||||
system.configureVideoPalette();
|
Emulator::video.setPalette();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(name == "Rotate Display" && value.is<bool>()) {
|
if(name == "Rotate Display" && value.is<bool>()) {
|
||||||
settings.rotateLeft = value.get<bool>();
|
settings.rotateLeft = value.get<bool>();
|
||||||
system.configureVideoEffects();
|
Emulator::video.setEffect(Emulator::Video::Effect::RotateLeft, settings.rotateLeft);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ namespace GameBoyAdvance {
|
||||||
System system;
|
System system;
|
||||||
Scheduler scheduler;
|
Scheduler scheduler;
|
||||||
#include "bios.cpp"
|
#include "bios.cpp"
|
||||||
#include "video.cpp"
|
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
|
|
||||||
auto System::init() -> void {
|
auto System::init() -> void {
|
||||||
|
@ -15,13 +14,12 @@ auto System::term() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::power() -> void {
|
auto System::power() -> void {
|
||||||
Emulator::video.reset();
|
Emulator::video.reset(interface);
|
||||||
Emulator::video.setInterface(interface);
|
Emulator::video.setPalette();
|
||||||
configureVideoPalette();
|
Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation);
|
||||||
configureVideoEffects();
|
Emulator::video.setEffect(Emulator::Video::Effect::RotateLeft, settings.rotateLeft);
|
||||||
|
|
||||||
Emulator::audio.reset();
|
Emulator::audio.reset(interface);
|
||||||
Emulator::audio.setInterface(interface);
|
|
||||||
|
|
||||||
scheduler.reset();
|
scheduler.reset();
|
||||||
bus.power();
|
bus.power();
|
||||||
|
|
|
@ -27,10 +27,6 @@ struct System {
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
auto runToSave() -> void;
|
auto runToSave() -> void;
|
||||||
|
|
||||||
//video.cpp
|
|
||||||
auto configureVideoPalette() -> void;
|
|
||||||
auto configureVideoEffects() -> void;
|
|
||||||
|
|
||||||
//serialization.cpp
|
//serialization.cpp
|
||||||
auto serialize() -> serializer;
|
auto serialize() -> serializer;
|
||||||
auto unserialize(serializer&) -> bool;
|
auto unserialize(serializer&) -> bool;
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
auto System::configureVideoPalette() -> void {
|
|
||||||
Emulator::video.setPalette();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto System::configureVideoEffects() -> void {
|
|
||||||
Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation);
|
|
||||||
Emulator::video.setEffect(Emulator::Video::Effect::RotateLeft, settings.rotateLeft);
|
|
||||||
}
|
|
|
@ -39,7 +39,6 @@ auto PSG::power(bool reset) -> void {
|
||||||
stream = Emulator::audio.createStream(1, frequency() / 16.0);
|
stream = Emulator::audio.createStream(1, frequency() / 16.0);
|
||||||
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.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::First, Emulator::Filter::Type::LowPass, 2840.0);
|
||||||
stream->addFilter(Emulator::Filter::Order::Second, Emulator::Filter::Type::LowPass, 20000.0, 3);
|
|
||||||
|
|
||||||
select = 0;
|
select = 0;
|
||||||
for(auto n : range(15)) {
|
for(auto n : range(15)) {
|
||||||
|
|
|
@ -62,12 +62,10 @@ auto System::unload() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::power(bool reset) -> void {
|
auto System::power(bool reset) -> void {
|
||||||
Emulator::video.reset();
|
Emulator::video.reset(interface);
|
||||||
Emulator::video.setInterface(interface);
|
|
||||||
Emulator::video.setPalette();
|
Emulator::video.setPalette();
|
||||||
|
|
||||||
Emulator::audio.reset();
|
Emulator::audio.reset(interface);
|
||||||
Emulator::audio.setInterface(interface);
|
|
||||||
|
|
||||||
scheduler.reset();
|
scheduler.reset();
|
||||||
cartridge.power();
|
cartridge.power();
|
||||||
|
|
|
@ -159,7 +159,6 @@ auto YM2612::power(bool reset) -> void {
|
||||||
stream = Emulator::audio.createStream(2, frequency() / 144.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::HighPass, 20.0);
|
||||||
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::LowPass, 2840.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 = {};
|
io = {};
|
||||||
lfo = {};
|
lfo = {};
|
||||||
|
|
|
@ -45,7 +45,6 @@ auto PSG::power() -> void {
|
||||||
create(PSG::Enter, system.colorburst() / 16.0);
|
create(PSG::Enter, system.colorburst() / 16.0);
|
||||||
stream = Emulator::audio.createStream(2, frequency());
|
stream = Emulator::audio.createStream(2, frequency());
|
||||||
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0);
|
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;
|
select = 0;
|
||||||
for(auto n : range(15)) {
|
for(auto n : range(15)) {
|
||||||
|
|
|
@ -59,12 +59,10 @@ auto System::unload() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::power() -> void {
|
auto System::power() -> void {
|
||||||
Emulator::video.reset();
|
Emulator::video.reset(interface);
|
||||||
Emulator::video.setInterface(interface);
|
|
||||||
Emulator::video.setPalette();
|
Emulator::video.setPalette();
|
||||||
|
|
||||||
Emulator::audio.reset();
|
Emulator::audio.reset(interface);
|
||||||
Emulator::audio.setInterface(interface);
|
|
||||||
|
|
||||||
scheduler.reset();
|
scheduler.reset();
|
||||||
cartridge.power();
|
cartridge.power();
|
||||||
|
|
|
@ -53,7 +53,6 @@ auto PSG::power() -> void {
|
||||||
create(PSG::Enter, system.colorburst());
|
create(PSG::Enter, system.colorburst());
|
||||||
stream = Emulator::audio.createStream(2, frequency());
|
stream = Emulator::audio.createStream(2, frequency());
|
||||||
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0);
|
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);
|
|
||||||
|
|
||||||
io = {};
|
io = {};
|
||||||
for(auto C : range(6)) channel[C].power(C);
|
for(auto C : range(6)) channel[C].power(C);
|
||||||
|
|
|
@ -49,12 +49,10 @@ auto System::unload() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::power() -> void {
|
auto System::power() -> void {
|
||||||
Emulator::video.reset();
|
Emulator::video.reset(interface);
|
||||||
Emulator::video.setInterface(interface);
|
|
||||||
Emulator::video.setPalette();
|
Emulator::video.setPalette();
|
||||||
|
|
||||||
Emulator::audio.reset();
|
Emulator::audio.reset(interface);
|
||||||
Emulator::audio.setInterface(interface);
|
|
||||||
|
|
||||||
scheduler.reset();
|
scheduler.reset();
|
||||||
cartridge.power();
|
cartridge.power();
|
||||||
|
|
|
@ -47,7 +47,6 @@ auto ICD::power() -> void {
|
||||||
create(ICD::Enter, (Frequency ? Frequency : system.cpuFrequency()) / 5.0);
|
create(ICD::Enter, (Frequency ? Frequency : system.cpuFrequency()) / 5.0);
|
||||||
stream = Emulator::audio.createStream(2, frequency() / 2.0);
|
stream = Emulator::audio.createStream(2, frequency() / 2.0);
|
||||||
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0);
|
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;
|
r6003 = 0x00;
|
||||||
r6004 = 0xff;
|
r6004 = 0xff;
|
||||||
|
@ -91,7 +90,7 @@ auto ICD::reset() -> void {
|
||||||
writeAddress = 0;
|
writeAddress = 0;
|
||||||
|
|
||||||
packetSize = 0;
|
packetSize = 0;
|
||||||
joypID = 0;
|
joypID = 3;
|
||||||
joyp15Lock = 0;
|
joyp15Lock = 0;
|
||||||
joyp14Lock = 0;
|
joyp14Lock = 0;
|
||||||
pulseLock = true;
|
pulseLock = true;
|
||||||
|
|
|
@ -139,8 +139,8 @@ private:
|
||||||
uint8 wrdivb = 0xff;
|
uint8 wrdivb = 0xff;
|
||||||
|
|
||||||
//$4207-$420a
|
//$4207-$420a
|
||||||
uint9 hirqPos = 0x1ff;
|
uint12 htime = 0x1ff + 1 << 2;
|
||||||
uint9 virqPos = 0x1ff;
|
uint9 vtime = 0x1ff;
|
||||||
|
|
||||||
//$420d
|
//$420d
|
||||||
uint romSpeed = 8;
|
uint romSpeed = 8;
|
||||||
|
|
|
@ -174,19 +174,23 @@ auto CPU::writeCPU(uint24 addr, uint8 data) -> void {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x4207: //HTIMEL
|
case 0x4207: //HTIMEL
|
||||||
io.hirqPos.bits(0,7) = data;
|
io.htime = (io.htime >> 2) - 1;
|
||||||
|
io.htime.bits(0,7) = data;
|
||||||
|
io.htime = (io.htime + 1) << 2;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x4208: //HTIMEH
|
case 0x4208: //HTIMEH
|
||||||
io.hirqPos.bit(8) = data.bit(0);
|
io.htime = (io.htime >> 2) - 1;
|
||||||
|
io.htime.bit(8) = data.bit(0);
|
||||||
|
io.htime = (io.htime + 1) << 2;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x4209: //VTIMEL
|
case 0x4209: //VTIMEL
|
||||||
io.virqPos.bits(0,7) = data;
|
io.vtime.bits(0,7) = data;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x420a: //VTIMEH
|
case 0x420a: //VTIMEH
|
||||||
io.virqPos.bit(8) = data.bit(0);
|
io.vtime.bit(8) = data.bit(0);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x420b: //DMAEN
|
case 0x420b: //DMAEN
|
||||||
|
|
|
@ -18,8 +18,9 @@ auto CPU::pollInterrupts() -> void {
|
||||||
|
|
||||||
//IRQ test
|
//IRQ test
|
||||||
if(status.irqValid.raise(io.irqEnable
|
if(status.irqValid.raise(io.irqEnable
|
||||||
&& (!io.virqEnable || vcounter(10) == io.virqPos)
|
&& (!io.virqEnable || vcounter(10) == io.vtime)
|
||||||
&& (!io.hirqEnable || hcounter(10) == io.hirqPos + 1 << 2)
|
&& (!io.hirqEnable || hcounter(10) == io.htime)
|
||||||
|
&& (vcounter(6) || hcounter(6)) //IRQs cannot trigger on last dot of fields
|
||||||
)) status.irqLine = status.irqHold = true; //hold /IRQ for four cycles
|
)) status.irqLine = status.irqHold = true; //hold /IRQ for four cycles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,8 +65,8 @@ auto CPU::serialize(serializer& s) -> void {
|
||||||
s.integer(io.wrdiva);
|
s.integer(io.wrdiva);
|
||||||
s.integer(io.wrdivb);
|
s.integer(io.wrdivb);
|
||||||
|
|
||||||
s.integer(io.hirqPos);
|
s.integer(io.htime);
|
||||||
s.integer(io.virqPos);
|
s.integer(io.vtime);
|
||||||
|
|
||||||
s.integer(io.romSpeed);
|
s.integer(io.romSpeed);
|
||||||
|
|
||||||
|
|
|
@ -91,12 +91,10 @@ auto System::power(bool reset) -> void {
|
||||||
hacks.fastPPU = settings.fastPPU;
|
hacks.fastPPU = settings.fastPPU;
|
||||||
hacks.fastDSP = settings.fastDSP;
|
hacks.fastDSP = settings.fastDSP;
|
||||||
|
|
||||||
Emulator::video.reset();
|
Emulator::video.reset(interface);
|
||||||
Emulator::video.setInterface(interface);
|
|
||||||
Emulator::video.setPalette();
|
Emulator::video.setPalette();
|
||||||
|
|
||||||
Emulator::audio.reset();
|
Emulator::audio.reset(interface);
|
||||||
Emulator::audio.setInterface(interface);
|
|
||||||
|
|
||||||
random.entropy(Random::Entropy::Low);
|
random.entropy(Random::Entropy::Low);
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,4 @@ auto Program::updateAudioEffects() -> void {
|
||||||
|
|
||||||
double balance = max(-1.0, min(+1.0, (settings["Audio/Balance"].integer() - 50) / 50.0));
|
double balance = max(-1.0, min(+1.0, (settings["Audio/Balance"].integer() - 50) / 50.0));
|
||||||
Emulator::audio.setBalance(balance);
|
Emulator::audio.setBalance(balance);
|
||||||
|
|
||||||
bool reverb = settings["Audio/Reverb"].boolean();
|
|
||||||
Emulator::audio.setReverb(reverb);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,7 @@ auto Program::load() -> void {
|
||||||
for(auto& media : emulator->media) {
|
for(auto& media : emulator->media) {
|
||||||
if(media.type != "sfc") continue;
|
if(media.type != "sfc") continue;
|
||||||
|
|
||||||
Emulator::audio.reset(2, audio->frequency());
|
|
||||||
if(emulator->load(media.id)) {
|
if(emulator->load(media.id)) {
|
||||||
gameQueue = {};
|
|
||||||
screenshot = {};
|
screenshot = {};
|
||||||
frameAdvance = false;
|
frameAdvance = false;
|
||||||
if(!verified() && settingsWindow->advanced.warnOnUnverifiedGames.checked()) {
|
if(!verified() && settingsWindow->advanced.warnOnUnverifiedGames.checked()) {
|
||||||
|
@ -56,6 +54,8 @@ auto Program::load() -> void {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gameQueue = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::loadFile(string location) -> vector<uint8_t> {
|
auto Program::loadFile(string location) -> vector<uint8_t> {
|
||||||
|
|
|
@ -52,12 +52,6 @@ AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||||
balanceValue.setText(value);
|
balanceValue.setText(value);
|
||||||
program->updateAudioEffects();
|
program->updateAudioEffects();
|
||||||
}).doChange();
|
}).doChange();
|
||||||
reverb.setText("Reverb").setChecked(settings["Audio/Reverb"].boolean()).onToggle([&] {
|
|
||||||
settings["Audio/Reverb"].setValue(reverb.checked());
|
|
||||||
program->updateAudioEffects();
|
|
||||||
});
|
|
||||||
//todo: does not work properly with Super Game Boy
|
|
||||||
reverb.setVisible(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto AudioSettings::updateDevice() -> void {
|
auto AudioSettings::updateDevice() -> void {
|
||||||
|
|
|
@ -55,7 +55,6 @@ public:
|
||||||
Label balanceLabel{&effectsLayout, Size{0, 0}};
|
Label balanceLabel{&effectsLayout, Size{0, 0}};
|
||||||
Label balanceValue{&effectsLayout, Size{50, 0}};
|
Label balanceValue{&effectsLayout, Size{50, 0}};
|
||||||
HorizontalSlider balanceSlider{&effectsLayout, Size{~0, 0}};
|
HorizontalSlider balanceSlider{&effectsLayout, Size{~0, 0}};
|
||||||
CheckLabel reverb{&layout, Size{~0, 0}};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InputSettings : TabFrameItem {
|
struct InputSettings : TabFrameItem {
|
||||||
|
|
|
@ -19,17 +19,16 @@ auto Program::loadMedium(Emulator::Interface& interface, const Emulator::Interfa
|
||||||
|
|
||||||
mediumPaths.append(locate({"systems/", medium.name, ".sys/"}));
|
mediumPaths.append(locate({"systems/", medium.name, ".sys/"}));
|
||||||
|
|
||||||
Emulator::audio.reset(2, audio->frequency());
|
|
||||||
inputManager->bind(emulator = &interface);
|
inputManager->bind(emulator = &interface);
|
||||||
if(!emulator->load(medium.id)) {
|
if(!emulator->load(medium.id)) {
|
||||||
emulator = nullptr;
|
emulator = nullptr;
|
||||||
mediumPaths.reset();
|
mediumPaths.reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
updateAudioDriver();
|
|
||||||
updateAudioEffects();
|
|
||||||
connectDevices();
|
connectDevices();
|
||||||
emulator->power();
|
emulator->power();
|
||||||
|
updateAudioDriver();
|
||||||
|
updateAudioEffects();
|
||||||
|
|
||||||
presentation->resizeViewport();
|
presentation->resizeViewport();
|
||||||
presentation->setTitle(emulator->title());
|
presentation->setTitle(emulator->title());
|
||||||
|
|
|
@ -171,9 +171,6 @@ auto Program::updateAudioEffects() -> void {
|
||||||
|
|
||||||
auto balance = max(-1.0, min(1.0, (settings["Audio/Balance"].integer() - 50) / 50.0));
|
auto balance = max(-1.0, min(1.0, (settings["Audio/Balance"].integer() - 50) / 50.0));
|
||||||
Emulator::audio.setBalance(balance);
|
Emulator::audio.setBalance(balance);
|
||||||
|
|
||||||
auto reverbEnable = settings["Audio/Reverb/Enable"].boolean();
|
|
||||||
Emulator::audio.setReverb(reverbEnable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::focused() -> bool {
|
auto Program::focused() -> bool {
|
||||||
|
|
|
@ -48,8 +48,6 @@ AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||||
balanceValue.setAlignment(0.5);
|
balanceValue.setAlignment(0.5);
|
||||||
balanceSlider.setLength(101).setPosition(settings["Audio/Balance"].natural()).onChange([&] { updateEffects(); });
|
balanceSlider.setLength(101).setPosition(settings["Audio/Balance"].natural()).onChange([&] { updateEffects(); });
|
||||||
|
|
||||||
reverbEnable.setText("Reverb").setChecked(settings["Audio/Reverb/Enable"].boolean()).onToggle([&] { updateEffects(); });
|
|
||||||
|
|
||||||
updateDevice();
|
updateDevice();
|
||||||
updateEffects(true);
|
updateEffects(true);
|
||||||
}
|
}
|
||||||
|
@ -79,7 +77,5 @@ auto AudioSettings::updateEffects(bool initializing) -> void {
|
||||||
settings["Audio/Balance"].setValue(balanceSlider.position());
|
settings["Audio/Balance"].setValue(balanceSlider.position());
|
||||||
balanceValue.setText({balanceSlider.position(), "%"});
|
balanceValue.setText({balanceSlider.position(), "%"});
|
||||||
|
|
||||||
settings["Audio/Reverb/Enable"].setValue(reverbEnable.checked());
|
|
||||||
|
|
||||||
if(!initializing) program->updateAudioEffects();
|
if(!initializing) program->updateAudioEffects();
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,6 @@ Settings::Settings() {
|
||||||
set("Audio/Mute", false);
|
set("Audio/Mute", false);
|
||||||
set("Audio/Volume", 100);
|
set("Audio/Volume", 100);
|
||||||
set("Audio/Balance", 50);
|
set("Audio/Balance", 50);
|
||||||
set("Audio/Reverb/Enable", false);
|
|
||||||
|
|
||||||
set("Input/Driver", ruby::Input::safestDriver());
|
set("Input/Driver", ruby::Input::safestDriver());
|
||||||
set("Input/Frequency", 5);
|
set("Input/Frequency", 5);
|
||||||
|
|
|
@ -109,7 +109,6 @@ struct AudioSettings : TabFrameItem {
|
||||||
Label balanceLabel{&balanceLayout, Size{80, 0}};
|
Label balanceLabel{&balanceLayout, Size{80, 0}};
|
||||||
Label balanceValue{&balanceLayout, Size{50, 0}};
|
Label balanceValue{&balanceLayout, Size{50, 0}};
|
||||||
HorizontalSlider balanceSlider{&balanceLayout, Size{~0, 0}};
|
HorizontalSlider balanceSlider{&balanceLayout, Size{~0, 0}};
|
||||||
CheckLabel reverbEnable{&layout, Size{~0, 0}};
|
|
||||||
|
|
||||||
auto updateDevice() -> void;
|
auto updateDevice() -> void;
|
||||||
auto updateEffects(bool initializing = false) -> void;
|
auto updateEffects(bool initializing = false) -> void;
|
||||||
|
|
|
@ -6,11 +6,12 @@ namespace Emulator {
|
||||||
Video video;
|
Video video;
|
||||||
|
|
||||||
Video::~Video() {
|
Video::~Video() {
|
||||||
reset();
|
reset(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Video::reset() -> void {
|
auto Video::reset(Interface* interface) -> void {
|
||||||
interface = nullptr;
|
this->interface = interface;
|
||||||
|
|
||||||
sprites.reset();
|
sprites.reset();
|
||||||
delete buffer;
|
delete buffer;
|
||||||
buffer = nullptr;
|
buffer = nullptr;
|
||||||
|
@ -25,10 +26,6 @@ auto Video::reset() -> void {
|
||||||
effects.rotateLeft = false;
|
effects.rotateLeft = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Video::setInterface(Interface* interface) -> void {
|
|
||||||
this->interface = interface;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Video::setPalette() -> void {
|
auto Video::setPalette() -> void {
|
||||||
if(!interface) return;
|
if(!interface) return;
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,7 @@ struct Video {
|
||||||
};
|
};
|
||||||
|
|
||||||
~Video();
|
~Video();
|
||||||
|
auto reset(Interface* interface) -> void;
|
||||||
auto reset() -> void;
|
|
||||||
auto setInterface(Interface* interface) -> void;
|
|
||||||
|
|
||||||
auto setPalette() -> void;
|
auto setPalette() -> void;
|
||||||
auto setSaturation(double saturation) -> void;
|
auto setSaturation(double saturation) -> void;
|
||||||
|
|
|
@ -68,7 +68,6 @@ auto APU::power() -> void {
|
||||||
create(APU::Enter, 3'072'000);
|
create(APU::Enter, 3'072'000);
|
||||||
stream = Emulator::audio.createStream(2, frequency());
|
stream = Emulator::audio.createStream(2, frequency());
|
||||||
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0);
|
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, 0x004a, 0x004c);
|
||||||
bus.map(this, 0x004e, 0x0050);
|
bus.map(this, 0x004e, 0x0050);
|
||||||
|
|
|
@ -106,19 +106,19 @@ auto Interface::get(const string& name) -> any {
|
||||||
auto Interface::set(const string& name, const any& value) -> bool {
|
auto Interface::set(const string& name, const any& value) -> bool {
|
||||||
if(name == "Blur Emulation" && value.is<bool>()) {
|
if(name == "Blur Emulation" && value.is<bool>()) {
|
||||||
settings.blurEmulation = value.get<bool>();
|
settings.blurEmulation = value.get<bool>();
|
||||||
system.configureVideoEffects();
|
Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(name == "Color Emulation" && value.is<bool>()) {
|
if(name == "Color Emulation" && value.is<bool>()) {
|
||||||
settings.colorEmulation = value.get<bool>();
|
settings.colorEmulation = value.get<bool>();
|
||||||
system.configureVideoPalette();
|
Emulator::video.setPalette();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(name == "Rotate Display" && value.is<bool>()) {
|
if(name == "Rotate Display" && value.is<bool>()) {
|
||||||
settings.rotateLeft = value.get<bool>();
|
settings.rotateLeft = value.get<bool>();
|
||||||
system.configureVideoEffects();
|
Emulator::video.setEffect(Emulator::Video::Effect::RotateLeft, settings.rotateLeft);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ System system;
|
||||||
Scheduler scheduler;
|
Scheduler scheduler;
|
||||||
Cheat cheat;
|
Cheat cheat;
|
||||||
#include "io.cpp"
|
#include "io.cpp"
|
||||||
#include "video.cpp"
|
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
|
|
||||||
auto System::init() -> void {
|
auto System::init() -> void {
|
||||||
|
@ -61,13 +60,12 @@ auto System::unload() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::power() -> void {
|
auto System::power() -> void {
|
||||||
Emulator::video.reset();
|
Emulator::video.reset(interface);
|
||||||
Emulator::video.setInterface(interface);
|
Emulator::video.setPalette();
|
||||||
configureVideoPalette();
|
Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation);
|
||||||
configureVideoEffects();
|
Emulator::video.setEffect(Emulator::Video::Effect::RotateLeft, settings.rotateLeft);
|
||||||
|
|
||||||
Emulator::audio.reset();
|
Emulator::audio.reset(interface);
|
||||||
Emulator::audio.setInterface(interface);
|
|
||||||
|
|
||||||
scheduler.reset();
|
scheduler.reset();
|
||||||
bus.power();
|
bus.power();
|
||||||
|
|
|
@ -22,10 +22,6 @@ struct System : IO {
|
||||||
auto portRead(uint16 addr) -> uint8 override;
|
auto portRead(uint16 addr) -> uint8 override;
|
||||||
auto portWrite(uint16 addr, uint8 data) -> void override;
|
auto portWrite(uint16 addr, uint8 data) -> void override;
|
||||||
|
|
||||||
//video.cpp
|
|
||||||
auto configureVideoPalette() -> void;
|
|
||||||
auto configureVideoEffects() -> void;
|
|
||||||
|
|
||||||
//serialization.cpp
|
//serialization.cpp
|
||||||
auto serializeInit() -> void;
|
auto serializeInit() -> void;
|
||||||
auto serialize() -> serializer;
|
auto serialize() -> serializer;
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
auto System::configureVideoPalette() -> void {
|
|
||||||
Emulator::video.setPalette();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto System::configureVideoEffects() -> void {
|
|
||||||
Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation);
|
|
||||||
Emulator::video.setEffect(Emulator::Video::Effect::RotateLeft, settings.rotateLeft);
|
|
||||||
}
|
|
|
@ -43,9 +43,13 @@
|
||||||
#include <gdk/gdkkeysyms.h>
|
#include <gdk/gdkkeysyms.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#if defined(Hiro_SourceEdit)
|
#if defined(Hiro_SourceEdit)
|
||||||
#include <gtksourceview/gtksourceview.h>
|
#if HIRO_GTK==2
|
||||||
#include <gtksourceview/gtksourcelanguagemanager.h>
|
#include <gtksourceview/gtksourceview.h>
|
||||||
#include <gtksourceview/gtksourcestyleschememanager.h>
|
#include <gtksourceview/gtksourcelanguagemanager.h>
|
||||||
|
#include <gtksourceview/gtksourcestyleschememanager.h>
|
||||||
|
#elif HIRO_GTK==3
|
||||||
|
#include <gtksourceview/gtksource.h>
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#include <nall/xorg/guard.hpp>
|
#include <nall/xorg/guard.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,16 +8,20 @@ Settings::Settings() {
|
||||||
auto document = BML::unserialize(file::read({path, "gtk3.bml"}));
|
auto document = BML::unserialize(file::read({path, "gtk3.bml"}));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto get = [&](string_view name) {
|
#define get(name, type, value) \
|
||||||
return document[name];
|
if(auto node = document[name]) value = node.type()
|
||||||
};
|
|
||||||
|
|
||||||
geometry.frameX = get("Geometry/FrameX").integer();
|
get("Geometry/FrameX", integer, geometry.frameX);
|
||||||
geometry.frameY = get("Geometry/FrameY").integer();
|
get("Geometry/FrameY", integer, geometry.frameY);
|
||||||
geometry.frameWidth = get("Geometry/FrameWidth").integer();
|
get("Geometry/FrameWidth", integer, geometry.frameWidth);
|
||||||
geometry.frameHeight = get("Geometry/FrameHeight").integer();
|
get("Geometry/FrameHeight", integer, geometry.frameHeight);
|
||||||
geometry.menuHeight = get("Geometry/MenuHeight").integer();
|
get("Geometry/MenuHeight", integer, geometry.menuHeight);
|
||||||
geometry.statusHeight = get("Geometry/StatusHeight").integer();
|
get("Geometry/StatusHeight", integer, geometry.statusHeight);
|
||||||
|
|
||||||
|
get("Theme/ActionIcons", boolean, theme.actionIcons);
|
||||||
|
get("Theme/WidgetColors", boolean, theme.widgetColors);
|
||||||
|
|
||||||
|
#undef get
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::~Settings() {
|
Settings::~Settings() {
|
||||||
|
@ -25,9 +29,9 @@ Settings::~Settings() {
|
||||||
directory::create(path, 0755);
|
directory::create(path, 0755);
|
||||||
|
|
||||||
Markup::Node document;
|
Markup::Node document;
|
||||||
auto set = [&](string_view name, string_view value) {
|
|
||||||
document(name).setValue(value);
|
#define set(name, value) \
|
||||||
};
|
document(name).setValue(value)
|
||||||
|
|
||||||
set("Geometry/FrameX", geometry.frameX);
|
set("Geometry/FrameX", geometry.frameX);
|
||||||
set("Geometry/FrameY", geometry.frameY);
|
set("Geometry/FrameY", geometry.frameY);
|
||||||
|
@ -36,6 +40,11 @@ Settings::~Settings() {
|
||||||
set("Geometry/MenuHeight", geometry.menuHeight);
|
set("Geometry/MenuHeight", geometry.menuHeight);
|
||||||
set("Geometry/StatusHeight", geometry.statusHeight);
|
set("Geometry/StatusHeight", geometry.statusHeight);
|
||||||
|
|
||||||
|
set("Theme/ActionIcons", theme.actionIcons);
|
||||||
|
set("Theme/WidgetColors", theme.widgetColors);
|
||||||
|
|
||||||
|
#undef set
|
||||||
|
|
||||||
#if HIRO_GTK==2
|
#if HIRO_GTK==2
|
||||||
file::write({path, "gtk2.bml"}, BML::serialize(document));
|
file::write({path, "gtk2.bml"}, BML::serialize(document));
|
||||||
#elif HIRO_GTK==3
|
#elif HIRO_GTK==3
|
||||||
|
|
|
@ -14,6 +14,11 @@ struct Settings {
|
||||||
int menuHeight = 8;
|
int menuHeight = 8;
|
||||||
int statusHeight = 4;
|
int statusHeight = 4;
|
||||||
} geometry;
|
} geometry;
|
||||||
|
|
||||||
|
struct Theme {
|
||||||
|
bool actionIcons = true;
|
||||||
|
bool widgetColors = true;
|
||||||
|
} theme;
|
||||||
};
|
};
|
||||||
|
|
||||||
static Settings settings;
|
static Settings settings;
|
||||||
|
|
|
@ -257,14 +257,14 @@ auto pTableView::_doDataFunc(GtkTreeViewColumn* gtkColumn, GtkCellRenderer* rend
|
||||||
pango_font_description_free(font);
|
pango_font_description_free(font);
|
||||||
if(auto color = cell->foregroundColor(true)) {
|
if(auto color = cell->foregroundColor(true)) {
|
||||||
auto gdkColor = CreateColor(color);
|
auto gdkColor = CreateColor(color);
|
||||||
g_object_set(G_OBJECT(renderer), "foreground-gdk", &gdkColor, nullptr);
|
if(settings.theme.widgetColors) g_object_set(G_OBJECT(renderer), "foreground-gdk", &gdkColor, nullptr);
|
||||||
} else {
|
} else {
|
||||||
g_object_set(G_OBJECT(renderer), "foreground-set", false, nullptr);
|
g_object_set(G_OBJECT(renderer), "foreground-set", false, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(auto color = cell->backgroundColor(true)) {
|
if(auto color = cell->backgroundColor(true)) {
|
||||||
auto gdkColor = CreateColor(color);
|
auto gdkColor = CreateColor(color);
|
||||||
g_object_set(G_OBJECT(renderer), "cell-background-gdk", &gdkColor, nullptr);
|
if(settings.theme.widgetColors) g_object_set(G_OBJECT(renderer), "cell-background-gdk", &gdkColor, nullptr);
|
||||||
} else {
|
} else {
|
||||||
g_object_set(G_OBJECT(renderer), "cell-background-set", false, nullptr);
|
g_object_set(G_OBJECT(renderer), "cell-background-set", false, nullptr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,16 +8,17 @@ Settings::Settings() {
|
||||||
auto document = BML::unserialize(file::read({path, "qt5.bml"}));
|
auto document = BML::unserialize(file::read({path, "qt5.bml"}));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto get = [&](string_view name) {
|
#define get(name, type, value) \
|
||||||
return document[name];
|
if(auto node = document[name]) value = node.type()
|
||||||
};
|
|
||||||
|
|
||||||
geometry.frameX = get("Geometry/FrameX").integer();
|
get("Geometry/FrameX", integer, geometry.frameX);
|
||||||
geometry.frameY = get("Geometry/FrameY").integer();
|
get("Geometry/FrameY", integer, geometry.frameY);
|
||||||
geometry.frameWidth = get("Geometry/FrameWidth").integer();
|
get("Geometry/FrameWidth", integer, geometry.frameWidth);
|
||||||
geometry.frameHeight = get("Geometry/FrameHeight").integer();
|
get("Geometry/FrameHeight", integer, geometry.frameHeight);
|
||||||
geometry.menuHeight = get("Geometry/MenuHeight").integer();
|
get("Geometry/MenuHeight", integer, geometry.menuHeight);
|
||||||
geometry.statusHeight = get("Geometry/StatusHeight").integer();
|
get("Geometry/StatusHeight", integer, geometry.statusHeight);
|
||||||
|
|
||||||
|
#undef get
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::~Settings() {
|
Settings::~Settings() {
|
||||||
|
@ -25,9 +26,9 @@ Settings::~Settings() {
|
||||||
directory::create(path, 0755);
|
directory::create(path, 0755);
|
||||||
|
|
||||||
Markup::Node document;
|
Markup::Node document;
|
||||||
auto set = [&](string_view name, string_view value) {
|
|
||||||
document(name).setValue(value);
|
#define set(name, value) \
|
||||||
};
|
document(name).setValue(value)
|
||||||
|
|
||||||
set("Geometry/FrameX", geometry.frameX);
|
set("Geometry/FrameX", geometry.frameX);
|
||||||
set("Geometry/FrameY", geometry.frameY);
|
set("Geometry/FrameY", geometry.frameY);
|
||||||
|
@ -36,6 +37,8 @@ Settings::~Settings() {
|
||||||
set("Geometry/MenuHeight", geometry.menuHeight);
|
set("Geometry/MenuHeight", geometry.menuHeight);
|
||||||
set("Geometry/StatusHeight", geometry.statusHeight);
|
set("Geometry/StatusHeight", geometry.statusHeight);
|
||||||
|
|
||||||
|
#undef set
|
||||||
|
|
||||||
#if HIRO_QT==4
|
#if HIRO_QT==4
|
||||||
file::write({path, "qt4.bml"}, BML::serialize(document));
|
file::write({path, "qt4.bml"}, BML::serialize(document));
|
||||||
#elif HIRO_QT==5
|
#elif HIRO_QT==5
|
||||||
|
|
|
@ -164,7 +164,6 @@ auto pWindow::setMaximumSize(Size size) -> void {
|
||||||
static auto maximumSize = qtWindow->maximumSize();
|
static auto maximumSize = qtWindow->maximumSize();
|
||||||
|
|
||||||
if(size) {
|
if(size) {
|
||||||
//once this is called, no matter what the size is, Qt will no longer allow the window to be maximized
|
|
||||||
qtWindow->setMaximumSize(size.width(), size.height() + _menuHeight() + _statusHeight());
|
qtWindow->setMaximumSize(size.width(), size.height() + _menuHeight() + _statusHeight());
|
||||||
} else {
|
} else {
|
||||||
qtWindow->setMaximumSize(maximumSize);
|
qtWindow->setMaximumSize(maximumSize);
|
||||||
|
|
|
@ -40,7 +40,9 @@ ifeq ($(platform),)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
flags.c = -x c -std=c11
|
flags.c = -x c -std=c11
|
||||||
|
flags.h = -x c-header -std=c11
|
||||||
flags.cpp = -x c++ -std=c++14
|
flags.cpp = -x c++ -std=c++14
|
||||||
|
flags.hpp = -x c++-header -std=c++14
|
||||||
flags.objc = -x objective-c -std=c11
|
flags.objc = -x objective-c -std=c11
|
||||||
flags.objcpp = -x objective-c++ -std=c++14
|
flags.objcpp = -x objective-c++ -std=c++14
|
||||||
flags.deps = -MMD -MP -MF $(@:.o=.d)
|
flags.deps = -MMD -MP -MF $(@:.o=.d)
|
||||||
|
@ -50,6 +52,7 @@ ifeq ($(compiler),)
|
||||||
ifeq ($(platform),windows)
|
ifeq ($(platform),windows)
|
||||||
compiler := g++
|
compiler := g++
|
||||||
flags.cpp := -x c++ -std=gnu++14
|
flags.cpp := -x c++ -std=gnu++14
|
||||||
|
flags.hpp := -x c++-header -std=gnu++14
|
||||||
else ifeq ($(platform),macos)
|
else ifeq ($(platform),macos)
|
||||||
compiler := clang++
|
compiler := clang++
|
||||||
else ifeq ($(platform),linux)
|
else ifeq ($(platform),linux)
|
||||||
|
@ -133,7 +136,10 @@ endif
|
||||||
|
|
||||||
# paths
|
# paths
|
||||||
prefix := $(HOME)/.local
|
prefix := $(HOME)/.local
|
||||||
object.path := obj
|
|
||||||
|
ifeq ($(object.path),)
|
||||||
|
object.path := obj
|
||||||
|
endif
|
||||||
|
|
||||||
# rules
|
# rules
|
||||||
default: all;
|
default: all;
|
||||||
|
@ -155,7 +161,11 @@ compile = \
|
||||||
$(compiler) $(flags.c) $(flags.deps) $(flags) $1 -c $< -o $@ \
|
$(compiler) $(flags.c) $(flags.deps) $(flags) $1 -c $< -o $@ \
|
||||||
,$(if $(filter %.cpp,$<), \
|
,$(if $(filter %.cpp,$<), \
|
||||||
$(compiler) $(flags.cpp) $(flags.deps) $(flags) $1 -c $< -o $@ \
|
$(compiler) $(flags.cpp) $(flags.deps) $(flags) $1 -c $< -o $@ \
|
||||||
)) \
|
,$(if $(filter %.h,$<), \
|
||||||
|
$(compiler) $(flags.h) $(flags) $1 -c $< -o $@ \
|
||||||
|
,$(if $(filter %.hpp,$<), \
|
||||||
|
$(compiler) $(flags.hpp) $(flags) $1 -c $< -o $@ \
|
||||||
|
)))) \
|
||||||
)
|
)
|
||||||
|
|
||||||
# function rwildcard(directory, pattern)
|
# function rwildcard(directory, pattern)
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace nall { namespace DSP {
|
||||||
|
|
||||||
|
#if defined(NALL_DSP_PRECISION)
|
||||||
|
using real = NALL_DSP_PRECISION;
|
||||||
|
#else
|
||||||
|
using real = double;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}}
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <nall/dsp/dsp.hpp>
|
||||||
|
|
||||||
//transposed direct form II biquadratic second-order IIR filter
|
//transposed direct form II biquadratic second-order IIR filter
|
||||||
|
|
||||||
namespace nall { namespace DSP { namespace IIR {
|
namespace nall { namespace DSP { namespace IIR {
|
||||||
|
@ -15,22 +17,22 @@ struct Biquad {
|
||||||
HighShelf,
|
HighShelf,
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto reset(Type type, double cutoffFrequency, double samplingFrequency, double quality, double gain = 0.0) -> void;
|
inline auto reset(Type type, real cutoffFrequency, real samplingFrequency, real quality, real gain = 0.0) -> void;
|
||||||
inline auto process(double in) -> double; //normalized sample (-1.0 to +1.0)
|
inline auto process(real in) -> real; //normalized sample (-1.0 to +1.0)
|
||||||
|
|
||||||
inline static auto butterworth(uint order, uint phase) -> double;
|
inline static auto butterworth(uint order, uint phase) -> real;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type type;
|
Type type;
|
||||||
double cutoffFrequency;
|
real cutoffFrequency;
|
||||||
double samplingFrequency;
|
real samplingFrequency;
|
||||||
double quality; //frequency response quality
|
real quality; //frequency response quality
|
||||||
double gain; //peak gain
|
real gain; //peak gain
|
||||||
double a0, a1, a2, b1, b2; //coefficients
|
real a0, a1, a2, b1, b2; //coefficients
|
||||||
double z1, z2; //second-order IIR
|
real z1, z2; //second-order IIR
|
||||||
};
|
};
|
||||||
|
|
||||||
auto Biquad::reset(Type type, double cutoffFrequency, double samplingFrequency, double quality, double gain) -> void {
|
auto Biquad::reset(Type type, real cutoffFrequency, real samplingFrequency, real quality, real gain) -> void {
|
||||||
this->type = type;
|
this->type = type;
|
||||||
this->cutoffFrequency = cutoffFrequency;
|
this->cutoffFrequency = cutoffFrequency;
|
||||||
this->samplingFrequency = samplingFrequency;
|
this->samplingFrequency = samplingFrequency;
|
||||||
|
@ -40,10 +42,10 @@ auto Biquad::reset(Type type, double cutoffFrequency, double samplingFrequency,
|
||||||
z1 = 0.0;
|
z1 = 0.0;
|
||||||
z2 = 0.0;
|
z2 = 0.0;
|
||||||
|
|
||||||
double v = pow(10, fabs(gain) / 20.0);
|
real v = pow(10, fabs(gain) / 20.0);
|
||||||
double k = tan(Math::Pi * cutoffFrequency / samplingFrequency);
|
real k = tan(Math::Pi * cutoffFrequency / samplingFrequency);
|
||||||
double q = quality;
|
real q = quality;
|
||||||
double n = 0.0;
|
real n = 0.0;
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
|
|
||||||
|
@ -140,15 +142,15 @@ auto Biquad::reset(Type type, double cutoffFrequency, double samplingFrequency,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Biquad::process(double in) -> double {
|
auto Biquad::process(real in) -> real {
|
||||||
double out = in * a0 + z1;
|
real out = in * a0 + z1;
|
||||||
z1 = in * a1 + z2 - b1 * out;
|
z1 = in * a1 + z2 - b1 * out;
|
||||||
z2 = in * a2 - b2 * out;
|
z2 = in * a2 - b2 * out;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
//compute Q values for N-order butterworth filtering
|
//compute Q values for N-order butterworth filtering
|
||||||
auto Biquad::butterworth(uint order, uint phase) -> double {
|
auto Biquad::butterworth(uint order, uint phase) -> real {
|
||||||
return -0.5 / cos(Math::Pi * (phase + order + 0.5) / order);
|
return -0.5 / cos(Math::Pi * (phase + order + 0.5) / order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <nall/dsp/dsp.hpp>
|
||||||
|
|
||||||
//one-pole first-order IIR filter
|
//one-pole first-order IIR filter
|
||||||
|
|
||||||
namespace nall { namespace DSP { namespace IIR {
|
namespace nall { namespace DSP { namespace IIR {
|
||||||
|
@ -10,24 +12,24 @@ struct OnePole {
|
||||||
HighPass,
|
HighPass,
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto reset(Type type, double cutoffFrequency, double samplingFrequency) -> void;
|
inline auto reset(Type type, real cutoffFrequency, real samplingFrequency) -> void;
|
||||||
inline auto process(double in) -> double; //normalized sample (-1.0 to +1.0)
|
inline auto process(real in) -> real; //normalized sample (-1.0 to +1.0)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type type;
|
Type type;
|
||||||
double cutoffFrequency;
|
real cutoffFrequency;
|
||||||
double samplingFrequency;
|
real samplingFrequency;
|
||||||
double a0, b1; //coefficients
|
real a0, b1; //coefficients
|
||||||
double z1; //first-order IIR
|
real z1; //first-order IIR
|
||||||
};
|
};
|
||||||
|
|
||||||
auto OnePole::reset(Type type, double cutoffFrequency, double samplingFrequency) -> void {
|
auto OnePole::reset(Type type, real cutoffFrequency, real samplingFrequency) -> void {
|
||||||
this->type = type;
|
this->type = type;
|
||||||
this->cutoffFrequency = cutoffFrequency;
|
this->cutoffFrequency = cutoffFrequency;
|
||||||
this->samplingFrequency = samplingFrequency;
|
this->samplingFrequency = samplingFrequency;
|
||||||
|
|
||||||
z1 = 0.0;
|
z1 = 0.0;
|
||||||
double x = cos(2.0 * Math::Pi * cutoffFrequency / samplingFrequency);
|
real x = cos(2.0 * Math::Pi * cutoffFrequency / samplingFrequency);
|
||||||
if(type == Type::LowPass) {
|
if(type == Type::LowPass) {
|
||||||
b1 = +2.0 - x - sqrt((+2.0 - x) * (+2.0 - x) - 1);
|
b1 = +2.0 - x - sqrt((+2.0 - x) * (+2.0 - x) - 1);
|
||||||
a0 = 1.0 - b1;
|
a0 = 1.0 - b1;
|
||||||
|
@ -37,7 +39,7 @@ auto OnePole::reset(Type type, double cutoffFrequency, double samplingFrequency)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto OnePole::process(double in) -> double {
|
auto OnePole::process(real in) -> real {
|
||||||
return z1 = in * a0 + z1 * b1;
|
return z1 = in * a0 + z1 * b1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,27 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <nall/queue.hpp>
|
#include <nall/queue.hpp>
|
||||||
|
#include <nall/dsp/dsp.hpp>
|
||||||
|
|
||||||
namespace nall { namespace DSP { namespace Resampler {
|
namespace nall { namespace DSP { namespace Resampler {
|
||||||
|
|
||||||
struct Cubic {
|
struct Cubic {
|
||||||
inline auto reset(double inputFrequency, double outputFrequency, uint queueSize = 0) -> void;
|
inline auto reset(real inputFrequency, real outputFrequency, uint queueSize = 0) -> void;
|
||||||
inline auto pending() const -> bool { return samples.pending(); }
|
inline auto pending() const -> bool { return samples.pending(); }
|
||||||
inline auto read() -> double { return samples.read(); }
|
inline auto read() -> real { return samples.read(); }
|
||||||
inline auto write(double sample) -> void;
|
inline auto write(real sample) -> void;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double inputFrequency;
|
real inputFrequency;
|
||||||
double outputFrequency;
|
real outputFrequency;
|
||||||
|
|
||||||
double ratio;
|
real ratio;
|
||||||
double fraction;
|
real fraction;
|
||||||
double history[4];
|
real history[4];
|
||||||
queue<double> samples;
|
queue<real> samples;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto Cubic::reset(double inputFrequency, double outputFrequency, uint queueSize) -> void {
|
auto Cubic::reset(real inputFrequency, real outputFrequency, uint queueSize) -> void {
|
||||||
this->inputFrequency = inputFrequency;
|
this->inputFrequency = inputFrequency;
|
||||||
this->outputFrequency = outputFrequency;
|
this->outputFrequency = outputFrequency;
|
||||||
if(!queueSize) queueSize = outputFrequency * 0.02; //20ms
|
if(!queueSize) queueSize = outputFrequency * 0.02; //20ms
|
||||||
|
@ -31,7 +32,7 @@ auto Cubic::reset(double inputFrequency, double outputFrequency, uint queueSize)
|
||||||
samples.resize(queueSize);
|
samples.resize(queueSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cubic::write(double sample) -> void {
|
auto Cubic::write(real sample) -> void {
|
||||||
auto& mu = fraction;
|
auto& mu = fraction;
|
||||||
auto& s = history;
|
auto& s = history;
|
||||||
|
|
||||||
|
@ -41,10 +42,10 @@ auto Cubic::write(double sample) -> void {
|
||||||
s[3] = sample;
|
s[3] = sample;
|
||||||
|
|
||||||
while(mu <= 1.0) {
|
while(mu <= 1.0) {
|
||||||
double A = s[3] - s[2] - s[0] + s[1];
|
real A = s[3] - s[2] - s[0] + s[1];
|
||||||
double B = s[0] - s[1] - A;
|
real B = s[0] - s[1] - A;
|
||||||
double C = s[2] - s[0];
|
real C = s[2] - s[0];
|
||||||
double D = s[1];
|
real D = s[1];
|
||||||
|
|
||||||
samples.write(A * mu * mu * mu + B * mu * mu + C * mu + D);
|
samples.write(A * mu * mu * mu + B * mu * mu + C * mu + D);
|
||||||
mu += ratio;
|
mu += ratio;
|
||||||
|
|
|
@ -63,6 +63,12 @@ struct Node {
|
||||||
auto natural() const -> uintmax { return text().natural(); }
|
auto natural() const -> uintmax { return text().natural(); }
|
||||||
auto real() const -> double { return text().real(); }
|
auto real() const -> double { return text().real(); }
|
||||||
|
|
||||||
|
auto text(const string& fallback) const -> string { return bool(*this) ? text() : fallback; }
|
||||||
|
auto boolean(bool fallback) const -> bool { return bool(*this) ? boolean() : fallback; }
|
||||||
|
auto integer(intmax fallback) const -> intmax { return bool(*this) ? integer() : fallback; }
|
||||||
|
auto natural(uintmax fallback) const -> uintmax { return bool(*this) ? natural() : fallback; }
|
||||||
|
auto real(double fallback) const -> double { return bool(*this) ? real() : fallback; }
|
||||||
|
|
||||||
auto setName(const string& name = "") -> Node& { shared->_name = name; return *this; }
|
auto setName(const string& name = "") -> Node& { shared->_name = name; return *this; }
|
||||||
auto setValue(const string& value = "") -> Node& { shared->_value = value; return *this; }
|
auto setValue(const string& value = "") -> Node& { shared->_value = value; return *this; }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue