Mesen-X/Core/EPSGAudio.h

167 lines
3.3 KiB
C
Raw Normal View History

#pragma once
#include "stdafx.h"
#include "Snapshotable.h"
#include "APU.h"
#include "BaseExpansionAudio.h"
#include "SSGAudio.h"
#include "Console.h"
#include <array>
#include "ym3438.h"
using EPSGSSGAudio = SSGAudio<AudioChannel::EPSG_L, AudioChannel::EPSG_R>;
class EPSGAudio : public EPSGSSGAudio
{
private:
ym3438_t _chip;
int16_t _lastOutputs[2];
int16_t _currentOutputs[2];
double _clock;
static constexpr uint8_t cycleCount = 24;
struct InputEntry
{
uint8_t addr = 0;
uint8_t data = 0;
uint8_t cycle = 0;
uint8_t wrote = 0;
};
static constexpr uint8_t INPUT_BUFFER_SIZE = cycleCount;
using InputBuffer = std::array<InputEntry, INPUT_BUFFER_SIZE>;
InputBuffer _inputBuffer;
void UpdateOutputLevel()
{
int16_t summedOutput = 0;
for (size_t x = 0; x < 2; x++)
{
_console->GetApu()->AddExpansionAudioDelta(x == 0 ? AudioChannel::EPSG_L : AudioChannel::EPSG_R, _currentOutputs[x] - _lastOutputs[x]);
_lastOutputs[x] = _currentOutputs[x];
}
}
uint8_t GetCurrentCycle() const
{
return static_cast<uint8_t>(std::floor(_clock)) % cycleCount;
}
void WriteToChip(uint8_t a, uint8_t d)
{
const auto cycle = GetCurrentCycle();
if (_inputBuffer[cycle].wrote)
{
std::cout << "EPSG CHIP DOUBLE WRITE" << std::endl;
}
_inputBuffer[cycle] = {
a,
d,
cycle,
true
};
}
uint32_t getClockFrequency()
{
return _console->GetSettings()->GetEPSGClockFrequency() / 6;
}
protected:
void StreamState(bool saving) override
{
EPSGSSGAudio::StreamState(saving);
ArrayInfo<int16_t> lastOutputs{ _lastOutputs, 2 };
ArrayInfo<int16_t> currentOutputs{ _currentOutputs, 2 };
ArrayInfo<InputBuffer> inputBuffer{ &_inputBuffer };
ValueInfo<ym3438_t> chip{ &_chip };
ValueInfo<double> clock { &_clock };
Stream(lastOutputs, currentOutputs, inputBuffer, chip, clock);
}
void ClockAudio() override
{
EPSGSSGAudio::ClockAudio();
_clock += getClockFrequency() / (double)_console->GetCpu()->GetClockRate(_console->GetModel());
while (_clock >= cycleCount)
{
for (uint8_t x = 0; x < 2; x++)
{
_currentOutputs[x] = 0;
}
for (uint8_t cycle = 0; cycle < cycleCount; cycle++)
{
_clock--;
int16_t samples[2];
OPN2_Clock(&_chip, samples);
for (uint8_t x = 0; x < 2; x++)
{
_currentOutputs[x] += samples[x];
}
auto& input = _inputBuffer[cycle];
if(input.wrote)
{
input.wrote = false;
OPN2_Write(&_chip, input.addr, input.data);
}
}
for (uint8_t x = 0; x < 2; x++)
{
_currentOutputs[x] /= 12;
}
UpdateOutputLevel();
}
}
virtual uint32_t GetSSGClockFrequency()
{
return EPSGSSGAudio::GetSSGClockFrequency() * (_console->GetSettings()->GetEPSGClockFrequency() / 3579545.0 );
}
public:
EPSGAudio(shared_ptr<Console> console) : EPSGSSGAudio(console)
{
memset(_lastOutputs, 0, sizeof(_lastOutputs));
memset(_currentOutputs, 0, sizeof(_currentOutputs));
_inputBuffer = {};
_clock = 0;
OPN2_Reset(&_chip);
OPN2_SetChipType(0);
}
void WriteRegister(uint16_t addr, uint8_t value)
{
EPSGSSGAudio::WriteRegister(addr, value);
switch(addr) {
case 0xC000:
case 0xE000:
case 0xC002:
case 0xE002:
const uint8_t a0 = (addr & 0xF000) == 0xE000;
const uint8_t a1 = !!(addr & 0xF);
WriteToChip(a0 | (a1 << 1), value);
break;
}
}
};