diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 7d799cc4..3664b3d9 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -6,7 +6,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "096.08"; + static const string Version = "097"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/gb/apu/apu.cpp b/higan/gb/apu/apu.cpp index a983205e..da32a507 100644 --- a/higan/gb/apu/apu.cpp +++ b/higan/gb/apu/apu.cpp @@ -2,11 +2,11 @@ namespace GameBoy { +#include "sequencer/sequencer.cpp" #include "square1/square1.cpp" #include "square2/square2.cpp" #include "wave/wave.cpp" #include "noise/noise.cpp" -#include "master/master.cpp" #include "serialization.cpp" APU apu; @@ -20,7 +20,19 @@ auto APU::main() -> void { scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); } - if(stage == 0) { //512hz + square1.run(); + square2.run(); + wave.run(); + noise.run(); + sequencer.run(); + + hipass(sequencer.center, sequencer.centerBias); + hipass(sequencer.left, sequencer.leftBias); + hipass(sequencer.right, sequencer.rightBias); + + interface->audioSample(sequencer.left, sequencer.right); + + if(cycle == 0) { //512hz if(phase == 0 || phase == 2 || phase == 4 || phase == 6) { //256hz square1.clockLength(); square2.clockLength(); @@ -37,25 +49,16 @@ auto APU::main() -> void { } phase++; } - stage++; - - square1.run(); - square2.run(); - wave.run(); - noise.run(); - master.run(); - - hipass(master.center, master.centerBias); - hipass(master.left, master.leftBias); - hipass(master.right, master.rightBias); - - interface->audioSample(master.left, master.right); + cycle++; clock += cpu.frequency; - if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(scheduler.active_thread = cpu.thread); + if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) { + co_switch(scheduler.active_thread = cpu.thread); + } } } +//filter to remove DC bias auto APU::hipass(int16& sample, int64& bias) -> void { bias += ((((int64)sample << 16) - (bias >> 16)) * 57593) >> 16; sample = sclamp<16>(sample - (bias >> 32)); @@ -65,14 +68,13 @@ auto APU::power() -> void { create(Main, 2 * 1024 * 1024); for(uint n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this; - stage = 0; - phase = 0; - square1.power(); square2.power(); wave.power(); noise.power(); - master.power(); + sequencer.power(); + phase = 0; + cycle = 0; LinearFeedbackShiftRegisterGenerator r; for(auto& n : wave.pattern) n = r(); @@ -83,16 +85,16 @@ auto APU::mmio_read(uint16 addr) -> uint8 { if(addr >= 0xff15 && addr <= 0xff19) return square2.read(addr); if(addr >= 0xff1a && addr <= 0xff1e) return wave.read(addr); if(addr >= 0xff1f && addr <= 0xff23) return noise.read(addr); - if(addr >= 0xff24 && addr <= 0xff26) return master.read(addr); + if(addr >= 0xff24 && addr <= 0xff26) return sequencer.read(addr); if(addr >= 0xff30 && addr <= 0xff3f) return wave.read(addr); return 0xff; } auto APU::mmio_write(uint16 addr, uint8 data) -> void { - if(!master.enable) { + if(!sequencer.enable) { bool valid = addr == 0xff26; //NR52 if(!system.cgb()) { - //NRx1 length is writable only on DMG/SGB; not on CGB + //NRx1 length is writable only on DMG,SGB; not on CGB if(addr == 0xff11) valid = true, data &= 0x3f; //NR11; duty is not writable (remains 0) if(addr == 0xff16) valid = true, data &= 0x3f; //NR21; duty is not writable (remains 0) if(addr == 0xff1b) valid = true; //NR31 @@ -105,7 +107,7 @@ auto APU::mmio_write(uint16 addr, uint8 data) -> void { if(addr >= 0xff15 && addr <= 0xff19) return square2.write(addr, data); if(addr >= 0xff1a && addr <= 0xff1e) return wave.write(addr, data); if(addr >= 0xff1f && addr <= 0xff23) return noise.write(addr, data); - if(addr >= 0xff24 && addr <= 0xff26) return master.write(addr, data); + if(addr >= 0xff24 && addr <= 0xff26) return sequencer.write(addr, data); if(addr >= 0xff30 && addr <= 0xff3f) return wave.write(addr, data); } diff --git a/higan/gb/apu/apu.hpp b/higan/gb/apu/apu.hpp index f30a6d15..8a20d2f4 100644 --- a/higan/gb/apu/apu.hpp +++ b/higan/gb/apu/apu.hpp @@ -13,16 +13,16 @@ struct APU : Thread, MMIO { #include "square2/square2.hpp" #include "wave/wave.hpp" #include "noise/noise.hpp" - #include "master/master.hpp" - - uint12 stage; - uint3 phase; + #include "sequencer/sequencer.hpp" Square1 square1; Square2 square2; Wave wave; Noise noise; - Master master; + Sequencer sequencer; + + uint3 phase; //high 3-bits of clock counter + uint12 cycle; //low 12-bits of clock counter }; extern APU apu; diff --git a/higan/gb/apu/master/master.cpp b/higan/gb/apu/sequencer/sequencer.cpp similarity index 93% rename from higan/gb/apu/master/master.cpp rename to higan/gb/apu/sequencer/sequencer.cpp index 3feb4ec6..907b3087 100644 --- a/higan/gb/apu/master/master.cpp +++ b/higan/gb/apu/sequencer/sequencer.cpp @@ -1,4 +1,4 @@ -auto APU::Master::run() -> void { +auto APU::Sequencer::run() -> void { if(enable == false) { center = 0; left = 0; @@ -39,7 +39,7 @@ auto APU::Master::run() -> void { right >>= 1; } -auto APU::Master::read(uint16 addr) -> uint8 { +auto APU::Sequencer::read(uint16 addr) -> uint8 { if(addr == 0xff24) { //NR50 return leftEnable << 7 | leftVolume << 4 | rightEnable << 3 | rightVolume; } @@ -66,7 +66,7 @@ auto APU::Master::read(uint16 addr) -> uint8 { return 0xff; } -auto APU::Master::write(uint16 addr, uint8 data) -> void { +auto APU::Sequencer::write(uint16 addr, uint8 data) -> void { if(addr == 0xff24) { //NR50 leftEnable = (uint1)(data >> 7); leftVolume = (uint3)(data >> 4); @@ -103,7 +103,7 @@ auto APU::Master::write(uint16 addr, uint8 data) -> void { } } -auto APU::Master::power() -> void { +auto APU::Sequencer::power() -> void { leftEnable = 0; leftVolume = 0; rightEnable = 0; @@ -127,7 +127,7 @@ auto APU::Master::power() -> void { rightBias = 0; } -auto APU::Master::serialize(serializer& s) -> void { +auto APU::Sequencer::serialize(serializer& s) -> void { s.integer(leftEnable); s.integer(leftVolume); s.integer(rightEnable); diff --git a/higan/gb/apu/master/master.hpp b/higan/gb/apu/sequencer/sequencer.hpp similarity index 96% rename from higan/gb/apu/master/master.hpp rename to higan/gb/apu/sequencer/sequencer.hpp index 0c861610..2dd64c9b 100644 --- a/higan/gb/apu/master/master.hpp +++ b/higan/gb/apu/sequencer/sequencer.hpp @@ -1,4 +1,4 @@ -struct Master { +struct Sequencer { auto run() -> void; auto read(uint16 addr) -> uint8; auto write(uint16 addr, uint8 data) -> void; diff --git a/higan/gb/apu/serialization.cpp b/higan/gb/apu/serialization.cpp index cfb2327d..1ae311aa 100644 --- a/higan/gb/apu/serialization.cpp +++ b/higan/gb/apu/serialization.cpp @@ -1,12 +1,12 @@ auto APU::serialize(serializer& s) -> void { Thread::serialize(s); - s.integer(stage); - s.integer(phase); - square1.serialize(s); square2.serialize(s); wave.serialize(s); noise.serialize(s); - master.serialize(s); + sequencer.serialize(s); + + s.integer(phase); + s.integer(cycle); } diff --git a/higan/gb/apu/wave/wave.cpp b/higan/gb/apu/wave/wave.cpp index 20f623f4..edb4e9f7 100644 --- a/higan/gb/apu/wave/wave.cpp +++ b/higan/gb/apu/wave/wave.cpp @@ -3,9 +3,12 @@ auto APU::Wave::getPattern(uint5 offset) const -> uint4 { } auto APU::Wave::run() -> void { + if(patternHold) patternHold--; + if(period && --period == 0) { period = 1 * (2048 - frequency); patternSample = getPattern(++patternOffset); + patternHold = 1; } static const uint shift[] = {4, 0, 1, 2}; //0%, 100%, 50%, 25% @@ -43,7 +46,12 @@ auto APU::Wave::read(uint16 addr) -> uint8 { } if(addr >= 0xff30 && addr <= 0xff3f) { - return pattern[addr & 15]; + if(enable) { + if(!system.cgb() && !patternHold) return 0xff; + return pattern[patternOffset >> 1]; + } else { + return pattern[addr & 15]; + } } return 0xff; @@ -77,9 +85,25 @@ auto APU::Wave::write(uint16 addr, uint8 data) -> void { frequency = ((data & 7) << 8) | (frequency & 0x00ff); if(initialize) { + if(!system.cgb() && patternHold) { + //DMG,SGB trigger while channel is being read corrupts wave RAM + if((patternOffset >> 1) <= 3) { + //if current pattern is with 0-3; only byte 0 is corrupted + pattern[0] = pattern[patternOffset >> 1]; + } else { + //if current pattern is within 4-15; pattern&~3 is copied to pattern[0-3] + pattern[0] = pattern[((patternOffset >> 1) & ~3) + 0]; + pattern[1] = pattern[((patternOffset >> 1) & ~3) + 1]; + pattern[2] = pattern[((patternOffset >> 1) & ~3) + 2]; + pattern[3] = pattern[((patternOffset >> 1) & ~3) + 3]; + } + } + enable = dacEnable; period = 1 * (2048 - frequency); patternOffset = 0; + patternSample = 0; + patternHold = 0; if(!length) { length = 256; @@ -89,7 +113,12 @@ auto APU::Wave::write(uint16 addr, uint8 data) -> void { } if(addr >= 0xff30 && addr <= 0xff3f) { - pattern[addr & 15] = data; + if(enable) { + if(!system.cgb() && !patternHold) return; + pattern[patternOffset >> 1] = data; + } else { + pattern[addr & 15] = data; + } } } @@ -105,6 +134,7 @@ auto APU::Wave::power(bool initializeLength) -> void { period = 0; patternOffset = 0; patternSample = 0; + patternHold = 0; if(initializeLength) length = 256; } @@ -123,4 +153,5 @@ auto APU::Wave::serialize(serializer& s) -> void { s.integer(period); s.integer(patternOffset); s.integer(patternSample); + s.integer(patternHold); } diff --git a/higan/gb/apu/wave/wave.hpp b/higan/gb/apu/wave/wave.hpp index 732c6cc6..5b4cd7e1 100644 --- a/higan/gb/apu/wave/wave.hpp +++ b/higan/gb/apu/wave/wave.hpp @@ -22,4 +22,5 @@ struct Wave { uint period; uint5 patternOffset; uint4 patternSample; + uint patternHold; }; diff --git a/higan/gb/cpu/cpu.cpp b/higan/gb/cpu/cpu.cpp index 3c2289d4..4cfab005 100644 --- a/higan/gb/cpu/cpu.cpp +++ b/higan/gb/cpu/cpu.cpp @@ -117,7 +117,6 @@ auto CPU::power() -> void { bus.mmio[0xff06] = this; //TMA bus.mmio[0xff07] = this; //TAC bus.mmio[0xff0f] = this; //IF - bus.mmio[0xff46] = this; //DMA bus.mmio[0xffff] = this; //IE if(system.cgb()) { @@ -199,10 +198,6 @@ auto CPU::power() -> void { status.interrupt_enable_timer = 0; status.interrupt_enable_stat = 0; status.interrupt_enable_vblank = 0; - - oamdma.active = false; - oamdma.clock = 0; - oamdma.bank = 0; } } diff --git a/higan/gb/cpu/cpu.hpp b/higan/gb/cpu/cpu.hpp index 02fdd800..50ed05c1 100644 --- a/higan/gb/cpu/cpu.hpp +++ b/higan/gb/cpu/cpu.hpp @@ -107,12 +107,6 @@ struct CPU : Processor::LR35902, Thread, MMIO { bool interrupt_enable_vblank; } status; - struct OAMDMA { - bool active; - uint clock; - uint8 bank; - } oamdma; - uint8 wram[32768]; //GB=8192, GBC=32768 uint8 hram[128]; }; diff --git a/higan/gb/cpu/memory.cpp b/higan/gb/cpu/memory.cpp index 6b743415..642876a0 100644 --- a/higan/gb/cpu/memory.cpp +++ b/higan/gb/cpu/memory.cpp @@ -6,16 +6,12 @@ auto CPU::op_io() -> void { auto CPU::op_read(uint16 addr) -> uint8 { cycle_edge(); add_clocks(4); - //OAM is inaccessible during OAMDMA transfer - if(oamdma.active && oamdma.clock >= 8 && addr >= 0xfe00 && addr <= 0xfe9f) return 0xff; return bus.read(addr); } auto CPU::op_write(uint16 addr, uint8 data) -> void { cycle_edge(); add_clocks(4); - //OAM is inaccessible during OAMDMA transfer - if(oamdma.active && oamdma.clock >= 8 && addr >= 0xfe00 && addr <= 0xfe9f) return; bus.write(addr, data); } diff --git a/higan/gb/cpu/mmio.cpp b/higan/gb/cpu/mmio.cpp index 104e169e..f5cdb6d9 100644 --- a/higan/gb/cpu/mmio.cpp +++ b/higan/gb/cpu/mmio.cpp @@ -186,13 +186,6 @@ auto CPU::mmio_write(uint16 addr, uint8 data) -> void { return; } - if(addr == 0xff46) { //DMA - oamdma.active = true; - oamdma.clock = 0; - oamdma.bank = data; - return; - } - if(addr == 0xff4d) { //KEY1 status.speed_switch = data & 0x01; return; diff --git a/higan/gb/cpu/serialization.cpp b/higan/gb/cpu/serialization.cpp index bc13028d..33ecf448 100644 --- a/higan/gb/cpu/serialization.cpp +++ b/higan/gb/cpu/serialization.cpp @@ -53,8 +53,4 @@ auto CPU::serialize(serializer& s) -> void { s.integer(status.interrupt_enable_timer); s.integer(status.interrupt_enable_stat); s.integer(status.interrupt_enable_vblank); - - s.integer(oamdma.active); - s.integer(oamdma.clock); - s.integer(oamdma.bank); } diff --git a/higan/gb/cpu/timing.cpp b/higan/gb/cpu/timing.cpp index 6af540d4..2f71ba26 100644 --- a/higan/gb/cpu/timing.cpp +++ b/higan/gb/cpu/timing.cpp @@ -6,21 +6,6 @@ auto CPU::add_clocks(uint clocks) -> void { if(system.sgb()) system.clocks_executed += clocks; while(clocks--) { - if(oamdma.active) { - uint offset = oamdma.clock++; - if((offset & 3) == 0) { - offset >>= 2; - if(offset == 0) { - //warm-up - } else if(offset == 161) { - //cool-down; disable - oamdma.active = false; - } else { - bus.write(0xfe00 + offset - 1, bus.read((oamdma.bank << 8) + offset - 1)); - } - } - } - if(++status.clock == 0) { cartridge.mbc3.second(); } diff --git a/higan/gb/ppu/mmio.cpp b/higan/gb/ppu/mmio.cpp index e6af4bf9..67567513 100644 --- a/higan/gb/ppu/mmio.cpp +++ b/higan/gb/ppu/mmio.cpp @@ -3,8 +3,14 @@ auto PPU::vram_addr(uint16 addr) const -> uint { } auto PPU::mmio_read(uint16 addr) -> uint8 { - if(addr >= 0x8000 && addr <= 0x9fff) return vram[vram_addr(addr)]; - if(addr >= 0xfe00 && addr <= 0xfe9f) return oam[addr & 0xff]; + if(addr >= 0x8000 && addr <= 0x9fff) { + return vram[vram_addr(addr)]; + } + + if(addr >= 0xfe00 && addr <= 0xfe9f) { + if(status.dma_active && status.dma_clock >= 8) return 0xff; + return oam[addr & 0xff]; + } if(addr == 0xff40) { //LCDC return (status.display_enable << 7) @@ -101,8 +107,16 @@ auto PPU::mmio_read(uint16 addr) -> uint8 { } auto PPU::mmio_write(uint16 addr, uint8 data) -> void { - if(addr >= 0x8000 && addr <= 0x9fff) { vram[vram_addr(addr)] = data; return; } - if(addr >= 0xfe00 && addr <= 0xfe9f) { oam[addr & 0xff] = data; return; } + if(addr >= 0x8000 && addr <= 0x9fff) { + vram[vram_addr(addr)] = data; + return; + } + + if(addr >= 0xfe00 && addr <= 0xfe9f) { + if(status.dma_active && status.dma_clock >= 8) return; + oam[addr & 0xff] = data; + return; + } if(addr == 0xff40) { //LCDC if(status.display_enable == false && (data & 0x80)) { @@ -154,6 +168,13 @@ auto PPU::mmio_write(uint16 addr, uint8 data) -> void { return; } + if(addr == 0xff46) { //DMA + status.dma_active = true; + status.dma_clock = 0; + status.dma_bank = data; + return; + } + if(addr == 0xff47) { //BGP bgp[3] = (data >> 6) & 3; bgp[2] = (data >> 4) & 3; diff --git a/higan/gb/ppu/ppu.cpp b/higan/gb/ppu/ppu.cpp index a097c754..34d3d95e 100644 --- a/higan/gb/ppu/ppu.cpp +++ b/higan/gb/ppu/ppu.cpp @@ -72,6 +72,22 @@ auto PPU::main() -> void { auto PPU::add_clocks(uint clocks) -> void { while(clocks--) { + if(status.dma_active) { + uint hi = status.dma_clock++; + uint lo = hi & (cpu.status.speed_double ? 1 : 3); + hi >>= cpu.status.speed_double ? 1 : 2; + if(lo == 0) { + if(hi == 0) { + //warm-up + } else if(hi == 161) { + //cool-down; disable + status.dma_active = false; + } else { + oam[hi - 1] = bus.read(status.dma_bank << 8 | hi - 1); + } + } + } + status.lx++; clock += cpu.frequency; if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) { @@ -107,6 +123,7 @@ auto PPU::power() -> void { bus.mmio[0xff43] = this; //SCX bus.mmio[0xff44] = this; //LY bus.mmio[0xff45] = this; //LYC + bus.mmio[0xff46] = this; //DMA bus.mmio[0xff47] = this; //BGP bus.mmio[0xff48] = this; //OBP0 bus.mmio[0xff49] = this; //OBP1 @@ -149,6 +166,11 @@ auto PPU::power() -> void { status.scx = 0; status.ly = 0; status.lyc = 0; + + status.dma_active = false; + status.dma_clock = 0; + status.dma_bank = 0; + status.wy = 0; status.wx = 0; diff --git a/higan/gb/ppu/ppu.hpp b/higan/gb/ppu/ppu.hpp index 7ffa8326..2736f319 100644 --- a/higan/gb/ppu/ppu.hpp +++ b/higan/gb/ppu/ppu.hpp @@ -71,6 +71,11 @@ struct PPU : Thread, MMIO { //$ff45 LYC uint8 lyc; + //$ff46 DMA + bool dma_active; + uint dma_clock; + uint8 dma_bank; + //$ff4a WY uint8 wy; diff --git a/higan/gb/ppu/serialization.cpp b/higan/gb/ppu/serialization.cpp index 8ce748fc..6c97ba77 100644 --- a/higan/gb/ppu/serialization.cpp +++ b/higan/gb/ppu/serialization.cpp @@ -31,6 +31,10 @@ auto PPU::serialize(serializer& s) -> void { s.integer(status.ly); s.integer(status.lyc); + s.integer(status.dma_active); + s.integer(status.dma_clock); + s.integer(status.dma_bank); + s.integer(status.wy); s.integer(status.wx); diff --git a/higan/target-tomoko/configuration/configuration.cpp b/higan/target-tomoko/configuration/configuration.cpp index 13c1466d..ce95d1b4 100644 --- a/higan/target-tomoko/configuration/configuration.cpp +++ b/higan/target-tomoko/configuration/configuration.cpp @@ -18,11 +18,10 @@ Settings::Settings() { set("Video/Synchronize", false); set("Video/Scale", "Small"); set("Video/AspectCorrection", true); - set("Video/Filter", "Blur"); - set("Video/Shader", "None"); + set("Video/Shader", "Blur"); set("Video/BlurEmulation", true); set("Video/ColorEmulation", true); - set("Video/ScanlineEmulation", true); + set("Video/ScanlineEmulation", false); set("Video/Saturation", 100); set("Video/Gamma", 100); set("Video/Luminance", 100); diff --git a/higan/target-tomoko/presentation/presentation.cpp b/higan/target-tomoko/presentation/presentation.cpp index e7a51123..3d86da90 100644 --- a/higan/target-tomoko/presentation/presentation.cpp +++ b/higan/target-tomoko/presentation/presentation.cpp @@ -80,8 +80,6 @@ Presentation::Presentation() { settings["Video/Overscan/Mask"].setValue(maskOverscan.checked()); }); videoShaderMenu.setText("Video Shader"); - if(settings["Video/Shader"].text() == "None") videoShaderNone.setChecked(); - if(settings["Video/Shader"].text() == "Blur") videoShaderBlur.setChecked(); videoShaderNone.setText("None").onActivate([&] { settings["Video/Shader"].setValue("None"); program->updateVideoShader(); @@ -277,20 +275,22 @@ auto Presentation::drawSplashScreen() -> void { } auto Presentation::loadShaders() -> void { - if(settings["Video/Driver"].text() != "OpenGL") { - return; + auto pathname = locate({localpath(), "higan/"}, "Video Shaders/"); + + if(settings["Video/Driver"].text() == "OpenGL") { + for(auto shader : directory::folders(pathname, "*.shader")) { + if(videoShaders.objectCount() == 2) videoShaderMenu.append(MenuSeparator()); + MenuRadioItem item{&videoShaderMenu}; + item.setText(string{shader}.rtrim(".shader/", 1L)).onActivate([=] { + settings["Video/Shader"].setValue({pathname, shader}); + program->updateVideoShader(); + }); + videoShaders.append(item); + } } - auto pathname = locate({localpath(), "higan/"}, "Video Shaders/"); - for(auto shader : directory::folders(pathname, "*.shader")) { - if(videoShaders.objectCount() == 2) videoShaderMenu.append(MenuSeparator()); - MenuRadioItem item{&videoShaderMenu}; - item.setText(string{shader}.rtrim(".shader/", 1L)).onActivate([=] { - settings["Video/Shader"].setValue({pathname, shader}); - program->updateVideoShader(); - }); - videoShaders.append(item); - } + if(settings["Video/Shader"].text() == "None") videoShaderNone.setChecked(); + if(settings["Video/Shader"].text() == "Blur") videoShaderBlur.setChecked(); for(auto radioItem : videoShaders.objects()) { if(settings["Video/Shader"].text() == string{pathname, radioItem.text(), ".shader/"}) { diff --git a/hiro/cocoa/widget/text-edit.cpp b/hiro/cocoa/widget/text-edit.cpp index 8be57b00..3b18ed56 100644 --- a/hiro/cocoa/widget/text-edit.cpp +++ b/hiro/cocoa/widget/text-edit.cpp @@ -84,7 +84,7 @@ auto pTextEdit::setEditable(bool editable) -> void { auto pTextEdit::setEnabled(bool enabled) -> void { pWidget::setEnabled(enabled); - setEditable(self().editable); //Cocoa lacks NSTextView::setEnabled; simulate via setEnabled() + setEditable(state().editable); //Cocoa lacks NSTextView::setEnabled; simulate via setEnabled() } auto pTextEdit::setFont(const Font& font) -> void { diff --git a/icarus/icarus.cpp b/icarus/icarus.cpp index 2da0855f..ffd9abe9 100644 --- a/icarus/icarus.cpp +++ b/icarus/icarus.cpp @@ -86,7 +86,7 @@ auto nall::main(lstring args) -> void { Application::Cocoa::onPreferences([&] { scanDialog->settingsButton.doActivate(); }); - Application::Cocoa::onQuit({ + Application::Cocoa::onQuit([&] { Application::quit(); }); #endif