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"
|
||||
|
||||
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; }
|
||||
void BaseMapper::InitMapper(RomData &romData) { }
|
||||
void BaseMapper::Reset(bool softReset) { }
|
||||
|
@ -508,8 +509,9 @@ void BaseMapper::StreamState(bool saving)
|
|||
ArrayInfo<ChrMemoryType> chrMemoryType = { _chrMemoryType, 0x40 };
|
||||
ArrayInfo<MemoryAccessType> prgMemoryAccess = { _prgMemoryAccess, 0x100 };
|
||||
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) {
|
||||
RestorePrgChrState();
|
||||
|
@ -636,6 +638,7 @@ void BaseMapper::Initialize(RomData &romData)
|
|||
|
||||
InitMapper();
|
||||
InitMapper(romData);
|
||||
_epsgaudio.reset(new EPSGAudio(_console));
|
||||
|
||||
//Load battery data if present
|
||||
LoadBattery();
|
||||
|
@ -778,6 +781,7 @@ uint8_t BaseMapper::DebugReadRAM(uint16_t addr)
|
|||
|
||||
void BaseMapper::WriteRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
if(addr == 0x4016){ WriteEPSG(addr, value); }
|
||||
if(_isWriteRegisterAddr[addr]) {
|
||||
if(_hasBusConflicts) {
|
||||
uint8_t prgValue = _prgPages[addr >> 8][(uint8_t)addr];
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "IBattery.h"
|
||||
#include "RomData.h"
|
||||
#include "Console.h"
|
||||
#include "CPU.h"
|
||||
#include "EPSGAudio.h"
|
||||
|
||||
class BaseControlDevice;
|
||||
|
||||
|
@ -104,6 +106,7 @@ protected:
|
|||
uint8_t InternalReadRam(uint16_t addr);
|
||||
|
||||
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);
|
||||
|
||||
void SelectPrgPage4x(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom);
|
||||
|
@ -155,7 +158,7 @@ protected:
|
|||
public:
|
||||
static constexpr uint32_t NametableCount = 0x10;
|
||||
static constexpr uint32_t NametableSize = 0x400;
|
||||
|
||||
unique_ptr<EPSGAudio> _epsgaudio;
|
||||
void Initialize(RomData &romData);
|
||||
|
||||
virtual ~BaseMapper();
|
||||
|
@ -165,6 +168,7 @@ public:
|
|||
|
||||
virtual void SetNesModel(NesModel model) { }
|
||||
virtual void ProcessCpuClock() { }
|
||||
virtual void ProcessEPSGClock() { _epsgaudio->Clock(); }
|
||||
virtual void NotifyVRAMAddressChange(uint16_t addr);
|
||||
virtual void GetMemoryRanges(MemoryRanges &ranges) override;
|
||||
|
||||
|
|
|
@ -465,6 +465,7 @@ bool Console::Initialize(VirtualFile &romFile, VirtualFile &patchFile, bool forP
|
|||
|
||||
void Console::ProcessCpuClock()
|
||||
{
|
||||
_mapper->ProcessEPSGClock();
|
||||
_mapper->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">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
|
@ -558,6 +558,8 @@
|
|||
<ClInclude Include="DummyCpu.h" />
|
||||
<ClInclude Include="Eeprom24C01.h" />
|
||||
<ClInclude Include="Eeprom24C02.h" />
|
||||
<ClInclude Include="emu2149.h" />
|
||||
<ClInclude Include="EPSGAudio.h" />
|
||||
<ClInclude Include="EventManager.h" />
|
||||
<ClInclude Include="FaridSlrom.h" />
|
||||
<ClInclude Include="FaridUnrom.h" />
|
||||
|
@ -586,12 +588,14 @@
|
|||
<ClInclude Include="NESHeader.h" />
|
||||
<ClInclude Include="NotificationManager.h" />
|
||||
<ClInclude Include="OpenBusHandler.h" />
|
||||
<ClInclude Include="opll.h" />
|
||||
<ClInclude Include="PerformanceTracker.h" />
|
||||
<ClInclude Include="RawVideoFilter.h" />
|
||||
<ClInclude Include="ResetTxrom.h" />
|
||||
<ClInclude Include="Sachen9602.h" />
|
||||
<ClInclude Include="ServerInformationMessage.h" />
|
||||
<ClInclude Include="FamicomBox.h" />
|
||||
<ClInclude Include="SSGAudio.h" />
|
||||
<ClInclude Include="StereoCombFilter.h" />
|
||||
<ClInclude Include="StudyBoxLoader.h" />
|
||||
<ClInclude Include="SystemActionManager.h" />
|
||||
|
@ -982,6 +986,7 @@
|
|||
<ClInclude Include="Waixing178.h" />
|
||||
<ClInclude Include="Waixing252.h" />
|
||||
<ClInclude Include="WaveRecorder.h" />
|
||||
<ClInclude Include="ym3438.h" />
|
||||
<ClInclude Include="Yoko.h" />
|
||||
<ClInclude Include="Zapper.h" />
|
||||
<ClInclude Include="PgoUtilities.h" />
|
||||
|
@ -996,6 +1001,7 @@
|
|||
<ClCompile Include="BatteryManager.cpp" />
|
||||
<ClCompile Include="DebugHud.cpp" />
|
||||
<ClCompile Include="DrawRectangleCommand.h" />
|
||||
<ClCompile Include="emu2149.cpp" />
|
||||
<ClCompile Include="EventManager.cpp" />
|
||||
<ClCompile Include="FceuxMovie.cpp" />
|
||||
<ClCompile Include="FdsLoader.cpp" />
|
||||
|
@ -1016,6 +1022,7 @@
|
|||
<ClCompile Include="NsfPpu.cpp" />
|
||||
<ClCompile Include="OggMixer.cpp" />
|
||||
<ClCompile Include="OggReader.cpp" />
|
||||
<ClCompile Include="opll.cpp" />
|
||||
<ClCompile Include="PerformanceTracker.cpp" />
|
||||
<ClCompile Include="PgoUtilities.cpp" />
|
||||
<ClCompile Include="RawVideoFilter.cpp" />
|
||||
|
@ -1098,6 +1105,7 @@
|
|||
<ClCompile Include="VsControlManager.cpp" />
|
||||
<ClCompile Include="ScaleFilter.cpp" />
|
||||
<ClCompile Include="WaveRecorder.cpp" />
|
||||
<ClCompile Include="ym3438.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<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">
|
||||
<ItemGroup>
|
||||
<Filter Include="Debugger">
|
||||
|
@ -116,6 +116,9 @@
|
|||
<Filter Include="Nes\MemoryManager">
|
||||
<UniqueIdentifier>{13af8497-e820-43f1-9888-85797a29b551}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Nes\Mappers\EPSG">
|
||||
<UniqueIdentifier>{c9c48ea8-7684-4959-9266-c0b4f0f86956}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="IAudioDevice.h">
|
||||
|
@ -1502,6 +1505,21 @@
|
|||
<ClInclude Include="VbController.h">
|
||||
<Filter>Nes\Input\Controllers</Filter>
|
||||
</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>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
@ -1804,5 +1822,14 @@
|
|||
<ClCompile Include="StudyBoxLoader.cpp">
|
||||
<Filter>Misc</Filter>
|
||||
</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>
|
||||
</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,
|
||||
VRC7 = 8,
|
||||
Namco163 = 9,
|
||||
Sunsoft5B = 10
|
||||
Sunsoft5B = 10,
|
||||
EPSG_L = 11,
|
||||
EPSG_R = 12,
|
||||
};
|
||||
|
||||
enum class EqualizerFilterType
|
||||
|
@ -657,8 +659,9 @@ private:
|
|||
|
||||
bool _audioSettingsChanged = false;
|
||||
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 };
|
||||
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 };
|
||||
uint32_t _EPSGClockFrequency = 3579545;
|
||||
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;
|
||||
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 } };
|
||||
|
@ -987,6 +990,12 @@ public:
|
|||
_audioSettingsChanged = true;
|
||||
}
|
||||
|
||||
void SetEPSGClockFrequency(uint32_t clockFrequency)
|
||||
{
|
||||
_EPSGClockFrequency = clockFrequency;
|
||||
_audioSettingsChanged = true;
|
||||
}
|
||||
|
||||
void SetAudioFilterSettings(AudioFilterSettings settings)
|
||||
{
|
||||
_audioFilterSettings = settings;
|
||||
|
@ -1158,6 +1167,11 @@ public:
|
|||
return _audioLatency;
|
||||
}
|
||||
|
||||
uint32_t GetEPSGClockFrequency()
|
||||
{
|
||||
return _EPSGClockFrequency;
|
||||
}
|
||||
|
||||
void SetVideoFilterType(VideoFilterType videoFilterType)
|
||||
{
|
||||
_videoFilterType = videoFilterType;
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
#include "EmulationSettings.h"
|
||||
#include "A12Watcher.h"
|
||||
|
||||
|
||||
class MMC3 : public BaseMapper
|
||||
{
|
||||
|
||||
private:
|
||||
enum class MMC3Registers
|
||||
{
|
||||
|
@ -200,6 +202,7 @@ class MMC3 : public BaseMapper
|
|||
|
||||
virtual void InitMapper() override
|
||||
{
|
||||
|
||||
//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.
|
||||
_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)) {
|
||||
_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) {
|
||||
chips.push_back("Namco 163");
|
||||
}
|
||||
if(header.SoundChips & 0x20) {
|
||||
if (header.SoundChips & 0x20) {
|
||||
chips.push_back("Sunsoft 5B");
|
||||
}
|
||||
if (header.SoundChips & 0x40) {
|
||||
chips.push_back("EPSG");
|
||||
}
|
||||
if(chips.empty()) {
|
||||
chips.push_back("<none>");
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ void NsfMapper::InitMapper()
|
|||
_fdsAudio.reset(new FdsAudio(_console));
|
||||
_namcoAudio.reset(new Namco163Audio(_console));
|
||||
_sunsoftAudio.reset(new Sunsoft5bAudio(_console));
|
||||
_epsgAudio.reset(new EPSGAudio(_console));
|
||||
|
||||
SetCpuMemoryMapping(0x3F00, 0x3FFF, PrgMemoryType::WorkRam, 0x2000, MemoryAccessType::Read);
|
||||
memcpy(GetWorkRam() + 0x2000, _nsfBios, 0x100);
|
||||
|
@ -107,6 +108,10 @@ void NsfMapper::InitMapper(RomData& romData)
|
|||
if(_nsfHeader.SoundChips & NsfSoundChips::FDS) {
|
||||
AddRegisterRange(0x4040, 0x4092, MemoryOperation::Any);
|
||||
}
|
||||
|
||||
if(_nsfHeader.SoundChips & NsfSoundChips::EPSG) {
|
||||
AddRegisterRange(0x4016, 0x4016, MemoryOperation::Write);
|
||||
}
|
||||
}
|
||||
|
||||
void NsfMapper::Reset(bool softReset)
|
||||
|
@ -272,6 +277,9 @@ void NsfMapper::ProcessCpuClock()
|
|||
if(_nsfHeader.SoundChips & NsfSoundChips::FDS) {
|
||||
_fdsAudio->Clock();
|
||||
}
|
||||
if (_nsfHeader.SoundChips & NsfSoundChips::EPSG) {
|
||||
_epsgAudio->Clock();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t NsfMapper::ReadRegister(uint16_t addr)
|
||||
|
@ -397,7 +405,11 @@ void NsfMapper::WriteRegister(uint16_t addr, uint8_t value)
|
|||
break;
|
||||
|
||||
case 0x9010: case 0x9030:
|
||||
_vrc7Audio->WriteReg(addr, value);
|
||||
_vrc7Audio->WriteRegister(addr, value);
|
||||
break;
|
||||
|
||||
case 0x4016:
|
||||
_epsgAudio->WriteRegister(addr, value);
|
||||
break;
|
||||
|
||||
}
|
||||
|
@ -478,10 +490,11 @@ void NsfMapper::StreamState(bool saving)
|
|||
SnapshotInfo fdsAudio { _fdsAudio.get() };
|
||||
SnapshotInfo namcoAudio { _namcoAudio.get() };
|
||||
SnapshotInfo sunsoftAudio { _sunsoftAudio.get() };
|
||||
SnapshotInfo epsgAudio{ _epsgAudio.get() };
|
||||
|
||||
Stream(
|
||||
_model, _needInit, _irqEnabled, _irqReloadValue, _irqCounter, _irqStatus, _debugIrqStatus, _mmc5MultiplierValues[0], _mmc5MultiplierValues[1],
|
||||
_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 "Namco163Audio.h"
|
||||
#include "Sunsoft5bAudio.h"
|
||||
#include "EPSGAudio.h"
|
||||
|
||||
enum class NsfIrqType
|
||||
{
|
||||
|
@ -25,7 +26,8 @@ private:
|
|||
FDS = 0x04,
|
||||
MMC5 = 0x08,
|
||||
Namco = 0x10,
|
||||
Sunsoft = 0x20
|
||||
Sunsoft = 0x20,
|
||||
EPSG = 0x40
|
||||
};
|
||||
|
||||
NesModel _model;
|
||||
|
@ -37,6 +39,7 @@ private:
|
|||
unique_ptr<FdsAudio> _fdsAudio;
|
||||
unique_ptr<Namco163Audio> _namcoAudio;
|
||||
unique_ptr<Sunsoft5bAudio> _sunsoftAudio;
|
||||
unique_ptr<EPSGAudio> _epsgAudio;
|
||||
|
||||
bool _needInit = 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::Sunsoft5B, forRightChannel) * 15 +
|
||||
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)
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
private:
|
||||
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 MaxChannelCount = 11;
|
||||
static constexpr uint32_t MaxChannelCount = 13;
|
||||
|
||||
IAudioDevice* _audioDevice;
|
||||
EmulationSettings* _settings;
|
||||
|
|
|
@ -2,130 +2,7 @@
|
|||
#include "stdafx.h"
|
||||
#include "Snapshotable.h"
|
||||
#include "APU.h"
|
||||
#include "BaseExpansionAudio.h"
|
||||
#include "SSGAudio.h"
|
||||
#include "Console.h"
|
||||
|
||||
class Sunsoft5bAudio : 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];
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
using Sunsoft5bAudio = SSGAudio<AudioChannel::Sunsoft5B>;
|
|
@ -63,7 +63,7 @@ protected:
|
|||
|
||||
UpdatePrgRamAccess();
|
||||
|
||||
_audio->SetMuteAudio((_controlFlags & 0x40) != 0);
|
||||
//_audio->SetMuteAudio((_controlFlags & 0x40) != 0);
|
||||
}
|
||||
|
||||
void WriteRegister(uint16_t addr, uint8_t value) override
|
||||
|
@ -78,7 +78,7 @@ protected:
|
|||
case 0x8008: SelectPRGPage(1, 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 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
|
||||
#include "stdafx.h"
|
||||
#include "BaseExpansionAudio.h"
|
||||
|
@ -16,12 +166,12 @@ private:
|
|||
protected:
|
||||
void ClockAudio() override
|
||||
{
|
||||
if(_clockTimer == 0) {
|
||||
if (_clockTimer == 0) {
|
||||
_clockTimer = ((double)_console->GetCpu()->GetClockRate(_console->GetModel())) / 49716;
|
||||
}
|
||||
|
||||
_clockTimer--;
|
||||
if(_clockTimer <= 0) {
|
||||
if (_clockTimer <= 0) {
|
||||
int16_t output = _opllEmulator->GetOutput();
|
||||
_console->GetApu()->AddExpansionAudioDelta(AudioChannel::VRC7, _muted ? 0 : (output - _previousOutput));
|
||||
_previousOutput = output;
|
||||
|
@ -52,15 +202,17 @@ public:
|
|||
_muted = muted;
|
||||
}
|
||||
|
||||
void WriteReg(uint16_t addr, uint8_t value)
|
||||
void WriteRegister(uint16_t addr, uint8_t value)
|
||||
{
|
||||
switch(addr & 0xF030) {
|
||||
case 0x9010:
|
||||
_currentReg = value;
|
||||
break;
|
||||
case 0x9030:
|
||||
_opllEmulator->WriteReg(_currentReg, value);
|
||||
break;
|
||||
switch (addr & 0xF030) {
|
||||
case 0x9010:
|
||||
_currentReg = value;
|
||||
break;
|
||||
case 0x9030:
|
||||
_opllEmulator->WriteReg(_currentReg, value);
|
||||
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 bool EnableAudio = true;
|
||||
public bool EnableEPSG = true;
|
||||
|
||||
public bool DisableDynamicSampleRate = false;
|
||||
|
||||
|
@ -23,6 +24,10 @@ namespace Mesen.GUI.Config
|
|||
[MinMax(0, 100)] public UInt32 Vrc7Volume = 100;
|
||||
[MinMax(0, 100)] public UInt32 Namco163Volume = 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 Square2Panning = 0;
|
||||
|
@ -35,6 +40,8 @@ namespace Mesen.GUI.Config
|
|||
[MinMax(-100, 100)] public Int32 Vrc7Panning = 0;
|
||||
[MinMax(-100, 100)] public Int32 Namco163Panning = 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;
|
||||
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);
|
||||
}
|
||||
|
@ -114,6 +121,8 @@ namespace Mesen.GUI.Config
|
|||
InteropEmu.SetChannelVolume(AudioChannel.VRC7, ConvertVolume(audioInfo.Vrc7Volume));
|
||||
InteropEmu.SetChannelVolume(AudioChannel.Namco163, ConvertVolume(audioInfo.Namco163Volume));
|
||||
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.Square2, ConvertPanning(audioInfo.Square2Panning));
|
||||
|
@ -126,6 +135,10 @@ namespace Mesen.GUI.Config
|
|||
InteropEmu.SetChannelPanning(AudioChannel.VRC7, ConvertPanning(audioInfo.Vrc7Panning));
|
||||
InteropEmu.SetChannelPanning(AudioChannel.Namco163, ConvertPanning(audioInfo.Namco163Panning));
|
||||
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);
|
||||
|
||||
|
|
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.lblVrc6 = 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.trkVolume = new System.Windows.Forms.TrackBar();
|
||||
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
|
@ -253,7 +254,7 @@
|
|||
//
|
||||
// tableLayoutPanel3
|
||||
//
|
||||
this.tableLayoutPanel3.ColumnCount = 6;
|
||||
this.tableLayoutPanel3.ColumnCount = 7;
|
||||
this.tlpNsfInfo.SetColumnSpan(this.tableLayoutPanel3, 2);
|
||||
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.lblVrc6, 4, 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.Location = new System.Drawing.Point(101, 66);
|
||||
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
|
||||
|
@ -355,6 +357,19 @@
|
|||
this.lblVrc7.TabIndex = 3;
|
||||
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
|
||||
//
|
||||
this.lblSoundChips.AutoSize = true;
|
||||
|
@ -728,6 +743,7 @@
|
|||
private System.Windows.Forms.Label lblSunsoft;
|
||||
private System.Windows.Forms.Label lblVrc6;
|
||||
private System.Windows.Forms.Label lblVrc7;
|
||||
private System.Windows.Forms.Label lblEpsg;
|
||||
private System.Windows.Forms.Label lblMmc5;
|
||||
private System.Windows.Forms.Label lblNamco;
|
||||
private System.Windows.Forms.Label lblFds;
|
||||
|
|
|
@ -274,8 +274,9 @@ namespace Mesen.GUI.Controls
|
|||
lblMmc5.ForeColor = (header.SoundChips & 0x08) == 0x08 ? Color.White : Color.Gray;
|
||||
lblNamco.ForeColor = (header.SoundChips & 0x10) == 0x10 ? 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;
|
||||
} else {
|
||||
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.chkDmc = 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.grpSquare1 = new System.Windows.Forms.GroupBox();
|
||||
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.chkDmc, 0, 4);
|
||||
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.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 16);
|
||||
|
@ -271,6 +273,20 @@
|
|||
this.chkSunsoft.UseVisualStyleBackColor = true;
|
||||
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
|
||||
//
|
||||
this.chkVrc6.AutoSize = true;
|
||||
|
@ -459,5 +475,6 @@
|
|||
private System.Windows.Forms.CheckBox chkVrc7;
|
||||
private System.Windows.Forms.CheckBox chkVrc6;
|
||||
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)
|
||||
{
|
||||
{
|
||||
AudioInfo audioInfo = ConfigManager.Config.AudioInfo;
|
||||
|
||||
InteropEmu.SetChannelVolume(AudioChannel.Square1, chkSquare1.Checked ? 1 : 0);
|
||||
InteropEmu.SetChannelVolume(AudioChannel.Square2, chkSquare2.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.MMC5, chkMmc5.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());
|
||||
|
||||
AddBinding("EnableAudio", chkEnableAudio);
|
||||
AddBinding("EnableEPSG", chkEnableEPSG);
|
||||
AddBinding("MasterVolume", trkMaster);
|
||||
AddBinding("Square1Volume", trkSquare1Vol);
|
||||
AddBinding("Square2Volume", trkSquare2Vol);
|
||||
|
@ -43,6 +44,8 @@ namespace Mesen.GUI.Forms.Config
|
|||
AddBinding("Vrc7Volume", trkVrc7Vol);
|
||||
AddBinding("Namco163Volume", trkNamco163Vol);
|
||||
AddBinding("Sunsoft5bVolume", trkSunsoft5b);
|
||||
AddBinding("EPSGVolume_L", trkEPSGVol_L);
|
||||
AddBinding("EPSGVolume_R", trkEPSGVol_R);
|
||||
|
||||
AddBinding("Square1Panning", trkSquare1Pan);
|
||||
AddBinding("Square2Panning", trkSquare2Pan);
|
||||
|
@ -55,6 +58,10 @@ namespace Mesen.GUI.Forms.Config
|
|||
AddBinding("Vrc7Panning", trkVrc7Pan);
|
||||
AddBinding("Namco163Panning", trkNamcoPan);
|
||||
AddBinding("Sunsoft5bPanning", trkSunsoftPan);
|
||||
AddBinding("EPSGPanning_L", trkEPSGPan_L);
|
||||
AddBinding("EPSGPanning_R", trkEPSGPan_R);
|
||||
|
||||
AddBinding("EPSGClockFrequency", nudEPSGClockFrequency);
|
||||
|
||||
AddBinding("AudioLatency", nudLatency);
|
||||
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 SetSampleRate(UInt32 sampleRate);
|
||||
[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 SetRunAheadFrames(UInt32 frameCount);
|
||||
|
||||
|
@ -2298,8 +2299,10 @@ namespace Mesen.GUI
|
|||
VRC6 = 7,
|
||||
VRC7 = 8,
|
||||
Namco163 = 9,
|
||||
Sunsoft5B = 10
|
||||
}
|
||||
Sunsoft5B = 10,
|
||||
EPSG_L = 11,
|
||||
EPSG_R= 12
|
||||
}
|
||||
|
||||
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 SetSampleRate(uint32_t sampleRate) { _settings->SetSampleRate(sampleRate); }
|
||||
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 SetRunAheadFrames(uint32_t frameCount) { _settings->SetRunAheadFrames(frameCount); }
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue