Merge pull request #20 from Perkka2/master
Adding basic EPSG support, Replacing old VRC7 with Nuked-OPLL
This commit is contained in:
commit
d7d919a392
33 changed files with 6139 additions and 2051 deletions
|
@ -13,6 +13,7 @@
|
||||||
#include "EmulationSettings.h"
|
#include "EmulationSettings.h"
|
||||||
|
|
||||||
void BaseMapper::WriteRegister(uint16_t addr, uint8_t value) { }
|
void BaseMapper::WriteRegister(uint16_t addr, uint8_t value) { }
|
||||||
|
void BaseMapper::WriteEPSG(uint16_t addr, uint8_t value) { _epsgaudio->WriteRegister(addr, value); }
|
||||||
uint8_t BaseMapper::ReadRegister(uint16_t addr) { return 0; }
|
uint8_t BaseMapper::ReadRegister(uint16_t addr) { return 0; }
|
||||||
void BaseMapper::InitMapper(RomData &romData) { }
|
void BaseMapper::InitMapper(RomData &romData) { }
|
||||||
void BaseMapper::Reset(bool softReset) { }
|
void BaseMapper::Reset(bool softReset) { }
|
||||||
|
@ -508,8 +509,9 @@ void BaseMapper::StreamState(bool saving)
|
||||||
ArrayInfo<ChrMemoryType> chrMemoryType = { _chrMemoryType, 0x40 };
|
ArrayInfo<ChrMemoryType> chrMemoryType = { _chrMemoryType, 0x40 };
|
||||||
ArrayInfo<MemoryAccessType> prgMemoryAccess = { _prgMemoryAccess, 0x100 };
|
ArrayInfo<MemoryAccessType> prgMemoryAccess = { _prgMemoryAccess, 0x100 };
|
||||||
ArrayInfo<MemoryAccessType> chrMemoryAccess = { _chrMemoryAccess, 0x40 };
|
ArrayInfo<MemoryAccessType> chrMemoryAccess = { _chrMemoryAccess, 0x40 };
|
||||||
|
SnapshotInfo epsgaudio{ _epsgaudio.get() };
|
||||||
|
|
||||||
Stream(_mirroringType, chrRam, workRam, saveRam, nametableRam, prgMemoryOffset, chrMemoryOffset, prgMemoryType, chrMemoryType, prgMemoryAccess, chrMemoryAccess);
|
Stream(_mirroringType, chrRam, workRam, saveRam, nametableRam, prgMemoryOffset, chrMemoryOffset, prgMemoryType, chrMemoryType, prgMemoryAccess, chrMemoryAccess, epsgaudio);
|
||||||
|
|
||||||
if(!saving) {
|
if(!saving) {
|
||||||
RestorePrgChrState();
|
RestorePrgChrState();
|
||||||
|
@ -636,6 +638,7 @@ void BaseMapper::Initialize(RomData &romData)
|
||||||
|
|
||||||
InitMapper();
|
InitMapper();
|
||||||
InitMapper(romData);
|
InitMapper(romData);
|
||||||
|
_epsgaudio.reset(new EPSGAudio(_console));
|
||||||
|
|
||||||
//Load battery data if present
|
//Load battery data if present
|
||||||
LoadBattery();
|
LoadBattery();
|
||||||
|
@ -778,6 +781,7 @@ uint8_t BaseMapper::DebugReadRAM(uint16_t addr)
|
||||||
|
|
||||||
void BaseMapper::WriteRAM(uint16_t addr, uint8_t value)
|
void BaseMapper::WriteRAM(uint16_t addr, uint8_t value)
|
||||||
{
|
{
|
||||||
|
if(addr == 0x4016){ WriteEPSG(addr, value); }
|
||||||
if(_isWriteRegisterAddr[addr]) {
|
if(_isWriteRegisterAddr[addr]) {
|
||||||
if(_hasBusConflicts) {
|
if(_hasBusConflicts) {
|
||||||
uint8_t prgValue = _prgPages[addr >> 8][(uint8_t)addr];
|
uint8_t prgValue = _prgPages[addr >> 8][(uint8_t)addr];
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include "IBattery.h"
|
#include "IBattery.h"
|
||||||
#include "RomData.h"
|
#include "RomData.h"
|
||||||
#include "Console.h"
|
#include "Console.h"
|
||||||
|
#include "CPU.h"
|
||||||
|
#include "EPSGAudio.h"
|
||||||
|
|
||||||
class BaseControlDevice;
|
class BaseControlDevice;
|
||||||
|
|
||||||
|
@ -104,6 +106,7 @@ protected:
|
||||||
uint8_t InternalReadRam(uint16_t addr);
|
uint8_t InternalReadRam(uint16_t addr);
|
||||||
|
|
||||||
virtual void WriteRegister(uint16_t addr, uint8_t value);
|
virtual void WriteRegister(uint16_t addr, uint8_t value);
|
||||||
|
virtual void WriteEPSG(uint16_t addr, uint8_t value);
|
||||||
virtual uint8_t ReadRegister(uint16_t addr);
|
virtual uint8_t ReadRegister(uint16_t addr);
|
||||||
|
|
||||||
void SelectPrgPage4x(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom);
|
void SelectPrgPage4x(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom);
|
||||||
|
@ -155,7 +158,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
static constexpr uint32_t NametableCount = 0x10;
|
static constexpr uint32_t NametableCount = 0x10;
|
||||||
static constexpr uint32_t NametableSize = 0x400;
|
static constexpr uint32_t NametableSize = 0x400;
|
||||||
|
unique_ptr<EPSGAudio> _epsgaudio;
|
||||||
void Initialize(RomData &romData);
|
void Initialize(RomData &romData);
|
||||||
|
|
||||||
virtual ~BaseMapper();
|
virtual ~BaseMapper();
|
||||||
|
@ -165,6 +168,7 @@ public:
|
||||||
|
|
||||||
virtual void SetNesModel(NesModel model) { }
|
virtual void SetNesModel(NesModel model) { }
|
||||||
virtual void ProcessCpuClock() { }
|
virtual void ProcessCpuClock() { }
|
||||||
|
virtual void ProcessEPSGClock() { _epsgaudio->Clock(); }
|
||||||
virtual void NotifyVRAMAddressChange(uint16_t addr);
|
virtual void NotifyVRAMAddressChange(uint16_t addr);
|
||||||
virtual void GetMemoryRanges(MemoryRanges &ranges) override;
|
virtual void GetMemoryRanges(MemoryRanges &ranges) override;
|
||||||
|
|
||||||
|
|
|
@ -465,6 +465,7 @@ bool Console::Initialize(VirtualFile &romFile, VirtualFile &patchFile, bool forP
|
||||||
|
|
||||||
void Console::ProcessCpuClock()
|
void Console::ProcessCpuClock()
|
||||||
{
|
{
|
||||||
|
_mapper->ProcessEPSGClock();
|
||||||
_mapper->ProcessCpuClock();
|
_mapper->ProcessCpuClock();
|
||||||
_apu->ProcessCpuClock();
|
_apu->ProcessCpuClock();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
<ProjectConfiguration Include="Debug|Win32">
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
@ -558,6 +558,8 @@
|
||||||
<ClInclude Include="DummyCpu.h" />
|
<ClInclude Include="DummyCpu.h" />
|
||||||
<ClInclude Include="Eeprom24C01.h" />
|
<ClInclude Include="Eeprom24C01.h" />
|
||||||
<ClInclude Include="Eeprom24C02.h" />
|
<ClInclude Include="Eeprom24C02.h" />
|
||||||
|
<ClInclude Include="emu2149.h" />
|
||||||
|
<ClInclude Include="EPSGAudio.h" />
|
||||||
<ClInclude Include="EventManager.h" />
|
<ClInclude Include="EventManager.h" />
|
||||||
<ClInclude Include="FaridSlrom.h" />
|
<ClInclude Include="FaridSlrom.h" />
|
||||||
<ClInclude Include="FaridUnrom.h" />
|
<ClInclude Include="FaridUnrom.h" />
|
||||||
|
@ -586,12 +588,14 @@
|
||||||
<ClInclude Include="NESHeader.h" />
|
<ClInclude Include="NESHeader.h" />
|
||||||
<ClInclude Include="NotificationManager.h" />
|
<ClInclude Include="NotificationManager.h" />
|
||||||
<ClInclude Include="OpenBusHandler.h" />
|
<ClInclude Include="OpenBusHandler.h" />
|
||||||
|
<ClInclude Include="opll.h" />
|
||||||
<ClInclude Include="PerformanceTracker.h" />
|
<ClInclude Include="PerformanceTracker.h" />
|
||||||
<ClInclude Include="RawVideoFilter.h" />
|
<ClInclude Include="RawVideoFilter.h" />
|
||||||
<ClInclude Include="ResetTxrom.h" />
|
<ClInclude Include="ResetTxrom.h" />
|
||||||
<ClInclude Include="Sachen9602.h" />
|
<ClInclude Include="Sachen9602.h" />
|
||||||
<ClInclude Include="ServerInformationMessage.h" />
|
<ClInclude Include="ServerInformationMessage.h" />
|
||||||
<ClInclude Include="FamicomBox.h" />
|
<ClInclude Include="FamicomBox.h" />
|
||||||
|
<ClInclude Include="SSGAudio.h" />
|
||||||
<ClInclude Include="StereoCombFilter.h" />
|
<ClInclude Include="StereoCombFilter.h" />
|
||||||
<ClInclude Include="StudyBoxLoader.h" />
|
<ClInclude Include="StudyBoxLoader.h" />
|
||||||
<ClInclude Include="SystemActionManager.h" />
|
<ClInclude Include="SystemActionManager.h" />
|
||||||
|
@ -982,6 +986,7 @@
|
||||||
<ClInclude Include="Waixing178.h" />
|
<ClInclude Include="Waixing178.h" />
|
||||||
<ClInclude Include="Waixing252.h" />
|
<ClInclude Include="Waixing252.h" />
|
||||||
<ClInclude Include="WaveRecorder.h" />
|
<ClInclude Include="WaveRecorder.h" />
|
||||||
|
<ClInclude Include="ym3438.h" />
|
||||||
<ClInclude Include="Yoko.h" />
|
<ClInclude Include="Yoko.h" />
|
||||||
<ClInclude Include="Zapper.h" />
|
<ClInclude Include="Zapper.h" />
|
||||||
<ClInclude Include="PgoUtilities.h" />
|
<ClInclude Include="PgoUtilities.h" />
|
||||||
|
@ -996,6 +1001,7 @@
|
||||||
<ClCompile Include="BatteryManager.cpp" />
|
<ClCompile Include="BatteryManager.cpp" />
|
||||||
<ClCompile Include="DebugHud.cpp" />
|
<ClCompile Include="DebugHud.cpp" />
|
||||||
<ClCompile Include="DrawRectangleCommand.h" />
|
<ClCompile Include="DrawRectangleCommand.h" />
|
||||||
|
<ClCompile Include="emu2149.cpp" />
|
||||||
<ClCompile Include="EventManager.cpp" />
|
<ClCompile Include="EventManager.cpp" />
|
||||||
<ClCompile Include="FceuxMovie.cpp" />
|
<ClCompile Include="FceuxMovie.cpp" />
|
||||||
<ClCompile Include="FdsLoader.cpp" />
|
<ClCompile Include="FdsLoader.cpp" />
|
||||||
|
@ -1016,6 +1022,7 @@
|
||||||
<ClCompile Include="NsfPpu.cpp" />
|
<ClCompile Include="NsfPpu.cpp" />
|
||||||
<ClCompile Include="OggMixer.cpp" />
|
<ClCompile Include="OggMixer.cpp" />
|
||||||
<ClCompile Include="OggReader.cpp" />
|
<ClCompile Include="OggReader.cpp" />
|
||||||
|
<ClCompile Include="opll.cpp" />
|
||||||
<ClCompile Include="PerformanceTracker.cpp" />
|
<ClCompile Include="PerformanceTracker.cpp" />
|
||||||
<ClCompile Include="PgoUtilities.cpp" />
|
<ClCompile Include="PgoUtilities.cpp" />
|
||||||
<ClCompile Include="RawVideoFilter.cpp" />
|
<ClCompile Include="RawVideoFilter.cpp" />
|
||||||
|
@ -1098,6 +1105,7 @@
|
||||||
<ClCompile Include="VsControlManager.cpp" />
|
<ClCompile Include="VsControlManager.cpp" />
|
||||||
<ClCompile Include="ScaleFilter.cpp" />
|
<ClCompile Include="ScaleFilter.cpp" />
|
||||||
<ClCompile Include="WaveRecorder.cpp" />
|
<ClCompile Include="WaveRecorder.cpp" />
|
||||||
|
<ClCompile Include="ym3438.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="Debugger">
|
<Filter Include="Debugger">
|
||||||
|
@ -116,6 +116,9 @@
|
||||||
<Filter Include="Nes\MemoryManager">
|
<Filter Include="Nes\MemoryManager">
|
||||||
<UniqueIdentifier>{13af8497-e820-43f1-9888-85797a29b551}</UniqueIdentifier>
|
<UniqueIdentifier>{13af8497-e820-43f1-9888-85797a29b551}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="Nes\Mappers\EPSG">
|
||||||
|
<UniqueIdentifier>{c9c48ea8-7684-4959-9266-c0b4f0f86956}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="IAudioDevice.h">
|
<ClInclude Include="IAudioDevice.h">
|
||||||
|
@ -1502,6 +1505,21 @@
|
||||||
<ClInclude Include="VbController.h">
|
<ClInclude Include="VbController.h">
|
||||||
<Filter>Nes\Input\Controllers</Filter>
|
<Filter>Nes\Input\Controllers</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="ym3438.h">
|
||||||
|
<Filter>Nes\Mappers\EPSG</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="EPSGAudio.h">
|
||||||
|
<Filter>Nes\Mappers\EPSG</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="SSGAudio.h">
|
||||||
|
<Filter>Nes\Mappers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="opll.h">
|
||||||
|
<Filter>Nes\Mappers\VRC</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="emu2149.h">
|
||||||
|
<Filter>Nes\Mappers\EPSG</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="stdafx.cpp">
|
<ClCompile Include="stdafx.cpp">
|
||||||
|
@ -1804,5 +1822,14 @@
|
||||||
<ClCompile Include="StudyBoxLoader.cpp">
|
<ClCompile Include="StudyBoxLoader.cpp">
|
||||||
<Filter>Misc</Filter>
|
<Filter>Misc</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="ym3438.cpp">
|
||||||
|
<Filter>Nes\Mappers\EPSG</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="opll.cpp">
|
||||||
|
<Filter>Nes\Mappers\VRC</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="emu2149.cpp">
|
||||||
|
<Filter>Nes\Mappers\EPSG</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
195
Core/EPSGAudio.h
Normal file
195
Core/EPSGAudio.h
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
#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];
|
||||||
|
uint8_t writeValue;
|
||||||
|
int16_t writeAddr;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (addr == 0x4016) {
|
||||||
|
if ((value & 0x0F) == 0x02) {
|
||||||
|
writeValue = value;
|
||||||
|
writeAddr = 0xC000;
|
||||||
|
}
|
||||||
|
if ((value & 0x0F) == 0x0A) {
|
||||||
|
writeValue = value;
|
||||||
|
writeAddr = 0xE000;
|
||||||
|
}
|
||||||
|
if ((value & 0x0F) == 0x06) {
|
||||||
|
writeValue = value;
|
||||||
|
writeAddr = 0xC002;
|
||||||
|
}
|
||||||
|
if ((value & 0x0F) == 0x0E) {
|
||||||
|
writeValue = value;
|
||||||
|
writeAddr = 0xE002;
|
||||||
|
}
|
||||||
|
if ((value & 0x0F) == 0x00) {
|
||||||
|
writeValue = (writeValue & 0xF0) | (value >> 4);
|
||||||
|
|
||||||
|
const uint8_t a04016 = (writeAddr & 0xF000) == 0xE000;
|
||||||
|
const uint8_t a14016 = !!(writeAddr & 0xF);
|
||||||
|
WriteToChip(a04016 | (a14016 << 1), writeValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -116,7 +116,9 @@ enum class AudioChannel
|
||||||
VRC6 = 7,
|
VRC6 = 7,
|
||||||
VRC7 = 8,
|
VRC7 = 8,
|
||||||
Namco163 = 9,
|
Namco163 = 9,
|
||||||
Sunsoft5B = 10
|
Sunsoft5B = 10,
|
||||||
|
EPSG_L = 11,
|
||||||
|
EPSG_R = 12,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class EqualizerFilterType
|
enum class EqualizerFilterType
|
||||||
|
@ -657,8 +659,9 @@ private:
|
||||||
|
|
||||||
bool _audioSettingsChanged = false;
|
bool _audioSettingsChanged = false;
|
||||||
uint32_t _audioLatency = 50;
|
uint32_t _audioLatency = 50;
|
||||||
double _channelVolume[11] = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
|
uint32_t _EPSGClockFrequency = 3579545;
|
||||||
double _channelPanning[11] = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
|
double _channelVolume[13] = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
|
||||||
|
double _channelPanning[13] = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 2.0 };
|
||||||
EqualizerFilterType _equalizerFilterType = EqualizerFilterType::None;
|
EqualizerFilterType _equalizerFilterType = EqualizerFilterType::None;
|
||||||
vector<double> _bandGains = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
|
vector<double> _bandGains = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
|
||||||
vector<double> _bands = { { 40,56,80,113,160,225,320,450,600,750,1000,2000,3000,4000,5000,6000,7000,10000,12500,15000 } };
|
vector<double> _bands = { { 40,56,80,113,160,225,320,450,600,750,1000,2000,3000,4000,5000,6000,7000,10000,12500,15000 } };
|
||||||
|
@ -987,6 +990,12 @@ public:
|
||||||
_audioSettingsChanged = true;
|
_audioSettingsChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetEPSGClockFrequency(uint32_t clockFrequency)
|
||||||
|
{
|
||||||
|
_EPSGClockFrequency = clockFrequency;
|
||||||
|
_audioSettingsChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
void SetAudioFilterSettings(AudioFilterSettings settings)
|
void SetAudioFilterSettings(AudioFilterSettings settings)
|
||||||
{
|
{
|
||||||
_audioFilterSettings = settings;
|
_audioFilterSettings = settings;
|
||||||
|
@ -1158,6 +1167,11 @@ public:
|
||||||
return _audioLatency;
|
return _audioLatency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t GetEPSGClockFrequency()
|
||||||
|
{
|
||||||
|
return _EPSGClockFrequency;
|
||||||
|
}
|
||||||
|
|
||||||
void SetVideoFilterType(VideoFilterType videoFilterType)
|
void SetVideoFilterType(VideoFilterType videoFilterType)
|
||||||
{
|
{
|
||||||
_videoFilterType = videoFilterType;
|
_videoFilterType = videoFilterType;
|
||||||
|
|
|
@ -6,8 +6,10 @@
|
||||||
#include "EmulationSettings.h"
|
#include "EmulationSettings.h"
|
||||||
#include "A12Watcher.h"
|
#include "A12Watcher.h"
|
||||||
|
|
||||||
|
|
||||||
class MMC3 : public BaseMapper
|
class MMC3 : public BaseMapper
|
||||||
{
|
{
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class MMC3Registers
|
enum class MMC3Registers
|
||||||
{
|
{
|
||||||
|
@ -200,6 +202,7 @@ class MMC3 : public BaseMapper
|
||||||
|
|
||||||
virtual void InitMapper() override
|
virtual void InitMapper() override
|
||||||
{
|
{
|
||||||
|
|
||||||
//Force MMC3A irqs for boards that are known to use the A revision.
|
//Force MMC3A irqs for boards that are known to use the A revision.
|
||||||
//Some MMC3B boards also have the A behavior, but currently no way to tell them apart.
|
//Some MMC3B boards also have the A behavior, but currently no way to tell them apart.
|
||||||
_forceMmc3RevAIrqs = _romInfo.DatabaseInfo.Chip.substr(0, 5).compare("MMC3A") == 0;
|
_forceMmc3RevAIrqs = _romInfo.DatabaseInfo.Chip.substr(0, 5).compare("MMC3A") == 0;
|
||||||
|
|
|
@ -133,6 +133,9 @@ void MemoryManager::Write(uint16_t addr, uint8_t value, MemoryOperationType oper
|
||||||
{
|
{
|
||||||
if(_console->DebugProcessRamOperation(operationType, addr, value)) {
|
if(_console->DebugProcessRamOperation(operationType, addr, value)) {
|
||||||
_ramWriteHandlers[addr]->WriteRAM(addr, value);
|
_ramWriteHandlers[addr]->WriteRAM(addr, value);
|
||||||
|
if (addr == 0x4016) {
|
||||||
|
_ramWriteHandlers[0xE000]->WriteRAM(addr, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,9 +87,12 @@ void NsfLoader::InitializeFromHeader(RomData &romData)
|
||||||
if(header.SoundChips & 0x10) {
|
if(header.SoundChips & 0x10) {
|
||||||
chips.push_back("Namco 163");
|
chips.push_back("Namco 163");
|
||||||
}
|
}
|
||||||
if(header.SoundChips & 0x20) {
|
if (header.SoundChips & 0x20) {
|
||||||
chips.push_back("Sunsoft 5B");
|
chips.push_back("Sunsoft 5B");
|
||||||
}
|
}
|
||||||
|
if (header.SoundChips & 0x40) {
|
||||||
|
chips.push_back("EPSG");
|
||||||
|
}
|
||||||
if(chips.empty()) {
|
if(chips.empty()) {
|
||||||
chips.push_back("<none>");
|
chips.push_back("<none>");
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ void NsfMapper::InitMapper()
|
||||||
_fdsAudio.reset(new FdsAudio(_console));
|
_fdsAudio.reset(new FdsAudio(_console));
|
||||||
_namcoAudio.reset(new Namco163Audio(_console));
|
_namcoAudio.reset(new Namco163Audio(_console));
|
||||||
_sunsoftAudio.reset(new Sunsoft5bAudio(_console));
|
_sunsoftAudio.reset(new Sunsoft5bAudio(_console));
|
||||||
|
_epsgAudio.reset(new EPSGAudio(_console));
|
||||||
|
|
||||||
SetCpuMemoryMapping(0x3F00, 0x3FFF, PrgMemoryType::WorkRam, 0x2000, MemoryAccessType::Read);
|
SetCpuMemoryMapping(0x3F00, 0x3FFF, PrgMemoryType::WorkRam, 0x2000, MemoryAccessType::Read);
|
||||||
memcpy(GetWorkRam() + 0x2000, _nsfBios, 0x100);
|
memcpy(GetWorkRam() + 0x2000, _nsfBios, 0x100);
|
||||||
|
@ -107,6 +108,10 @@ void NsfMapper::InitMapper(RomData& romData)
|
||||||
if(_nsfHeader.SoundChips & NsfSoundChips::FDS) {
|
if(_nsfHeader.SoundChips & NsfSoundChips::FDS) {
|
||||||
AddRegisterRange(0x4040, 0x4092, MemoryOperation::Any);
|
AddRegisterRange(0x4040, 0x4092, MemoryOperation::Any);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(_nsfHeader.SoundChips & NsfSoundChips::EPSG) {
|
||||||
|
AddRegisterRange(0x4016, 0x4016, MemoryOperation::Write);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NsfMapper::Reset(bool softReset)
|
void NsfMapper::Reset(bool softReset)
|
||||||
|
@ -272,6 +277,9 @@ void NsfMapper::ProcessCpuClock()
|
||||||
if(_nsfHeader.SoundChips & NsfSoundChips::FDS) {
|
if(_nsfHeader.SoundChips & NsfSoundChips::FDS) {
|
||||||
_fdsAudio->Clock();
|
_fdsAudio->Clock();
|
||||||
}
|
}
|
||||||
|
if (_nsfHeader.SoundChips & NsfSoundChips::EPSG) {
|
||||||
|
_epsgAudio->Clock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t NsfMapper::ReadRegister(uint16_t addr)
|
uint8_t NsfMapper::ReadRegister(uint16_t addr)
|
||||||
|
@ -397,7 +405,11 @@ void NsfMapper::WriteRegister(uint16_t addr, uint8_t value)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x9010: case 0x9030:
|
case 0x9010: case 0x9030:
|
||||||
_vrc7Audio->WriteReg(addr, value);
|
_vrc7Audio->WriteRegister(addr, value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x4016:
|
||||||
|
_epsgAudio->WriteRegister(addr, value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -478,10 +490,11 @@ void NsfMapper::StreamState(bool saving)
|
||||||
SnapshotInfo fdsAudio { _fdsAudio.get() };
|
SnapshotInfo fdsAudio { _fdsAudio.get() };
|
||||||
SnapshotInfo namcoAudio { _namcoAudio.get() };
|
SnapshotInfo namcoAudio { _namcoAudio.get() };
|
||||||
SnapshotInfo sunsoftAudio { _sunsoftAudio.get() };
|
SnapshotInfo sunsoftAudio { _sunsoftAudio.get() };
|
||||||
|
SnapshotInfo epsgAudio{ _epsgAudio.get() };
|
||||||
|
|
||||||
Stream(
|
Stream(
|
||||||
_model, _needInit, _irqEnabled, _irqReloadValue, _irqCounter, _irqStatus, _debugIrqStatus, _mmc5MultiplierValues[0], _mmc5MultiplierValues[1],
|
_model, _needInit, _irqEnabled, _irqReloadValue, _irqCounter, _irqStatus, _debugIrqStatus, _mmc5MultiplierValues[0], _mmc5MultiplierValues[1],
|
||||||
_trackEndCounter, _trackFadeCounter, _fadeLength, _silenceDetectDelay, _trackEnded, _allowSilenceDetection, _hasBankSwitching, _ntscSpeed,
|
_trackEndCounter, _trackFadeCounter, _fadeLength, _silenceDetectDelay, _trackEnded, _allowSilenceDetection, _hasBankSwitching, _ntscSpeed,
|
||||||
_palSpeed, _dendySpeed, _songNumber, mmc5Audio, vrc6Audio, vrc7Audio, fdsAudio, namcoAudio, sunsoftAudio
|
_palSpeed, _dendySpeed, _songNumber, mmc5Audio, vrc6Audio, vrc7Audio, fdsAudio, namcoAudio, sunsoftAudio, epsgAudio
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
#include "FdsAudio.h"
|
#include "FdsAudio.h"
|
||||||
#include "Namco163Audio.h"
|
#include "Namco163Audio.h"
|
||||||
#include "Sunsoft5bAudio.h"
|
#include "Sunsoft5bAudio.h"
|
||||||
|
#include "EPSGAudio.h"
|
||||||
|
|
||||||
enum class NsfIrqType
|
enum class NsfIrqType
|
||||||
{
|
{
|
||||||
|
@ -25,7 +26,8 @@ private:
|
||||||
FDS = 0x04,
|
FDS = 0x04,
|
||||||
MMC5 = 0x08,
|
MMC5 = 0x08,
|
||||||
Namco = 0x10,
|
Namco = 0x10,
|
||||||
Sunsoft = 0x20
|
Sunsoft = 0x20,
|
||||||
|
EPSG = 0x40
|
||||||
};
|
};
|
||||||
|
|
||||||
NesModel _model;
|
NesModel _model;
|
||||||
|
@ -37,6 +39,7 @@ private:
|
||||||
unique_ptr<FdsAudio> _fdsAudio;
|
unique_ptr<FdsAudio> _fdsAudio;
|
||||||
unique_ptr<Namco163Audio> _namcoAudio;
|
unique_ptr<Namco163Audio> _namcoAudio;
|
||||||
unique_ptr<Sunsoft5bAudio> _sunsoftAudio;
|
unique_ptr<Sunsoft5bAudio> _sunsoftAudio;
|
||||||
|
unique_ptr<EPSGAudio> _epsgAudio;
|
||||||
|
|
||||||
bool _needInit = false;
|
bool _needInit = false;
|
||||||
bool _irqEnabled = false;
|
bool _irqEnabled = false;
|
||||||
|
|
145
Core/SSGAudio.h
Normal file
145
Core/SSGAudio.h
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
#pragma once
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "Snapshotable.h"
|
||||||
|
#include "APU.h"
|
||||||
|
#include "BaseExpansionAudio.h"
|
||||||
|
#include "Console.h"
|
||||||
|
|
||||||
|
|
||||||
|
template<AudioChannel...channels>
|
||||||
|
class SSGAudio : public BaseExpansionAudio
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint8_t _volumeLut[0x10];
|
||||||
|
uint8_t _currentRegister;
|
||||||
|
uint8_t _registers[0x10];
|
||||||
|
int16_t _lastOutput;
|
||||||
|
int16_t _timer[3];
|
||||||
|
uint8_t _toneStep[3];
|
||||||
|
double _clock;
|
||||||
|
bool _processTick;
|
||||||
|
|
||||||
|
uint16_t GetPeriod(int channel)
|
||||||
|
{
|
||||||
|
return _registers[channel * 2] | (_registers[channel * 2 + 1] << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t GetEnvelopePeriod()
|
||||||
|
{
|
||||||
|
return _registers[0x0B] | (_registers[0x0C] << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t GetNoisePeriod()
|
||||||
|
{
|
||||||
|
return _registers[6];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t GetVolume(int channel)
|
||||||
|
{
|
||||||
|
return _volumeLut[_registers[8 + channel] & 0x0F];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsEnvelopeEnabled(int channel)
|
||||||
|
{
|
||||||
|
return (_registers[8 + channel] & 0x10) == 0x10;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsToneEnabled(int channel)
|
||||||
|
{
|
||||||
|
return ((_registers[7] >> channel) & 0x01) == 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsNoiseEnabled(int channel)
|
||||||
|
{
|
||||||
|
return ((_registers[7] >> (channel + 3)) & 0x01) == 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateChannel(int channel)
|
||||||
|
{
|
||||||
|
_timer[channel]--;
|
||||||
|
if(_timer[channel] <= 0) {
|
||||||
|
_timer[channel] = GetPeriod(channel);
|
||||||
|
_toneStep[channel] = (_toneStep[channel] + 1) & 0x0F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateOutputLevel()
|
||||||
|
{
|
||||||
|
int16_t summedOutput = 0;
|
||||||
|
for(int i = 0; i < 3; i++) {
|
||||||
|
if(IsToneEnabled(i) && _toneStep[i] < 0x08) {
|
||||||
|
summedOutput += GetVolume(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto delta = (summedOutput - _lastOutput);
|
||||||
|
(_console->GetApu()->AddExpansionAudioDelta(channels, summedOutput - _lastOutput), ...);
|
||||||
|
_lastOutput = summedOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void StreamState(bool saving) override
|
||||||
|
{
|
||||||
|
BaseExpansionAudio::StreamState(saving);
|
||||||
|
|
||||||
|
ArrayInfo<int16_t> timer{ _timer, 3 };
|
||||||
|
ArrayInfo<uint8_t> registers{ _registers, 0x10 };
|
||||||
|
ArrayInfo<uint8_t> toneStep{ _toneStep, 3 };
|
||||||
|
Stream(timer, registers, toneStep, _currentRegister, _lastOutput, _clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClockAudio() override
|
||||||
|
{
|
||||||
|
_clock += GetSSGClockFrequency() / (double)_console->GetCpu()->GetClockRate(_console->GetModel());
|
||||||
|
|
||||||
|
while (_clock >= 1)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
UpdateChannel(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
_clock--;
|
||||||
|
UpdateOutputLevel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint32_t GetSSGClockFrequency()
|
||||||
|
{
|
||||||
|
return _console->GetCpu()->GetClockRate(_console->GetModel()) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
SSGAudio(shared_ptr<Console> console) : BaseExpansionAudio(console)
|
||||||
|
{
|
||||||
|
memset(_timer, 0, sizeof(_timer));
|
||||||
|
memset(_registers, 0, sizeof(_registers));
|
||||||
|
memset(_toneStep, 0, sizeof(_toneStep));
|
||||||
|
_currentRegister = 0;
|
||||||
|
_lastOutput = 0;
|
||||||
|
_clock = 0;
|
||||||
|
|
||||||
|
double output = 1.0;
|
||||||
|
_volumeLut[0] = 0;
|
||||||
|
for(int i = 1; i < 0x10; i++) {
|
||||||
|
//+1.5 dB 2x for every 1 step in volume
|
||||||
|
output *= 1.1885022274370184377301224648922;
|
||||||
|
output *= 1.1885022274370184377301224648922;
|
||||||
|
|
||||||
|
_volumeLut[i] = (uint8_t)output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteRegister(uint16_t addr, uint8_t value)
|
||||||
|
{
|
||||||
|
switch(addr) {
|
||||||
|
case 0xC000:
|
||||||
|
_currentRegister = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xE000:
|
||||||
|
if(_currentRegister <= 0xF)
|
||||||
|
_registers[_currentRegister] = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -266,7 +266,18 @@ int16_t SoundMixer::GetOutputVolume(bool forRightChannel)
|
||||||
GetChannelOutput(AudioChannel::Namco163, forRightChannel) * 20 +
|
GetChannelOutput(AudioChannel::Namco163, forRightChannel) * 20 +
|
||||||
GetChannelOutput(AudioChannel::Sunsoft5B, forRightChannel) * 15 +
|
GetChannelOutput(AudioChannel::Sunsoft5B, forRightChannel) * 15 +
|
||||||
GetChannelOutput(AudioChannel::VRC6, forRightChannel) * 75 +
|
GetChannelOutput(AudioChannel::VRC6, forRightChannel) * 75 +
|
||||||
GetChannelOutput(AudioChannel::VRC7, forRightChannel));
|
#ifndef VRC7_USE_OLD_EMU
|
||||||
|
#define VRC7_USE_NUKED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VRC7_USE_NUKED
|
||||||
|
GetChannelOutput(AudioChannel::VRC7, forRightChannel) * 12 +
|
||||||
|
#else
|
||||||
|
GetChannelOutput(AudioChannel::VRC7, forRightChannel) +
|
||||||
|
#endif
|
||||||
|
GetChannelOutput(AudioChannel::EPSG_L, forRightChannel) * 15 +
|
||||||
|
GetChannelOutput(AudioChannel::EPSG_R, forRightChannel) * 15
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::AddDelta(AudioChannel channel, uint32_t time, int16_t delta)
|
void SoundMixer::AddDelta(AudioChannel channel, uint32_t time, int16_t delta)
|
||||||
|
|
|
@ -30,7 +30,7 @@ public:
|
||||||
private:
|
private:
|
||||||
static constexpr uint32_t MaxSampleRate = 96000;
|
static constexpr uint32_t MaxSampleRate = 96000;
|
||||||
static constexpr uint32_t MaxSamplesPerFrame = MaxSampleRate / 60 * 4 * 2; //x4 to allow CPU overclocking up to 10x, x2 for panning stereo
|
static constexpr uint32_t MaxSamplesPerFrame = MaxSampleRate / 60 * 4 * 2; //x4 to allow CPU overclocking up to 10x, x2 for panning stereo
|
||||||
static constexpr uint32_t MaxChannelCount = 11;
|
static constexpr uint32_t MaxChannelCount = 13;
|
||||||
|
|
||||||
IAudioDevice* _audioDevice;
|
IAudioDevice* _audioDevice;
|
||||||
EmulationSettings* _settings;
|
EmulationSettings* _settings;
|
||||||
|
|
|
@ -2,130 +2,7 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "Snapshotable.h"
|
#include "Snapshotable.h"
|
||||||
#include "APU.h"
|
#include "APU.h"
|
||||||
#include "BaseExpansionAudio.h"
|
#include "SSGAudio.h"
|
||||||
#include "Console.h"
|
#include "Console.h"
|
||||||
|
|
||||||
class Sunsoft5bAudio : public BaseExpansionAudio
|
using Sunsoft5bAudio = SSGAudio<AudioChannel::Sunsoft5B>;
|
||||||
{
|
|
||||||
private:
|
|
||||||
uint8_t _volumeLut[0x10];
|
|
||||||
uint8_t _currentRegister;
|
|
||||||
uint8_t _registers[0x10];
|
|
||||||
int16_t _lastOutput;
|
|
||||||
int16_t _timer[3];
|
|
||||||
uint8_t _toneStep[3];
|
|
||||||
bool _processTick;
|
|
||||||
|
|
||||||
uint16_t GetPeriod(int channel)
|
|
||||||
{
|
|
||||||
return _registers[channel * 2] | (_registers[channel * 2 + 1] << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t GetEnvelopePeriod()
|
|
||||||
{
|
|
||||||
return _registers[0x0B] | (_registers[0x0C] << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t GetNoisePeriod()
|
|
||||||
{
|
|
||||||
return _registers[6];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t GetVolume(int channel)
|
|
||||||
{
|
|
||||||
return _volumeLut[_registers[8 + channel] & 0x0F];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsEnvelopeEnabled(int channel)
|
|
||||||
{
|
|
||||||
return (_registers[8 + channel] & 0x10) == 0x10;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsToneEnabled(int channel)
|
|
||||||
{
|
|
||||||
return ((_registers[7] >> channel) & 0x01) == 0x00;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsNoiseEnabled(int channel)
|
|
||||||
{
|
|
||||||
return ((_registers[7] >> (channel + 3)) & 0x01) == 0x00;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateChannel(int channel)
|
|
||||||
{
|
|
||||||
_timer[channel]--;
|
|
||||||
if(_timer[channel] <= 0) {
|
|
||||||
_timer[channel] = GetPeriod(channel);
|
|
||||||
_toneStep[channel] = (_toneStep[channel] + 1) & 0x0F;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateOutputLevel()
|
|
||||||
{
|
|
||||||
int16_t summedOutput = 0;
|
|
||||||
for(int i = 0; i < 3; i++) {
|
|
||||||
if(IsToneEnabled(i) && _toneStep[i] < 0x08) {
|
|
||||||
summedOutput += GetVolume(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_console->GetApu()->AddExpansionAudioDelta(AudioChannel::Sunsoft5B, summedOutput - _lastOutput);
|
|
||||||
_lastOutput = summedOutput;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void StreamState(bool saving) override
|
|
||||||
{
|
|
||||||
BaseExpansionAudio::StreamState(saving);
|
|
||||||
|
|
||||||
ArrayInfo<int16_t> timer{ _timer, 3 };
|
|
||||||
ArrayInfo<uint8_t> registers{ _registers, 0x10 };
|
|
||||||
ArrayInfo<uint8_t> toneStep{ _toneStep, 3 };
|
|
||||||
Stream(timer, registers, toneStep, _currentRegister, _lastOutput, _processTick);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClockAudio() override
|
|
||||||
{
|
|
||||||
if(_processTick) {
|
|
||||||
for(int i = 0; i < 3; i++) {
|
|
||||||
UpdateChannel(i);
|
|
||||||
}
|
|
||||||
UpdateOutputLevel();
|
|
||||||
}
|
|
||||||
_processTick = !_processTick;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
Sunsoft5bAudio(shared_ptr<Console> console) : BaseExpansionAudio(console)
|
|
||||||
{
|
|
||||||
memset(_timer, 0, sizeof(_timer));
|
|
||||||
memset(_registers, 0, sizeof(_registers));
|
|
||||||
memset(_toneStep, 0, sizeof(_toneStep));
|
|
||||||
_currentRegister = 0;
|
|
||||||
_lastOutput = 0;
|
|
||||||
_processTick = false;
|
|
||||||
|
|
||||||
double output = 1.0;
|
|
||||||
_volumeLut[0] = 0;
|
|
||||||
for(int i = 1; i < 0x10; i++) {
|
|
||||||
//+1.5 dB 2x for every 1 step in volume
|
|
||||||
output *= 1.1885022274370184377301224648922;
|
|
||||||
output *= 1.1885022274370184377301224648922;
|
|
||||||
|
|
||||||
_volumeLut[i] = (uint8_t)output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteRegister(uint16_t addr, uint8_t value)
|
|
||||||
{
|
|
||||||
switch(addr & 0xE000) {
|
|
||||||
case 0xC000:
|
|
||||||
_currentRegister = value & 0x0F;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xE000:
|
|
||||||
_registers[_currentRegister] = value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -63,7 +63,7 @@ protected:
|
||||||
|
|
||||||
UpdatePrgRamAccess();
|
UpdatePrgRamAccess();
|
||||||
|
|
||||||
_audio->SetMuteAudio((_controlFlags & 0x40) != 0);
|
//_audio->SetMuteAudio((_controlFlags & 0x40) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteRegister(uint16_t addr, uint8_t value) override
|
void WriteRegister(uint16_t addr, uint8_t value) override
|
||||||
|
@ -78,7 +78,7 @@ protected:
|
||||||
case 0x8008: SelectPRGPage(1, value & 0x3F); break;
|
case 0x8008: SelectPRGPage(1, value & 0x3F); break;
|
||||||
case 0x9000: SelectPRGPage(2, value & 0x3F); break;
|
case 0x9000: SelectPRGPage(2, value & 0x3F); break;
|
||||||
|
|
||||||
case 0x9010: case 0x9030: _audio->WriteReg(addr, value); break;
|
case 0x9010: case 0x9030: _audio->WriteRegister(addr, value); break;
|
||||||
|
|
||||||
case 0xA000: SelectCHRPage(0, value); break;
|
case 0xA000: SelectCHRPage(0, value); break;
|
||||||
case 0xA008: SelectCHRPage(1, value); break;
|
case 0xA008: SelectCHRPage(1, value); break;
|
||||||
|
|
174
Core/Vrc7Audio.h
174
Core/Vrc7Audio.h
|
@ -1,3 +1,153 @@
|
||||||
|
#pragma once
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "Snapshotable.h"
|
||||||
|
#include "APU.h"
|
||||||
|
#include "BaseExpansionAudio.h"
|
||||||
|
#include "SSGAudio.h"
|
||||||
|
#include "Console.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include "opll.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef VRC7_USE_OLD_EMU
|
||||||
|
#define VRC7_USE_NUKED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VRC7_USE_NUKED
|
||||||
|
class Vrc7Audio : public BaseExpansionAudio
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
opll_t _chip;
|
||||||
|
|
||||||
|
int16_t _lastOutput;
|
||||||
|
int16_t _currentOutput;
|
||||||
|
|
||||||
|
double _clock;
|
||||||
|
|
||||||
|
static constexpr uint8_t cycleCount = 12;
|
||||||
|
|
||||||
|
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;
|
||||||
|
_console->GetApu()->AddExpansionAudioDelta(AudioChannel::VRC7, _currentOutput - _lastOutput);
|
||||||
|
_lastOutput = _currentOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 << "VRC7 CHIP DOUBLE WRITE" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
_inputBuffer[cycle] = {
|
||||||
|
a,
|
||||||
|
d,
|
||||||
|
cycle,
|
||||||
|
true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getClockFrequency()
|
||||||
|
{
|
||||||
|
uint32_t vrc7clock = 3579545 / 4;
|
||||||
|
return vrc7clock;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void StreamState(bool saving) override
|
||||||
|
{
|
||||||
|
|
||||||
|
ValueInfo<int16_t> lastOutput{ &_lastOutput };
|
||||||
|
ValueInfo<int16_t> currentOutput{ &_currentOutput };
|
||||||
|
ArrayInfo<InputBuffer> inputBuffer{ &_inputBuffer };
|
||||||
|
ValueInfo<opll_t> chip{ &_chip };
|
||||||
|
ValueInfo<double> clock{ &_clock };
|
||||||
|
Stream(lastOutput, currentOutput, inputBuffer, chip, clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClockAudio() override
|
||||||
|
{
|
||||||
|
|
||||||
|
_clock += getClockFrequency() / (double)_console->GetCpu()->GetClockRate(_console->GetModel());
|
||||||
|
|
||||||
|
while (_clock >= cycleCount)
|
||||||
|
{
|
||||||
|
|
||||||
|
_currentOutput = 0;
|
||||||
|
|
||||||
|
|
||||||
|
for (uint8_t cycle = 0; cycle < cycleCount; cycle++)
|
||||||
|
{
|
||||||
|
_clock--;
|
||||||
|
|
||||||
|
int32_t samples[2];
|
||||||
|
OPLL_Clock(&_chip, samples);
|
||||||
|
|
||||||
|
for (uint8_t x = 0; x < 2; x++)
|
||||||
|
{
|
||||||
|
_currentOutput += samples[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& input = _inputBuffer[cycle];
|
||||||
|
if (input.wrote)
|
||||||
|
{
|
||||||
|
input.wrote = false;
|
||||||
|
|
||||||
|
OPLL_Write(&_chip, input.addr, input.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateOutputLevel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Vrc7Audio(shared_ptr<Console> console) : BaseExpansionAudio(console)
|
||||||
|
{
|
||||||
|
_lastOutput = 0;
|
||||||
|
_currentOutput = 0;
|
||||||
|
_inputBuffer = {};
|
||||||
|
|
||||||
|
_clock = 0;
|
||||||
|
|
||||||
|
OPLL_Reset(&_chip, opll_type_ds1001);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteRegister(uint16_t addr, uint8_t value)
|
||||||
|
{
|
||||||
|
switch (addr) {
|
||||||
|
case 0x9010:
|
||||||
|
case 0x9030:
|
||||||
|
|
||||||
|
const uint8_t a0 = (addr & 0xF030) == 0x9030;
|
||||||
|
WriteToChip(a0, value);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#else
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "BaseExpansionAudio.h"
|
#include "BaseExpansionAudio.h"
|
||||||
|
@ -16,12 +166,12 @@ private:
|
||||||
protected:
|
protected:
|
||||||
void ClockAudio() override
|
void ClockAudio() override
|
||||||
{
|
{
|
||||||
if(_clockTimer == 0) {
|
if (_clockTimer == 0) {
|
||||||
_clockTimer = ((double)_console->GetCpu()->GetClockRate(_console->GetModel())) / 49716;
|
_clockTimer = ((double)_console->GetCpu()->GetClockRate(_console->GetModel())) / 49716;
|
||||||
}
|
}
|
||||||
|
|
||||||
_clockTimer--;
|
_clockTimer--;
|
||||||
if(_clockTimer <= 0) {
|
if (_clockTimer <= 0) {
|
||||||
int16_t output = _opllEmulator->GetOutput();
|
int16_t output = _opllEmulator->GetOutput();
|
||||||
_console->GetApu()->AddExpansionAudioDelta(AudioChannel::VRC7, _muted ? 0 : (output - _previousOutput));
|
_console->GetApu()->AddExpansionAudioDelta(AudioChannel::VRC7, _muted ? 0 : (output - _previousOutput));
|
||||||
_previousOutput = output;
|
_previousOutput = output;
|
||||||
|
@ -52,15 +202,17 @@ public:
|
||||||
_muted = muted;
|
_muted = muted;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteReg(uint16_t addr, uint8_t value)
|
void WriteRegister(uint16_t addr, uint8_t value)
|
||||||
{
|
{
|
||||||
switch(addr & 0xF030) {
|
switch (addr & 0xF030) {
|
||||||
case 0x9010:
|
case 0x9010:
|
||||||
_currentReg = value;
|
_currentReg = value;
|
||||||
break;
|
break;
|
||||||
case 0x9030:
|
case 0x9030:
|
||||||
_opllEmulator->WriteReg(_currentReg, value);
|
_opllEmulator->WriteReg(_currentReg, value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
375
Core/emu2149.cpp
Normal file
375
Core/emu2149.cpp
Normal file
|
@ -0,0 +1,375 @@
|
||||||
|
/****************************************************************************
|
||||||
|
|
||||||
|
emu2149.c -- YM2149/AY-3-8910 emulator by Mitsutaka Okazaki 2001-2016
|
||||||
|
|
||||||
|
2001 04-28 : Version 1.00beta -- 1st Beta Release.
|
||||||
|
2001 08-14 : Version 1.10
|
||||||
|
2001 10-03 : Version 1.11 -- Added PSG_set_quality().
|
||||||
|
2002 03-02 : Version 1.12 -- Removed PSG_init & PSG_close.
|
||||||
|
2002 10-13 : Version 1.14 -- Fixed the envelope unit.
|
||||||
|
2003 09-19 : Version 1.15 -- Added PSG_setMask and PSG_toggleMask
|
||||||
|
2004 01-11 : Version 1.16 -- Fixed the envelope problem where the envelope
|
||||||
|
frequency register is written before key-on.
|
||||||
|
2015 12-13 : Version 1.17 -- Changed own integer types to C99 stdint.h types.
|
||||||
|
2016 09-06 : Version 1.20 -- Support per-channel output.
|
||||||
|
|
||||||
|
References:
|
||||||
|
psg.vhd -- 2000 written by Kazuhiro Tsujikawa.
|
||||||
|
s_fme7.c -- 1999,2000 written by Mamiya (NEZplug).
|
||||||
|
ay8910.c -- 1998-2001 Author unknown (MAME).
|
||||||
|
MSX-Datapack -- 1991 ASCII Corp.
|
||||||
|
AY-3-8910 data sheet
|
||||||
|
|
||||||
|
*****************************************************************************/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "emu2149.h"
|
||||||
|
|
||||||
|
static uint32_t voltbl[2][32] = {
|
||||||
|
{0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09,
|
||||||
|
0x0B, 0x0D, 0x0F, 0x12,
|
||||||
|
0x16, 0x1A, 0x1F, 0x25, 0x2D, 0x35, 0x3F, 0x4C, 0x5A, 0x6A, 0x7F, 0x97,
|
||||||
|
0xB4, 0xD6, 0xFF, 0xFF},
|
||||||
|
{0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x05, 0x05, 0x07, 0x07,
|
||||||
|
0x0B, 0x0B, 0x0F, 0x0F,
|
||||||
|
0x16, 0x16, 0x1F, 0x1F, 0x2D, 0x2D, 0x3F, 0x3F, 0x5A, 0x5A, 0x7F, 0x7F,
|
||||||
|
0xB4, 0xB4, 0xFF, 0xFF}
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t regmsk[16] = {
|
||||||
|
0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x1f, 0x3f,
|
||||||
|
0x1f, 0x1f, 0x1f, 0xff, 0xff, 0x0f, 0xff, 0xff
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GETA_BITS 24
|
||||||
|
|
||||||
|
static void
|
||||||
|
internal_refresh (PSG * psg)
|
||||||
|
{
|
||||||
|
if (psg->quality)
|
||||||
|
{
|
||||||
|
psg->base_incr = 1 << GETA_BITS;
|
||||||
|
psg->realstep = (uint32_t) ((1 << 31) / psg->rate);
|
||||||
|
psg->psgstep = (uint32_t) ((1 << 31) / (psg->clk / 16));
|
||||||
|
psg->psgtime = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
psg->base_incr =
|
||||||
|
(uint32_t) ((double) psg->clk * (1 << GETA_BITS) / (16 * psg->rate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PSG_set_rate (PSG * psg, uint32_t r)
|
||||||
|
{
|
||||||
|
psg->rate = r ? r : 44100;
|
||||||
|
internal_refresh (psg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PSG_set_quality (PSG * psg, uint32_t q)
|
||||||
|
{
|
||||||
|
psg->quality = q;
|
||||||
|
internal_refresh (psg);
|
||||||
|
}
|
||||||
|
|
||||||
|
PSG *
|
||||||
|
PSG_new (uint32_t c, uint32_t r)
|
||||||
|
{
|
||||||
|
PSG *psg;
|
||||||
|
|
||||||
|
psg = (PSG *) malloc (sizeof (PSG));
|
||||||
|
if (psg == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
PSG_setVolumeMode (psg, EMU2149_VOL_DEFAULT);
|
||||||
|
psg->clk = c;
|
||||||
|
psg->rate = r ? r : 44100;
|
||||||
|
PSG_set_quality (psg, 0);
|
||||||
|
|
||||||
|
return psg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PSG_setVolumeMode (PSG * psg, int type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
psg->voltbl = voltbl[EMU2149_VOL_YM2149];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
psg->voltbl = voltbl[EMU2149_VOL_AY_3_8910];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
psg->voltbl = voltbl[EMU2149_VOL_DEFAULT];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
PSG_setMask (PSG *psg, uint32_t mask)
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
if(psg)
|
||||||
|
{
|
||||||
|
ret = psg->mask;
|
||||||
|
psg->mask = mask;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
PSG_toggleMask (PSG *psg, uint32_t mask)
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
if(psg)
|
||||||
|
{
|
||||||
|
ret = psg->mask;
|
||||||
|
psg->mask ^= mask;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PSG_reset (PSG * psg)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
psg->base_count = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
psg->count[i] = 0x1000;
|
||||||
|
psg->freq[i] = 0;
|
||||||
|
psg->edge[i] = 0;
|
||||||
|
psg->volume[i] = 0;
|
||||||
|
psg->ch_out[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
psg->mask = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
psg->reg[i] = 0;
|
||||||
|
psg->adr = 0;
|
||||||
|
|
||||||
|
psg->noise_seed = 0xffff;
|
||||||
|
psg->noise_count = 0x40;
|
||||||
|
psg->noise_freq = 0;
|
||||||
|
|
||||||
|
psg->env_volume = 0;
|
||||||
|
psg->env_ptr = 0;
|
||||||
|
psg->env_freq = 0;
|
||||||
|
psg->env_count = 0;
|
||||||
|
psg->env_pause = 1;
|
||||||
|
|
||||||
|
psg->out = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PSG_delete (PSG * psg)
|
||||||
|
{
|
||||||
|
free (psg);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
PSG_readIO (PSG * psg)
|
||||||
|
{
|
||||||
|
return (uint8_t) (psg->reg[psg->adr]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
PSG_readReg (PSG * psg, uint32_t reg)
|
||||||
|
{
|
||||||
|
return (uint8_t) (psg->reg[reg & 0x1f]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PSG_writeIO (PSG * psg, uint32_t adr, uint32_t val)
|
||||||
|
{
|
||||||
|
if (adr & 1)
|
||||||
|
PSG_writeReg (psg, psg->adr, val);
|
||||||
|
else
|
||||||
|
psg->adr = val & 0x1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
update_output (PSG * psg)
|
||||||
|
{
|
||||||
|
|
||||||
|
int i, noise;
|
||||||
|
uint32_t incr;
|
||||||
|
|
||||||
|
psg->base_count += psg->base_incr;
|
||||||
|
incr = (psg->base_count >> GETA_BITS);
|
||||||
|
psg->base_count &= (1 << GETA_BITS) - 1;
|
||||||
|
|
||||||
|
/* Envelope */
|
||||||
|
psg->env_count += incr;
|
||||||
|
while (psg->env_count>=0x10000 && psg->env_freq!=0)
|
||||||
|
{
|
||||||
|
if (!psg->env_pause)
|
||||||
|
{
|
||||||
|
if(psg->env_face)
|
||||||
|
psg->env_ptr = (psg->env_ptr + 1) & 0x3f ;
|
||||||
|
else
|
||||||
|
psg->env_ptr = (psg->env_ptr + 0x3f) & 0x3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (psg->env_ptr & 0x20) /* if carry or borrow */
|
||||||
|
{
|
||||||
|
if (psg->env_continue)
|
||||||
|
{
|
||||||
|
if (psg->env_alternate^psg->env_hold) psg->env_face ^= 1;
|
||||||
|
if (psg->env_hold) psg->env_pause = 1;
|
||||||
|
psg->env_ptr = psg->env_face?0:0x1f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
psg->env_pause = 1;
|
||||||
|
psg->env_ptr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
psg->env_count -= psg->env_freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Noise */
|
||||||
|
psg->noise_count += incr;
|
||||||
|
if (psg->noise_count & 0x40)
|
||||||
|
{
|
||||||
|
if (psg->noise_seed & 1)
|
||||||
|
psg->noise_seed ^= 0x24000;
|
||||||
|
psg->noise_seed >>= 1;
|
||||||
|
psg->noise_count -= psg->noise_freq?psg->noise_freq:(1<<1);
|
||||||
|
}
|
||||||
|
noise = psg->noise_seed & 1;
|
||||||
|
|
||||||
|
/* Tone */
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
psg->count[i] += incr;
|
||||||
|
if (psg->count[i] & 0x1000)
|
||||||
|
{
|
||||||
|
if (psg->freq[i] > 1)
|
||||||
|
{
|
||||||
|
psg->edge[i] = !psg->edge[i];
|
||||||
|
psg->count[i] -= psg->freq[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
psg->edge[i] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (psg->mask&PSG_MASK_CH(i))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((psg->tmask[i]||psg->edge[i]) && (psg->nmask[i]||noise))
|
||||||
|
{
|
||||||
|
if (!(psg->volume[i] & 32))
|
||||||
|
psg->ch_out[i] += (psg->voltbl[psg->volume[i] & 31] << 4);
|
||||||
|
else
|
||||||
|
psg->ch_out[i] += (psg->voltbl[psg->env_ptr] << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
psg->ch_out[i] >>= 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int16_t
|
||||||
|
mix_output(PSG *psg) {
|
||||||
|
return (int16_t)(psg->out = psg->ch_out[0] + psg->ch_out[1] + psg->ch_out[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t
|
||||||
|
PSG_calc (PSG * psg)
|
||||||
|
{
|
||||||
|
if (!psg->quality) {
|
||||||
|
update_output(psg);
|
||||||
|
return mix_output(psg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simple rate converter */
|
||||||
|
while (psg->realstep > psg->psgtime)
|
||||||
|
{
|
||||||
|
psg->psgtime += psg->psgstep;
|
||||||
|
update_output(psg);
|
||||||
|
}
|
||||||
|
psg->psgtime = psg->psgtime - psg->realstep;
|
||||||
|
|
||||||
|
return mix_output(psg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PSG_writeReg (PSG * psg, uint32_t reg, uint32_t val)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
if (reg > 15) return;
|
||||||
|
|
||||||
|
val &= regmsk[reg];
|
||||||
|
|
||||||
|
psg->reg[reg] = (uint8_t) (val & 0xff);
|
||||||
|
switch (reg)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 2:
|
||||||
|
case 4:
|
||||||
|
case 1:
|
||||||
|
case 3:
|
||||||
|
case 5:
|
||||||
|
c = reg >> 1;
|
||||||
|
psg->freq[c] = ((psg->reg[c * 2 + 1] & 15) << 8) + psg->reg[c * 2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
psg->noise_freq = (val & 31) << 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
psg->tmask[0] = (val & 1);
|
||||||
|
psg->tmask[1] = (val & 2);
|
||||||
|
psg->tmask[2] = (val & 4);
|
||||||
|
psg->nmask[0] = (val & 8);
|
||||||
|
psg->nmask[1] = (val & 16);
|
||||||
|
psg->nmask[2] = (val & 32);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
case 9:
|
||||||
|
case 10:
|
||||||
|
psg->volume[reg - 8] = val << 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 11:
|
||||||
|
case 12:
|
||||||
|
psg->env_freq = (psg->reg[12] << 8) + psg->reg[11];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 13:
|
||||||
|
psg->env_continue = (val >> 3) & 1;
|
||||||
|
psg->env_attack = (val >> 2) & 1;
|
||||||
|
psg->env_alternate = (val >> 1) & 1;
|
||||||
|
psg->env_hold = val & 1;
|
||||||
|
psg->env_face = psg->env_attack;
|
||||||
|
psg->env_pause = 0;
|
||||||
|
psg->env_count = 0x10000 - psg->env_freq;
|
||||||
|
psg->env_ptr = psg->env_face?0:0x1f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 14:
|
||||||
|
case 15:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
88
Core/emu2149.h
Normal file
88
Core/emu2149.h
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/* emu2149.h */
|
||||||
|
#ifndef _EMU2149_H_
|
||||||
|
#define _EMU2149_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define EMU2149_VOL_DEFAULT 1
|
||||||
|
#define EMU2149_VOL_YM2149 0
|
||||||
|
#define EMU2149_VOL_AY_3_8910 1
|
||||||
|
|
||||||
|
#define PSG_MASK_CH(x) (1<<(x))
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct __PSG
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Volume Table */
|
||||||
|
uint32_t *voltbl;
|
||||||
|
|
||||||
|
uint8_t reg[0x20];
|
||||||
|
int32_t out;
|
||||||
|
|
||||||
|
uint32_t clk, rate, base_incr, quality;
|
||||||
|
|
||||||
|
uint32_t count[3];
|
||||||
|
uint32_t volume[3];
|
||||||
|
uint32_t freq[3];
|
||||||
|
uint32_t edge[3];
|
||||||
|
uint32_t tmask[3];
|
||||||
|
uint32_t nmask[3];
|
||||||
|
uint32_t mask;
|
||||||
|
|
||||||
|
uint32_t base_count;
|
||||||
|
|
||||||
|
uint32_t env_volume;
|
||||||
|
uint32_t env_ptr;
|
||||||
|
uint32_t env_face;
|
||||||
|
|
||||||
|
uint32_t env_continue;
|
||||||
|
uint32_t env_attack;
|
||||||
|
uint32_t env_alternate;
|
||||||
|
uint32_t env_hold;
|
||||||
|
uint32_t env_pause;
|
||||||
|
uint32_t env_reset;
|
||||||
|
|
||||||
|
uint32_t env_freq;
|
||||||
|
uint32_t env_count;
|
||||||
|
|
||||||
|
uint32_t noise_seed;
|
||||||
|
uint32_t noise_count;
|
||||||
|
uint32_t noise_freq;
|
||||||
|
|
||||||
|
/* rate converter */
|
||||||
|
uint32_t realstep;
|
||||||
|
uint32_t psgtime;
|
||||||
|
uint32_t psgstep;
|
||||||
|
|
||||||
|
/* I/O Ctrl */
|
||||||
|
uint32_t adr;
|
||||||
|
|
||||||
|
/* output of channels */
|
||||||
|
int16_t ch_out[3];
|
||||||
|
|
||||||
|
} PSG;
|
||||||
|
|
||||||
|
void PSG_set_quality (PSG * psg, uint32_t q);
|
||||||
|
void PSG_set_rate (PSG * psg, uint32_t r);
|
||||||
|
PSG *PSG_new (uint32_t clk, uint32_t rate);
|
||||||
|
void PSG_reset (PSG *);
|
||||||
|
void PSG_delete (PSG *);
|
||||||
|
void PSG_writeReg (PSG *, uint32_t reg, uint32_t val);
|
||||||
|
void PSG_writeIO (PSG * psg, uint32_t adr, uint32_t val);
|
||||||
|
uint8_t PSG_readReg (PSG * psg, uint32_t reg);
|
||||||
|
uint8_t PSG_readIO (PSG * psg);
|
||||||
|
int16_t PSG_calc (PSG *);
|
||||||
|
void PSG_setVolumeMode (PSG * psg, int type);
|
||||||
|
uint32_t PSG_setMask (PSG *, uint32_t mask);
|
||||||
|
uint32_t PSG_toggleMask (PSG *, uint32_t mask);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
1118
Core/opll.cpp
Normal file
1118
Core/opll.cpp
Normal file
File diff suppressed because it is too large
Load diff
199
Core/opll.h
Normal file
199
Core/opll.h
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Nuke.YKT
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Yamaha YM2413 emulator
|
||||||
|
* Thanks:
|
||||||
|
* siliconpr0n.org(digshadow, John McMaster):
|
||||||
|
* VRC VII decap and die shot.
|
||||||
|
*
|
||||||
|
* version: 1.0.1
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OPLL_H
|
||||||
|
#define OPLL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
opll_type_ym2413 = 0x00, /* Yamaha YM2413 */
|
||||||
|
opll_type_ds1001, /* Konami VRC VII */
|
||||||
|
opll_type_ym2413b, /* Yamaha YM2413B */
|
||||||
|
opll_type_ymf281, /* Yamaha YMF281 */
|
||||||
|
opll_type_ymf281b, /* Yamaha YMF281B */
|
||||||
|
opll_type_ym2420, /* Yamaha YM2420 */
|
||||||
|
opll_type_ym2423, /* Yamaha YM2423 */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
opll_patch_1 = 0x00,
|
||||||
|
opll_patch_2,
|
||||||
|
opll_patch_3,
|
||||||
|
opll_patch_4,
|
||||||
|
opll_patch_5,
|
||||||
|
opll_patch_6,
|
||||||
|
opll_patch_7,
|
||||||
|
opll_patch_8,
|
||||||
|
opll_patch_9,
|
||||||
|
opll_patch_10,
|
||||||
|
opll_patch_11,
|
||||||
|
opll_patch_12,
|
||||||
|
opll_patch_13,
|
||||||
|
opll_patch_14,
|
||||||
|
opll_patch_15,
|
||||||
|
opll_patch_drum_0,
|
||||||
|
opll_patch_drum_1,
|
||||||
|
opll_patch_drum_2,
|
||||||
|
opll_patch_drum_3,
|
||||||
|
opll_patch_drum_4,
|
||||||
|
opll_patch_drum_5,
|
||||||
|
opll_patch_max
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t tl;
|
||||||
|
uint8_t dc;
|
||||||
|
uint8_t dm;
|
||||||
|
uint8_t fb;
|
||||||
|
uint8_t am[2];
|
||||||
|
uint8_t vib[2];
|
||||||
|
uint8_t et[2];
|
||||||
|
uint8_t ksr[2];
|
||||||
|
uint8_t multi[2];
|
||||||
|
uint8_t ksl[2];
|
||||||
|
uint8_t ar[2];
|
||||||
|
uint8_t dr[2];
|
||||||
|
uint8_t sl[2];
|
||||||
|
uint8_t rr[2];
|
||||||
|
} opll_patch_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t chip_type;
|
||||||
|
uint32_t cycles;
|
||||||
|
uint32_t slot;
|
||||||
|
const opll_patch_t *patchrom;
|
||||||
|
/* IO */
|
||||||
|
uint8_t write_data;
|
||||||
|
uint8_t write_a;
|
||||||
|
uint8_t write_d;
|
||||||
|
uint8_t write_a_en;
|
||||||
|
uint8_t write_d_en;
|
||||||
|
uint8_t write_fm_address;
|
||||||
|
uint8_t write_fm_data;
|
||||||
|
uint8_t write_mode_address;
|
||||||
|
uint8_t address;
|
||||||
|
uint8_t data;
|
||||||
|
/* Envelope generator */
|
||||||
|
uint8_t eg_counter_state;
|
||||||
|
uint8_t eg_counter_state_prev;
|
||||||
|
uint32_t eg_timer;
|
||||||
|
uint8_t eg_timer_low_lock;
|
||||||
|
uint8_t eg_timer_carry;
|
||||||
|
uint8_t eg_timer_shift;
|
||||||
|
uint8_t eg_timer_shift_lock;
|
||||||
|
uint8_t eg_timer_shift_stop;
|
||||||
|
uint8_t eg_state[18];
|
||||||
|
uint8_t eg_level[18];
|
||||||
|
uint8_t eg_kon;
|
||||||
|
uint32_t eg_dokon;
|
||||||
|
uint8_t eg_off;
|
||||||
|
uint8_t eg_rate;
|
||||||
|
uint8_t eg_maxrate;
|
||||||
|
uint8_t eg_zerorate;
|
||||||
|
uint8_t eg_inc_lo;
|
||||||
|
uint8_t eg_inc_hi;
|
||||||
|
uint8_t eg_rate_hi;
|
||||||
|
uint16_t eg_sl;
|
||||||
|
uint16_t eg_ksltl;
|
||||||
|
uint8_t eg_out;
|
||||||
|
uint8_t eg_silent;
|
||||||
|
/* Phase generator */
|
||||||
|
uint16_t pg_fnum;
|
||||||
|
uint8_t pg_block;
|
||||||
|
uint16_t pg_out;
|
||||||
|
uint32_t pg_inc;
|
||||||
|
uint32_t pg_phase[18];
|
||||||
|
uint32_t pg_phase_next;
|
||||||
|
/* Operator */
|
||||||
|
int16_t op_fb1[9];
|
||||||
|
int16_t op_fb2[9];
|
||||||
|
int16_t op_fbsum;
|
||||||
|
int16_t op_mod;
|
||||||
|
uint8_t op_neg;
|
||||||
|
uint16_t op_logsin;
|
||||||
|
uint16_t op_exp_m;
|
||||||
|
uint16_t op_exp_s;
|
||||||
|
/* Channel */
|
||||||
|
int16_t ch_out;
|
||||||
|
int16_t ch_out_hh;
|
||||||
|
int16_t ch_out_tm;
|
||||||
|
int16_t ch_out_bd;
|
||||||
|
int16_t ch_out_sd;
|
||||||
|
int16_t ch_out_tc;
|
||||||
|
/* LFO */
|
||||||
|
uint16_t lfo_counter;
|
||||||
|
uint8_t lfo_vib_counter;
|
||||||
|
uint16_t lfo_am_counter;
|
||||||
|
uint8_t lfo_am_step;
|
||||||
|
uint8_t lfo_am_dir;
|
||||||
|
uint8_t lfo_am_car;
|
||||||
|
uint8_t lfo_am_out;
|
||||||
|
/* Register set */
|
||||||
|
uint16_t fnum[9];
|
||||||
|
uint8_t block[9];
|
||||||
|
uint8_t kon[9];
|
||||||
|
uint8_t son[9];
|
||||||
|
uint8_t vol[9];
|
||||||
|
uint8_t inst[9];
|
||||||
|
uint8_t rhythm;
|
||||||
|
uint8_t testmode;
|
||||||
|
opll_patch_t patch;
|
||||||
|
uint8_t c_instr;
|
||||||
|
uint8_t c_op;
|
||||||
|
uint8_t c_tl;
|
||||||
|
uint8_t c_dc;
|
||||||
|
uint8_t c_dm;
|
||||||
|
uint8_t c_fb;
|
||||||
|
uint8_t c_am;
|
||||||
|
uint8_t c_vib;
|
||||||
|
uint8_t c_et;
|
||||||
|
uint8_t c_ksr;
|
||||||
|
uint8_t c_ksr_freq;
|
||||||
|
uint8_t c_ksl_freq;
|
||||||
|
uint8_t c_ksl_block;
|
||||||
|
uint8_t c_multi;
|
||||||
|
uint8_t c_ksl;
|
||||||
|
uint8_t c_adrr[3];
|
||||||
|
uint8_t c_sl;
|
||||||
|
uint16_t c_fnum;
|
||||||
|
uint16_t c_block;
|
||||||
|
/* Rhythm mode */
|
||||||
|
int8_t rm_enable;
|
||||||
|
uint32_t rm_noise;
|
||||||
|
uint32_t rm_select;
|
||||||
|
uint8_t rm_hh_bit2;
|
||||||
|
uint8_t rm_hh_bit3;
|
||||||
|
uint8_t rm_hh_bit7;
|
||||||
|
uint8_t rm_hh_bit8;
|
||||||
|
uint8_t rm_tc_bit3;
|
||||||
|
uint8_t rm_tc_bit5;
|
||||||
|
|
||||||
|
int16_t output_m;
|
||||||
|
int16_t output_r;
|
||||||
|
|
||||||
|
} opll_t;
|
||||||
|
|
||||||
|
void OPLL_Reset(opll_t *chip, uint32_t chip_type);
|
||||||
|
void OPLL_Clock(opll_t *chip, int32_t *buffer);
|
||||||
|
void OPLL_Write(opll_t *chip, uint32_t port, uint8_t data);
|
||||||
|
#endif
|
1429
Core/ym3438.cpp
Normal file
1429
Core/ym3438.cpp
Normal file
File diff suppressed because it is too large
Load diff
211
Core/ym3438.h
Normal file
211
Core/ym3438.h
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017-2018 Alexey Khokholov (Nuke.YKT)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Nuked OPN2(Yamaha YM3438) emulator.
|
||||||
|
* Thanks:
|
||||||
|
* Silicon Pr0n:
|
||||||
|
* Yamaha YM3438 decap and die shot(digshadow).
|
||||||
|
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
|
||||||
|
* OPL2 ROMs.
|
||||||
|
*
|
||||||
|
* version: 1.0.9
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef YM3438_H
|
||||||
|
#define YM3438_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ym3438_mode_ym2612 = 0x01, /* Enables YM2612 emulation (MD1, MD2 VA2) */
|
||||||
|
ym3438_mode_readmode = 0x02 /* Enables status read on any port (TeraDrive, MD1 VA7, MD2, etc) */
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef uintptr_t Bitu;
|
||||||
|
typedef intptr_t Bits;
|
||||||
|
typedef uint64_t Bit64u;
|
||||||
|
typedef int64_t Bit64s;
|
||||||
|
typedef uint32_t Bit32u;
|
||||||
|
typedef int32_t Bit32s;
|
||||||
|
typedef uint16_t Bit16u;
|
||||||
|
typedef int16_t Bit16s;
|
||||||
|
typedef uint8_t Bit8u;
|
||||||
|
typedef int8_t Bit8s;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Bit32u cycles;
|
||||||
|
Bit32u channel;
|
||||||
|
Bit16s mol, mor;
|
||||||
|
/* IO */
|
||||||
|
Bit16u write_data;
|
||||||
|
Bit8u write_a;
|
||||||
|
Bit8u write_d;
|
||||||
|
Bit8u write_a_en;
|
||||||
|
Bit8u write_d_en;
|
||||||
|
Bit8u write_busy;
|
||||||
|
Bit8u write_busy_cnt;
|
||||||
|
Bit8u write_fm_address;
|
||||||
|
Bit8u write_fm_data;
|
||||||
|
Bit16u write_fm_mode_a;
|
||||||
|
Bit16u address;
|
||||||
|
Bit8u data;
|
||||||
|
Bit8u pin_test_in;
|
||||||
|
Bit8u pin_irq;
|
||||||
|
Bit8u busy;
|
||||||
|
/* LFO */
|
||||||
|
Bit8u lfo_en;
|
||||||
|
Bit8u lfo_freq;
|
||||||
|
Bit8u lfo_pm;
|
||||||
|
Bit8u lfo_am;
|
||||||
|
Bit8u lfo_cnt;
|
||||||
|
Bit8u lfo_inc;
|
||||||
|
Bit8u lfo_quotient;
|
||||||
|
/* Phase generator */
|
||||||
|
Bit16u pg_fnum;
|
||||||
|
Bit8u pg_block;
|
||||||
|
Bit8u pg_kcode;
|
||||||
|
Bit32u pg_inc[24];
|
||||||
|
Bit32u pg_phase[24];
|
||||||
|
Bit8u pg_reset[24];
|
||||||
|
Bit32u pg_read;
|
||||||
|
/* Envelope generator */
|
||||||
|
Bit8u eg_cycle;
|
||||||
|
Bit8u eg_cycle_stop;
|
||||||
|
Bit8u eg_shift;
|
||||||
|
Bit8u eg_shift_lock;
|
||||||
|
Bit8u eg_timer_low_lock;
|
||||||
|
Bit16u eg_timer;
|
||||||
|
Bit8u eg_timer_inc;
|
||||||
|
Bit16u eg_quotient;
|
||||||
|
Bit8u eg_custom_timer;
|
||||||
|
Bit8u eg_rate;
|
||||||
|
Bit8u eg_ksv;
|
||||||
|
Bit8u eg_inc;
|
||||||
|
Bit8u eg_ratemax;
|
||||||
|
Bit8u eg_sl[2];
|
||||||
|
Bit8u eg_lfo_am;
|
||||||
|
Bit8u eg_tl[2];
|
||||||
|
Bit8u eg_state[24];
|
||||||
|
Bit16u eg_level[24];
|
||||||
|
Bit16u eg_out[24];
|
||||||
|
Bit8u eg_kon[24];
|
||||||
|
Bit8u eg_kon_csm[24];
|
||||||
|
Bit8u eg_kon_latch[24];
|
||||||
|
Bit8u eg_csm_mode[24];
|
||||||
|
Bit8u eg_ssg_enable[24];
|
||||||
|
Bit8u eg_ssg_pgrst_latch[24];
|
||||||
|
Bit8u eg_ssg_repeat_latch[24];
|
||||||
|
Bit8u eg_ssg_hold_up_latch[24];
|
||||||
|
Bit8u eg_ssg_dir[24];
|
||||||
|
Bit8u eg_ssg_inv[24];
|
||||||
|
Bit32u eg_read[2];
|
||||||
|
Bit8u eg_read_inc;
|
||||||
|
/* FM */
|
||||||
|
Bit16s fm_op1[6][2];
|
||||||
|
Bit16s fm_op2[6];
|
||||||
|
Bit16s fm_out[24];
|
||||||
|
Bit16u fm_mod[24];
|
||||||
|
/* Channel */
|
||||||
|
Bit16s ch_acc[6];
|
||||||
|
Bit16s ch_out[6];
|
||||||
|
Bit16s ch_lock;
|
||||||
|
Bit8u ch_lock_l;
|
||||||
|
Bit8u ch_lock_r;
|
||||||
|
Bit16s ch_read;
|
||||||
|
/* Timer */
|
||||||
|
Bit16u timer_a_cnt;
|
||||||
|
Bit16u timer_a_reg;
|
||||||
|
Bit8u timer_a_load_lock;
|
||||||
|
Bit8u timer_a_load;
|
||||||
|
Bit8u timer_a_enable;
|
||||||
|
Bit8u timer_a_reset;
|
||||||
|
Bit8u timer_a_load_latch;
|
||||||
|
Bit8u timer_a_overflow_flag;
|
||||||
|
Bit8u timer_a_overflow;
|
||||||
|
|
||||||
|
Bit16u timer_b_cnt;
|
||||||
|
Bit8u timer_b_subcnt;
|
||||||
|
Bit16u timer_b_reg;
|
||||||
|
Bit8u timer_b_load_lock;
|
||||||
|
Bit8u timer_b_load;
|
||||||
|
Bit8u timer_b_enable;
|
||||||
|
Bit8u timer_b_reset;
|
||||||
|
Bit8u timer_b_load_latch;
|
||||||
|
Bit8u timer_b_overflow_flag;
|
||||||
|
Bit8u timer_b_overflow;
|
||||||
|
|
||||||
|
/* Register set */
|
||||||
|
Bit8u mode_test_21[8];
|
||||||
|
Bit8u mode_test_2c[8];
|
||||||
|
Bit8u mode_ch3;
|
||||||
|
Bit8u mode_kon_channel;
|
||||||
|
Bit8u mode_kon_operator[4];
|
||||||
|
Bit8u mode_kon[24];
|
||||||
|
Bit8u mode_csm;
|
||||||
|
Bit8u mode_kon_csm;
|
||||||
|
Bit8u dacen;
|
||||||
|
Bit16s dacdata;
|
||||||
|
|
||||||
|
Bit8u ks[24];
|
||||||
|
Bit8u ar[24];
|
||||||
|
Bit8u sr[24];
|
||||||
|
Bit8u dt[24];
|
||||||
|
Bit8u multi[24];
|
||||||
|
Bit8u sl[24];
|
||||||
|
Bit8u rr[24];
|
||||||
|
Bit8u dr[24];
|
||||||
|
Bit8u am[24];
|
||||||
|
Bit8u tl[24];
|
||||||
|
Bit8u ssg_eg[24];
|
||||||
|
|
||||||
|
Bit16u fnum[6];
|
||||||
|
Bit8u block[6];
|
||||||
|
Bit8u kcode[6];
|
||||||
|
Bit16u fnum_3ch[6];
|
||||||
|
Bit8u block_3ch[6];
|
||||||
|
Bit8u kcode_3ch[6];
|
||||||
|
Bit8u reg_a4;
|
||||||
|
Bit8u reg_ac;
|
||||||
|
Bit8u connect[6];
|
||||||
|
Bit8u fb[6];
|
||||||
|
Bit8u pan_l[6], pan_r[6];
|
||||||
|
Bit8u ams[6];
|
||||||
|
Bit8u pms[6];
|
||||||
|
Bit8u status;
|
||||||
|
Bit32u status_time;
|
||||||
|
} ym3438_t;
|
||||||
|
|
||||||
|
void OPN2_Reset(ym3438_t *chip);
|
||||||
|
void OPN2_SetChipType(Bit32u type);
|
||||||
|
void OPN2_Clock(ym3438_t *chip, Bit16s *buffer);
|
||||||
|
void OPN2_Write(ym3438_t *chip, Bit32u port, Bit8u data);
|
||||||
|
void OPN2_SetTestPin(ym3438_t *chip, Bit32u value);
|
||||||
|
Bit32u OPN2_ReadTestPin(ym3438_t *chip);
|
||||||
|
Bit32u OPN2_ReadIRQPin(ym3438_t *chip);
|
||||||
|
Bit8u OPN2_Read(ym3438_t *chip, Bit32u port);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -6,6 +6,7 @@ namespace Mesen.GUI.Config
|
||||||
{
|
{
|
||||||
public string AudioDevice = "";
|
public string AudioDevice = "";
|
||||||
public bool EnableAudio = true;
|
public bool EnableAudio = true;
|
||||||
|
public bool EnableEPSG = true;
|
||||||
|
|
||||||
public bool DisableDynamicSampleRate = false;
|
public bool DisableDynamicSampleRate = false;
|
||||||
|
|
||||||
|
@ -23,6 +24,10 @@ namespace Mesen.GUI.Config
|
||||||
[MinMax(0, 100)] public UInt32 Vrc7Volume = 100;
|
[MinMax(0, 100)] public UInt32 Vrc7Volume = 100;
|
||||||
[MinMax(0, 100)] public UInt32 Namco163Volume = 100;
|
[MinMax(0, 100)] public UInt32 Namco163Volume = 100;
|
||||||
[MinMax(0, 100)] public UInt32 Sunsoft5bVolume = 100;
|
[MinMax(0, 100)] public UInt32 Sunsoft5bVolume = 100;
|
||||||
|
[MinMax(0, 100)] public UInt32 EPSGVolume_L = 50;
|
||||||
|
[MinMax(0, 100)] public UInt32 EPSGVolume_R = 50;
|
||||||
|
|
||||||
|
[MinMax(10000, 32000000)] public UInt32 EPSGClockFrequency = 3579545;
|
||||||
|
|
||||||
[MinMax(-100, 100)] public Int32 Square1Panning = 0;
|
[MinMax(-100, 100)] public Int32 Square1Panning = 0;
|
||||||
[MinMax(-100, 100)] public Int32 Square2Panning = 0;
|
[MinMax(-100, 100)] public Int32 Square2Panning = 0;
|
||||||
|
@ -35,6 +40,8 @@ namespace Mesen.GUI.Config
|
||||||
[MinMax(-100, 100)] public Int32 Vrc7Panning = 0;
|
[MinMax(-100, 100)] public Int32 Vrc7Panning = 0;
|
||||||
[MinMax(-100, 100)] public Int32 Namco163Panning = 0;
|
[MinMax(-100, 100)] public Int32 Namco163Panning = 0;
|
||||||
[MinMax(-100, 100)] public Int32 Sunsoft5bPanning = 0;
|
[MinMax(-100, 100)] public Int32 Sunsoft5bPanning = 0;
|
||||||
|
[MinMax(-100, 100)] public Int32 EPSGPanning_L = -100;
|
||||||
|
[MinMax(-100, 100)] public Int32 EPSGPanning_R = 100;
|
||||||
|
|
||||||
[ValidValues(11025, 22050, 44100, 48000, 96000)] public UInt32 SampleRate = 48000;
|
[ValidValues(11025, 22050, 44100, 48000, 96000)] public UInt32 SampleRate = 48000;
|
||||||
public bool ReduceSoundInBackground = true;
|
public bool ReduceSoundInBackground = true;
|
||||||
|
@ -87,7 +94,7 @@ namespace Mesen.GUI.Config
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static private double ConvertVolume(UInt32 volume)
|
static public double ConvertVolume(UInt32 volume)
|
||||||
{
|
{
|
||||||
return ((double)volume / 100d);
|
return ((double)volume / 100d);
|
||||||
}
|
}
|
||||||
|
@ -114,6 +121,8 @@ namespace Mesen.GUI.Config
|
||||||
InteropEmu.SetChannelVolume(AudioChannel.VRC7, ConvertVolume(audioInfo.Vrc7Volume));
|
InteropEmu.SetChannelVolume(AudioChannel.VRC7, ConvertVolume(audioInfo.Vrc7Volume));
|
||||||
InteropEmu.SetChannelVolume(AudioChannel.Namco163, ConvertVolume(audioInfo.Namco163Volume));
|
InteropEmu.SetChannelVolume(AudioChannel.Namco163, ConvertVolume(audioInfo.Namco163Volume));
|
||||||
InteropEmu.SetChannelVolume(AudioChannel.Sunsoft5B, ConvertVolume(audioInfo.Sunsoft5bVolume));
|
InteropEmu.SetChannelVolume(AudioChannel.Sunsoft5B, ConvertVolume(audioInfo.Sunsoft5bVolume));
|
||||||
|
InteropEmu.SetChannelVolume(AudioChannel.EPSG_L, ConvertVolume(audioInfo.EPSGVolume_L));
|
||||||
|
InteropEmu.SetChannelVolume(AudioChannel.EPSG_R, ConvertVolume(audioInfo.EPSGVolume_R));
|
||||||
|
|
||||||
InteropEmu.SetChannelPanning(AudioChannel.Square1, ConvertPanning(audioInfo.Square1Panning));
|
InteropEmu.SetChannelPanning(AudioChannel.Square1, ConvertPanning(audioInfo.Square1Panning));
|
||||||
InteropEmu.SetChannelPanning(AudioChannel.Square2, ConvertPanning(audioInfo.Square2Panning));
|
InteropEmu.SetChannelPanning(AudioChannel.Square2, ConvertPanning(audioInfo.Square2Panning));
|
||||||
|
@ -126,6 +135,10 @@ namespace Mesen.GUI.Config
|
||||||
InteropEmu.SetChannelPanning(AudioChannel.VRC7, ConvertPanning(audioInfo.Vrc7Panning));
|
InteropEmu.SetChannelPanning(AudioChannel.VRC7, ConvertPanning(audioInfo.Vrc7Panning));
|
||||||
InteropEmu.SetChannelPanning(AudioChannel.Namco163, ConvertPanning(audioInfo.Namco163Panning));
|
InteropEmu.SetChannelPanning(AudioChannel.Namco163, ConvertPanning(audioInfo.Namco163Panning));
|
||||||
InteropEmu.SetChannelPanning(AudioChannel.Sunsoft5B, ConvertPanning(audioInfo.Sunsoft5bPanning));
|
InteropEmu.SetChannelPanning(AudioChannel.Sunsoft5B, ConvertPanning(audioInfo.Sunsoft5bPanning));
|
||||||
|
InteropEmu.SetChannelPanning(AudioChannel.EPSG_L, ConvertPanning(audioInfo.EPSGPanning_L));
|
||||||
|
InteropEmu.SetChannelPanning(AudioChannel.EPSG_R, ConvertPanning(audioInfo.EPSGPanning_R));
|
||||||
|
|
||||||
|
InteropEmu.SetEPSGClockFrequency(audioInfo.EPSGClockFrequency);
|
||||||
|
|
||||||
InteropEmu.SetEqualizerFilterType(audioInfo.EnableEqualizer ? audioInfo.EqualizerFilterType : EqualizerFilterType.None);
|
InteropEmu.SetEqualizerFilterType(audioInfo.EnableEqualizer ? audioInfo.EqualizerFilterType : EqualizerFilterType.None);
|
||||||
|
|
||||||
|
|
18
GUI.NET/Controls/ctrlNsfPlayer.Designer.cs
generated
18
GUI.NET/Controls/ctrlNsfPlayer.Designer.cs
generated
|
@ -46,6 +46,7 @@
|
||||||
this.lblSunsoft = new System.Windows.Forms.Label();
|
this.lblSunsoft = new System.Windows.Forms.Label();
|
||||||
this.lblVrc6 = new System.Windows.Forms.Label();
|
this.lblVrc6 = new System.Windows.Forms.Label();
|
||||||
this.lblVrc7 = new System.Windows.Forms.Label();
|
this.lblVrc7 = new System.Windows.Forms.Label();
|
||||||
|
this.lblEpsg = new System.Windows.Forms.Label();
|
||||||
this.lblSoundChips = new System.Windows.Forms.Label();
|
this.lblSoundChips = new System.Windows.Forms.Label();
|
||||||
this.trkVolume = new System.Windows.Forms.TrackBar();
|
this.trkVolume = new System.Windows.Forms.TrackBar();
|
||||||
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
|
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
|
||||||
|
@ -253,7 +254,7 @@
|
||||||
//
|
//
|
||||||
// tableLayoutPanel3
|
// tableLayoutPanel3
|
||||||
//
|
//
|
||||||
this.tableLayoutPanel3.ColumnCount = 6;
|
this.tableLayoutPanel3.ColumnCount = 7;
|
||||||
this.tlpNsfInfo.SetColumnSpan(this.tableLayoutPanel3, 2);
|
this.tlpNsfInfo.SetColumnSpan(this.tableLayoutPanel3, 2);
|
||||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||||
|
@ -267,6 +268,7 @@
|
||||||
this.tableLayoutPanel3.Controls.Add(this.lblSunsoft, 3, 0);
|
this.tableLayoutPanel3.Controls.Add(this.lblSunsoft, 3, 0);
|
||||||
this.tableLayoutPanel3.Controls.Add(this.lblVrc6, 4, 0);
|
this.tableLayoutPanel3.Controls.Add(this.lblVrc6, 4, 0);
|
||||||
this.tableLayoutPanel3.Controls.Add(this.lblVrc7, 5, 0);
|
this.tableLayoutPanel3.Controls.Add(this.lblVrc7, 5, 0);
|
||||||
|
this.tableLayoutPanel3.Controls.Add(this.lblEpsg, 6, 0);
|
||||||
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill;
|
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
this.tableLayoutPanel3.Location = new System.Drawing.Point(101, 66);
|
this.tableLayoutPanel3.Location = new System.Drawing.Point(101, 66);
|
||||||
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
|
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
|
||||||
|
@ -355,6 +357,19 @@
|
||||||
this.lblVrc7.TabIndex = 3;
|
this.lblVrc7.TabIndex = 3;
|
||||||
this.lblVrc7.Text = "VRC7";
|
this.lblVrc7.Text = "VRC7";
|
||||||
//
|
//
|
||||||
|
// lblEpsg
|
||||||
|
//
|
||||||
|
this.lblEpsg.AutoSize = true;
|
||||||
|
this.lblEpsg.BackColor = System.Drawing.Color.Transparent;
|
||||||
|
this.lblEpsg.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.lblEpsg.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.lblEpsg.Location = new System.Drawing.Point(220, 0);
|
||||||
|
this.lblEpsg.Margin = new System.Windows.Forms.Padding(0);
|
||||||
|
this.lblEpsg.Name = "lblEpsg";
|
||||||
|
this.lblEpsg.Size = new System.Drawing.Size(35, 13);
|
||||||
|
this.lblEpsg.TabIndex = 3;
|
||||||
|
this.lblEpsg.Text = "EPSG";
|
||||||
|
//
|
||||||
// lblSoundChips
|
// lblSoundChips
|
||||||
//
|
//
|
||||||
this.lblSoundChips.AutoSize = true;
|
this.lblSoundChips.AutoSize = true;
|
||||||
|
@ -728,6 +743,7 @@
|
||||||
private System.Windows.Forms.Label lblSunsoft;
|
private System.Windows.Forms.Label lblSunsoft;
|
||||||
private System.Windows.Forms.Label lblVrc6;
|
private System.Windows.Forms.Label lblVrc6;
|
||||||
private System.Windows.Forms.Label lblVrc7;
|
private System.Windows.Forms.Label lblVrc7;
|
||||||
|
private System.Windows.Forms.Label lblEpsg;
|
||||||
private System.Windows.Forms.Label lblMmc5;
|
private System.Windows.Forms.Label lblMmc5;
|
||||||
private System.Windows.Forms.Label lblNamco;
|
private System.Windows.Forms.Label lblNamco;
|
||||||
private System.Windows.Forms.Label lblFds;
|
private System.Windows.Forms.Label lblFds;
|
||||||
|
|
|
@ -274,8 +274,9 @@ namespace Mesen.GUI.Controls
|
||||||
lblMmc5.ForeColor = (header.SoundChips & 0x08) == 0x08 ? Color.White : Color.Gray;
|
lblMmc5.ForeColor = (header.SoundChips & 0x08) == 0x08 ? Color.White : Color.Gray;
|
||||||
lblNamco.ForeColor = (header.SoundChips & 0x10) == 0x10 ? Color.White : Color.Gray;
|
lblNamco.ForeColor = (header.SoundChips & 0x10) == 0x10 ? Color.White : Color.Gray;
|
||||||
lblSunsoft.ForeColor = (header.SoundChips & 0x20) == 0x20 ? Color.White : Color.Gray;
|
lblSunsoft.ForeColor = (header.SoundChips & 0x20) == 0x20 ? Color.White : Color.Gray;
|
||||||
|
lblEpsg.ForeColor = (header.SoundChips & 0x40) == 0x40 ? Color.White : Color.Gray;
|
||||||
|
|
||||||
if(InteropEmu.IsPaused()) {
|
if (InteropEmu.IsPaused()) {
|
||||||
btnPause.Image = Properties.Resources.Play;
|
btnPause.Image = Properties.Resources.Play;
|
||||||
} else {
|
} else {
|
||||||
btnPause.Image = Properties.Resources.Pause;
|
btnPause.Image = Properties.Resources.Pause;
|
||||||
|
|
17
GUI.NET/Debugger/frmApuViewer.Designer.cs
generated
17
GUI.NET/Debugger/frmApuViewer.Designer.cs
generated
|
@ -41,6 +41,7 @@
|
||||||
this.chkVrc7 = new System.Windows.Forms.CheckBox();
|
this.chkVrc7 = new System.Windows.Forms.CheckBox();
|
||||||
this.chkDmc = new System.Windows.Forms.CheckBox();
|
this.chkDmc = new System.Windows.Forms.CheckBox();
|
||||||
this.chkSunsoft = new System.Windows.Forms.CheckBox();
|
this.chkSunsoft = new System.Windows.Forms.CheckBox();
|
||||||
|
this.chkEPSG = new System.Windows.Forms.CheckBox();
|
||||||
this.chkVrc6 = new System.Windows.Forms.CheckBox();
|
this.chkVrc6 = new System.Windows.Forms.CheckBox();
|
||||||
this.grpSquare1 = new System.Windows.Forms.GroupBox();
|
this.grpSquare1 = new System.Windows.Forms.GroupBox();
|
||||||
this.ctrlSquareInfo1 = new Mesen.GUI.Debugger.Controls.ctrlSquareInfo();
|
this.ctrlSquareInfo1 = new Mesen.GUI.Debugger.Controls.ctrlSquareInfo();
|
||||||
|
@ -118,6 +119,7 @@
|
||||||
this.tableLayoutPanel2.Controls.Add(this.chkVrc7, 2, 1);
|
this.tableLayoutPanel2.Controls.Add(this.chkVrc7, 2, 1);
|
||||||
this.tableLayoutPanel2.Controls.Add(this.chkDmc, 0, 4);
|
this.tableLayoutPanel2.Controls.Add(this.chkDmc, 0, 4);
|
||||||
this.tableLayoutPanel2.Controls.Add(this.chkSunsoft, 1, 3);
|
this.tableLayoutPanel2.Controls.Add(this.chkSunsoft, 1, 3);
|
||||||
|
this.tableLayoutPanel2.Controls.Add(this.chkEPSG, 1, 4);
|
||||||
this.tableLayoutPanel2.Controls.Add(this.chkVrc6, 2, 0);
|
this.tableLayoutPanel2.Controls.Add(this.chkVrc6, 2, 0);
|
||||||
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
|
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 16);
|
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 16);
|
||||||
|
@ -271,6 +273,20 @@
|
||||||
this.chkSunsoft.UseVisualStyleBackColor = true;
|
this.chkSunsoft.UseVisualStyleBackColor = true;
|
||||||
this.chkSunsoft.CheckedChanged += new System.EventHandler(this.chkSoundChannel_CheckedChanged);
|
this.chkSunsoft.CheckedChanged += new System.EventHandler(this.chkSoundChannel_CheckedChanged);
|
||||||
//
|
//
|
||||||
|
// chkEPSG
|
||||||
|
//
|
||||||
|
this.chkEPSG.AutoSize = true;
|
||||||
|
this.chkEPSG.Checked = true;
|
||||||
|
this.chkEPSG.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||||
|
this.chkEPSG.Location = new System.Drawing.Point(99, 80);
|
||||||
|
this.chkEPSG.Margin = new System.Windows.Forms.Padding(3, 0, 3, 3);
|
||||||
|
this.chkEPSG.Name = "chkEPSG";
|
||||||
|
this.chkEPSG.Size = new System.Drawing.Size(78, 17);
|
||||||
|
this.chkEPSG.TabIndex = 10;
|
||||||
|
this.chkEPSG.Text = "EPSG";
|
||||||
|
this.chkEPSG.UseVisualStyleBackColor = true;
|
||||||
|
this.chkEPSG.CheckedChanged += new System.EventHandler(this.chkSoundChannel_CheckedChanged);
|
||||||
|
//
|
||||||
// chkVrc6
|
// chkVrc6
|
||||||
//
|
//
|
||||||
this.chkVrc6.AutoSize = true;
|
this.chkVrc6.AutoSize = true;
|
||||||
|
@ -459,5 +475,6 @@
|
||||||
private System.Windows.Forms.CheckBox chkVrc7;
|
private System.Windows.Forms.CheckBox chkVrc7;
|
||||||
private System.Windows.Forms.CheckBox chkVrc6;
|
private System.Windows.Forms.CheckBox chkVrc6;
|
||||||
private System.Windows.Forms.CheckBox chkSunsoft;
|
private System.Windows.Forms.CheckBox chkSunsoft;
|
||||||
|
private System.Windows.Forms.CheckBox chkEPSG;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -54,7 +54,9 @@ namespace Mesen.GUI.Debugger
|
||||||
}
|
}
|
||||||
|
|
||||||
private void chkSoundChannel_CheckedChanged(object sender, EventArgs e)
|
private void chkSoundChannel_CheckedChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
AudioInfo audioInfo = ConfigManager.Config.AudioInfo;
|
||||||
|
|
||||||
InteropEmu.SetChannelVolume(AudioChannel.Square1, chkSquare1.Checked ? 1 : 0);
|
InteropEmu.SetChannelVolume(AudioChannel.Square1, chkSquare1.Checked ? 1 : 0);
|
||||||
InteropEmu.SetChannelVolume(AudioChannel.Square2, chkSquare2.Checked ? 1 : 0);
|
InteropEmu.SetChannelVolume(AudioChannel.Square2, chkSquare2.Checked ? 1 : 0);
|
||||||
InteropEmu.SetChannelVolume(AudioChannel.Triangle, chkTriangle.Checked ? 1 : 0);
|
InteropEmu.SetChannelVolume(AudioChannel.Triangle, chkTriangle.Checked ? 1 : 0);
|
||||||
|
@ -66,6 +68,8 @@ namespace Mesen.GUI.Debugger
|
||||||
InteropEmu.SetChannelVolume(AudioChannel.VRC7, chkVrc7.Checked ? 1 : 0);
|
InteropEmu.SetChannelVolume(AudioChannel.VRC7, chkVrc7.Checked ? 1 : 0);
|
||||||
InteropEmu.SetChannelVolume(AudioChannel.MMC5, chkMmc5.Checked ? 1 : 0);
|
InteropEmu.SetChannelVolume(AudioChannel.MMC5, chkMmc5.Checked ? 1 : 0);
|
||||||
InteropEmu.SetChannelVolume(AudioChannel.Sunsoft5B, chkSunsoft.Checked ? 1 : 0);
|
InteropEmu.SetChannelVolume(AudioChannel.Sunsoft5B, chkSunsoft.Checked ? 1 : 0);
|
||||||
}
|
InteropEmu.SetChannelVolume(AudioChannel.EPSG_L, chkEPSG.Checked ? AudioInfo.ConvertVolume(audioInfo.EPSGVolume_L) : 0);
|
||||||
|
InteropEmu.SetChannelVolume(AudioChannel.EPSG_R, chkEPSG.Checked ? AudioInfo.ConvertVolume(audioInfo.EPSGVolume_R) : 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
3929
GUI.NET/Forms/Config/frmAudioConfig.Designer.cs
generated
3929
GUI.NET/Forms/Config/frmAudioConfig.Designer.cs
generated
File diff suppressed because it is too large
Load diff
|
@ -31,6 +31,7 @@ namespace Mesen.GUI.Forms.Config
|
||||||
cboAudioDevice.Items.AddRange(InteropEmu.GetAudioDevices().ToArray());
|
cboAudioDevice.Items.AddRange(InteropEmu.GetAudioDevices().ToArray());
|
||||||
|
|
||||||
AddBinding("EnableAudio", chkEnableAudio);
|
AddBinding("EnableAudio", chkEnableAudio);
|
||||||
|
AddBinding("EnableEPSG", chkEnableEPSG);
|
||||||
AddBinding("MasterVolume", trkMaster);
|
AddBinding("MasterVolume", trkMaster);
|
||||||
AddBinding("Square1Volume", trkSquare1Vol);
|
AddBinding("Square1Volume", trkSquare1Vol);
|
||||||
AddBinding("Square2Volume", trkSquare2Vol);
|
AddBinding("Square2Volume", trkSquare2Vol);
|
||||||
|
@ -43,6 +44,8 @@ namespace Mesen.GUI.Forms.Config
|
||||||
AddBinding("Vrc7Volume", trkVrc7Vol);
|
AddBinding("Vrc7Volume", trkVrc7Vol);
|
||||||
AddBinding("Namco163Volume", trkNamco163Vol);
|
AddBinding("Namco163Volume", trkNamco163Vol);
|
||||||
AddBinding("Sunsoft5bVolume", trkSunsoft5b);
|
AddBinding("Sunsoft5bVolume", trkSunsoft5b);
|
||||||
|
AddBinding("EPSGVolume_L", trkEPSGVol_L);
|
||||||
|
AddBinding("EPSGVolume_R", trkEPSGVol_R);
|
||||||
|
|
||||||
AddBinding("Square1Panning", trkSquare1Pan);
|
AddBinding("Square1Panning", trkSquare1Pan);
|
||||||
AddBinding("Square2Panning", trkSquare2Pan);
|
AddBinding("Square2Panning", trkSquare2Pan);
|
||||||
|
@ -55,6 +58,10 @@ namespace Mesen.GUI.Forms.Config
|
||||||
AddBinding("Vrc7Panning", trkVrc7Pan);
|
AddBinding("Vrc7Panning", trkVrc7Pan);
|
||||||
AddBinding("Namco163Panning", trkNamcoPan);
|
AddBinding("Namco163Panning", trkNamcoPan);
|
||||||
AddBinding("Sunsoft5bPanning", trkSunsoftPan);
|
AddBinding("Sunsoft5bPanning", trkSunsoftPan);
|
||||||
|
AddBinding("EPSGPanning_L", trkEPSGPan_L);
|
||||||
|
AddBinding("EPSGPanning_R", trkEPSGPan_R);
|
||||||
|
|
||||||
|
AddBinding("EPSGClockFrequency", nudEPSGClockFrequency);
|
||||||
|
|
||||||
AddBinding("AudioLatency", nudLatency);
|
AddBinding("AudioLatency", nudLatency);
|
||||||
AddBinding("SampleRate", cboSampleRate);
|
AddBinding("SampleRate", cboSampleRate);
|
||||||
|
|
|
@ -208,6 +208,7 @@ namespace Mesen.GUI
|
||||||
[DllImport(DLLPath)] public static extern void SetBandGain(int band, double gain);
|
[DllImport(DLLPath)] public static extern void SetBandGain(int band, double gain);
|
||||||
[DllImport(DLLPath)] public static extern void SetSampleRate(UInt32 sampleRate);
|
[DllImport(DLLPath)] public static extern void SetSampleRate(UInt32 sampleRate);
|
||||||
[DllImport(DLLPath)] public static extern void SetAudioLatency(UInt32 msLatency);
|
[DllImport(DLLPath)] public static extern void SetAudioLatency(UInt32 msLatency);
|
||||||
|
[DllImport(DLLPath)] public static extern void SetEPSGClockFrequency(UInt32 clockFrequency);
|
||||||
[DllImport(DLLPath)] public static extern void SetAudioFilterSettings(AudioFilterSettings settings);
|
[DllImport(DLLPath)] public static extern void SetAudioFilterSettings(AudioFilterSettings settings);
|
||||||
[DllImport(DLLPath)] public static extern void SetRunAheadFrames(UInt32 frameCount);
|
[DllImport(DLLPath)] public static extern void SetRunAheadFrames(UInt32 frameCount);
|
||||||
|
|
||||||
|
@ -2298,8 +2299,10 @@ namespace Mesen.GUI
|
||||||
VRC6 = 7,
|
VRC6 = 7,
|
||||||
VRC7 = 8,
|
VRC7 = 8,
|
||||||
Namco163 = 9,
|
Namco163 = 9,
|
||||||
Sunsoft5B = 10
|
Sunsoft5B = 10,
|
||||||
}
|
EPSG_L = 11,
|
||||||
|
EPSG_R= 12
|
||||||
|
}
|
||||||
|
|
||||||
public enum EqualizerFilterType
|
public enum EqualizerFilterType
|
||||||
{
|
{
|
||||||
|
|
|
@ -633,6 +633,7 @@ namespace InteropEmu {
|
||||||
DllExport void __stdcall SetMasterVolume(double volume, double volumeReduction, ConsoleId consoleId) { GetConsoleById(consoleId)->GetSettings()->SetMasterVolume(volume, volumeReduction); }
|
DllExport void __stdcall SetMasterVolume(double volume, double volumeReduction, ConsoleId consoleId) { GetConsoleById(consoleId)->GetSettings()->SetMasterVolume(volume, volumeReduction); }
|
||||||
DllExport void __stdcall SetSampleRate(uint32_t sampleRate) { _settings->SetSampleRate(sampleRate); }
|
DllExport void __stdcall SetSampleRate(uint32_t sampleRate) { _settings->SetSampleRate(sampleRate); }
|
||||||
DllExport void __stdcall SetAudioLatency(uint32_t msLatency) { _settings->SetAudioLatency(msLatency); }
|
DllExport void __stdcall SetAudioLatency(uint32_t msLatency) { _settings->SetAudioLatency(msLatency); }
|
||||||
|
DllExport void __stdcall SetEPSGClockFrequency(uint32_t clockFrequency) { _settings->SetEPSGClockFrequency(clockFrequency); }
|
||||||
DllExport void __stdcall SetAudioFilterSettings(AudioFilterSettings settings) { _settings->SetAudioFilterSettings(settings); }
|
DllExport void __stdcall SetAudioFilterSettings(AudioFilterSettings settings) { _settings->SetAudioFilterSettings(settings); }
|
||||||
DllExport void __stdcall SetRunAheadFrames(uint32_t frameCount) { _settings->SetRunAheadFrames(frameCount); }
|
DllExport void __stdcall SetRunAheadFrames(uint32_t frameCount) { _settings->SetRunAheadFrames(frameCount); }
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue