diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index b359f9bc..febe62da 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -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" />
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index bc1eee58..023b30d4 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -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">
diff --git a/Core/MapperFactory.cpp b/Core/MapperFactory.cpp
index 421ded68..41cc63fb 100644
--- a/Core/MapperFactory.cpp
+++ b/Core/MapperFactory.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);
diff --git a/Core/SoundMixer.cpp b/Core/SoundMixer.cpp
index 7a90ab1b..dee7d51f 100644
--- a/Core/SoundMixer.cpp
+++ b/Core/SoundMixer.cpp
@@ -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;
 }
diff --git a/Core/SunSoft3.h b/Core/Sunsoft3.h
similarity index 97%
rename from Core/SunSoft3.h
rename to Core/Sunsoft3.h
index 0239f3f5..ef050c92 100644
--- a/Core/SunSoft3.h
+++ b/Core/Sunsoft3.h
@@ -3,7 +3,7 @@
 #include "BaseMapper.h"
 #include "CPU.h"
 
-class SunSoft3 : public BaseMapper
+class Sunsoft3 : public BaseMapper
 {
 private:
 	bool _irqLatch = false;
diff --git a/Core/SunSoft4.h b/Core/Sunsoft4.h
similarity index 96%
rename from Core/SunSoft4.h
rename to Core/Sunsoft4.h
index c510dd53..e5b43d32 100644
--- a/Core/SunSoft4.h
+++ b/Core/Sunsoft4.h
@@ -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; }
diff --git a/Core/Sunsoft5bAudio.h b/Core/Sunsoft5bAudio.h
new file mode 100644
index 00000000..eb64a456
--- /dev/null
+++ b/Core/Sunsoft5bAudio.h
@@ -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;
+		}
+	}
+};
\ No newline at end of file
diff --git a/Core/SunsoftFme7.h b/Core/SunsoftFme7.h
new file mode 100644
index 00000000..f6e4e5bb
--- /dev/null
+++ b/Core/SunsoftFme7.h
@@ -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;
+		}
+	}
+};
\ No newline at end of file
diff --git a/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs b/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs
index 134767bf..69028f12 100644
--- a/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs
+++ b/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs
@@ -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;