Merge pull request #20 from Perkka2/master

Adding basic EPSG support, Replacing old VRC7 with Nuked-OPLL
This commit is contained in:
NovaSquirrel 2021-02-24 12:16:19 -05:00 committed by GitHub
commit d7d919a392
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 6139 additions and 2051 deletions

View file

@ -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];

View file

@ -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;

View file

@ -465,6 +465,7 @@ bool Console::Initialize(VirtualFile &romFile, VirtualFile &patchFile, bool forP
void Console::ProcessCpuClock()
{
_mapper->ProcessEPSGClock();
_mapper->ProcessCpuClock();
_apu->ProcessCpuClock();
}

View file

@ -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">

View file

@ -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
View 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;
}
}
};

View file

@ -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;

View file

@ -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;

View file

@ -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);
}
}
}

View file

@ -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>");
}

View file

@ -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
);
}

View file

@ -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
View 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;
}
}
};

View file

@ -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)

View file

@ -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;

View file

@ -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>;

View file

@ -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;

View file

@ -1,5 +1,155 @@
#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"
#include "Console.h"
#include "OpllEmulator.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,9 +202,9 @@ public:
_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:
_currentReg = value;
break;
@ -64,3 +214,5 @@ public:
}
}
};
#endif

375
Core/emu2149.cpp Normal file
View 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
View 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

File diff suppressed because it is too large Load diff

199
Core/opll.h Normal file
View 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

File diff suppressed because it is too large Load diff

211
Core/ym3438.h Normal file
View 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

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;
}
}

View file

@ -55,6 +55,8 @@ 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);
}
}
}

View file

@ -43,9 +43,12 @@ namespace Mesen.GUI.Forms.Config
this.trkVrc7Vol = new Mesen.GUI.Controls.ctrlTrackbar();
this.trkNamco163Vol = new Mesen.GUI.Controls.ctrlTrackbar();
this.trkSunsoft5b = new Mesen.GUI.Controls.ctrlTrackbar();
this.trkEPSGVol_L = new Mesen.GUI.Controls.ctrlTrackbar();
this.trkEPSGVol_R = new Mesen.GUI.Controls.ctrlTrackbar();
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
this.lblVolumeReductionSettings = new System.Windows.Forms.Label();
this.chkEnableAudio = new System.Windows.Forms.CheckBox();
this.chkEnableEPSG = new System.Windows.Forms.CheckBox();
this.lblSampleRate = new System.Windows.Forms.Label();
this.lblAudioLatency = new System.Windows.Forms.Label();
this.cboSampleRate = new System.Windows.Forms.ComboBox();
@ -78,6 +81,8 @@ namespace Mesen.GUI.Forms.Config
this.trkVrc7Pan = new Mesen.GUI.Controls.ctrlHorizontalTrackbar();
this.trkNamcoPan = new Mesen.GUI.Controls.ctrlHorizontalTrackbar();
this.trkSunsoftPan = new Mesen.GUI.Controls.ctrlHorizontalTrackbar();
this.trkEPSGPan_L = new Mesen.GUI.Controls.ctrlHorizontalTrackbar();
this.trkEPSGPan_R = new Mesen.GUI.Controls.ctrlHorizontalTrackbar();
this.tpgEqualizer = new System.Windows.Forms.TabPage();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.chkEnableEqualizer = new System.Windows.Forms.CheckBox();
@ -142,6 +147,8 @@ namespace Mesen.GUI.Forms.Config
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
this.chkDisableDynamicSampleRate = new Mesen.GUI.Controls.ctrlRiskyOption();
this.chkDisableNoiseModeFlag = new Mesen.GUI.Controls.ctrlRiskyOption();
this.nudEPSGClockFrequency = new Mesen.GUI.Controls.MesenNumericUpDown();
this.lblEPSGClockFrequency = new System.Windows.Forms.Label();
this.chkSilenceTriangleHighFreq = new System.Windows.Forms.CheckBox();
this.chkSwapDutyCycles = new Mesen.GUI.Controls.ctrlRiskyOption();
this.chkReduceDmcPopping = new System.Windows.Forms.CheckBox();
@ -179,7 +186,7 @@ namespace Mesen.GUI.Forms.Config
// baseConfigPanel
//
this.baseConfigPanel.Controls.Add(this.btnReset);
this.baseConfigPanel.Location = new System.Drawing.Point(0, 373);
this.baseConfigPanel.Location = new System.Drawing.Point(0, 421);
this.baseConfigPanel.Size = new System.Drawing.Size(477, 29);
this.baseConfigPanel.Controls.SetChildIndex(this.btnReset, 0);
//
@ -189,20 +196,21 @@ namespace Mesen.GUI.Forms.Config
this.grpVolume.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpVolume.Location = new System.Drawing.Point(3, 3);
this.grpVolume.Name = "grpVolume";
this.grpVolume.Size = new System.Drawing.Size(463, 341);
this.grpVolume.Size = new System.Drawing.Size(463, 357);
this.grpVolume.TabIndex = 2;
this.grpVolume.TabStop = false;
this.grpVolume.Text = "Volume";
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 6;
this.tableLayoutPanel1.ColumnCount = 7;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel1.Controls.Add(this.trkDmcVol, 5, 0);
this.tableLayoutPanel1.Controls.Add(this.trkNoiseVol, 4, 0);
this.tableLayoutPanel1.Controls.Add(this.trkTriangleVol, 3, 0);
@ -214,7 +222,9 @@ namespace Mesen.GUI.Forms.Config
this.tableLayoutPanel1.Controls.Add(this.trkVrc6Vol, 2, 1);
this.tableLayoutPanel1.Controls.Add(this.trkVrc7Vol, 3, 1);
this.tableLayoutPanel1.Controls.Add(this.trkNamco163Vol, 4, 1);
this.tableLayoutPanel1.Controls.Add(this.trkSunsoft5b, 5, 1);
this.tableLayoutPanel1.Controls.Add(this.trkSunsoft5b, 6, 0);
this.tableLayoutPanel1.Controls.Add(this.trkEPSGVol_L, 5, 1);
this.tableLayoutPanel1.Controls.Add(this.trkEPSGVol_R, 6, 1);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 16);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
@ -222,13 +232,13 @@ namespace Mesen.GUI.Forms.Config
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(457, 322);
this.tableLayoutPanel1.Size = new System.Drawing.Size(457, 338);
this.tableLayoutPanel1.TabIndex = 2;
//
// trkDmcVol
//
this.trkDmcVol.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkDmcVol.Location = new System.Drawing.Point(387, 0);
this.trkDmcVol.Location = new System.Drawing.Point(364, 0);
this.trkDmcVol.Margin = new System.Windows.Forms.Padding(0);
this.trkDmcVol.Maximum = 100;
this.trkDmcVol.MaximumSize = new System.Drawing.Size(63, 160);
@ -243,7 +253,7 @@ namespace Mesen.GUI.Forms.Config
// trkNoiseVol
//
this.trkNoiseVol.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkNoiseVol.Location = new System.Drawing.Point(310, 0);
this.trkNoiseVol.Location = new System.Drawing.Point(292, 0);
this.trkNoiseVol.Margin = new System.Windows.Forms.Padding(0);
this.trkNoiseVol.Maximum = 100;
this.trkNoiseVol.MaximumSize = new System.Drawing.Size(63, 160);
@ -258,7 +268,7 @@ namespace Mesen.GUI.Forms.Config
// trkTriangleVol
//
this.trkTriangleVol.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkTriangleVol.Location = new System.Drawing.Point(234, 0);
this.trkTriangleVol.Location = new System.Drawing.Point(220, 0);
this.trkTriangleVol.Margin = new System.Windows.Forms.Padding(0);
this.trkTriangleVol.Maximum = 100;
this.trkTriangleVol.MaximumSize = new System.Drawing.Size(63, 160);
@ -273,7 +283,7 @@ namespace Mesen.GUI.Forms.Config
// trkSquare2Vol
//
this.trkSquare2Vol.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkSquare2Vol.Location = new System.Drawing.Point(158, 0);
this.trkSquare2Vol.Location = new System.Drawing.Point(148, 0);
this.trkSquare2Vol.Margin = new System.Windows.Forms.Padding(0);
this.trkSquare2Vol.Maximum = 100;
this.trkSquare2Vol.MaximumSize = new System.Drawing.Size(63, 160);
@ -288,7 +298,7 @@ namespace Mesen.GUI.Forms.Config
// trkSquare1Vol
//
this.trkSquare1Vol.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkSquare1Vol.Location = new System.Drawing.Point(82, 0);
this.trkSquare1Vol.Location = new System.Drawing.Point(76, 0);
this.trkSquare1Vol.Margin = new System.Windows.Forms.Padding(0);
this.trkSquare1Vol.Maximum = 100;
this.trkSquare1Vol.MaximumSize = new System.Drawing.Size(63, 160);
@ -303,7 +313,7 @@ namespace Mesen.GUI.Forms.Config
// trkMaster
//
this.trkMaster.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkMaster.Location = new System.Drawing.Point(6, 0);
this.trkMaster.Location = new System.Drawing.Point(4, 0);
this.trkMaster.Margin = new System.Windows.Forms.Padding(0);
this.trkMaster.Maximum = 100;
this.trkMaster.MaximumSize = new System.Drawing.Size(63, 160);
@ -318,7 +328,7 @@ namespace Mesen.GUI.Forms.Config
// trkFdsVol
//
this.trkFdsVol.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkFdsVol.Location = new System.Drawing.Point(6, 160);
this.trkFdsVol.Location = new System.Drawing.Point(4, 160);
this.trkFdsVol.Margin = new System.Windows.Forms.Padding(0);
this.trkFdsVol.Maximum = 100;
this.trkFdsVol.MaximumSize = new System.Drawing.Size(63, 160);
@ -333,7 +343,7 @@ namespace Mesen.GUI.Forms.Config
// trkMmc5Vol
//
this.trkMmc5Vol.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkMmc5Vol.Location = new System.Drawing.Point(82, 160);
this.trkMmc5Vol.Location = new System.Drawing.Point(76, 160);
this.trkMmc5Vol.Margin = new System.Windows.Forms.Padding(0);
this.trkMmc5Vol.Maximum = 100;
this.trkMmc5Vol.MaximumSize = new System.Drawing.Size(63, 160);
@ -348,7 +358,7 @@ namespace Mesen.GUI.Forms.Config
// trkVrc6Vol
//
this.trkVrc6Vol.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkVrc6Vol.Location = new System.Drawing.Point(158, 160);
this.trkVrc6Vol.Location = new System.Drawing.Point(148, 160);
this.trkVrc6Vol.Margin = new System.Windows.Forms.Padding(0);
this.trkVrc6Vol.Maximum = 100;
this.trkVrc6Vol.MaximumSize = new System.Drawing.Size(63, 160);
@ -363,7 +373,7 @@ namespace Mesen.GUI.Forms.Config
// trkVrc7Vol
//
this.trkVrc7Vol.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkVrc7Vol.Location = new System.Drawing.Point(234, 160);
this.trkVrc7Vol.Location = new System.Drawing.Point(220, 160);
this.trkVrc7Vol.Margin = new System.Windows.Forms.Padding(0);
this.trkVrc7Vol.Maximum = 100;
this.trkVrc7Vol.MaximumSize = new System.Drawing.Size(63, 160);
@ -378,7 +388,7 @@ namespace Mesen.GUI.Forms.Config
// trkNamco163Vol
//
this.trkNamco163Vol.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkNamco163Vol.Location = new System.Drawing.Point(310, 160);
this.trkNamco163Vol.Location = new System.Drawing.Point(292, 160);
this.trkNamco163Vol.Margin = new System.Windows.Forms.Padding(0);
this.trkNamco163Vol.Maximum = 100;
this.trkNamco163Vol.MaximumSize = new System.Drawing.Size(63, 160);
@ -393,7 +403,7 @@ namespace Mesen.GUI.Forms.Config
// trkSunsoft5b
//
this.trkSunsoft5b.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkSunsoft5b.Location = new System.Drawing.Point(387, 160);
this.trkSunsoft5b.Location = new System.Drawing.Point(432, 0);
this.trkSunsoft5b.Margin = new System.Windows.Forms.Padding(0);
this.trkSunsoft5b.Maximum = 100;
this.trkSunsoft5b.MaximumSize = new System.Drawing.Size(63, 160);
@ -405,13 +415,43 @@ namespace Mesen.GUI.Forms.Config
this.trkSunsoft5b.Text = "Sunsoft";
this.trkSunsoft5b.Value = 50;
//
// trkEPSGVol_L
//
this.trkEPSGVol_L.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkEPSGVol_L.Location = new System.Drawing.Point(364, 160);
this.trkEPSGVol_L.Margin = new System.Windows.Forms.Padding(0);
this.trkEPSGVol_L.Maximum = 100;
this.trkEPSGVol_L.MaximumSize = new System.Drawing.Size(63, 160);
this.trkEPSGVol_L.Minimum = 0;
this.trkEPSGVol_L.MinimumSize = new System.Drawing.Size(63, 160);
this.trkEPSGVol_L.Name = "trkEPSGVol_L";
this.trkEPSGVol_L.Size = new System.Drawing.Size(63, 160);
this.trkEPSGVol_L.TabIndex = 22;
this.trkEPSGVol_L.Text = "EPSG Left";
this.trkEPSGVol_L.Value = 100;
//
// trkEPSGVol_R
//
this.trkEPSGVol_R.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkEPSGVol_R.Location = new System.Drawing.Point(432, 160);
this.trkEPSGVol_R.Margin = new System.Windows.Forms.Padding(0);
this.trkEPSGVol_R.Maximum = 100;
this.trkEPSGVol_R.MaximumSize = new System.Drawing.Size(63, 160);
this.trkEPSGVol_R.Minimum = 0;
this.trkEPSGVol_R.MinimumSize = new System.Drawing.Size(63, 160);
this.trkEPSGVol_R.Name = "trkEPSGVol_R";
this.trkEPSGVol_R.Size = new System.Drawing.Size(63, 160);
this.trkEPSGVol_R.TabIndex = 22;
this.trkEPSGVol_R.Text = "EPSG Right";
this.trkEPSGVol_R.Value = 100;
//
// tableLayoutPanel2
//
this.tableLayoutPanel2.ColumnCount = 2;
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.Controls.Add(this.lblVolumeReductionSettings, 0, 4);
this.tableLayoutPanel2.Controls.Add(this.chkEnableAudio, 0, 0);
this.tableLayoutPanel2.Controls.Add(this.chkEnableEPSG, 0, 0);
this.tableLayoutPanel2.Controls.Add(this.lblSampleRate, 0, 2);
this.tableLayoutPanel2.Controls.Add(this.lblAudioLatency, 0, 3);
this.tableLayoutPanel2.Controls.Add(this.cboSampleRate, 1, 2);
@ -419,6 +459,7 @@ namespace Mesen.GUI.Forms.Config
this.tableLayoutPanel2.Controls.Add(this.cboAudioDevice, 1, 1);
this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel7, 1, 3);
this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel8, 0, 5);
this.tableLayoutPanel2.Controls.Add(this.lblVolumeReductionSettings, 0, 5);
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 3);
this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(0);
@ -428,12 +469,12 @@ namespace Mesen.GUI.Forms.Config
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 22F));
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel2.Size = new System.Drawing.Size(463, 341);
this.tableLayoutPanel2.Size = new System.Drawing.Size(463, 389);
this.tableLayoutPanel2.TabIndex = 3;
//
// lblVolumeReductionSettings
@ -442,8 +483,8 @@ namespace Mesen.GUI.Forms.Config
this.lblVolumeReductionSettings.AutoSize = true;
this.tableLayoutPanel2.SetColumnSpan(this.lblVolumeReductionSettings, 2);
this.lblVolumeReductionSettings.ForeColor = System.Drawing.SystemColors.GrayText;
this.lblVolumeReductionSettings.Location = new System.Drawing.Point(0, 116);
this.lblVolumeReductionSettings.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
this.lblVolumeReductionSettings.Location = new System.Drawing.Point(0, 136);
this.lblVolumeReductionSettings.Margin = new System.Windows.Forms.Padding(0, 3, 3, 0);
this.lblVolumeReductionSettings.Name = "lblVolumeReductionSettings";
this.lblVolumeReductionSettings.Size = new System.Drawing.Size(94, 13);
this.lblVolumeReductionSettings.TabIndex = 24;
@ -453,7 +494,7 @@ namespace Mesen.GUI.Forms.Config
//
this.chkEnableAudio.AutoSize = true;
this.tableLayoutPanel2.SetColumnSpan(this.chkEnableAudio, 2);
this.chkEnableAudio.Location = new System.Drawing.Point(6, 6);
this.chkEnableAudio.Location = new System.Drawing.Point(6, 32);
this.chkEnableAudio.Margin = new System.Windows.Forms.Padding(6, 6, 6, 3);
this.chkEnableAudio.Name = "chkEnableAudio";
this.chkEnableAudio.Size = new System.Drawing.Size(89, 17);
@ -461,11 +502,23 @@ namespace Mesen.GUI.Forms.Config
this.chkEnableAudio.Text = "Enable Audio";
this.chkEnableAudio.UseVisualStyleBackColor = true;
//
// chkEnableEPSG
//
this.chkEnableEPSG.AutoSize = true;
this.tableLayoutPanel2.SetColumnSpan(this.chkEnableEPSG, 2);
this.chkEnableEPSG.Location = new System.Drawing.Point(6, 6);
this.chkEnableEPSG.Margin = new System.Windows.Forms.Padding(6, 6, 6, 3);
this.chkEnableEPSG.Name = "chkEnableEPSG";
this.chkEnableEPSG.Size = new System.Drawing.Size(91, 17);
this.chkEnableEPSG.TabIndex = 3;
this.chkEnableEPSG.Text = "Enable EPSG";
this.chkEnableEPSG.UseVisualStyleBackColor = true;
//
// lblSampleRate
//
this.lblSampleRate.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblSampleRate.AutoSize = true;
this.lblSampleRate.Location = new System.Drawing.Point(3, 60);
this.lblSampleRate.Location = new System.Drawing.Point(3, 86);
this.lblSampleRate.Name = "lblSampleRate";
this.lblSampleRate.Size = new System.Drawing.Size(71, 13);
this.lblSampleRate.TabIndex = 0;
@ -475,7 +528,7 @@ namespace Mesen.GUI.Forms.Config
//
this.lblAudioLatency.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblAudioLatency.AutoSize = true;
this.lblAudioLatency.Location = new System.Drawing.Point(3, 87);
this.lblAudioLatency.Location = new System.Drawing.Point(3, 113);
this.lblAudioLatency.Name = "lblAudioLatency";
this.lblAudioLatency.Size = new System.Drawing.Size(48, 13);
this.lblAudioLatency.TabIndex = 0;
@ -491,7 +544,7 @@ namespace Mesen.GUI.Forms.Config
"44,100 Hz",
"48,000 Hz",
"96,000 Hz"});
this.cboSampleRate.Location = new System.Drawing.Point(80, 56);
this.cboSampleRate.Location = new System.Drawing.Point(80, 82);
this.cboSampleRate.Name = "cboSampleRate";
this.cboSampleRate.Size = new System.Drawing.Size(75, 21);
this.cboSampleRate.TabIndex = 5;
@ -500,7 +553,7 @@ namespace Mesen.GUI.Forms.Config
//
this.lblAudioDevice.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblAudioDevice.AutoSize = true;
this.lblAudioDevice.Location = new System.Drawing.Point(3, 33);
this.lblAudioDevice.Location = new System.Drawing.Point(3, 59);
this.lblAudioDevice.Name = "lblAudioDevice";
this.lblAudioDevice.Size = new System.Drawing.Size(44, 13);
this.lblAudioDevice.TabIndex = 6;
@ -510,7 +563,7 @@ namespace Mesen.GUI.Forms.Config
//
this.cboAudioDevice.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboAudioDevice.FormattingEnabled = true;
this.cboAudioDevice.Location = new System.Drawing.Point(80, 29);
this.cboAudioDevice.Location = new System.Drawing.Point(80, 55);
this.cboAudioDevice.Name = "cboAudioDevice";
this.cboAudioDevice.Size = new System.Drawing.Size(209, 21);
this.cboAudioDevice.TabIndex = 7;
@ -529,7 +582,7 @@ namespace Mesen.GUI.Forms.Config
this.tableLayoutPanel7.Controls.Add(this.lblLatencyMs, 1, 0);
this.tableLayoutPanel7.Controls.Add(this.nudLatency, 0, 0);
this.tableLayoutPanel7.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel7.Location = new System.Drawing.Point(77, 80);
this.tableLayoutPanel7.Location = new System.Drawing.Point(77, 106);
this.tableLayoutPanel7.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel7.Name = "tableLayoutPanel7";
this.tableLayoutPanel7.RowCount = 1;
@ -579,6 +632,7 @@ namespace Mesen.GUI.Forms.Config
0,
0,
0});
this.nudLatency.IsHex = false;
this.nudLatency.Location = new System.Drawing.Point(3, 3);
this.nudLatency.Maximum = new decimal(new int[] {
300,
@ -612,7 +666,7 @@ namespace Mesen.GUI.Forms.Config
this.tableLayoutPanel8.Controls.Add(this.chkReduceSoundInFastForward, 0, 2);
this.tableLayoutPanel8.Controls.Add(this.trkVolumeReduction, 1, 1);
this.tableLayoutPanel8.Controls.Add(this.chkMuteSoundInBackground, 0, 0);
this.tableLayoutPanel8.Location = new System.Drawing.Point(10, 132);
this.tableLayoutPanel8.Location = new System.Drawing.Point(10, 152);
this.tableLayoutPanel8.Margin = new System.Windows.Forms.Padding(10, 3, 0, 0);
this.tableLayoutPanel8.Name = "tableLayoutPanel8";
this.tableLayoutPanel8.RowCount = 4;
@ -696,7 +750,7 @@ namespace Mesen.GUI.Forms.Config
this.tabMain.Location = new System.Drawing.Point(0, 0);
this.tabMain.Name = "tabMain";
this.tabMain.SelectedIndex = 0;
this.tabMain.Size = new System.Drawing.Size(477, 373);
this.tabMain.Size = new System.Drawing.Size(477, 421);
this.tabMain.TabIndex = 4;
//
// tpgGeneral
@ -705,7 +759,7 @@ namespace Mesen.GUI.Forms.Config
this.tpgGeneral.Location = new System.Drawing.Point(4, 22);
this.tpgGeneral.Name = "tpgGeneral";
this.tpgGeneral.Padding = new System.Windows.Forms.Padding(3);
this.tpgGeneral.Size = new System.Drawing.Size(469, 347);
this.tpgGeneral.Size = new System.Drawing.Size(469, 395);
this.tpgGeneral.TabIndex = 0;
this.tpgGeneral.Text = "General";
this.tpgGeneral.UseVisualStyleBackColor = true;
@ -716,7 +770,7 @@ namespace Mesen.GUI.Forms.Config
this.tpgVolume.Location = new System.Drawing.Point(4, 22);
this.tpgVolume.Name = "tpgVolume";
this.tpgVolume.Padding = new System.Windows.Forms.Padding(3);
this.tpgVolume.Size = new System.Drawing.Size(469, 347);
this.tpgVolume.Size = new System.Drawing.Size(469, 363);
this.tpgVolume.TabIndex = 1;
this.tpgVolume.Text = "Volume";
this.tpgVolume.UseVisualStyleBackColor = true;
@ -727,7 +781,7 @@ namespace Mesen.GUI.Forms.Config
this.tpgPanning.Location = new System.Drawing.Point(4, 22);
this.tpgPanning.Name = "tpgPanning";
this.tpgPanning.Padding = new System.Windows.Forms.Padding(3);
this.tpgPanning.Size = new System.Drawing.Size(469, 347);
this.tpgPanning.Size = new System.Drawing.Size(469, 363);
this.tpgPanning.TabIndex = 4;
this.tpgPanning.Text = "Panning";
this.tpgPanning.UseVisualStyleBackColor = true;
@ -747,11 +801,13 @@ namespace Mesen.GUI.Forms.Config
this.tableLayoutPanel6.Controls.Add(this.trkVrc6Pan, 1, 2);
this.tableLayoutPanel6.Controls.Add(this.trkVrc7Pan, 1, 3);
this.tableLayoutPanel6.Controls.Add(this.trkNamcoPan, 1, 4);
this.tableLayoutPanel6.Controls.Add(this.trkSunsoftPan, 1, 5);
this.tableLayoutPanel6.Controls.Add(this.trkSunsoftPan, 0, 6);
this.tableLayoutPanel6.Controls.Add(this.trkEPSGPan_L, 0, 5);
this.tableLayoutPanel6.Controls.Add(this.trkEPSGPan_R, 1, 5);
this.tableLayoutPanel6.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel6.Location = new System.Drawing.Point(3, 3);
this.tableLayoutPanel6.Name = "tableLayoutPanel6";
this.tableLayoutPanel6.RowCount = 7;
this.tableLayoutPanel6.RowCount = 8;
this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle());
@ -760,7 +816,7 @@ namespace Mesen.GUI.Forms.Config
this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel6.Size = new System.Drawing.Size(463, 341);
this.tableLayoutPanel6.Size = new System.Drawing.Size(463, 357);
this.tableLayoutPanel6.TabIndex = 3;
//
// trkSquare1Pan
@ -916,7 +972,7 @@ namespace Mesen.GUI.Forms.Config
// trkSunsoftPan
//
this.trkSunsoftPan.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkSunsoftPan.Location = new System.Drawing.Point(244, 275);
this.trkSunsoftPan.Location = new System.Drawing.Point(12, 330);
this.trkSunsoftPan.Margin = new System.Windows.Forms.Padding(0);
this.trkSunsoftPan.Maximum = 100;
this.trkSunsoftPan.MaximumSize = new System.Drawing.Size(63, 160);
@ -928,13 +984,43 @@ namespace Mesen.GUI.Forms.Config
this.trkSunsoftPan.Text = "Sunsoft";
this.trkSunsoftPan.Value = 0;
//
// trkEPSGPan_L
//
this.trkEPSGPan_L.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkEPSGPan_L.Location = new System.Drawing.Point(12, 275);
this.trkEPSGPan_L.Margin = new System.Windows.Forms.Padding(0);
this.trkEPSGPan_L.Maximum = 100;
this.trkEPSGPan_L.MaximumSize = new System.Drawing.Size(63, 160);
this.trkEPSGPan_L.Minimum = -100;
this.trkEPSGPan_L.MinimumSize = new System.Drawing.Size(206, 55);
this.trkEPSGPan_L.Name = "trkEPSGPan_L";
this.trkEPSGPan_L.Size = new System.Drawing.Size(206, 55);
this.trkEPSGPan_L.TabIndex = 22;
this.trkEPSGPan_L.Text = "EPSG Left";
this.trkEPSGPan_L.Value = -100;
//
// trkEPSGPan_R
//
this.trkEPSGPan_R.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.trkEPSGPan_R.Location = new System.Drawing.Point(244, 275);
this.trkEPSGPan_R.Margin = new System.Windows.Forms.Padding(0);
this.trkEPSGPan_R.Maximum = 100;
this.trkEPSGPan_R.MaximumSize = new System.Drawing.Size(63, 160);
this.trkEPSGPan_R.Minimum = -100;
this.trkEPSGPan_R.MinimumSize = new System.Drawing.Size(206, 55);
this.trkEPSGPan_R.Name = "trkEPSGPan_R";
this.trkEPSGPan_R.Size = new System.Drawing.Size(206, 55);
this.trkEPSGPan_R.TabIndex = 22;
this.trkEPSGPan_R.Text = "EPSG Right";
this.trkEPSGPan_R.Value = 100;
//
// tpgEqualizer
//
this.tpgEqualizer.Controls.Add(this.groupBox1);
this.tpgEqualizer.Location = new System.Drawing.Point(4, 22);
this.tpgEqualizer.Name = "tpgEqualizer";
this.tpgEqualizer.Padding = new System.Windows.Forms.Padding(3);
this.tpgEqualizer.Size = new System.Drawing.Size(469, 347);
this.tpgEqualizer.Size = new System.Drawing.Size(469, 363);
this.tpgEqualizer.TabIndex = 5;
this.tpgEqualizer.Text = "Equalizer";
this.tpgEqualizer.UseVisualStyleBackColor = true;
@ -946,7 +1032,7 @@ namespace Mesen.GUI.Forms.Config
this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill;
this.groupBox1.Location = new System.Drawing.Point(3, 3);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(463, 341);
this.groupBox1.Size = new System.Drawing.Size(463, 357);
this.groupBox1.TabIndex = 4;
this.groupBox1.TabStop = false;
//
@ -1006,7 +1092,7 @@ namespace Mesen.GUI.Forms.Config
this.tlpEqualizer.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpEqualizer.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpEqualizer.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tlpEqualizer.Size = new System.Drawing.Size(457, 322);
this.tlpEqualizer.Size = new System.Drawing.Size(457, 338);
this.tlpEqualizer.TabIndex = 3;
//
// trkBand6Gain
@ -1405,7 +1491,7 @@ namespace Mesen.GUI.Forms.Config
this.tpgEffects.Location = new System.Drawing.Point(4, 22);
this.tpgEffects.Name = "tpgEffects";
this.tpgEffects.Padding = new System.Windows.Forms.Padding(3);
this.tpgEffects.Size = new System.Drawing.Size(469, 347);
this.tpgEffects.Size = new System.Drawing.Size(469, 363);
this.tpgEffects.TabIndex = 3;
this.tpgEffects.Text = "Effects";
this.tpgEffects.UseVisualStyleBackColor = true;
@ -1425,7 +1511,7 @@ namespace Mesen.GUI.Forms.Config
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel4.Size = new System.Drawing.Size(463, 341);
this.tableLayoutPanel4.Size = new System.Drawing.Size(463, 357);
this.tableLayoutPanel4.TabIndex = 0;
//
// grpStereo
@ -1544,6 +1630,7 @@ namespace Mesen.GUI.Forms.Config
0,
0,
0});
this.nudStereoDelay.IsHex = false;
this.nudStereoDelay.Location = new System.Drawing.Point(83, 24);
this.nudStereoDelay.Margin = new System.Windows.Forms.Padding(0);
this.nudStereoDelay.Maximum = new decimal(new int[] {
@ -1576,6 +1663,7 @@ namespace Mesen.GUI.Forms.Config
0,
0,
0});
this.nudStereoPanning.IsHex = false;
this.nudStereoPanning.Location = new System.Drawing.Point(83, 47);
this.nudStereoPanning.Margin = new System.Windows.Forms.Padding(0);
this.nudStereoPanning.Maximum = new decimal(new int[] {
@ -1634,6 +1722,7 @@ namespace Mesen.GUI.Forms.Config
0,
0,
0});
this.nudStereoCombFilterStrength.IsHex = false;
this.nudStereoCombFilterStrength.Location = new System.Drawing.Point(187, 1);
this.nudStereoCombFilterStrength.Margin = new System.Windows.Forms.Padding(0);
this.nudStereoCombFilterStrength.Maximum = new decimal(new int[] {
@ -1676,6 +1765,7 @@ namespace Mesen.GUI.Forms.Config
0,
0,
0});
this.nudStereoCombFilterDelay.IsHex = false;
this.nudStereoCombFilterDelay.Location = new System.Drawing.Point(43, 1);
this.nudStereoCombFilterDelay.Margin = new System.Windows.Forms.Padding(0);
this.nudStereoCombFilterDelay.Maximum = new decimal(new int[] {
@ -1847,6 +1937,7 @@ namespace Mesen.GUI.Forms.Config
0,
0,
0});
this.nudCrossFeedRatio.IsHex = false;
this.nudCrossFeedRatio.Location = new System.Drawing.Point(118, 2);
this.nudCrossFeedRatio.Margin = new System.Windows.Forms.Padding(0);
this.nudCrossFeedRatio.Maximum = new decimal(new int[] {
@ -1886,7 +1977,7 @@ namespace Mesen.GUI.Forms.Config
this.tpgAdvanced.Location = new System.Drawing.Point(4, 22);
this.tpgAdvanced.Name = "tpgAdvanced";
this.tpgAdvanced.Padding = new System.Windows.Forms.Padding(3);
this.tpgAdvanced.Size = new System.Drawing.Size(469, 347);
this.tpgAdvanced.Size = new System.Drawing.Size(469, 363);
this.tpgAdvanced.TabIndex = 2;
this.tpgAdvanced.Text = "Advanced";
this.tpgAdvanced.UseVisualStyleBackColor = true;
@ -1897,20 +1988,23 @@ namespace Mesen.GUI.Forms.Config
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel3.Controls.Add(this.chkDisableDynamicSampleRate, 0, 2);
this.tableLayoutPanel3.Controls.Add(this.chkDisableNoiseModeFlag, 0, 4);
this.tableLayoutPanel3.Controls.Add(this.nudEPSGClockFrequency, 0, 5);
this.tableLayoutPanel3.Controls.Add(this.lblEPSGClockFrequency, 0, 5);
this.tableLayoutPanel3.Controls.Add(this.chkSilenceTriangleHighFreq, 0, 0);
this.tableLayoutPanel3.Controls.Add(this.chkSwapDutyCycles, 0, 3);
this.tableLayoutPanel3.Controls.Add(this.chkReduceDmcPopping, 0, 1);
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel3.Location = new System.Drawing.Point(3, 3);
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
this.tableLayoutPanel3.RowCount = 6;
this.tableLayoutPanel3.RowCount = 7;
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F));
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F));
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F));
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F));
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F));
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F));
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel3.Size = new System.Drawing.Size(463, 341);
this.tableLayoutPanel3.Size = new System.Drawing.Size(463, 357);
this.tableLayoutPanel3.TabIndex = 1;
//
// chkDisableDynamicSampleRate
@ -1933,6 +2027,48 @@ namespace Mesen.GUI.Forms.Config
this.chkDisableNoiseModeFlag.TabIndex = 3;
this.chkDisableNoiseModeFlag.Text = "Disable noise channel mode flag";
//
// nudEPSGClockFrequency
//
this.nudEPSGClockFrequency.DecimalPlaces = 0;
this.nudEPSGClockFrequency.Dock = System.Windows.Forms.DockStyle.Fill;
this.nudEPSGClockFrequency.Increment = new decimal(new int[] {
100000,
0,
0,
0});
this.nudEPSGClockFrequency.IsHex = false;
this.nudEPSGClockFrequency.Location = new System.Drawing.Point(3, 147);
this.nudEPSGClockFrequency.Maximum = new decimal(new int[] {
32000000,
0,
0,
0});
this.nudEPSGClockFrequency.MaximumSize = new System.Drawing.Size(10000, 20);
this.nudEPSGClockFrequency.Minimum = new decimal(new int[] {
10000,
0,
0,
0});
this.nudEPSGClockFrequency.MinimumSize = new System.Drawing.Size(200, 21);
this.nudEPSGClockFrequency.Name = "nudEPSGClockFrequency";
this.nudEPSGClockFrequency.Size = new System.Drawing.Size(457, 21);
this.nudEPSGClockFrequency.TabIndex = 3;
this.nudEPSGClockFrequency.Value = new decimal(new int[] {
10000,
0,
0,
0});
//
// lblEPSGClockFrequency
//
this.lblEPSGClockFrequency.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblEPSGClockFrequency.AutoSize = true;
this.lblEPSGClockFrequency.Location = new System.Drawing.Point(3, 125);
this.lblEPSGClockFrequency.Name = "lblEPSGClockFrequency";
this.lblEPSGClockFrequency.Size = new System.Drawing.Size(228, 13);
this.lblEPSGClockFrequency.TabIndex = 3;
this.lblEPSGClockFrequency.Text = "EPSG Clock Frequency (default is 3579545Hz)";
//
// chkSilenceTriangleHighFreq
//
this.chkSilenceTriangleHighFreq.AutoSize = true;
@ -1968,7 +2104,7 @@ namespace Mesen.GUI.Forms.Config
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(477, 402);
this.ClientSize = new System.Drawing.Size(477, 450);
this.Controls.Add(this.tabMain);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
@ -2030,6 +2166,7 @@ namespace Mesen.GUI.Forms.Config
private System.Windows.Forms.GroupBox grpVolume;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
private System.Windows.Forms.CheckBox chkEnableAudio;
private System.Windows.Forms.CheckBox chkEnableEPSG;
private System.Windows.Forms.Label lblAudioLatency;
private MesenNumericUpDown nudLatency;
private System.Windows.Forms.Label lblLatencyMs;
@ -2051,6 +2188,8 @@ namespace Mesen.GUI.Forms.Config
private Controls.ctrlTrackbar trkVrc7Vol;
private Controls.ctrlTrackbar trkNamco163Vol;
private Controls.ctrlTrackbar trkSunsoft5b;
private Controls.ctrlTrackbar trkEPSGVol_L;
private Controls.ctrlTrackbar trkEPSGVol_R;
private System.Windows.Forms.TabControl tabMain;
private System.Windows.Forms.TabPage tpgGeneral;
private System.Windows.Forms.TabPage tpgVolume;
@ -2091,6 +2230,8 @@ namespace Mesen.GUI.Forms.Config
private Controls.ctrlHorizontalTrackbar trkVrc7Pan;
private Controls.ctrlHorizontalTrackbar trkNamcoPan;
private Controls.ctrlHorizontalTrackbar trkSunsoftPan;
private Controls.ctrlHorizontalTrackbar trkEPSGPan_L;
private Controls.ctrlHorizontalTrackbar trkEPSGPan_R;
private Controls.ctrlHorizontalTrackbar trkSquare1Pan;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel5;
private System.Windows.Forms.CheckBox chkCrossFeedEnabled;
@ -2098,6 +2239,8 @@ namespace Mesen.GUI.Forms.Config
private System.Windows.Forms.Label lblCrossFeedRatio;
private Controls.ctrlHorizontalTrackbar trkTrianglePan;
private ctrlRiskyOption chkDisableNoiseModeFlag;
private MesenNumericUpDown nudEPSGClockFrequency;
private System.Windows.Forms.Label lblEPSGClockFrequency;
private System.Windows.Forms.TabPage tpgEqualizer;
private System.Windows.Forms.TableLayoutPanel tlpEqualizer;
private ctrlTrackbar trkBand6Gain;

View file

@ -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);

View file

@ -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,7 +2299,9 @@ namespace Mesen.GUI
VRC6 = 7,
VRC7 = 8,
Namco163 = 9,
Sunsoft5B = 10
Sunsoft5B = 10,
EPSG_L = 11,
EPSG_R= 12
}
public enum EqualizerFilterType

View file

@ -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); }