mirror of
https://github.com/libretro/Mesen.git
synced 2025-01-31 22:01:52 +00:00
Sunsoft FME-7/5A/5B support (Mapper 69) (partial audio chip support)
This commit is contained in:
parent
618c8e0b5e
commit
cdf0e8751a
@ -529,10 +529,12 @@
|
||||
<ClInclude Include="StereoDelayFilter.h" />
|
||||
<ClInclude Include="StereoPanningFilter.h" />
|
||||
<ClInclude Include="Sunsoft184.h" />
|
||||
<ClInclude Include="SunSoft3.h" />
|
||||
<ClInclude Include="SunSoft4.h" />
|
||||
<ClInclude Include="Sunsoft3.h" />
|
||||
<ClInclude Include="Sunsoft4.h" />
|
||||
<ClInclude Include="Sunsoft5bAudio.h" />
|
||||
<ClInclude Include="Sunsoft89.h" />
|
||||
<ClInclude Include="Sunsoft93.h" />
|
||||
<ClInclude Include="SunsoftFme7.h" />
|
||||
<ClInclude Include="TaitoTc0190.h" />
|
||||
<ClInclude Include="TaitoX1005.h" />
|
||||
<ClInclude Include="TaitoX1017.h" />
|
||||
|
@ -403,12 +403,6 @@
|
||||
<ClInclude Include="Mapper246.h">
|
||||
<Filter>Nes\Mappers\Unnamed</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SunSoft3.h">
|
||||
<Filter>Nes\Mappers\Sunsoft</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SunSoft4.h">
|
||||
<Filter>Nes\Mappers\Sunsoft</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Sunsoft89.h">
|
||||
<Filter>Nes\Mappers\Sunsoft</Filter>
|
||||
</ClInclude>
|
||||
@ -604,6 +598,18 @@
|
||||
<ClInclude Include="Namco163Audio.h">
|
||||
<Filter>Nes\Mappers\Namco</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SunsoftFme7.h">
|
||||
<Filter>Nes\Mappers\Sunsoft</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Sunsoft5bAudio.h">
|
||||
<Filter>Nes\Mappers\Sunsoft</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Sunsoft3.h">
|
||||
<Filter>Nes\Mappers\Sunsoft</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Sunsoft4.h">
|
||||
<Filter>Nes\Mappers\Sunsoft</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
@ -79,6 +79,7 @@
|
||||
#include "Sunsoft89.h"
|
||||
#include "Sunsoft93.h"
|
||||
#include "Sunsoft184.h"
|
||||
#include "SunsoftFme7.h"
|
||||
#include "TaitoTc0190.h"
|
||||
#include "TaitoX1005.h"
|
||||
#include "TaitoX1017.h"
|
||||
@ -147,8 +148,9 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
|
||||
case 64: return new Rambo1();
|
||||
case 65: return new IremH3001();
|
||||
case 66: return new GxRom();
|
||||
case 67: return new SunSoft3();
|
||||
case 68: return new SunSoft4(); //incomplete support
|
||||
case 67: return new Sunsoft3();
|
||||
case 68: return new Sunsoft4(); //incomplete support
|
||||
case 69: return new SunsoftFme7();
|
||||
case 70: return new Bandai74161_7432(false);
|
||||
case 71: return new BF909x();
|
||||
case 72: return new JalecoJf17_19(false);
|
||||
|
@ -153,6 +153,7 @@ int16_t SoundMixer::GetOutputVolume()
|
||||
case AudioChannel::FDS: expansionOutput = (int16_t)(_currentOutput[ExpansionAudioIndex] * _volumes[ExpansionAudioIndex] * 20); break;
|
||||
case AudioChannel::VRC6: expansionOutput = (int16_t)(_currentOutput[ExpansionAudioIndex] * _volumes[ExpansionAudioIndex] * 75); break;
|
||||
case AudioChannel::Namco163: expansionOutput = (int16_t)(_currentOutput[ExpansionAudioIndex] * _volumes[ExpansionAudioIndex] * 20); break;
|
||||
case AudioChannel::Sunsoft5B: expansionOutput = (int16_t)(_currentOutput[ExpansionAudioIndex] * _volumes[ExpansionAudioIndex] * 20); break;
|
||||
}
|
||||
return squareVolume + tndVolume + expansionOutput;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include "BaseMapper.h"
|
||||
#include "CPU.h"
|
||||
|
||||
class SunSoft3 : public BaseMapper
|
||||
class Sunsoft3 : public BaseMapper
|
||||
{
|
||||
private:
|
||||
bool _irqLatch = false;
|
@ -3,7 +3,7 @@
|
||||
#include "BaseMapper.h"
|
||||
#include "CPU.h"
|
||||
|
||||
class SunSoft4 : public BaseMapper
|
||||
class Sunsoft4 : public BaseMapper
|
||||
{
|
||||
protected:
|
||||
virtual uint16_t GetPRGPageSize() { return 0x4000; }
|
127
Core/Sunsoft5bAudio.h
Normal file
127
Core/Sunsoft5bAudio.h
Normal file
@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "Snapshotable.h"
|
||||
#include "APU.h"
|
||||
|
||||
class Sunsoft5bAudio : public Snapshotable
|
||||
{
|
||||
private:
|
||||
uint8_t _volumeLut[0x10];
|
||||
uint8_t _currentRegister;
|
||||
uint8_t _registers[0x10];
|
||||
int16_t _lastOutput;
|
||||
uint16_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) + 1;
|
||||
_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);
|
||||
}
|
||||
}
|
||||
|
||||
APU::AddExpansionAudioDelta(AudioChannel::Sunsoft5B, summedOutput - _lastOutput);
|
||||
_lastOutput = summedOutput;
|
||||
}
|
||||
|
||||
protected:
|
||||
void StreamState(bool saving)
|
||||
{
|
||||
ArrayInfo<uint16_t> timer{ _timer, 3 };
|
||||
ArrayInfo<uint8_t> registers{ _registers, 0x10 };
|
||||
ArrayInfo<uint8_t> toneStep{ _toneStep, 3 };
|
||||
Stream(timer, registers, toneStep, _currentRegister, _lastOutput, _processTick);
|
||||
}
|
||||
|
||||
public:
|
||||
Sunsoft5bAudio()
|
||||
{
|
||||
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 ProcessCpuClock()
|
||||
{
|
||||
if(_processTick) {
|
||||
for(int i = 0; i < 3; i++) {
|
||||
UpdateChannel(i);
|
||||
}
|
||||
UpdateOutputLevel();
|
||||
}
|
||||
_processTick = !_processTick;
|
||||
}
|
||||
|
||||
void WriteRegister(uint16_t addr, uint8_t value)
|
||||
{
|
||||
switch(addr & 0xE000) {
|
||||
case 0xC000:
|
||||
_currentRegister = value & 0x0F;
|
||||
break;
|
||||
|
||||
case 0xE000:
|
||||
_registers[_currentRegister] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
124
Core/SunsoftFme7.h
Normal file
124
Core/SunsoftFme7.h
Normal file
@ -0,0 +1,124 @@
|
||||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "BaseMapper.h"
|
||||
#include "CPU.h"
|
||||
#include "Sunsoft5bAudio.h"
|
||||
|
||||
class SunsoftFme7 : public BaseMapper
|
||||
{
|
||||
private:
|
||||
Sunsoft5bAudio _audio;
|
||||
uint8_t _command;
|
||||
uint8_t _workRamValue;
|
||||
bool _irqEnabled;
|
||||
bool _irqCounterEnabled;
|
||||
uint16_t _irqCounter;
|
||||
|
||||
protected:
|
||||
virtual uint16_t GetPRGPageSize() { return 0x2000; }
|
||||
virtual uint16_t GetCHRPageSize() { return 0x400; }
|
||||
virtual uint32_t GetWorkRamSize() { return 0x80000; }
|
||||
virtual uint32_t GetWorkRamPageSize() { return 0x2000; }
|
||||
virtual uint32_t GetSaveRamSize() { return 0x80000; }
|
||||
virtual uint32_t GetSaveRamPageSize() { return 0x2000; }
|
||||
|
||||
void InitMapper()
|
||||
{
|
||||
_command = 0;
|
||||
_workRamValue = 0;
|
||||
_irqEnabled = false;
|
||||
_irqCounterEnabled = false;
|
||||
_irqCounter = 0;
|
||||
|
||||
SelectPRGPage(3, -1);
|
||||
|
||||
UpdateWorkRam();
|
||||
}
|
||||
|
||||
void StreamState(bool saving)
|
||||
{
|
||||
SnapshotInfo audio{ &_audio };
|
||||
Stream(_command, _workRamValue, _irqEnabled, _irqCounterEnabled, _irqCounter, audio);
|
||||
if(!saving) {
|
||||
UpdateWorkRam();
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessCpuClock()
|
||||
{
|
||||
if(_irqCounterEnabled) {
|
||||
_irqCounter--;
|
||||
if(_irqCounter == 0xFFFF) {
|
||||
if(_irqEnabled) {
|
||||
CPU::SetIRQSource(IRQSource::External);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_audio.ProcessCpuClock();
|
||||
}
|
||||
|
||||
void UpdateWorkRam()
|
||||
{
|
||||
if(_workRamValue & 0x40) {
|
||||
MemoryAccessType accessType = (_workRamValue & 0x80) ? MemoryAccessType::ReadWrite : MemoryAccessType::NoAccess;
|
||||
SetCpuMemoryMapping(0x6000, 0x7FFF, _workRamValue & 0x3F, HasBattery() ? PrgMemoryType::SaveRam : PrgMemoryType::WorkRam, accessType);
|
||||
} else {
|
||||
SetCpuMemoryMapping(0x6000, 0x7FFF, _workRamValue & 0x3F, PrgMemoryType::PrgRom);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteRegister(uint16_t addr, uint8_t value)
|
||||
{
|
||||
switch(addr & 0xE000) {
|
||||
case 0x8000:
|
||||
_command = value;
|
||||
break;
|
||||
case 0xA000:
|
||||
switch(_command) {
|
||||
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
|
||||
SelectCHRPage(_command, value);
|
||||
break;
|
||||
|
||||
case 8: {
|
||||
_workRamValue = value;
|
||||
UpdateWorkRam();
|
||||
break;
|
||||
}
|
||||
|
||||
case 9: case 0xA: case 0xB:
|
||||
SelectPRGPage(_command - 9, value & 0x3F);
|
||||
break;
|
||||
|
||||
case 0xC:
|
||||
switch(value & 0x03) {
|
||||
case 0: SetMirroringType(MirroringType::Vertical); break;
|
||||
case 1: SetMirroringType(MirroringType::Horizontal); break;
|
||||
case 2: SetMirroringType(MirroringType::ScreenAOnly); break;
|
||||
case 3: SetMirroringType(MirroringType::ScreenBOnly); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD:
|
||||
_irqEnabled = (value & 0x01) == 0x01;
|
||||
_irqCounterEnabled = (value & 0x80) == 0x80;
|
||||
CPU::ClearIRQSource(IRQSource::External);
|
||||
break;
|
||||
|
||||
case 0xE:
|
||||
_irqCounter = _irqCounter & 0xFF00 | value;
|
||||
break;
|
||||
|
||||
case 0xF:
|
||||
_irqCounter = _irqCounter & 0xFF | (value << 8);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC000:
|
||||
case 0xE000:
|
||||
_audio.WriteRegister(addr, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
1
GUI.NET/Forms/Config/frmAudioConfig.Designer.cs
generated
1
GUI.NET/Forms/Config/frmAudioConfig.Designer.cs
generated
@ -312,7 +312,6 @@
|
||||
// trkSunsoft5b
|
||||
//
|
||||
this.trkSunsoft5b.Anchor = System.Windows.Forms.AnchorStyles.Top;
|
||||
this.trkSunsoft5b.Enabled = false;
|
||||
this.trkSunsoft5b.Location = new System.Drawing.Point(384, 160);
|
||||
this.trkSunsoft5b.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.trkSunsoft5b.Maximum = 100;
|
||||
|
Loading…
x
Reference in New Issue
Block a user