f3df2ecf17
-Optimizations + PGO (profile guided optimization) build support
152 lines
No EOL
3.7 KiB
C++
152 lines
No EOL
3.7 KiB
C++
#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<uint32_t>(_currentClock);
|
|
|
|
StreamArray<uint8_t>(snapshot.w40xx, 0x14);
|
|
Stream<uint8_t>(snapshot.w4015);
|
|
Stream<uint8_t>(snapshot.w4017);
|
|
Stream<uint16_t>(snapshot.delay);
|
|
Stream<uint8_t>(snapshot.step);
|
|
Stream<uint8_t>(snapshot.irq_flag);
|
|
|
|
Stream<uint16_t>(snapshot.square1.delay);
|
|
StreamArray<uint8_t>(snapshot.square1.env, 3);
|
|
Stream<uint8_t>(snapshot.square1.length);
|
|
Stream<uint8_t>(snapshot.square1.phase);
|
|
Stream<uint8_t>(snapshot.square1.swp_delay);
|
|
Stream<uint8_t>(snapshot.square1.swp_reset);
|
|
StreamArray<uint8_t>(snapshot.square1.unused, 1);
|
|
|
|
Stream<uint16_t>(snapshot.square2.delay);
|
|
StreamArray<uint8_t>(snapshot.square2.env, 3);
|
|
Stream<uint8_t>(snapshot.square2.length);
|
|
Stream<uint8_t>(snapshot.square2.phase);
|
|
Stream<uint8_t>(snapshot.square2.swp_delay);
|
|
Stream<uint8_t>(snapshot.square2.swp_reset);
|
|
StreamArray<uint8_t>(snapshot.square2.unused, 1);
|
|
|
|
Stream<uint16_t>(snapshot.triangle.delay);
|
|
Stream<uint8_t>(snapshot.triangle.length);
|
|
Stream<uint8_t>(snapshot.triangle.phase);
|
|
Stream<uint8_t>(snapshot.triangle.linear_counter);
|
|
Stream<uint8_t>(snapshot.triangle.linear_mode);
|
|
|
|
Stream<uint16_t>(snapshot.noise.delay);
|
|
StreamArray<uint8_t>(snapshot.noise.env, 3);
|
|
Stream<uint8_t>(snapshot.noise.length);
|
|
Stream<uint16_t>(snapshot.noise.shift_reg);
|
|
|
|
Stream<uint16_t>(snapshot.dmc.delay);
|
|
Stream<uint16_t>(snapshot.dmc.remain);
|
|
Stream<uint16_t>(snapshot.dmc.addr);
|
|
Stream<uint8_t>(snapshot.dmc.buf);
|
|
Stream<uint8_t>(snapshot.dmc.bits_remain);
|
|
Stream<uint8_t>(snapshot.dmc.bits);
|
|
Stream<uint8_t>(snapshot.dmc.buf_empty);
|
|
Stream<uint8_t>(snapshot.dmc.silence);
|
|
Stream<uint8_t>(snapshot.dmc.irq_flag);
|
|
|
|
if(!saving) {
|
|
_apu.load_snapshot(snapshot);
|
|
}
|
|
} |