#pragma once #include "stdafx.h" #include "APU.h" #include "CPU.h" #include "Nes_Apu\apu_snapshot.h" APU* APU::Instance = nullptr; IAudioDevice* APU::AudioDevice = nullptr; APU::APU(MemoryManager* memoryManager) { APU::Instance = this; _memoryManager = memoryManager; _buf.sample_rate(APU::SampleRate); _buf.clock_rate(CPU::ClockRate); _apu.output(&_buf); _apu.dmc_reader(&APU::DMCRead); //_apu.irq_notifier(&APU::IRQChanged); _outputBuffer = new int16_t[APU::SamplesPerFrame]; } APU::~APU() { delete[] _outputBuffer; } void APU::Reset() { _apu.reset(); } int APU::DMCRead(void*, cpu_addr_t addr) { return APU::Instance->_memoryManager->Read(addr); } uint8_t APU::ReadRAM(uint16_t addr) { switch(addr) { case 0x4015: CPU::ClearIRQSource(IRQSource::FrameCounter); return _apu.read_status(_currentClock + 4); } return 0; } void APU::WriteRAM(uint16_t addr, uint8_t value) { _apu.write_register(_currentClock + 4, addr, value); if(addr == 0x4017 && (value & 0x40) == 0x40) { //Disable frame interrupts CPU::ClearIRQSource(IRQSource::FrameCounter); } } bool APU::Exec(uint32_t currentCPUCycle) { _currentClock = currentCPUCycle; if(_currentClock >= 29780) { _apu.end_frame(_currentClock); _buf.end_frame(_currentClock); _currentClock = 0; if(APU::Instance->_apu.earliest_irq() == Nes_Apu::irq_waiting) { CPU::SetIRQSource(IRQSource::FrameCounter); } // Read some samples out of Blip_Buffer if there are enough to fill our output buffer uint32_t availableSampleCount = _buf.samples_avail(); if(availableSampleCount >= APU::SamplesPerFrame) { size_t sampleCount = _buf.read_samples(_outputBuffer, APU::SamplesPerFrame); if(APU::AudioDevice) { APU::AudioDevice->PlayBuffer(_outputBuffer, sampleCount * BitsPerSample / 8); } } return true; } return false; } void APU::StopAudio() { if(APU::AudioDevice) { APU::AudioDevice->Pause(); } } void APU::StreamState(bool saving) { apu_snapshot_t snapshot; if(saving) { _apu.save_snapshot(&snapshot); } Stream(_currentClock); StreamArray(snapshot.w40xx, 0x14); Stream(snapshot.w4015); Stream(snapshot.w4017); Stream(snapshot.delay); Stream(snapshot.step); Stream(snapshot.irq_flag); Stream(snapshot.square1.delay); StreamArray(snapshot.square1.env, 3); Stream(snapshot.square1.length); Stream(snapshot.square1.phase); Stream(snapshot.square1.swp_delay); Stream(snapshot.square1.swp_reset); StreamArray(snapshot.square1.unused, 1); Stream(snapshot.square2.delay); StreamArray(snapshot.square2.env, 3); Stream(snapshot.square2.length); Stream(snapshot.square2.phase); Stream(snapshot.square2.swp_delay); Stream(snapshot.square2.swp_reset); StreamArray(snapshot.square2.unused, 1); Stream(snapshot.triangle.delay); Stream(snapshot.triangle.length); Stream(snapshot.triangle.phase); Stream(snapshot.triangle.linear_counter); Stream(snapshot.triangle.linear_mode); Stream(snapshot.noise.delay); StreamArray(snapshot.noise.env, 3); Stream(snapshot.noise.length); Stream(snapshot.noise.shift_reg); Stream(snapshot.dmc.delay); Stream(snapshot.dmc.remain); Stream(snapshot.dmc.addr); Stream(snapshot.dmc.buf); Stream(snapshot.dmc.bits_remain); Stream(snapshot.dmc.bits); Stream(snapshot.dmc.buf_empty); Stream(snapshot.dmc.silence); Stream(snapshot.dmc.irq_flag); if(!saving) { _apu.load_snapshot(snapshot); } }