NSF/NSFe support
This commit is contained in:
parent
c74903799c
commit
b852edfec8
49 changed files with 2773 additions and 122 deletions
|
@ -234,6 +234,5 @@ void APU::StreamState(bool saving)
|
|||
|
||||
void APU::AddExpansionAudioDelta(AudioChannel channel, int16_t delta)
|
||||
{
|
||||
Instance->_mixer->SetExpansionAudioType(channel);
|
||||
Instance->_mixer->AddExpansionAudioDelta(Instance->_currentCycle, delta);
|
||||
Instance->_mixer->AddDelta(channel, Instance->_currentCycle, delta);
|
||||
}
|
|
@ -13,7 +13,8 @@ protected:
|
|||
|
||||
uint32_t _timer = 0;
|
||||
|
||||
uint8_t _masterSpeed = 0;
|
||||
//"Few FDS NSFs write to this register. The BIOS initializes this to $FF."
|
||||
uint8_t _masterSpeed = 0xFF;
|
||||
|
||||
void StreamState(bool saving)
|
||||
{
|
||||
|
|
|
@ -65,11 +65,23 @@ void BaseMapper::SetCpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, int16
|
|||
}
|
||||
source = &source[pageNumber * pageSize];
|
||||
|
||||
accessType = accessType != -1 ? accessType : defaultAccessType;
|
||||
SetCpuMemoryMapping(startAddr, endAddr, source, accessType);
|
||||
}
|
||||
|
||||
void BaseMapper::SetCpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, uint8_t *source, int8_t accessType)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if((startAddr & 0xFF) || (endAddr & 0xFF) != 0xFF) {
|
||||
throw new std::runtime_error("Start/End address must be multiples of 256/0x100");
|
||||
}
|
||||
#endif
|
||||
|
||||
startAddr >>= 8;
|
||||
endAddr >>= 8;
|
||||
for(uint16_t i = startAddr; i <= endAddr; i++) {
|
||||
_prgPages[i] = source;
|
||||
_prgPageAccessType[i] = accessType != -1 ? accessType : defaultAccessType;
|
||||
_prgPageAccessType[i] = accessType != -1 ? accessType : MemoryAccessType::Read;
|
||||
|
||||
source += 0x100;
|
||||
}
|
||||
|
|
|
@ -124,6 +124,7 @@ protected:
|
|||
void SelectPrgPage2x(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom);
|
||||
virtual void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom);
|
||||
void SetCpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, int16_t pageNumber, PrgMemoryType type, int8_t accessType = -1);
|
||||
void SetCpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, uint8_t *source, int8_t accessType = -1);
|
||||
|
||||
virtual void SelectChrPage8x(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default);
|
||||
virtual void SelectChrPage4x(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default);
|
||||
|
@ -165,7 +166,7 @@ public:
|
|||
virtual void ProcessCpuClock() { }
|
||||
virtual void NotifyVRAMAddressChange(uint16_t addr);
|
||||
void ProcessNotification(ConsoleNotificationType type, void* parameter);
|
||||
void GetMemoryRanges(MemoryRanges &ranges);
|
||||
virtual void GetMemoryRanges(MemoryRanges &ranges);
|
||||
|
||||
void ApplyCheats();
|
||||
|
||||
|
|
16
Core/CPU.cpp
16
Core/CPU.cpp
|
@ -5,6 +5,7 @@
|
|||
#include "DeltaModulationChannel.h"
|
||||
#include "TraceLogger.h"
|
||||
#include "Debugger.h"
|
||||
#include "NsfMapper.h"
|
||||
|
||||
CPU* CPU::Instance = nullptr;
|
||||
|
||||
|
@ -68,6 +69,9 @@ void CPU::Reset(bool softReset)
|
|||
_dmcCounter = -1;
|
||||
_dmcDmaRunning = false;
|
||||
|
||||
//Used by NSF code to disable Frame Counter & DMC interrupts
|
||||
_irqMask = 0xFF;
|
||||
|
||||
//Use _memoryManager->Read() directly to prevent clocking the PPU/APU when setting PC at reset
|
||||
_state.PC = _memoryManager->Read(CPU::ResetVector) | _memoryManager->Read(CPU::ResetVector+1) << 8;
|
||||
|
||||
|
@ -118,8 +122,16 @@ uint16_t CPU::FetchOperand()
|
|||
case AddrMode::AbsYW: return GetAbsYAddr(true);
|
||||
default: break;
|
||||
}
|
||||
|
||||
Debugger::BreakIfDebugging();
|
||||
throw std::runtime_error("Invalid OP code - CPU crashed");
|
||||
|
||||
if(NsfMapper::GetInstance()) {
|
||||
//Don't stop emulation on CPU crash when playing NSFs, reset cpu instead
|
||||
Reset(false);
|
||||
return 0;
|
||||
} else {
|
||||
throw std::runtime_error("Invalid OP code - CPU crashed");
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::IncCycleCount()
|
||||
|
@ -148,7 +160,7 @@ void CPU::IncCycleCount()
|
|||
//"it's really the status of the interrupt lines at the end of the second-to-last cycle that matters."
|
||||
//Keep the irq lines values from the previous cycle. The before-to-last cycle's values will be used
|
||||
_prevRunIrq = _runIrq;
|
||||
_runIrq = _state.NMIFlag || (_state.IRQFlag > 0 && !CheckFlag(PSFlags::Interrupt));
|
||||
_runIrq = _state.NMIFlag || ((_state.IRQFlag & _irqMask) > 0 && !CheckFlag(PSFlags::Interrupt));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,8 @@ private:
|
|||
bool _cpuWrite = false;
|
||||
uint16_t _writeAddr = 0;
|
||||
|
||||
uint8_t _irqMask;
|
||||
|
||||
State _state;
|
||||
MemoryManager *_memoryManager = nullptr;
|
||||
|
||||
|
@ -873,6 +875,7 @@ public:
|
|||
static int32_t GetCycleCount() { return CPU::Instance->_cycleCount; }
|
||||
static void SetNMIFlag() { CPU::Instance->_state.NMIFlag = true; }
|
||||
static void ClearNMIFlag() { CPU::Instance->_state.NMIFlag = false; }
|
||||
static void SetIRQMask(uint8_t mask) { CPU::Instance->_irqMask = mask; }
|
||||
static void SetIRQSource(IRQSource source) { CPU::Instance->_state.IRQFlag |= (int)source; }
|
||||
static bool HasIRQSource(IRQSource source) { return (CPU::Instance->_state.IRQFlag & (int)source) != 0; }
|
||||
static void ClearIRQSource(IRQSource source) { CPU::Instance->_state.IRQFlag &= ~(int)source; }
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
#include "../Utilities/Timer.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
#include "HdPpu.h"
|
||||
#include "NsfPpu.h"
|
||||
#include "SoundMixer.h"
|
||||
#include "NsfMapper.h"
|
||||
|
||||
shared_ptr<Console> Console::Instance(new Console());
|
||||
|
||||
|
@ -53,6 +55,9 @@ void Console::Initialize(string romFilename, stringstream *filestream, string ip
|
|||
_cpu.reset(new CPU(_memoryManager.get()));
|
||||
if(HdNesPack::HasHdPack(_romFilepath)) {
|
||||
_ppu.reset(new HdPpu(_memoryManager.get()));
|
||||
} else if(NsfMapper::GetInstance()) {
|
||||
//Disable most of the PPU for NSFs
|
||||
_ppu.reset(new NsfPpu(_memoryManager.get()));
|
||||
} else {
|
||||
_ppu.reset(new PPU(_memoryManager.get()));
|
||||
}
|
||||
|
@ -61,10 +66,10 @@ void Console::Initialize(string romFilename, stringstream *filestream, string ip
|
|||
_controlManager.reset(_mapper->GetGameSystem() == GameSystem::VsUniSystem ? new VsControlManager() : new ControlManager());
|
||||
_controlManager->UpdateControlDevices();
|
||||
|
||||
_memoryManager->RegisterIODevice(_mapper.get());
|
||||
_memoryManager->RegisterIODevice(_ppu.get());
|
||||
_memoryManager->RegisterIODevice(_apu.get());
|
||||
_memoryManager->RegisterIODevice(_controlManager.get());
|
||||
_memoryManager->RegisterIODevice(_mapper.get());
|
||||
|
||||
UpdateNesModel(false);
|
||||
|
||||
|
@ -180,12 +185,12 @@ void Console::ResetComponents(bool softReset)
|
|||
Movie::Stop();
|
||||
SoundMixer::StopRecording();
|
||||
|
||||
_memoryManager->Reset(softReset);
|
||||
_ppu->Reset();
|
||||
_apu->Reset(softReset);
|
||||
_cpu->Reset(softReset);
|
||||
_controlManager->Reset(softReset);
|
||||
|
||||
_memoryManager->Reset(softReset);
|
||||
|
||||
SoundMixer::StopAudio(true);
|
||||
|
||||
if(softReset) {
|
||||
|
@ -257,6 +262,12 @@ void Console::Run()
|
|||
|
||||
//Sleep until we're ready to start the next frame
|
||||
clockTimer.WaitUntil(targetTime);
|
||||
|
||||
if(_resetRequested) {
|
||||
//Used by NSF player to reset console after changing track
|
||||
ResetComponents(true);
|
||||
_resetRequested = false;
|
||||
}
|
||||
|
||||
if(!_pauseLock.IsFree()) {
|
||||
//Need to temporarely pause the emu (to save/load a state, etc.)
|
||||
|
@ -411,6 +422,11 @@ void Console::StopDebugger()
|
|||
_debugger.reset();
|
||||
}
|
||||
|
||||
void Console::RequestReset()
|
||||
{
|
||||
Instance->_resetRequested = true;
|
||||
}
|
||||
|
||||
NesModel Console::GetNesModel()
|
||||
{
|
||||
return Instance->_model;
|
||||
|
|
|
@ -33,6 +33,8 @@ class Console
|
|||
|
||||
bool _stop = false;
|
||||
bool _reset = false;
|
||||
|
||||
atomic<bool> _resetRequested = false;
|
||||
|
||||
bool _initialized = false;
|
||||
|
||||
|
@ -45,6 +47,7 @@ class Console
|
|||
~Console();
|
||||
void Run();
|
||||
void Stop();
|
||||
static void RequestReset();
|
||||
static void Reset(bool softReset = true);
|
||||
|
||||
//Used to pause the emu loop to perform thread-safe operations
|
||||
|
|
|
@ -186,6 +186,8 @@
|
|||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<ShowIncludes>
|
||||
</ShowIncludes>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
@ -215,6 +217,8 @@
|
|||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<ShowIncludes>
|
||||
</ShowIncludes>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
@ -243,6 +247,8 @@
|
|||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ShowIncludes>
|
||||
</ShowIncludes>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
@ -269,6 +275,8 @@
|
|||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ShowIncludes>
|
||||
</ShowIncludes>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
@ -295,6 +303,8 @@
|
|||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ShowIncludes>
|
||||
</ShowIncludes>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
@ -321,6 +331,8 @@
|
|||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ShowIncludes>
|
||||
</ShowIncludes>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
@ -347,6 +359,8 @@
|
|||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ShowIncludes>
|
||||
</ShowIncludes>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
@ -373,6 +387,8 @@
|
|||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DisableLanguageExtensions>true</DisableLanguageExtensions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ShowIncludes>
|
||||
</ShowIncludes>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
@ -452,6 +468,10 @@
|
|||
<ClInclude Include="ModChannel.h" />
|
||||
<ClInclude Include="Namco163.h" />
|
||||
<ClInclude Include="Namco163Audio.h" />
|
||||
<ClInclude Include="NsfeLoader.h" />
|
||||
<ClInclude Include="NsfLoader.h" />
|
||||
<ClInclude Include="NsfMapper.h" />
|
||||
<ClInclude Include="NsfPpu.h" />
|
||||
<ClInclude Include="PlayerListMessage.h" />
|
||||
<ClInclude Include="ReverbFilter.h" />
|
||||
<ClInclude Include="RomData.h" />
|
||||
|
@ -610,6 +630,7 @@
|
|||
<ClCompile Include="GameServerConnection.cpp" />
|
||||
<ClCompile Include="HdVideoFilter.cpp" />
|
||||
<ClCompile Include="iNesLoader.cpp" />
|
||||
<ClCompile Include="NsfMapper.cpp" />
|
||||
<ClCompile Include="NtscFilter.cpp" />
|
||||
<ClCompile Include="ReverbFilter.cpp" />
|
||||
<ClCompile Include="RomLoader.cpp" />
|
||||
|
|
|
@ -670,6 +670,18 @@
|
|||
<ClInclude Include="VsZapper.h">
|
||||
<Filter>Nes\Controllers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NsfLoader.h">
|
||||
<Filter>Nes\RomLoader</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NsfMapper.h">
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NsfeLoader.h">
|
||||
<Filter>Nes\RomLoader</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NsfPpu.h">
|
||||
<Filter>Nes</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
@ -831,5 +843,8 @@
|
|||
<ClCompile Include="VsZapper.cpp">
|
||||
<Filter>Nes\Controllers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NsfMapper.cpp">
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -34,6 +34,10 @@ double EmulationSettings::_effectiveOverclockRateSound = 100;
|
|||
bool EmulationSettings::_overclockAdjustApu = true;
|
||||
bool EmulationSettings::_disableOverclocking = false;
|
||||
|
||||
int32_t EmulationSettings::_nsfAutoDetectSilenceDelay = 3000;
|
||||
int32_t EmulationSettings::_nsfMoveToNextTrackTime = 120;
|
||||
bool EmulationSettings::_nsfDisableApuIrqs = true;
|
||||
|
||||
OverscanDimensions EmulationSettings::_overscan;
|
||||
VideoFilterType EmulationSettings::_videoFilterType = VideoFilterType::None;
|
||||
VideoResizeFilter EmulationSettings::_resizeFilter = VideoResizeFilter::NearestNeighbor;
|
||||
|
|
|
@ -266,6 +266,10 @@ private:
|
|||
static KeyMappingSet _controllerKeys[4];
|
||||
static bool _needControllerUpdate;
|
||||
|
||||
static int32_t _nsfAutoDetectSilenceDelay;
|
||||
static int32_t _nsfMoveToNextTrackTime;
|
||||
static bool _nsfDisableApuIrqs;
|
||||
|
||||
public:
|
||||
static uint32_t GetMesenVersion()
|
||||
{
|
||||
|
@ -694,4 +698,26 @@ public:
|
|||
{
|
||||
return _controllerTypes[0] == ControllerType::ArkanoidController || _controllerTypes[1] == ControllerType::ArkanoidController || (_consoleType == ConsoleType::Famicom && _expansionDevice == ExpansionPortDevice::ArkanoidController);
|
||||
}
|
||||
|
||||
static void SetNsfConfig(int32_t autoDetectSilence, int32_t moveToNextTrackTime, bool disableApuIrqs)
|
||||
{
|
||||
_nsfAutoDetectSilenceDelay = autoDetectSilence;
|
||||
_nsfMoveToNextTrackTime = moveToNextTrackTime;
|
||||
_nsfDisableApuIrqs = disableApuIrqs;
|
||||
}
|
||||
|
||||
static int32_t GetNsfAutoDetectSilenceDelay()
|
||||
{
|
||||
return _nsfAutoDetectSilenceDelay;
|
||||
}
|
||||
|
||||
static int32_t GetNsfMoveToNextTrackTime()
|
||||
{
|
||||
return _nsfMoveToNextTrackTime;
|
||||
}
|
||||
|
||||
static bool GetNsfDisableApuIrqs()
|
||||
{
|
||||
return _nsfDisableApuIrqs;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,11 +14,22 @@ class MemoryRanges
|
|||
private:
|
||||
vector<uint16_t> _ramReadAddresses;
|
||||
vector<uint16_t> _ramWriteAddresses;
|
||||
bool _allowOverride = false;
|
||||
|
||||
public:
|
||||
vector<uint16_t>* GetRAMReadAddresses() { return &_ramReadAddresses; }
|
||||
vector<uint16_t>* GetRAMWriteAddresses() { return &_ramWriteAddresses; }
|
||||
|
||||
bool GetAllowOverride()
|
||||
{
|
||||
return _allowOverride;
|
||||
}
|
||||
|
||||
void SetAllowOverride()
|
||||
{
|
||||
_allowOverride = true;
|
||||
}
|
||||
|
||||
void AddHandler(MemoryOperation operation, uint16_t start, uint16_t end = 0)
|
||||
{
|
||||
if(end == 0) {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "stdafx.h"
|
||||
#include "SquareChannel.h"
|
||||
#include "BaseExpansionAudio.h"
|
||||
#include "CPU.h"
|
||||
|
||||
class MMC5Square : public SquareChannel
|
||||
{
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
#include "Nina01.h"
|
||||
#include "Nina03_06.h"
|
||||
#include "NROM.h"
|
||||
#include "NsfMapper.h"
|
||||
#include "NtdecTc112.h"
|
||||
#include "Rambo1.h"
|
||||
#include "Sachen_143.h"
|
||||
|
@ -109,6 +110,9 @@
|
|||
#include "Waixing164.h"
|
||||
#include "Waixing176.h"
|
||||
|
||||
const uint16_t MapperFactory::FdsMapperID;
|
||||
const uint16_t MapperFactory::NsfMapperID;
|
||||
|
||||
BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
|
@ -256,6 +260,7 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
|
|||
case 243: return new Sachen74LS374N();
|
||||
case 246: return new Mapper246();
|
||||
|
||||
case MapperFactory::NsfMapperID: return new NsfMapper();
|
||||
case MapperFactory::FdsMapperID: return new FDS();
|
||||
}
|
||||
|
||||
|
|
|
@ -10,5 +10,6 @@ class MapperFactory
|
|||
|
||||
public:
|
||||
static const uint16_t FdsMapperID = 65535;
|
||||
static const uint16_t NsfMapperID = 65534;
|
||||
static shared_ptr<BaseMapper> InitializeFromFile(string romFilename, stringstream *filestream, string ipsFilename, int32_t archiveFileIndex);
|
||||
};
|
||||
|
|
|
@ -60,10 +60,10 @@ void MemoryManager::WriteRegister(uint16_t addr, uint8_t value)
|
|||
}
|
||||
}
|
||||
|
||||
void MemoryManager::InitializeMemoryHandlers(IMemoryHandler** memoryHandlers, IMemoryHandler* handler, vector<uint16_t> *addresses)
|
||||
void MemoryManager::InitializeMemoryHandlers(IMemoryHandler** memoryHandlers, IMemoryHandler* handler, vector<uint16_t> *addresses, bool allowOverride)
|
||||
{
|
||||
for(uint16_t address : *addresses) {
|
||||
if(memoryHandlers[address] != nullptr) {
|
||||
if(!allowOverride && memoryHandlers[address] != nullptr) {
|
||||
throw std::runtime_error("Not supported");
|
||||
}
|
||||
memoryHandlers[address] = handler;
|
||||
|
@ -75,8 +75,8 @@ void MemoryManager::RegisterIODevice(IMemoryHandler *handler)
|
|||
MemoryRanges ranges;
|
||||
handler->GetMemoryRanges(ranges);
|
||||
|
||||
InitializeMemoryHandlers(_ramReadHandlers, handler, ranges.GetRAMReadAddresses());
|
||||
InitializeMemoryHandlers(_ramWriteHandlers, handler, ranges.GetRAMWriteAddresses());
|
||||
InitializeMemoryHandlers(_ramReadHandlers, handler, ranges.GetRAMReadAddresses(), ranges.GetAllowOverride());
|
||||
InitializeMemoryHandlers(_ramWriteHandlers, handler, ranges.GetRAMWriteAddresses(), ranges.GetAllowOverride());
|
||||
}
|
||||
|
||||
uint8_t* MemoryManager::GetInternalRAM()
|
||||
|
|
|
@ -33,6 +33,7 @@ class MemoryManager: public Snapshotable
|
|||
|
||||
uint8_t ReadRegister(uint16_t addr);
|
||||
void WriteRegister(uint16_t addr, uint8_t value);
|
||||
void InitializeMemoryHandlers(IMemoryHandler** memoryHandlers, IMemoryHandler* handler, vector<uint16_t> *addresses, bool allowOverride);
|
||||
|
||||
protected:
|
||||
void StreamState(bool saving);
|
||||
|
@ -42,8 +43,6 @@ class MemoryManager: public Snapshotable
|
|||
~MemoryManager();
|
||||
|
||||
void Reset(bool softReset);
|
||||
|
||||
void InitializeMemoryHandlers(IMemoryHandler** memoryHandlers, IMemoryHandler* handler, vector<uint16_t> *addresses);
|
||||
void RegisterIODevice(IMemoryHandler *handler);
|
||||
|
||||
uint8_t DebugRead(uint16_t addr);
|
||||
|
|
160
Core/NsfLoader.h
Normal file
160
Core/NsfLoader.h
Normal file
|
@ -0,0 +1,160 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "RomData.h"
|
||||
|
||||
class NsfLoader
|
||||
{
|
||||
private:
|
||||
void Read(uint8_t* &data, uint8_t& dest)
|
||||
{
|
||||
dest = data[0];
|
||||
data++;
|
||||
}
|
||||
|
||||
void Read(uint8_t* &data, uint16_t& dest)
|
||||
{
|
||||
dest = data[0] | (data[1] << 8);
|
||||
data += 2;
|
||||
}
|
||||
|
||||
void Read(uint8_t* &data, char* dest, size_t len)
|
||||
{
|
||||
memcpy(dest, data, len);
|
||||
data += len;
|
||||
}
|
||||
protected:
|
||||
void InitializeFromHeader(RomData& romData)
|
||||
{
|
||||
NsfHeader &header = romData.NsfHeader;
|
||||
|
||||
romData.MapperID = MapperFactory::NsfMapperID;
|
||||
|
||||
if(header.LoadAddress < 0x6000) {
|
||||
romData.Error = true;
|
||||
}
|
||||
|
||||
if(header.Flags == 0x01) {
|
||||
romData.System = GameSystem::NesPal;
|
||||
}
|
||||
|
||||
//Log window output
|
||||
MessageManager::Log("[NSF] Region: " + string(header.Flags == 0x00 ? "NTSC" : (header.Flags == 0x01 ? "PAL" : "NTSC & PAL")));
|
||||
if(header.PlaySpeedNtsc > 0) {
|
||||
MessageManager::Log("[NSF] Play speed (NTSC): " + std::to_string(1000000.0 / (double)header.PlaySpeedNtsc) + " Hz");
|
||||
}
|
||||
if(header.PlaySpeedPal > 0) {
|
||||
MessageManager::Log("[NSF] Play speed (PAL): " + std::to_string(1000000.0 / (double)header.PlaySpeedPal) + " Hz");
|
||||
}
|
||||
MessageManager::Log("[NSF] Title: " + string(header.SongName));
|
||||
MessageManager::Log("[NSF] Artist: " + string(header.ArtistName));
|
||||
MessageManager::Log("[NSF] Copyright: " + string(header.CopyrightHolder));
|
||||
MessageManager::Log("[NSF] Ripper: " + string(header.RipperName));
|
||||
|
||||
stringstream ss;
|
||||
ss << "[NSF] Load Address: 0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << header.LoadAddress;
|
||||
MessageManager::Log(ss.str());
|
||||
ss = stringstream();
|
||||
ss << "[NSF] Init Address: 0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << header.InitAddress;
|
||||
MessageManager::Log(ss.str());
|
||||
ss = stringstream();
|
||||
ss << "[NSF] Play Address: 0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << header.PlayAddress;
|
||||
MessageManager::Log(ss.str());
|
||||
|
||||
vector<string> chips;
|
||||
if(header.SoundChips & 0x01) {
|
||||
chips.push_back("VRC6");
|
||||
}
|
||||
if(header.SoundChips & 0x02) {
|
||||
chips.push_back("VRC7");
|
||||
}
|
||||
if(header.SoundChips & 0x04) {
|
||||
chips.push_back("FDS");
|
||||
}
|
||||
if(header.SoundChips & 0x08) {
|
||||
chips.push_back("MMC5");
|
||||
}
|
||||
if(header.SoundChips & 0x10) {
|
||||
chips.push_back("Namco 163");
|
||||
}
|
||||
if(header.SoundChips & 0x20) {
|
||||
chips.push_back("Sunsoft 5B");
|
||||
}
|
||||
if(chips.empty()) {
|
||||
chips.push_back("<none>");
|
||||
}
|
||||
|
||||
ss = stringstream();
|
||||
for(size_t i = 0; i < chips.size(); i++) {
|
||||
if(i > 0) {
|
||||
ss << ", ";
|
||||
}
|
||||
ss << chips[i];
|
||||
}
|
||||
|
||||
MessageManager::Log("[NSF] Sound Chips: " + ss.str());
|
||||
MessageManager::Log("[NSF] ROM size: " + std::to_string(romData.PrgRom.size() / 1024) + " KB");
|
||||
}
|
||||
|
||||
void InitHeader(NsfHeader& header)
|
||||
{
|
||||
memset(&header, 0, sizeof(NsfHeader));
|
||||
for(int i = 0; i < 256; i++) {
|
||||
//Used by NSFE
|
||||
header.TrackLength[i] = -1;
|
||||
header.TrackFade[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
RomData LoadRom(vector<uint8_t>& romFile)
|
||||
{
|
||||
RomData romData;
|
||||
NsfHeader &header = romData.NsfHeader;
|
||||
|
||||
InitHeader(header);
|
||||
|
||||
uint8_t* data = romFile.data();
|
||||
Read(data, header.Header, 5);
|
||||
Read(data, header.Version);
|
||||
Read(data, header.TotalSongs);
|
||||
Read(data, header.StartingSong);
|
||||
Read(data, header.LoadAddress);
|
||||
Read(data, header.InitAddress);
|
||||
Read(data, header.PlayAddress);
|
||||
Read(data, header.SongName, 32);
|
||||
Read(data, header.ArtistName, 32);
|
||||
Read(data, header.CopyrightHolder, 32);
|
||||
Read(data, header.PlaySpeedNtsc);
|
||||
Read(data, (char*)header.BankSetup, 8);
|
||||
Read(data, header.PlaySpeedPal);
|
||||
Read(data, header.Flags);
|
||||
Read(data, header.SoundChips);
|
||||
Read(data, (char*)header.Padding, 4);
|
||||
|
||||
//Ensure strings are null terminated
|
||||
header.SongName[31] = 0;
|
||||
header.ArtistName[31] = 0;
|
||||
header.CopyrightHolder[31] = 0;
|
||||
|
||||
if(header.PlaySpeedNtsc == 16666 || header.PlaySpeedNtsc == 16667) {
|
||||
header.PlaySpeedNtsc = 16639;
|
||||
}
|
||||
if(header.PlaySpeedPal == 20000) {
|
||||
header.PlaySpeedPal = 19997;
|
||||
}
|
||||
|
||||
//Pad start of file to make the first block start at a multiple of 4k
|
||||
romData.PrgRom.insert(romData.PrgRom.end(), header.LoadAddress % 4096, 0);
|
||||
|
||||
romData.PrgRom.insert(romData.PrgRom.end(), data, data + romFile.size() - 0x80);
|
||||
|
||||
//Pad out the last block to be a multiple of 4k
|
||||
if(romData.PrgRom.size() % 4096 != 0) {
|
||||
romData.PrgRom.insert(romData.PrgRom.end(), 4096 - (romData.PrgRom.size() % 4096), 0);
|
||||
}
|
||||
|
||||
InitializeFromHeader(romData);
|
||||
|
||||
return romData;
|
||||
}
|
||||
};
|
389
Core/NsfMapper.cpp
Normal file
389
Core/NsfMapper.cpp
Normal file
|
@ -0,0 +1,389 @@
|
|||
#include "stdafx.h"
|
||||
#include "NsfMapper.h"
|
||||
#include "CPU.h"
|
||||
#include "Console.h"
|
||||
|
||||
NsfMapper* NsfMapper::_instance;
|
||||
|
||||
NsfMapper::NsfMapper()
|
||||
{
|
||||
_instance = this;
|
||||
EmulationSettings::DisableOverclocking(true);
|
||||
}
|
||||
|
||||
NsfMapper::~NsfMapper()
|
||||
{
|
||||
if(_instance == this) {
|
||||
_instance = nullptr;
|
||||
EmulationSettings::DisableOverclocking(false);
|
||||
}
|
||||
}
|
||||
|
||||
NsfMapper * NsfMapper::GetInstance()
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
|
||||
void NsfMapper::InitMapper()
|
||||
{
|
||||
SetCpuMemoryMapping(0x3F00, 0x3FFF, GetWorkRam() + 0x2000, MemoryAccessType::Read);
|
||||
memcpy(GetWorkRam() + 0x2000, _nsfBios, 0x100);
|
||||
|
||||
//Clear all register settings
|
||||
RemoveRegisterRange(0x0000, 0xFFFF, MemoryOperation::Any);
|
||||
|
||||
AddRegisterRange(0x3E00, 0x3E13, MemoryOperation::Read);
|
||||
AddRegisterRange(0x3E10, 0x3E13, MemoryOperation::Write);
|
||||
|
||||
//NSF registers
|
||||
AddRegisterRange(0x5FF6, 0x5FFF, MemoryOperation::Write);
|
||||
}
|
||||
|
||||
void NsfMapper::InitMapper(RomData& romData)
|
||||
{
|
||||
_nsfHeader = romData.NsfHeader;
|
||||
|
||||
_hasBankSwitching = HasBankSwitching();
|
||||
if(!_hasBankSwitching) {
|
||||
//Update bank config to allow BIOS to select the right banks on init
|
||||
int8_t startBank = (_nsfHeader.LoadAddress / 0x1000);
|
||||
for(int32_t i = 0; i < (int32_t)GetPRGPageCount(); i++) {
|
||||
if((startBank + i) > 0x0F) {
|
||||
break;
|
||||
}
|
||||
if(startBank + i - 8 >= 0) {
|
||||
_nsfHeader.BankSetup[startBank + i - 8] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_songNumber = _nsfHeader.StartingSong - 1;
|
||||
_ntscSpeed = _nsfHeader.PlaySpeedNtsc * (CPU::ClockRateNtsc / 1000000.0);
|
||||
_palSpeed = _nsfHeader.PlaySpeedPal * (CPU::ClockRatePal / 1000000.0);
|
||||
|
||||
if(_nsfHeader.SoundChips & NsfSoundChips::MMC5) {
|
||||
AddRegisterRange(0x5000, 0x5015, MemoryOperation::Write); //Registers
|
||||
AddRegisterRange(0x5205, 0x5206, MemoryOperation::Any); //Multiplication
|
||||
SetCpuMemoryMapping(0x5C00, 0x5FFF, GetWorkRam() + 0x3000, MemoryAccessType::ReadWrite); //Exram
|
||||
}
|
||||
|
||||
if(_nsfHeader.SoundChips & NsfSoundChips::VRC6) {
|
||||
AddRegisterRange(0x9000, 0x9003, MemoryOperation::Write);
|
||||
AddRegisterRange(0xA000, 0xA002, MemoryOperation::Write);
|
||||
AddRegisterRange(0xB000, 0xB002, MemoryOperation::Write);
|
||||
}
|
||||
|
||||
if(_nsfHeader.SoundChips & NsfSoundChips::Namco) {
|
||||
AddRegisterRange(0x4800, 0x4FFF, MemoryOperation::Any);
|
||||
AddRegisterRange(0xF800, 0xFFFF, MemoryOperation::Write);
|
||||
}
|
||||
|
||||
if(_nsfHeader.SoundChips & NsfSoundChips::Sunsoft) {
|
||||
AddRegisterRange(0xC000, 0xFFFF, MemoryOperation::Write);
|
||||
}
|
||||
|
||||
if(_nsfHeader.SoundChips & NsfSoundChips::FDS) {
|
||||
AddRegisterRange(0x4040, 0x4092, MemoryOperation::Any);
|
||||
}
|
||||
}
|
||||
|
||||
void NsfMapper::Reset(bool softReset)
|
||||
{
|
||||
if(EmulationSettings::GetNsfDisableApuIrqs()) {
|
||||
CPU::SetIRQMask((uint8_t)IRQSource::External);
|
||||
}
|
||||
|
||||
if(!softReset) {
|
||||
_songNumber = _nsfHeader.StartingSong - 1;
|
||||
}
|
||||
|
||||
_needInit = true;
|
||||
_irqEnabled = false;
|
||||
_irqCounter = 0;
|
||||
_irqReloadValue = 0;
|
||||
_irqStatus = NsfIrqType::None;
|
||||
|
||||
_allowSilenceDetection = false;
|
||||
_trackEndCounter = -1;
|
||||
_trackEnded = false;
|
||||
_trackFadeCounter = -1;
|
||||
|
||||
InternalSelectTrack(_songNumber, false);
|
||||
|
||||
//Reset/IRQ vector
|
||||
AddRegisterRange(0xFFFC, 0xFFFF, MemoryOperation::Read);
|
||||
}
|
||||
|
||||
void NsfMapper::GetMemoryRanges(MemoryRanges& ranges)
|
||||
{
|
||||
BaseMapper::GetMemoryRanges(ranges);
|
||||
|
||||
//Allows us to override the PPU's range (0x3E00 - 0x3FFF)
|
||||
ranges.SetAllowOverride();
|
||||
ranges.AddHandler(MemoryOperation::Read, 0x3E00, 0x3FFF);
|
||||
ranges.AddHandler(MemoryOperation::Write, 0x3E00, 0x3FFF);
|
||||
}
|
||||
|
||||
bool NsfMapper::HasBankSwitching()
|
||||
{
|
||||
for(int i = 0; i < 8; i++) {
|
||||
if(_nsfHeader.BankSetup[i] != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void NsfMapper::TriggerIrq(NsfIrqType type)
|
||||
{
|
||||
if(type == NsfIrqType::Init) {
|
||||
_trackEnded = false;
|
||||
}
|
||||
|
||||
_irqStatus = type;
|
||||
CPU::SetIRQSource(IRQSource::External);
|
||||
}
|
||||
|
||||
void NsfMapper::ClearIrq()
|
||||
{
|
||||
_irqStatus = NsfIrqType::None;
|
||||
CPU::ClearIRQSource(IRQSource::External);
|
||||
}
|
||||
|
||||
void NsfMapper::ClockLengthAndFadeCounters()
|
||||
{
|
||||
if(_trackEndCounter > 0) {
|
||||
_trackEndCounter--;
|
||||
if(_trackEndCounter == 0) {
|
||||
_trackEnded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if((_trackEndCounter < 0 || _allowSilenceDetection) && EmulationSettings::GetNsfAutoDetectSilenceDelay() > 0) {
|
||||
//No track length specified
|
||||
if(SoundMixer::GetMuteFrameCount() * SoundMixer::CycleLength > _silenceDetectDelay) {
|
||||
//Auto detect end of track after AutoDetectSilenceDelay (in ms) has gone by without sound
|
||||
_trackEnded = true;
|
||||
SoundMixer::ResetMuteFrameCount();
|
||||
}
|
||||
}
|
||||
|
||||
if(_trackEnded) {
|
||||
if(_trackFadeCounter > 0) {
|
||||
if(_fadeLength != 0) {
|
||||
double fadeRatio = (double)_trackFadeCounter / (double)_fadeLength * 1.2;
|
||||
SoundMixer::SetFadeRatio(std::max(0.0, fadeRatio - 0.2));
|
||||
}
|
||||
_trackFadeCounter--;
|
||||
}
|
||||
|
||||
if(_trackFadeCounter <= 0) {
|
||||
_songNumber = (_songNumber + 1) % _nsfHeader.TotalSongs;
|
||||
InternalSelectTrack(_songNumber);
|
||||
_trackEnded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NsfMapper::ProcessCpuClock()
|
||||
{
|
||||
if(_needInit) {
|
||||
TriggerIrq(NsfIrqType::Init);
|
||||
_needInit = false;
|
||||
}
|
||||
|
||||
if(_irqEnabled) {
|
||||
_irqCounter--;
|
||||
if(_irqCounter == 0) {
|
||||
_irqCounter = _irqReloadValue;
|
||||
TriggerIrq(NsfIrqType::Play);
|
||||
}
|
||||
}
|
||||
|
||||
ClockLengthAndFadeCounters();
|
||||
|
||||
if(_nsfHeader.SoundChips & NsfSoundChips::MMC5) {
|
||||
_mmc5Audio.Clock();
|
||||
}
|
||||
if(_nsfHeader.SoundChips & NsfSoundChips::VRC6) {
|
||||
_vrc6Audio.Clock();
|
||||
}
|
||||
if(_nsfHeader.SoundChips & NsfSoundChips::Namco) {
|
||||
_namcoAudio.Clock();
|
||||
}
|
||||
if(_nsfHeader.SoundChips & NsfSoundChips::Sunsoft) {
|
||||
_sunsoftAudio.Clock();
|
||||
}
|
||||
if(_nsfHeader.SoundChips & NsfSoundChips::FDS) {
|
||||
_fdsAudio.Clock();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t NsfMapper::ReadRegister(uint16_t addr)
|
||||
{
|
||||
if((_nsfHeader.SoundChips & NsfSoundChips::FDS) && addr >= 0x4040 && addr <= 0x4092) {
|
||||
return _fdsAudio.ReadRegister(addr);
|
||||
} else if((_nsfHeader.SoundChips & NsfSoundChips::Namco) && addr >= 0x4800 && addr <= 0x4FFF) {
|
||||
return _namcoAudio.ReadRegister(addr);
|
||||
} else {
|
||||
switch(addr) {
|
||||
case 0x3E00: return _nsfHeader.InitAddress & 0xFF; break;
|
||||
case 0x3E01: return (_nsfHeader.InitAddress >> 8) & 0xFF; break;
|
||||
case 0x3E02: return _nsfHeader.PlayAddress & 0xFF; break;
|
||||
case 0x3E03: return (_nsfHeader.PlayAddress >> 8) & 0xFF; break;
|
||||
case 0x3E04: return _ntscSpeed & 0xFF; break;
|
||||
case 0x3E06: return (_ntscSpeed >> 8) & 0xFF; break;
|
||||
case 0x3E05: return _palSpeed & 0xFF; break;
|
||||
case 0x3E07: return (_palSpeed >> 8) & 0xFF; break;
|
||||
|
||||
case 0x3E08: case 0x3E09: case 0x3E0A: case 0x3E0B:
|
||||
case 0x3E0C: case 0x3E0D: case 0x3E0E: case 0x3E0F:
|
||||
return _nsfHeader.BankSetup[addr & 0x07]; break;
|
||||
|
||||
case 0x3E10: return _songNumber; break;
|
||||
case 0x3E11: return _nsfHeader.Flags == 0x01 ? 0x01 : 0x00; break;
|
||||
case 0x3E12: {
|
||||
NsfIrqType result = _irqStatus;
|
||||
ClearIrq();
|
||||
return (uint8_t)result;
|
||||
}
|
||||
|
||||
case 0x3E13: return _nsfHeader.SoundChips & 0x3F; break;
|
||||
|
||||
case 0x5205: return (_mmc5MultiplierValues[0] * _mmc5MultiplierValues[1]) & 0xFF;
|
||||
case 0x5206: return (_mmc5MultiplierValues[0] * _mmc5MultiplierValues[0]) >> 8;
|
||||
|
||||
//Reset/irq vectors
|
||||
case 0xFFFC: case 0xFFFD: case 0xFFFE: case 0xFFFF:
|
||||
return _nsfBios[addr & 0xFF];
|
||||
}
|
||||
}
|
||||
|
||||
//Open bus
|
||||
return (addr >> 8);
|
||||
}
|
||||
|
||||
void NsfMapper::WriteRegister(uint16_t addr, uint8_t value)
|
||||
{
|
||||
if((_nsfHeader.SoundChips & NsfSoundChips::FDS) && addr >= 0x4040 && addr <= 0x4092) {
|
||||
_fdsAudio.WriteRegister(addr, value);
|
||||
} else if((_nsfHeader.SoundChips & NsfSoundChips::MMC5) && addr >= 0x5000 && addr <= 0x5015) {
|
||||
_mmc5Audio.WriteRegister(addr, value);
|
||||
} else if((_nsfHeader.SoundChips & NsfSoundChips::Namco) && (addr >= 0x4800 && addr <= 0x4FFF || addr >= 0xF800 && addr <= 0xFFFF)) {
|
||||
_namcoAudio.WriteRegister(addr, value);
|
||||
|
||||
//Technically we should call this, but doing so breaks some NSFs
|
||||
/*if(addr >= 0xF800 && _nsfHeader.SoundChips & NsfSoundChips::Sunsoft) {
|
||||
_sunsoftAudio.WriteRegister(addr, value);
|
||||
}*/
|
||||
} else if((_nsfHeader.SoundChips & NsfSoundChips::Sunsoft) && addr >= 0xC000 && addr <= 0xFFFF) {
|
||||
_sunsoftAudio.WriteRegister(addr, value);
|
||||
} else {
|
||||
switch(addr) {
|
||||
case 0x3E10: _irqReloadValue = (_irqReloadValue & 0xFF00) | value; break;
|
||||
case 0x3E11: _irqReloadValue = (_irqReloadValue & 0xFF) | (value << 8); break;
|
||||
|
||||
case 0x3E12:
|
||||
_irqCounter = _irqReloadValue * 5;
|
||||
_irqEnabled = (value > 0);
|
||||
break;
|
||||
|
||||
case 0x3E13:
|
||||
_irqCounter = _irqReloadValue;
|
||||
break;
|
||||
|
||||
//MMC5 multiplication
|
||||
case 0x5205: _mmc5MultiplierValues[0] = value; break;
|
||||
case 0x5206: _mmc5MultiplierValues[1] = value; break;
|
||||
|
||||
case 0x5FF6: case 0x5FF7: {
|
||||
uint16_t addrOffset = (addr == 0x5FF7 ? 0x1000 : 0x0000);
|
||||
if(value == 0xFF || value == 0xFE) {
|
||||
if(!_hasBankSwitching && _nsfHeader.LoadAddress < 0x7000) {
|
||||
//Load address = 0x6000, put bank 0 at $6000
|
||||
SetCpuMemoryMapping(0x6000 + addrOffset, 0x6FFF + addrOffset, value & 0x01, PrgMemoryType::PrgRom, MemoryAccessType::ReadWrite);
|
||||
} else if(!_hasBankSwitching && addrOffset == 0x1000 && _nsfHeader.LoadAddress < 0x8000) {
|
||||
//Load address = 0x7000, put bank 0 at $7000
|
||||
SetCpuMemoryMapping(0x6000 + addrOffset, 0x6FFF + addrOffset, 0, PrgMemoryType::PrgRom, MemoryAccessType::ReadWrite);
|
||||
} else {
|
||||
//Set ram at $6000/7000 (default behavior)
|
||||
SetCpuMemoryMapping(0x6000 + addrOffset, 0x6FFF + addrOffset, value & 0x01, PrgMemoryType::WorkRam);
|
||||
}
|
||||
} else {
|
||||
SetCpuMemoryMapping(0x6000 + addrOffset, 0x6FFF + addrOffset, value, PrgMemoryType::PrgRom, MemoryAccessType::ReadWrite);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x5FF8: case 0x5FF9: case 0x5FFA: case 0x5FFB:
|
||||
case 0x5FFC: case 0x5FFD: case 0x5FFE: case 0x5FFF:
|
||||
SetCpuMemoryMapping(0x8000 + (addr & 0x07) * 0x1000, 0x8FFF + (addr & 0x07) * 0x1000, value, PrgMemoryType::PrgRom, (addr <= 0x5FFD && (_nsfHeader.SoundChips & NsfSoundChips::FDS)) ? MemoryAccessType::ReadWrite : MemoryAccessType::Read);
|
||||
break;
|
||||
|
||||
case 0x9000: case 0x9001: case 0x9002: case 0x9003: case 0xA000: case 0xA001: case 0xA002: case 0xB000: case 0xB001: case 0xB002:
|
||||
_vrc6Audio.WriteRegister(addr, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t NsfMapper::GetClockRate()
|
||||
{
|
||||
return ((_nsfHeader.Flags & 0x01) ? CPU::ClockRatePal : CPU::ClockRateNtsc);
|
||||
}
|
||||
|
||||
void NsfMapper::InternalSelectTrack(uint8_t trackNumber, bool requestReset)
|
||||
{
|
||||
_songNumber = trackNumber;
|
||||
if(requestReset) {
|
||||
//Need to change track while running
|
||||
//Some NSFs keep the interrupt flag on at all times, preventing us from triggering an IRQ to change tracks
|
||||
//Forcing the console to reset ensures changing tracks always works, even with a bad NSF file
|
||||
Console::RequestReset();
|
||||
} else {
|
||||
//Selecting tracking after a reset
|
||||
SoundMixer::SetFadeRatio(1.0);
|
||||
|
||||
//Set track length/fade counters (NSFe)
|
||||
if(_nsfHeader.TrackLength[trackNumber] >= 0) {
|
||||
_trackEndCounter = (double)_nsfHeader.TrackLength[trackNumber] / 1000.0 * GetClockRate();
|
||||
_allowSilenceDetection = false;
|
||||
} else if(_nsfHeader.TotalSongs > 1) {
|
||||
//Only apply a maximum duration to multi-track NSFs
|
||||
//Single track NSFs will loop or restart after a portion of silence
|
||||
//Substract 1 sec from default track time to account for 1 sec default fade time
|
||||
_trackEndCounter = (EmulationSettings::GetNsfMoveToNextTrackTime() - 1) * GetClockRate();
|
||||
_allowSilenceDetection = true;
|
||||
}
|
||||
if(_nsfHeader.TrackFade[trackNumber] >= 0) {
|
||||
_trackFadeCounter = (double)_nsfHeader.TrackFade[trackNumber] / 1000.0 * GetClockRate();
|
||||
} else {
|
||||
//Default to 1 sec fade if none is specified (negative number)
|
||||
_trackFadeCounter = GetClockRate();
|
||||
}
|
||||
|
||||
_silenceDetectDelay = (double)EmulationSettings::GetNsfAutoDetectSilenceDelay() / 1000.0 * GetClockRate();
|
||||
|
||||
_fadeLength = _trackFadeCounter;
|
||||
TriggerIrq(NsfIrqType::Init);
|
||||
}
|
||||
}
|
||||
|
||||
void NsfMapper::SelectTrack(uint8_t trackNumber)
|
||||
{
|
||||
if(trackNumber < _nsfHeader.TotalSongs) {
|
||||
Console::Pause();
|
||||
InternalSelectTrack(trackNumber);
|
||||
Console::Resume();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t NsfMapper::GetCurrentTrack()
|
||||
{
|
||||
return _songNumber;
|
||||
}
|
||||
|
||||
NsfHeader NsfMapper::GetNsfHeader()
|
||||
{
|
||||
return _nsfHeader;
|
||||
}
|
279
Core/NsfMapper.h
Normal file
279
Core/NsfMapper.h
Normal file
|
@ -0,0 +1,279 @@
|
|||
#pragma once
|
||||
#include "BaseMapper.h"
|
||||
#include "MMC5Audio.h"
|
||||
#include "Vrc6Audio.h"
|
||||
#include "FdsAudio.h"
|
||||
#include "Namco163Audio.h"
|
||||
#include "Sunsoft5bAudio.h"
|
||||
|
||||
enum class NsfIrqType
|
||||
{
|
||||
Init = 0,
|
||||
Stop = 1,
|
||||
Play = 2,
|
||||
None = 0xFF
|
||||
};
|
||||
|
||||
class NsfMapper : public BaseMapper
|
||||
{
|
||||
private:
|
||||
static NsfMapper *_instance;
|
||||
|
||||
enum NsfSoundChips
|
||||
{
|
||||
VRC6 = 0x01,
|
||||
VRC7 = 0x02,
|
||||
FDS = 0x04,
|
||||
MMC5 = 0x08,
|
||||
Namco = 0x10,
|
||||
Sunsoft = 0x20
|
||||
};
|
||||
|
||||
NsfHeader _nsfHeader;
|
||||
MMC5Audio _mmc5Audio;
|
||||
Vrc6Audio _vrc6Audio;
|
||||
FdsAudio _fdsAudio;
|
||||
Namco163Audio _namcoAudio;
|
||||
Sunsoft5bAudio _sunsoftAudio;
|
||||
|
||||
bool _needInit = false;
|
||||
bool _irqEnabled = false;
|
||||
uint32_t _irqReloadValue = 0;
|
||||
uint32_t _irqCounter = 0;
|
||||
NsfIrqType _irqStatus = NsfIrqType::None;
|
||||
uint8_t _mmc5MultiplierValues[2];
|
||||
|
||||
int32_t _trackEndCounter;
|
||||
int32_t _trackFadeCounter;
|
||||
int32_t _fadeLength;
|
||||
uint32_t _silenceDetectDelay;
|
||||
bool _trackEnded;
|
||||
bool _allowSilenceDetection;
|
||||
|
||||
bool _hasBankSwitching;
|
||||
|
||||
uint16_t _ntscSpeed;
|
||||
uint16_t _palSpeed;
|
||||
|
||||
uint8_t _songNumber = 0;
|
||||
|
||||
/*****************************************
|
||||
* NSF BIOS by Quietust, all credits to him!
|
||||
* Taken from the Nintendulator source code:
|
||||
* http://www.qmtpro.com/~nes/nintendulator/
|
||||
* See below for assembly source code
|
||||
******************************************/
|
||||
uint8_t _nsfBios[256] = {
|
||||
0xFF,0xFF,0xFF,0x78,0xA2,0xFF,0x8E,0x17,0x40,0xE8,0x20,0x30,0x3F,0x8E,0x00,0x20,
|
||||
0x8E,0x01,0x20,0x8E,0x12,0x3E,0x58,0x4C,0x17,0x3F,0x48,0x8A,0x48,0x98,0x48,0xAE,
|
||||
0x12,0x3E,0xF0,0x59,0xCA,0xF0,0xDC,0x20,0xF9,0x3F,0x68,0xA8,0x68,0xAA,0x68,0x40,
|
||||
0x8E,0x15,0x40,0xAD,0x13,0x3E,0x4A,0x90,0x09,0x8E,0x02,0x90,0x8E,0x02,0xA0,0x8E,
|
||||
0x02,0xB0,0x4A,0x90,0x0D,0xA0,0x20,0x8C,0x10,0x90,0x8E,0x30,0x90,0xC8,0xC0,0x26,
|
||||
0xD0,0xF5,0x4A,0x90,0x0B,0xA0,0x80,0x8C,0x83,0x40,0x8C,0x87,0x40,0x8C,0x89,0x40,
|
||||
0x4A,0x90,0x03,0x8E,0x15,0x50,0x4A,0x90,0x08,0xCA,0x8E,0x00,0xF8,0xE8,0x8E,0x00,
|
||||
0x48,0x4A,0x90,0x08,0xA0,0x07,0x8C,0x00,0xC0,0x8C,0x00,0xE0,0x60,0x20,0x30,0x3F,
|
||||
0x8A,0xCA,0x9A,0x8E,0xF7,0x5F,0xCA,0x8E,0xF6,0x5F,0xA2,0x7F,0x85,0x00,0x86,0x01,
|
||||
0xA8,0xA2,0x27,0x91,0x00,0xC8,0xD0,0xFB,0xCA,0x30,0x0A,0xC6,0x01,0xE0,0x07,0xD0,
|
||||
0xF2,0x86,0x01,0xF0,0xEE,0xA2,0x14,0xCA,0x9D,0x00,0x40,0xD0,0xFA,0xA2,0x07,0xBD,
|
||||
0x08,0x3E,0x9D,0xF8,0x5F,0xCA,0x10,0xF7,0xA0,0x0F,0x8C,0x15,0x40,0xAD,0x13,0x3E,
|
||||
0x29,0x04,0xF0,0x10,0xAD,0x0E,0x3E,0xF0,0x03,0x8D,0xF6,0x5F,0xAD,0x0F,0x3E,0xF0,
|
||||
0x03,0x8D,0xF7,0x5F,0xAE,0x11,0x3E,0xBD,0x04,0x3E,0x8D,0x10,0x3E,0xBD,0x06,0x3E,
|
||||
0x8D,0x11,0x3E,0x8C,0x12,0x3E,0xAD,0x12,0x3E,0x58,0xAD,0x10,0x3E,0x20,0xF6,0x3F,
|
||||
0x8D,0x13,0x3E,0x4C,0x17,0x3F,0x6C,0x00,0x3E,0x6C,0x02,0x3E,0x03,0x3F,0x1A,0x3F
|
||||
};
|
||||
|
||||
private:
|
||||
void TriggerIrq(NsfIrqType type);
|
||||
void ClearIrq();
|
||||
|
||||
bool HasBankSwitching();
|
||||
uint32_t GetClockRate();
|
||||
|
||||
void InternalSelectTrack(uint8_t trackNumber, bool requestReset = true);
|
||||
void ClockLengthAndFadeCounters();
|
||||
|
||||
protected:
|
||||
uint16_t GetPRGPageSize() { return 0x1000; }
|
||||
uint16_t GetCHRPageSize() { return 0x2000; }
|
||||
uint32_t GetWorkRamSize() { return 0x4000; }
|
||||
uint32_t GetWorkRamPageSize() { return 0x1000; }
|
||||
bool AllowRegisterRead() { return true; }
|
||||
|
||||
void InitMapper();
|
||||
void InitMapper(RomData& romData);
|
||||
void Reset(bool softReset);
|
||||
void GetMemoryRanges(MemoryRanges &ranges);
|
||||
|
||||
void ProcessCpuClock();
|
||||
uint8_t ReadRegister(uint16_t addr);
|
||||
void WriteRegister(uint16_t addr, uint8_t value);
|
||||
|
||||
public:
|
||||
NsfMapper();
|
||||
~NsfMapper();
|
||||
|
||||
static NsfMapper* GetInstance();
|
||||
|
||||
void SelectTrack(uint8_t trackNumber);
|
||||
uint8_t GetCurrentTrack();
|
||||
NsfHeader GetNsfHeader();
|
||||
};
|
||||
|
||||
/*
|
||||
;BIOS Source Code
|
||||
;NSF BIOS by Quietust, all credits to him!
|
||||
;Taken from the Nintendulator source code:
|
||||
;http://www.qmtpro.com/~nes/nintendulator/
|
||||
|
||||
;NSF Mapper
|
||||
;R $3E00-$3E01 - INIT address
|
||||
;R $3E02-$3E03 - PLAY address
|
||||
;R $3E04/$3E06 - NTSC speed value
|
||||
;R $3E05/$3E07 - PAL speed value
|
||||
;R $3E08-$3E0F - Initial bankswitch values
|
||||
;R $3E10 - Song Number (start at 0)
|
||||
;R $3E11 - NTSC/PAL setting (0 for NTSC, 1 for PAL)
|
||||
;W $3E10-$3E11 - IRQ counter (for PLAY)
|
||||
;R $3E12 - IRQ status (0=INIT, 1=STOP, 2+=PLAY)
|
||||
;W $3E12 - IRQ enable (for PLAY)
|
||||
;R $3E13 - Sound chip info
|
||||
;W $3E13 - clear watchdog timer
|
||||
|
||||
.org $3F00
|
||||
.db $FF,$FF,$FF ;pad to 256 bytes
|
||||
reset:SEI
|
||||
LDX #$FF
|
||||
STX $4017 ;kill frame IRQs
|
||||
INX
|
||||
JSR silence ;silence all sound channels
|
||||
STX $2000 ;we don't rely on the presence of a PPU
|
||||
STX $2001 ;but we don't want it getting in the way
|
||||
STX $3E12 ;kill PLAY timer
|
||||
CLI
|
||||
loop: JMP loop
|
||||
|
||||
irq: PHA
|
||||
TXA
|
||||
PHA
|
||||
TYA
|
||||
PHA
|
||||
LDX $3E12 ;check IRQ status
|
||||
BEQ init
|
||||
DEX
|
||||
BEQ reset ;"Proper" way to play a tune
|
||||
JSR song_play ;1) Call the play address of the music at periodic intervals determined by the speed words.
|
||||
PLA
|
||||
TAY
|
||||
PLA
|
||||
TAX
|
||||
PLA
|
||||
RTI
|
||||
|
||||
.module silence
|
||||
silence: ;X=0 coming in, must also be coming out
|
||||
STX $4015 ;silence all sound channels
|
||||
LDA $3E13
|
||||
LSR A
|
||||
BCC _1
|
||||
STX $9002
|
||||
STX $A002
|
||||
STX $B002 ;stop VRC6
|
||||
_1: LSR A
|
||||
BCC _2
|
||||
LDY #$20
|
||||
__2: STY $9010
|
||||
STX $9030 ;stop VRC7
|
||||
INY
|
||||
CPY #$26
|
||||
BNE __2
|
||||
_2: LSR A
|
||||
BCC _3
|
||||
LDY #$80
|
||||
STY $4083
|
||||
STY $4087
|
||||
STY $4089 ;stop FDS
|
||||
_3: LSR A
|
||||
BCC _4
|
||||
STX $5015 ;stop MMC5
|
||||
_4: LSR A
|
||||
BCC _5
|
||||
DEX
|
||||
STX $F800
|
||||
INX
|
||||
STX $4800 ;stop Namco-163
|
||||
_5: LSR A
|
||||
BCC _6
|
||||
LDY #$07
|
||||
STY $C000
|
||||
STY $E000 ;stop SUN5
|
||||
_6: RTS
|
||||
|
||||
.module init ;"Proper" way to init a tune
|
||||
init: JSR silence
|
||||
TXA ;(X=0)
|
||||
DEX
|
||||
TXS ;clear the stack
|
||||
STX $5FF7 ;1.5) Map RAM to $6000-$7FFF
|
||||
DEX
|
||||
STX $5FF6 ;(banks FE/FF are treated as RAM)
|
||||
|
||||
LDX #$7F
|
||||
STA $00
|
||||
STX $01
|
||||
TAY
|
||||
LDX #$27
|
||||
_1: STA ($00),Y ;1) Clear all RAM at $0000-$07FF.
|
||||
INY ;2) Clear all RAM at $6000-$7FFF.
|
||||
BNE _1
|
||||
DEX
|
||||
BMI _2
|
||||
DEC $01
|
||||
CPX #$07
|
||||
BNE _1
|
||||
STX $01
|
||||
BEQ _1
|
||||
|
||||
_2: LDX #$14
|
||||
_3: DEX
|
||||
STA $4000,X ;3) Init the sound registers by writing $00 to $4000-$4013
|
||||
BNE _3
|
||||
|
||||
LDX #$07
|
||||
_4: LDA $3E08,X ;5) If this is a banked tune, load the bank values from the header into $5FF8-$5FFF.
|
||||
STA $5FF8,X ;For this player, *all* tunes are considered banked (the loader will fill in appropriate values)
|
||||
DEX
|
||||
BPL _4
|
||||
|
||||
LDY #$0F ;4) Set volume register $4015 to $0F.
|
||||
STY $4015
|
||||
|
||||
LDA $3E13 ;For FDS games, banks E/F also get mapped to 6/7
|
||||
AND #$04 ;For non-FDS games, we don't want to do this
|
||||
BEQ _6
|
||||
LDA $3E0E ;if these are zero, let's leave them as plain RAM
|
||||
BEQ _5
|
||||
STA $5FF6
|
||||
_5: LDA $3E0F ;TODO - need to allow FDS NSF data to be writeable
|
||||
BEQ _6
|
||||
STA $5FF7
|
||||
|
||||
_6: LDX $3E11 ;4.5) Set up the PLAY timer. Which word to use is determined by which mode you are in - PAL or NTSC.
|
||||
LDA $3E04,X ;X is 0 for NTSC and 1 for PAL, as needed for #6 below
|
||||
STA $3E10
|
||||
LDA $3E06,X
|
||||
STA $3E11
|
||||
STY $3E12
|
||||
LDA $3E12 ;if we have a pending IRQ here, we need to cancel it NOW
|
||||
CLI ;re-enable interrupts now - this way, we can allow the init routine to not return (ex: for raw PCM)
|
||||
|
||||
LDA $3E10 ;6) Set the accumulator and X registers for the desired song.
|
||||
JSR song_init ;7) Call the music init routine.
|
||||
STA $3E13 ;kill the watchdog timer (and fire a 'Play' interrupt after 1 frame; otherwise, it'll wait 4 frames)
|
||||
JMP loop ;we don't actually RTI from here; this way, the init code is faster
|
||||
|
||||
.module song
|
||||
song_init: JMP ($3E00)
|
||||
song_play: JMP ($3E02)
|
||||
.dw reset,irq ;no NMI vector
|
||||
.end
|
||||
*/
|
22
Core/NsfPpu.h
Normal file
22
Core/NsfPpu.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "PPU.h"
|
||||
|
||||
class NsfPpu : public PPU
|
||||
{
|
||||
protected:
|
||||
void DrawPixel()
|
||||
{
|
||||
}
|
||||
|
||||
void SendFrame()
|
||||
{
|
||||
MessageManager::SendNotification(ConsoleNotificationType::PpuFrameDone);
|
||||
}
|
||||
|
||||
public:
|
||||
NsfPpu(MemoryManager* memoryManager) : PPU(memoryManager)
|
||||
{
|
||||
_simpleMode = true;
|
||||
}
|
||||
};
|
194
Core/NsfeLoader.h
Normal file
194
Core/NsfeLoader.h
Normal file
|
@ -0,0 +1,194 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "RomData.h"
|
||||
#include <algorithm>
|
||||
#include "NsfLoader.h"
|
||||
|
||||
class NsfeLoader : public NsfLoader
|
||||
{
|
||||
private:
|
||||
void Read(uint8_t* &data, uint8_t& dest)
|
||||
{
|
||||
dest = data[0];
|
||||
data++;
|
||||
}
|
||||
|
||||
void Read(uint8_t* &data, uint16_t& dest)
|
||||
{
|
||||
dest = data[0] | (data[1] << 8);
|
||||
data += 2;
|
||||
}
|
||||
|
||||
void Read(uint8_t* &data, uint32_t& dest)
|
||||
{
|
||||
dest = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
|
||||
data += 4;
|
||||
}
|
||||
|
||||
void Read(uint8_t* &data, int32_t& dest)
|
||||
{
|
||||
dest = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
|
||||
data += 4;
|
||||
}
|
||||
|
||||
void Read(uint8_t* &data, char* dest, size_t len)
|
||||
{
|
||||
memcpy(dest, data, len);
|
||||
data += len;
|
||||
}
|
||||
|
||||
vector<string> ReadStrings(uint8_t* &data, uint8_t* chunkEnd)
|
||||
{
|
||||
vector<string> strings;
|
||||
stringstream ss;
|
||||
while(data < chunkEnd) {
|
||||
if(data[0] == 0) {
|
||||
//end of string
|
||||
strings.push_back(ss.str());
|
||||
ss = stringstream();
|
||||
} else {
|
||||
ss << (char)data[0];
|
||||
}
|
||||
data++;
|
||||
}
|
||||
|
||||
//truncate all strings to 255 characters + null
|
||||
for(int i = 0; i < strings.size(); i++) {
|
||||
strings[i] = strings[i].substr(0, std::min((int)strings[i].size(), 255));
|
||||
}
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
string ReadFourCC(uint8_t* &data)
|
||||
{
|
||||
stringstream ss;
|
||||
for(int i = 0; i < 4; i++) {
|
||||
ss << (char)data[i];
|
||||
}
|
||||
data += 4;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
bool ReadChunk(uint8_t* &data, uint8_t* dataEnd, RomData& romData)
|
||||
{
|
||||
NsfHeader& header = romData.NsfHeader;
|
||||
|
||||
uint32_t length;
|
||||
Read(data, length);
|
||||
|
||||
uint8_t* chunkEnd = data + 4 + length;
|
||||
|
||||
if(chunkEnd > dataEnd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
string fourCC = ReadFourCC(data);
|
||||
if(fourCC.compare("INFO") == 0) {
|
||||
Read(data, header.LoadAddress);
|
||||
Read(data, header.InitAddress);
|
||||
Read(data, header.PlayAddress);
|
||||
Read(data, header.Flags);
|
||||
Read(data, header.SoundChips);
|
||||
Read(data, header.TotalSongs);
|
||||
Read(data, header.StartingSong);
|
||||
|
||||
header.PlaySpeedNtsc = 16639;
|
||||
header.PlaySpeedPal = 19997;
|
||||
|
||||
//Adjust to match NSF spec
|
||||
header.StartingSong++;
|
||||
} else if(fourCC.compare("DATA") == 0) {
|
||||
//Pad start of file to make the first block start at a multiple of 4k
|
||||
romData.PrgRom.insert(romData.PrgRom.end(), header.LoadAddress % 4096, 0);
|
||||
|
||||
romData.PrgRom.insert(romData.PrgRom.end(), (uint8_t*)data, data+length);
|
||||
|
||||
//Pad out the last block to be a multiple of 4k
|
||||
if(romData.PrgRom.size() % 4096 != 0) {
|
||||
romData.PrgRom.insert(romData.PrgRom.end(), 4096 - (romData.PrgRom.size() % 4096), 0);
|
||||
}
|
||||
} else if(fourCC.compare("NEND") == 0) {
|
||||
//End of file
|
||||
romData.Error = false;
|
||||
return false;
|
||||
} else if(fourCC.compare("BANK") == 0) {
|
||||
memset(header.BankSetup, 0, sizeof(header.BankSetup));
|
||||
Read(data, (char*)header.BankSetup, std::min(8, (int)length));
|
||||
} else if(fourCC.compare("plst") == 0) {
|
||||
//not supported
|
||||
} else if(fourCC.compare("time") == 0) {
|
||||
int i = 0;
|
||||
while(data < chunkEnd) {
|
||||
Read(data, header.TrackLength[i]);
|
||||
i++;
|
||||
}
|
||||
} else if(fourCC.compare("fade") == 0) {
|
||||
int i = 0;
|
||||
while(data < chunkEnd) {
|
||||
Read(data, header.TrackFade[i]);
|
||||
i++;
|
||||
}
|
||||
} else if(fourCC.compare("tlbl") == 0) {
|
||||
vector<string> trackNames = ReadStrings(data, chunkEnd);
|
||||
stringstream ss;
|
||||
for(string &trackName : trackNames) {
|
||||
ss << trackName;
|
||||
ss << "[!|!]";
|
||||
}
|
||||
strcpy_s(header.TrackName, ss.str().c_str());
|
||||
|
||||
} else if(fourCC.compare("auth") == 0) {
|
||||
vector<string> infoStrings = ReadStrings(data, chunkEnd);
|
||||
|
||||
if(infoStrings.size() > 0) {
|
||||
strcpy_s(header.SongName, infoStrings[0].c_str());
|
||||
if(infoStrings.size() > 1) {
|
||||
strcpy_s(header.ArtistName, infoStrings[1].c_str());
|
||||
if(infoStrings.size() > 2) {
|
||||
strcpy_s(header.CopyrightHolder, infoStrings[2].c_str());
|
||||
if(infoStrings.size() > 3) {
|
||||
strcpy_s(header.RipperName, infoStrings[3].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(fourCC.compare("text") == 0) {
|
||||
//not supported
|
||||
} else {
|
||||
if(fourCC[0] >= 'A' && fourCC[0] <= 'Z') {
|
||||
//unknown required block, can't read file
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
data = chunkEnd;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
RomData LoadRom(vector<uint8_t>& romFile)
|
||||
{
|
||||
RomData romData;
|
||||
NsfHeader &header = romData.NsfHeader;
|
||||
|
||||
InitHeader(header);
|
||||
|
||||
uint8_t* data = romFile.data() + 4;
|
||||
|
||||
memset(header.SongName, 0, sizeof(header.SongName));
|
||||
memset(header.ArtistName, 0, sizeof(header.ArtistName));
|
||||
memset(header.CopyrightHolder, 0, sizeof(header.CopyrightHolder));
|
||||
|
||||
//Will be set to false when we read NEND block
|
||||
romData.Error = true;
|
||||
while(ReadChunk(data, data + romFile.size(), romData)) {
|
||||
//Read all chunks
|
||||
}
|
||||
|
||||
InitializeFromHeader(romData);
|
||||
|
||||
return romData;
|
||||
}
|
||||
};
|
27
Core/PPU.cpp
27
Core/PPU.cpp
|
@ -25,6 +25,8 @@ PPU::PPU(MemoryManager *memoryManager)
|
|||
memset(_spriteRAM, 0xFF, 0x100);
|
||||
memset(_secondarySpriteRAM, 0xFF, 0x20);
|
||||
|
||||
_simpleMode = false;
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
@ -877,14 +879,23 @@ void PPU::Exec()
|
|||
|
||||
Debugger::ProcessPpuCycle();
|
||||
|
||||
if(_scanline != -1 && _scanline < 240) {
|
||||
ProcessVisibleScanline();
|
||||
} else if(_scanline == -1) {
|
||||
ProcessPrerenderScanline();
|
||||
} else if(_scanline == _nmiScanline) {
|
||||
BeginVBlank();
|
||||
} else if(_scanline == _vblankEnd) {
|
||||
EndVBlank();
|
||||
if(!_simpleMode) {
|
||||
if(_scanline != -1 && _scanline < 240) {
|
||||
ProcessVisibleScanline();
|
||||
} else if(_scanline == -1) {
|
||||
ProcessPrerenderScanline();
|
||||
} else if(_scanline == _nmiScanline) {
|
||||
BeginVBlank();
|
||||
} else if(_scanline == _vblankEnd) {
|
||||
EndVBlank();
|
||||
}
|
||||
} else {
|
||||
//Used by NSF player to speed things up
|
||||
if(_scanline == _nmiScanline) {
|
||||
BeginVBlank();
|
||||
} else if(_scanline == _vblankEnd) {
|
||||
EndVBlank();
|
||||
}
|
||||
}
|
||||
|
||||
//Rendering enabled flag is apparently set with a 1 cycle delay (i.e setting it at cycle 5 will render cycle 6 like cycle 5 and then take the new settings for cycle 7)
|
||||
|
|
|
@ -152,6 +152,9 @@ class PPU : public IMemoryHandler, public Snapshotable
|
|||
|
||||
double _cyclesNeeded;
|
||||
|
||||
//Used by NSF player for higher performance
|
||||
bool _simpleMode;
|
||||
|
||||
//Used to resolve a race condition when the 2nd write to $2006 occurs at cycle 255 (i.e approx. the same time as the PPU tries to increase Y scrolling)
|
||||
bool _skipScrollingIncrement;
|
||||
|
||||
|
@ -204,6 +207,11 @@ class PPU : public IMemoryHandler, public Snapshotable
|
|||
}
|
||||
}
|
||||
|
||||
void SetSimpleMode()
|
||||
{
|
||||
_simpleMode = true;
|
||||
}
|
||||
|
||||
void StreamState(bool saving);
|
||||
|
||||
public:
|
||||
|
|
|
@ -196,17 +196,43 @@ struct NESHeader
|
|||
}
|
||||
};
|
||||
|
||||
struct NsfHeader
|
||||
{
|
||||
char Header[5];
|
||||
uint8_t Version;
|
||||
uint8_t TotalSongs;
|
||||
uint8_t StartingSong;
|
||||
uint16_t LoadAddress;
|
||||
uint16_t InitAddress;
|
||||
uint16_t PlayAddress;
|
||||
char SongName[256];
|
||||
char ArtistName[256];
|
||||
char CopyrightHolder[256];
|
||||
uint16_t PlaySpeedNtsc;
|
||||
uint8_t BankSetup[8];
|
||||
uint16_t PlaySpeedPal;
|
||||
uint8_t Flags;
|
||||
uint8_t SoundChips;
|
||||
uint8_t Padding[4];
|
||||
|
||||
//NSFe extensions
|
||||
char RipperName[256];
|
||||
char TrackName[20000];
|
||||
int32_t TrackLength[256];
|
||||
int32_t TrackFade[256];
|
||||
};
|
||||
|
||||
struct RomData
|
||||
{
|
||||
string RomName;
|
||||
string Filename;
|
||||
|
||||
uint16_t MapperID;
|
||||
uint16_t MapperID = 0;
|
||||
uint8_t SubMapperID = 0;
|
||||
GameSystem System = GameSystem::Unknown;
|
||||
bool HasBattery = false;
|
||||
bool HasTrainer = false;
|
||||
MirroringType MirroringType;
|
||||
MirroringType MirroringType = MirroringType::Horizontal;
|
||||
int32_t ChrRamSize = -1;
|
||||
|
||||
bool IsNes20Header = false;
|
||||
|
@ -217,9 +243,10 @@ struct RomData
|
|||
vector<vector<uint8_t>> FdsDiskData;
|
||||
|
||||
vector<uint8_t> RawData;
|
||||
uint32_t Crc32;
|
||||
uint32_t Crc32 = 0;
|
||||
|
||||
bool Error = false;
|
||||
|
||||
NESHeader NesHeader;
|
||||
NsfHeader NsfHeader;
|
||||
};
|
|
@ -5,6 +5,8 @@
|
|||
#include "RomLoader.h"
|
||||
#include "iNesLoader.h"
|
||||
#include "FdsLoader.h"
|
||||
#include "NsfLoader.h"
|
||||
#include "NsfeLoader.h"
|
||||
|
||||
vector<string> RomLoader::GetArchiveRomList(string filename)
|
||||
{
|
||||
|
@ -17,11 +19,11 @@ vector<string> RomLoader::GetArchiveRomList(string filename)
|
|||
if(memcmp(header, "PK", 2) == 0) {
|
||||
ZipReader reader;
|
||||
reader.LoadArchive(filename);
|
||||
return reader.GetFileList({ ".nes", ".fds" });
|
||||
return reader.GetFileList({ ".nes", ".fds", ".nsf", ".nsfe" });
|
||||
} else if(memcmp(header, "7z", 2) == 0) {
|
||||
SZReader reader;
|
||||
reader.LoadArchive(filename);
|
||||
return reader.GetFileList({ ".nes", ".fds" });
|
||||
return reader.GetFileList({ ".nes", ".fds", ".nsf", ".nsfe" });
|
||||
}
|
||||
}
|
||||
return{};
|
||||
|
@ -36,7 +38,7 @@ bool RomLoader::LoadFromArchive(istream &zipFile, ArchiveReader& reader, int32_t
|
|||
|
||||
reader.LoadArchive(buffer, fileSize);
|
||||
|
||||
vector<string> fileList = reader.GetFileList({ ".nes", ".fds" });
|
||||
vector<string> fileList = reader.GetFileList({ ".nes", ".fds", ".nsf", ".nsfe" });
|
||||
int32_t currentIndex = 0;
|
||||
if(archiveFileIndex > (int32_t)fileList.size()) {
|
||||
return false;
|
||||
|
@ -110,6 +112,12 @@ bool RomLoader::LoadFromMemory(uint8_t* buffer, size_t length, string romName)
|
|||
} else if(memcmp(buffer, "FDS\x1a", 4) == 0 || memcmp(buffer, "\x1*NINTENDO-HVC*", 15) == 0) {
|
||||
FdsLoader loader;
|
||||
_romData = loader.LoadRom(fileData, _filename);
|
||||
} else if(memcmp(buffer, "NESM\x1a", 5) == 0) {
|
||||
NsfLoader loader;
|
||||
_romData = loader.LoadRom(fileData);
|
||||
} else if(memcmp(buffer, "NSFE", 4) == 0) {
|
||||
NsfeLoader loader;
|
||||
_romData = loader.LoadRom(fileData);
|
||||
} else {
|
||||
MessageManager::Log("Invalid rom file.");
|
||||
_romData.Error = true;
|
||||
|
@ -159,7 +167,7 @@ bool RomLoader::LoadFile(string filename, istream *filestream, string ipsFilenam
|
|||
} else if(memcmp(header, "7z", 2) == 0) {
|
||||
SZReader reader;
|
||||
return LoadFromArchive(*input, reader, archiveFileIndex);
|
||||
} else if(memcmp(header, "NES\x1a", 4) == 0 || memcmp(header, "FDS\x1a", 4) == 0 || memcmp(header, "\x1*NINTENDO-HVC*", 15) == 0) {
|
||||
} else if(memcmp(header, "NES\x1a", 4) == 0 || memcmp(header, "NESM\x1a", 5) == 0 || memcmp(header, "NSFE", 4) == 0 || memcmp(header, "FDS\x1a", 4) == 0 || memcmp(header, "\x1*NINTENDO-HVC*", 15) == 0) {
|
||||
if(archiveFileIndex > 0) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
IAudioDevice* SoundMixer::AudioDevice = nullptr;
|
||||
unique_ptr<WaveRecorder> SoundMixer::_waveRecorder;
|
||||
SimpleLock SoundMixer::_waveRecorderLock;
|
||||
double SoundMixer::_fadeRatio;
|
||||
uint32_t SoundMixer::_muteFrameCount;
|
||||
|
||||
SoundMixer::SoundMixer()
|
||||
{
|
||||
|
@ -27,7 +29,7 @@ SoundMixer::~SoundMixer()
|
|||
|
||||
void SoundMixer::StreamState(bool saving)
|
||||
{
|
||||
Stream(_clockRate, _sampleRate, _expansionAudioType);
|
||||
Stream(_clockRate, _sampleRate);
|
||||
|
||||
if(!saving) {
|
||||
Reset();
|
||||
|
@ -56,6 +58,9 @@ void SoundMixer::StopAudio(bool clearBuffer)
|
|||
|
||||
void SoundMixer::Reset()
|
||||
{
|
||||
_fadeRatio = 1.0;
|
||||
_muteFrameCount = 0;
|
||||
|
||||
_previousOutput = 0;
|
||||
blip_clear(_blipBuf);
|
||||
|
||||
|
@ -153,15 +158,12 @@ int16_t SoundMixer::GetOutputVolume()
|
|||
uint16_t squareVolume = (uint16_t)(95.52 / (8128.0 / squareOutput + 100.0) * 5000);
|
||||
uint16_t tndVolume = (uint16_t)(163.67 / (24329.0 / tndOutput + 100.0) * 5000);
|
||||
|
||||
int16_t expansionOutput = 0;
|
||||
switch(_expansionAudioType) {
|
||||
case AudioChannel::FDS: expansionOutput = (int16_t)(_currentOutput[ExpansionAudioIndex] * _volumes[ExpansionAudioIndex] * 20); break;
|
||||
case AudioChannel::MMC5: expansionOutput = (int16_t)(_currentOutput[ExpansionAudioIndex] * _volumes[ExpansionAudioIndex] * 40); 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;
|
||||
case AudioChannel::VRC6: expansionOutput = (int16_t)(_currentOutput[ExpansionAudioIndex] * _volumes[ExpansionAudioIndex] * 75); break;
|
||||
}
|
||||
return squareVolume + tndVolume + expansionOutput;
|
||||
return (int16_t)(squareVolume + tndVolume +
|
||||
GetChannelOutput(AudioChannel::FDS) * 20 +
|
||||
GetChannelOutput(AudioChannel::MMC5) * 40 +
|
||||
GetChannelOutput(AudioChannel::Namco163) * 20 +
|
||||
GetChannelOutput(AudioChannel::Sunsoft5B) * 15 +
|
||||
GetChannelOutput(AudioChannel::VRC6) * 75);
|
||||
}
|
||||
|
||||
void SoundMixer::AddDelta(AudioChannel channel, uint32_t time, int16_t delta)
|
||||
|
@ -172,25 +174,14 @@ void SoundMixer::AddDelta(AudioChannel channel, uint32_t time, int16_t delta)
|
|||
}
|
||||
}
|
||||
|
||||
void SoundMixer::AddExpansionAudioDelta(uint32_t time, int16_t delta)
|
||||
{
|
||||
if(delta != 0) {
|
||||
_timestamps.push_back(time);
|
||||
_channelOutput[ExpansionAudioIndex][time] += delta;
|
||||
}
|
||||
}
|
||||
|
||||
void SoundMixer::SetExpansionAudioType(AudioChannel channel)
|
||||
{
|
||||
_expansionAudioType = channel;
|
||||
}
|
||||
|
||||
void SoundMixer::EndFrame(uint32_t time)
|
||||
{
|
||||
double masterVolume = EmulationSettings::GetMasterVolume();
|
||||
sort(_timestamps.begin(), _timestamps.end());
|
||||
_timestamps.erase(std::unique(_timestamps.begin(), _timestamps.end()), _timestamps.end());
|
||||
|
||||
bool muteFrame = true;
|
||||
int16_t originalOutput = _previousOutput;
|
||||
for(size_t i = 0, len = _timestamps.size(); i < len; i++) {
|
||||
uint32_t stamp = _timestamps[i];
|
||||
for(int j = 0; j < MaxChannelCount; j++) {
|
||||
|
@ -198,14 +189,32 @@ void SoundMixer::EndFrame(uint32_t time)
|
|||
}
|
||||
|
||||
int16_t currentOutput = GetOutputVolume();
|
||||
blip_add_delta(_blipBuf, stamp, (int)((currentOutput - _previousOutput) * masterVolume));
|
||||
_previousOutput = currentOutput;
|
||||
blip_add_delta(_blipBuf, stamp, (int)((currentOutput - _previousOutput) * masterVolume * _fadeRatio));
|
||||
|
||||
if(currentOutput != _previousOutput) {
|
||||
if(std::abs(currentOutput - _previousOutput) > 100) {
|
||||
muteFrame = false;
|
||||
}
|
||||
_previousOutput = currentOutput;
|
||||
}
|
||||
}
|
||||
|
||||
if(std::abs(originalOutput - _previousOutput) > 1500) {
|
||||
//Count mute frames (10000 cycles each) - used by NSF player
|
||||
muteFrame = false;
|
||||
}
|
||||
|
||||
blip_end_frame(_blipBuf, time);
|
||||
|
||||
if(muteFrame) {
|
||||
_muteFrameCount++;
|
||||
} else {
|
||||
_muteFrameCount = 0;
|
||||
}
|
||||
|
||||
//Reset everything
|
||||
for(int i = 0; i < MaxChannelCount; i++) {
|
||||
_volumes[i] = EmulationSettings::GetChannelVolume(i < 5 ? (AudioChannel)i : _expansionAudioType);
|
||||
_volumes[i] = EmulationSettings::GetChannelVolume((AudioChannel)i);
|
||||
}
|
||||
|
||||
_timestamps.clear();
|
||||
|
@ -227,4 +236,19 @@ void SoundMixer::StopRecording()
|
|||
bool SoundMixer::IsRecording()
|
||||
{
|
||||
return _waveRecorder.get() != nullptr;
|
||||
}
|
||||
|
||||
void SoundMixer::SetFadeRatio(double fadeRatio)
|
||||
{
|
||||
_fadeRatio = fadeRatio;
|
||||
}
|
||||
|
||||
uint32_t SoundMixer::GetMuteFrameCount()
|
||||
{
|
||||
return _muteFrameCount;
|
||||
}
|
||||
|
||||
void SoundMixer::ResetMuteFrameCount()
|
||||
{
|
||||
_muteFrameCount = 0;
|
||||
}
|
|
@ -20,14 +20,14 @@ public:
|
|||
private:
|
||||
static unique_ptr<WaveRecorder> _waveRecorder;
|
||||
static SimpleLock _waveRecorderLock;
|
||||
static double _fadeRatio;
|
||||
static uint32_t _muteFrameCount;
|
||||
|
||||
static IAudioDevice* AudioDevice;
|
||||
static const uint32_t MaxSampleRate = 48000;
|
||||
static const uint32_t MaxSamplesPerFrame = MaxSampleRate / 60 * 4; //x4 to allow CPU overclocking up to 10x
|
||||
static const uint32_t MaxChannelCount = 6;
|
||||
static const uint32_t ExpansionAudioIndex = MaxChannelCount - 1;
|
||||
static const uint32_t MaxChannelCount = 11;
|
||||
|
||||
AudioChannel _expansionAudioType;
|
||||
LowPassFilter _lowPassFilter;
|
||||
StereoPanningFilter _stereoPanning;
|
||||
StereoDelayFilter _stereoDelay;
|
||||
|
@ -73,6 +73,11 @@ public:
|
|||
static void StopRecording();
|
||||
static bool IsRecording();
|
||||
|
||||
//For NSF/NSFe
|
||||
static uint32_t GetMuteFrameCount();
|
||||
static void ResetMuteFrameCount();
|
||||
static void SetFadeRatio(double fadeRatio);
|
||||
|
||||
static void StopAudio(bool clearBuffer = false);
|
||||
static void RegisterAudioDevice(IAudioDevice *audioDevice);
|
||||
};
|
||||
|
|
|
@ -30,6 +30,14 @@ namespace Mesen.GUI.Config
|
|||
public bool AssociateFdsFiles = false;
|
||||
public bool AssociateMmoFiles = false;
|
||||
public bool AssociateMstFiles = false;
|
||||
public bool AssociateNsfFiles = false;
|
||||
public bool AssociateNsfeFiles = false;
|
||||
|
||||
public bool NsfDisableApuIrqs = true;
|
||||
public bool NsfMoveToNextTrackAfterTime = true;
|
||||
public Int32 NsfMoveToNextTrackTime = 120;
|
||||
public bool NsfAutoDetectSilence = true;
|
||||
public Int32 NsfAutoDetectSilenceDelay = 3000;
|
||||
|
||||
public bool PauseOnMovieEnd = true;
|
||||
public bool AutomaticallyCheckForUpdates = true;
|
||||
|
@ -68,6 +76,8 @@ namespace Mesen.GUI.Config
|
|||
UpdateFileAssociation("fds", preferenceInfo.AssociateFdsFiles);
|
||||
UpdateFileAssociation("mmo", preferenceInfo.AssociateMmoFiles);
|
||||
UpdateFileAssociation("mst", preferenceInfo.AssociateMstFiles);
|
||||
UpdateFileAssociation("nsf", preferenceInfo.AssociateNsfFiles);
|
||||
UpdateFileAssociation("nsfe", preferenceInfo.AssociateNsfeFiles);
|
||||
|
||||
InteropEmu.SetFlag(EmulationFlags.Mmc3IrqAltBehavior, preferenceInfo.UseAlternativeMmc3Irq);
|
||||
InteropEmu.SetFlag(EmulationFlags.AllowInvalidInput, preferenceInfo.AllowInvalidInput);
|
||||
|
@ -78,6 +88,8 @@ namespace Mesen.GUI.Config
|
|||
InteropEmu.SetFlag(EmulationFlags.AllowBackgroundInput, preferenceInfo.AllowBackgroundInput);
|
||||
InteropEmu.SetFlag(EmulationFlags.PauseWhenInBackground, preferenceInfo.PauseWhenInBackground);
|
||||
InteropEmu.SetFlag(EmulationFlags.DisableGameDatabase, preferenceInfo.DisableGameDatabase);
|
||||
|
||||
InteropEmu.NsfSetNsfConfig(preferenceInfo.NsfAutoDetectSilence ? preferenceInfo.NsfAutoDetectSilenceDelay : 0, preferenceInfo.NsfMoveToNextTrackAfterTime ? preferenceInfo.NsfMoveToNextTrackTime : -1, preferenceInfo.NsfDisableApuIrqs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
484
GUI.NET/Controls/ctrlNsfPlayer.Designer.cs
generated
Normal file
484
GUI.NET/Controls/ctrlNsfPlayer.Designer.cs
generated
Normal file
|
@ -0,0 +1,484 @@
|
|||
namespace Mesen.GUI.Controls
|
||||
{
|
||||
partial class ctrlNsfPlayer
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if(disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.btnPrevious = new System.Windows.Forms.Button();
|
||||
this.btnPause = new System.Windows.Forms.Button();
|
||||
this.btnNext = new System.Windows.Forms.Button();
|
||||
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.lblCopyrightValue = new System.Windows.Forms.Label();
|
||||
this.lblArtistValue = new System.Windows.Forms.Label();
|
||||
this.lblTitleValue = new System.Windows.Forms.Label();
|
||||
this.lblArtist = new System.Windows.Forms.Label();
|
||||
this.lblTitle = new System.Windows.Forms.Label();
|
||||
this.lblCopyright = new System.Windows.Forms.Label();
|
||||
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.lblMmc5 = new System.Windows.Forms.Label();
|
||||
this.lblFds = new System.Windows.Forms.Label();
|
||||
this.lblNamco = new System.Windows.Forms.Label();
|
||||
this.lblSunsoft = new System.Windows.Forms.Label();
|
||||
this.lblVrc6 = new System.Windows.Forms.Label();
|
||||
this.lblVrc7 = new System.Windows.Forms.Label();
|
||||
this.lblSoundChips = new System.Windows.Forms.Label();
|
||||
this.picBackground = new System.Windows.Forms.PictureBox();
|
||||
this.trkVolume = new System.Windows.Forms.TrackBar();
|
||||
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.cboTrack = new System.Windows.Forms.ComboBox();
|
||||
this.lblTrackTotal = new System.Windows.Forms.Label();
|
||||
this.lblTime = new System.Windows.Forms.Label();
|
||||
this.tmrFastForward = new System.Windows.Forms.Timer(this.components);
|
||||
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.tableLayoutPanel2.SuspendLayout();
|
||||
this.tableLayoutPanel3.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.picBackground)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trkVolume)).BeginInit();
|
||||
this.flowLayoutPanel1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 5;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel1.Controls.Add(this.btnPrevious, 1, 2);
|
||||
this.tableLayoutPanel1.Controls.Add(this.btnPause, 2, 2);
|
||||
this.tableLayoutPanel1.Controls.Add(this.btnNext, 3, 2);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.picBackground, 0, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.trkVolume, 4, 2);
|
||||
this.tableLayoutPanel1.Controls.Add(this.flowLayoutPanel1, 0, 2);
|
||||
this.tableLayoutPanel1.Controls.Add(this.lblTime, 0, 3);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 4;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
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());
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(371, 281);
|
||||
this.tableLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// btnPrevious
|
||||
//
|
||||
this.btnPrevious.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.btnPrevious.Image = global::Mesen.GUI.Properties.Resources.PrevTrack;
|
||||
this.btnPrevious.Location = new System.Drawing.Point(126, 220);
|
||||
this.btnPrevious.Name = "btnPrevious";
|
||||
this.btnPrevious.Size = new System.Drawing.Size(33, 25);
|
||||
this.btnPrevious.TabIndex = 1;
|
||||
this.btnPrevious.UseVisualStyleBackColor = true;
|
||||
this.btnPrevious.Click += new System.EventHandler(this.btnPrevious_Click);
|
||||
//
|
||||
// btnPause
|
||||
//
|
||||
this.btnPause.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.btnPause.Image = global::Mesen.GUI.Properties.Resources.Pause;
|
||||
this.btnPause.Location = new System.Drawing.Point(165, 216);
|
||||
this.btnPause.Name = "btnPause";
|
||||
this.btnPause.Size = new System.Drawing.Size(40, 33);
|
||||
this.btnPause.TabIndex = 0;
|
||||
this.btnPause.UseVisualStyleBackColor = true;
|
||||
this.btnPause.Click += new System.EventHandler(this.btnPause_Click);
|
||||
//
|
||||
// btnNext
|
||||
//
|
||||
this.btnNext.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.btnNext.Image = global::Mesen.GUI.Properties.Resources.NextTrack;
|
||||
this.btnNext.Location = new System.Drawing.Point(211, 220);
|
||||
this.btnNext.Name = "btnNext";
|
||||
this.btnNext.Size = new System.Drawing.Size(33, 25);
|
||||
this.btnNext.TabIndex = 2;
|
||||
this.btnNext.UseVisualStyleBackColor = true;
|
||||
this.btnNext.Click += new System.EventHandler(this.btnNext_Click);
|
||||
this.btnNext.MouseDown += new System.Windows.Forms.MouseEventHandler(this.btnNext_MouseDown);
|
||||
//
|
||||
// tableLayoutPanel2
|
||||
//
|
||||
this.tableLayoutPanel2.AutoSize = true;
|
||||
this.tableLayoutPanel2.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.tableLayoutPanel2.ColumnCount = 4;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.tableLayoutPanel2, 5);
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 250F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel2.Controls.Add(this.lblCopyrightValue, 2, 2);
|
||||
this.tableLayoutPanel2.Controls.Add(this.lblArtistValue, 2, 1);
|
||||
this.tableLayoutPanel2.Controls.Add(this.lblTitleValue, 2, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.lblArtist, 1, 1);
|
||||
this.tableLayoutPanel2.Controls.Add(this.lblTitle, 1, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.lblCopyright, 1, 2);
|
||||
this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel3, 2, 3);
|
||||
this.tableLayoutPanel2.Controls.Add(this.lblSoundChips, 1, 3);
|
||||
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 121);
|
||||
this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
this.tableLayoutPanel2.RowCount = 4;
|
||||
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.Size = new System.Drawing.Size(371, 86);
|
||||
this.tableLayoutPanel2.TabIndex = 3;
|
||||
//
|
||||
// lblCopyrightValue
|
||||
//
|
||||
this.lblCopyrightValue.AutoSize = true;
|
||||
this.lblCopyrightValue.ForeColor = System.Drawing.Color.White;
|
||||
this.lblCopyrightValue.Location = new System.Drawing.Point(101, 42);
|
||||
this.lblCopyrightValue.Name = "lblCopyrightValue";
|
||||
this.lblCopyrightValue.Padding = new System.Windows.Forms.Padding(0, 4, 0, 4);
|
||||
this.lblCopyrightValue.Size = new System.Drawing.Size(63, 21);
|
||||
this.lblCopyrightValue.TabIndex = 5;
|
||||
this.lblCopyrightValue.Text = "[[Copyright]]";
|
||||
//
|
||||
// lblArtistValue
|
||||
//
|
||||
this.lblArtistValue.AutoSize = true;
|
||||
this.lblArtistValue.ForeColor = System.Drawing.Color.White;
|
||||
this.lblArtistValue.Location = new System.Drawing.Point(101, 21);
|
||||
this.lblArtistValue.Name = "lblArtistValue";
|
||||
this.lblArtistValue.Padding = new System.Windows.Forms.Padding(0, 4, 0, 4);
|
||||
this.lblArtistValue.Size = new System.Drawing.Size(42, 21);
|
||||
this.lblArtistValue.TabIndex = 4;
|
||||
this.lblArtistValue.Text = "[[Artist]]";
|
||||
//
|
||||
// lblTitleValue
|
||||
//
|
||||
this.lblTitleValue.AutoSize = true;
|
||||
this.lblTitleValue.ForeColor = System.Drawing.Color.White;
|
||||
this.lblTitleValue.Location = new System.Drawing.Point(101, 0);
|
||||
this.lblTitleValue.Name = "lblTitleValue";
|
||||
this.lblTitleValue.Padding = new System.Windows.Forms.Padding(0, 4, 0, 4);
|
||||
this.lblTitleValue.Size = new System.Drawing.Size(39, 21);
|
||||
this.lblTitleValue.TabIndex = 3;
|
||||
this.lblTitleValue.Text = "[[Title]]";
|
||||
//
|
||||
// lblArtist
|
||||
//
|
||||
this.lblArtist.AutoSize = true;
|
||||
this.lblArtist.ForeColor = System.Drawing.Color.White;
|
||||
this.lblArtist.Location = new System.Drawing.Point(25, 21);
|
||||
this.lblArtist.Name = "lblArtist";
|
||||
this.lblArtist.Padding = new System.Windows.Forms.Padding(0, 4, 0, 4);
|
||||
this.lblArtist.Size = new System.Drawing.Size(33, 21);
|
||||
this.lblArtist.TabIndex = 2;
|
||||
this.lblArtist.Text = "Artist:";
|
||||
//
|
||||
// lblTitle
|
||||
//
|
||||
this.lblTitle.AutoSize = true;
|
||||
this.lblTitle.ForeColor = System.Drawing.Color.White;
|
||||
this.lblTitle.Location = new System.Drawing.Point(25, 0);
|
||||
this.lblTitle.Name = "lblTitle";
|
||||
this.lblTitle.Padding = new System.Windows.Forms.Padding(0, 4, 0, 4);
|
||||
this.lblTitle.Size = new System.Drawing.Size(30, 21);
|
||||
this.lblTitle.TabIndex = 0;
|
||||
this.lblTitle.Text = "Title:";
|
||||
//
|
||||
// lblCopyright
|
||||
//
|
||||
this.lblCopyright.AutoSize = true;
|
||||
this.lblCopyright.ForeColor = System.Drawing.Color.White;
|
||||
this.lblCopyright.Location = new System.Drawing.Point(25, 42);
|
||||
this.lblCopyright.Name = "lblCopyright";
|
||||
this.lblCopyright.Padding = new System.Windows.Forms.Padding(0, 4, 0, 4);
|
||||
this.lblCopyright.Size = new System.Drawing.Size(54, 21);
|
||||
this.lblCopyright.TabIndex = 1;
|
||||
this.lblCopyright.Text = "Copyright:";
|
||||
//
|
||||
// tableLayoutPanel3
|
||||
//
|
||||
this.tableLayoutPanel3.ColumnCount = 6;
|
||||
this.tableLayoutPanel2.SetColumnSpan(this.tableLayoutPanel3, 2);
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel3.Controls.Add(this.lblMmc5, 1, 0);
|
||||
this.tableLayoutPanel3.Controls.Add(this.lblFds, 0, 0);
|
||||
this.tableLayoutPanel3.Controls.Add(this.lblNamco, 2, 0);
|
||||
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.Location = new System.Drawing.Point(101, 66);
|
||||
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
|
||||
this.tableLayoutPanel3.RowCount = 1;
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 17F));
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 17F));
|
||||
this.tableLayoutPanel3.Size = new System.Drawing.Size(197, 17);
|
||||
this.tableLayoutPanel3.TabIndex = 6;
|
||||
//
|
||||
// lblMmc5
|
||||
//
|
||||
this.lblMmc5.AutoSize = true;
|
||||
this.lblMmc5.BackColor = System.Drawing.Color.Transparent;
|
||||
this.lblMmc5.Font = new System.Drawing.Font("Arial Narrow", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.lblMmc5.ForeColor = System.Drawing.Color.White;
|
||||
this.lblMmc5.Location = new System.Drawing.Point(25, 0);
|
||||
this.lblMmc5.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.lblMmc5.Name = "lblMmc5";
|
||||
this.lblMmc5.Size = new System.Drawing.Size(35, 15);
|
||||
this.lblMmc5.TabIndex = 2;
|
||||
this.lblMmc5.Text = "MMC5";
|
||||
//
|
||||
// lblFds
|
||||
//
|
||||
this.lblFds.AutoSize = true;
|
||||
this.lblFds.BackColor = System.Drawing.Color.Transparent;
|
||||
this.lblFds.Font = new System.Drawing.Font("Arial Narrow", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.lblFds.ForeColor = System.Drawing.Color.White;
|
||||
this.lblFds.Location = new System.Drawing.Point(0, 0);
|
||||
this.lblFds.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.lblFds.Name = "lblFds";
|
||||
this.lblFds.Size = new System.Drawing.Size(25, 15);
|
||||
this.lblFds.TabIndex = 0;
|
||||
this.lblFds.Text = "FDS";
|
||||
//
|
||||
// lblNamco
|
||||
//
|
||||
this.lblNamco.AutoSize = true;
|
||||
this.lblNamco.BackColor = System.Drawing.Color.Transparent;
|
||||
this.lblNamco.Font = new System.Drawing.Font("Arial Narrow", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.lblNamco.ForeColor = System.Drawing.Color.White;
|
||||
this.lblNamco.Location = new System.Drawing.Point(60, 0);
|
||||
this.lblNamco.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.lblNamco.Name = "lblNamco";
|
||||
this.lblNamco.Size = new System.Drawing.Size(37, 15);
|
||||
this.lblNamco.TabIndex = 1;
|
||||
this.lblNamco.Text = "Namco";
|
||||
//
|
||||
// lblSunsoft
|
||||
//
|
||||
this.lblSunsoft.AutoSize = true;
|
||||
this.lblSunsoft.BackColor = System.Drawing.Color.Transparent;
|
||||
this.lblSunsoft.Font = new System.Drawing.Font("Arial Narrow", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.lblSunsoft.ForeColor = System.Drawing.Color.White;
|
||||
this.lblSunsoft.Location = new System.Drawing.Point(97, 0);
|
||||
this.lblSunsoft.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.lblSunsoft.Name = "lblSunsoft";
|
||||
this.lblSunsoft.Size = new System.Drawing.Size(37, 15);
|
||||
this.lblSunsoft.TabIndex = 5;
|
||||
this.lblSunsoft.Text = "Sunsoft";
|
||||
//
|
||||
// lblVrc6
|
||||
//
|
||||
this.lblVrc6.AutoSize = true;
|
||||
this.lblVrc6.BackColor = System.Drawing.Color.Transparent;
|
||||
this.lblVrc6.Font = new System.Drawing.Font("Arial Narrow", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.lblVrc6.ForeColor = System.Drawing.Color.White;
|
||||
this.lblVrc6.Location = new System.Drawing.Point(134, 0);
|
||||
this.lblVrc6.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.lblVrc6.Name = "lblVrc6";
|
||||
this.lblVrc6.Size = new System.Drawing.Size(32, 15);
|
||||
this.lblVrc6.TabIndex = 4;
|
||||
this.lblVrc6.Text = "VRC6";
|
||||
//
|
||||
// lblVrc7
|
||||
//
|
||||
this.lblVrc7.AutoSize = true;
|
||||
this.lblVrc7.BackColor = System.Drawing.Color.Transparent;
|
||||
this.lblVrc7.Font = new System.Drawing.Font("Arial Narrow", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.lblVrc7.ForeColor = System.Drawing.Color.White;
|
||||
this.lblVrc7.Location = new System.Drawing.Point(166, 0);
|
||||
this.lblVrc7.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.lblVrc7.Name = "lblVrc7";
|
||||
this.lblVrc7.Size = new System.Drawing.Size(32, 15);
|
||||
this.lblVrc7.TabIndex = 3;
|
||||
this.lblVrc7.Text = "VRC7";
|
||||
//
|
||||
// lblSoundChips
|
||||
//
|
||||
this.lblSoundChips.AutoSize = true;
|
||||
this.lblSoundChips.ForeColor = System.Drawing.Color.White;
|
||||
this.lblSoundChips.Location = new System.Drawing.Point(25, 63);
|
||||
this.lblSoundChips.Name = "lblSoundChips";
|
||||
this.lblSoundChips.Padding = new System.Windows.Forms.Padding(0, 4, 0, 4);
|
||||
this.lblSoundChips.Size = new System.Drawing.Size(70, 21);
|
||||
this.lblSoundChips.TabIndex = 7;
|
||||
this.lblSoundChips.Text = "Sound Chips:";
|
||||
//
|
||||
// picBackground
|
||||
//
|
||||
this.picBackground.Anchor = System.Windows.Forms.AnchorStyles.None;
|
||||
this.picBackground.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.picBackground, 5);
|
||||
this.picBackground.Image = global::Mesen.GUI.Properties.Resources.NsfBackground;
|
||||
this.picBackground.Location = new System.Drawing.Point(66, 13);
|
||||
this.picBackground.Margin = new System.Windows.Forms.Padding(10);
|
||||
this.picBackground.MaximumSize = new System.Drawing.Size(334, 380);
|
||||
this.picBackground.Name = "picBackground";
|
||||
this.picBackground.Size = new System.Drawing.Size(238, 95);
|
||||
this.picBackground.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.picBackground.TabIndex = 5;
|
||||
this.picBackground.TabStop = false;
|
||||
//
|
||||
// trkVolume
|
||||
//
|
||||
this.trkVolume.Location = new System.Drawing.Point(257, 210);
|
||||
this.trkVolume.Margin = new System.Windows.Forms.Padding(10, 3, 3, 3);
|
||||
this.trkVolume.Maximum = 100;
|
||||
this.trkVolume.Name = "trkVolume";
|
||||
this.trkVolume.Size = new System.Drawing.Size(104, 45);
|
||||
this.trkVolume.TabIndex = 6;
|
||||
this.trkVolume.TickFrequency = 10;
|
||||
this.trkVolume.TickStyle = System.Windows.Forms.TickStyle.Both;
|
||||
this.trkVolume.ValueChanged += new System.EventHandler(this.trkVolume_ValueChanged);
|
||||
//
|
||||
// flowLayoutPanel1
|
||||
//
|
||||
this.flowLayoutPanel1.Anchor = System.Windows.Forms.AnchorStyles.Right;
|
||||
this.flowLayoutPanel1.AutoSize = true;
|
||||
this.flowLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.flowLayoutPanel1.Controls.Add(this.cboTrack);
|
||||
this.flowLayoutPanel1.Controls.Add(this.lblTrackTotal);
|
||||
this.flowLayoutPanel1.Location = new System.Drawing.Point(28, 219);
|
||||
this.flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(0, 0, 15, 0);
|
||||
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
|
||||
this.flowLayoutPanel1.Size = new System.Drawing.Size(80, 27);
|
||||
this.flowLayoutPanel1.TabIndex = 9;
|
||||
//
|
||||
// cboTrack
|
||||
//
|
||||
this.cboTrack.BackColor = System.Drawing.Color.Black;
|
||||
this.cboTrack.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cboTrack.DropDownWidth = 200;
|
||||
this.cboTrack.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.cboTrack.ForeColor = System.Drawing.Color.White;
|
||||
this.cboTrack.FormattingEnabled = true;
|
||||
this.cboTrack.Items.AddRange(new object[] {
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6"});
|
||||
this.cboTrack.Location = new System.Drawing.Point(3, 3);
|
||||
this.cboTrack.Name = "cboTrack";
|
||||
this.cboTrack.Size = new System.Drawing.Size(47, 21);
|
||||
this.cboTrack.TabIndex = 8;
|
||||
this.cboTrack.DropDown += new System.EventHandler(this.cboTrack_DropDown);
|
||||
this.cboTrack.SelectedIndexChanged += new System.EventHandler(this.cboTrack_SelectedIndexChanged);
|
||||
this.cboTrack.DropDownClosed += new System.EventHandler(this.cboTrack_DropDownClosed);
|
||||
//
|
||||
// lblTrackTotal
|
||||
//
|
||||
this.lblTrackTotal.Anchor = System.Windows.Forms.AnchorStyles.Right;
|
||||
this.lblTrackTotal.AutoSize = true;
|
||||
this.lblTrackTotal.ForeColor = System.Drawing.Color.White;
|
||||
this.lblTrackTotal.Location = new System.Drawing.Point(53, 7);
|
||||
this.lblTrackTotal.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.lblTrackTotal.Name = "lblTrackTotal";
|
||||
this.lblTrackTotal.Size = new System.Drawing.Size(27, 13);
|
||||
this.lblTrackTotal.TabIndex = 4;
|
||||
this.lblTrackTotal.Text = "/ 24";
|
||||
//
|
||||
// lblTime
|
||||
//
|
||||
this.lblTime.Anchor = System.Windows.Forms.AnchorStyles.None;
|
||||
this.lblTime.AutoSize = true;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.lblTime, 5);
|
||||
this.lblTime.ForeColor = System.Drawing.Color.White;
|
||||
this.lblTime.Location = new System.Drawing.Point(168, 258);
|
||||
this.lblTime.Margin = new System.Windows.Forms.Padding(3, 0, 3, 10);
|
||||
this.lblTime.Name = "lblTime";
|
||||
this.lblTime.Size = new System.Drawing.Size(34, 13);
|
||||
this.lblTime.TabIndex = 10;
|
||||
this.lblTime.Text = "00:00";
|
||||
this.lblTime.TextAlign = System.Drawing.ContentAlignment.TopCenter;
|
||||
//
|
||||
// tmrFastForward
|
||||
//
|
||||
this.tmrFastForward.Interval = 500;
|
||||
this.tmrFastForward.Tick += new System.EventHandler(this.tmrFastForward_Tick);
|
||||
//
|
||||
// ctrlNsfPlayer
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = System.Drawing.Color.Black;
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.Name = "ctrlNsfPlayer";
|
||||
this.Size = new System.Drawing.Size(371, 281);
|
||||
this.VisibleChanged += new System.EventHandler(this.ctrlNsfPlayer_VisibleChanged);
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
this.tableLayoutPanel2.ResumeLayout(false);
|
||||
this.tableLayoutPanel2.PerformLayout();
|
||||
this.tableLayoutPanel3.ResumeLayout(false);
|
||||
this.tableLayoutPanel3.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.picBackground)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trkVolume)).EndInit();
|
||||
this.flowLayoutPanel1.ResumeLayout(false);
|
||||
this.flowLayoutPanel1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.Button btnPause;
|
||||
private System.Windows.Forms.Button btnPrevious;
|
||||
private System.Windows.Forms.Button btnNext;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
|
||||
private System.Windows.Forms.Label lblCopyrightValue;
|
||||
private System.Windows.Forms.Label lblArtistValue;
|
||||
private System.Windows.Forms.Label lblTitleValue;
|
||||
private System.Windows.Forms.Label lblArtist;
|
||||
private System.Windows.Forms.Label lblTitle;
|
||||
private System.Windows.Forms.Label lblCopyright;
|
||||
private System.Windows.Forms.Label lblTrackTotal;
|
||||
private System.Windows.Forms.PictureBox picBackground;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
|
||||
private System.Windows.Forms.Label lblSunsoft;
|
||||
private System.Windows.Forms.Label lblVrc6;
|
||||
private System.Windows.Forms.Label lblVrc7;
|
||||
private System.Windows.Forms.Label lblMmc5;
|
||||
private System.Windows.Forms.Label lblNamco;
|
||||
private System.Windows.Forms.Label lblFds;
|
||||
private System.Windows.Forms.Label lblSoundChips;
|
||||
private System.Windows.Forms.TrackBar trkVolume;
|
||||
private System.Windows.Forms.ComboBox cboTrack;
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
|
||||
private System.Windows.Forms.Label lblTime;
|
||||
private System.Windows.Forms.Timer tmrFastForward;
|
||||
private System.Windows.Forms.ToolTip toolTip;
|
||||
}
|
||||
}
|
281
GUI.NET/Controls/ctrlNsfPlayer.cs
Normal file
281
GUI.NET/Controls/ctrlNsfPlayer.cs
Normal file
|
@ -0,0 +1,281 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Mesen.GUI.Forms;
|
||||
using Mesen.GUI.Config;
|
||||
|
||||
namespace Mesen.GUI.Controls
|
||||
{
|
||||
public partial class ctrlNsfPlayer : UserControl
|
||||
{
|
||||
private List<ComboboxItem> _trackList = new List<ComboboxItem>();
|
||||
private int _frameCount = 0;
|
||||
private bool _fastForwarding = false;
|
||||
private UInt32 _originalSpeed = 100;
|
||||
|
||||
public ctrlNsfPlayer()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void ResetCount()
|
||||
{
|
||||
_frameCount = 0;
|
||||
this.BeginInvoke((MethodInvoker)(() => this.UpdateTimeDisplay(_frameCount)));
|
||||
}
|
||||
|
||||
public void CountFrame()
|
||||
{
|
||||
_frameCount++;
|
||||
if(_frameCount % 30 == 0) {
|
||||
this.BeginInvoke((MethodInvoker)(() => this.UpdateTimeDisplay(_frameCount)));
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTimeDisplay(int frameCount)
|
||||
{
|
||||
if(!InteropEmu.IsNsf()) {
|
||||
_frameCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
NsfHeader header = InteropEmu.NsfGetHeader();
|
||||
int currentTrack = InteropEmu.NsfGetCurrentTrack();
|
||||
|
||||
TimeSpan time = TimeSpan.FromSeconds((double)frameCount / ((header.Flags & 0x01) == 0x01 ? 50.006978 : 60.098812));
|
||||
string label = time.ToString(time.TotalHours < 1 ? @"mm\:ss" : @"hh\:mm\:ss");
|
||||
|
||||
TimeSpan trackTime = GetTrackLength(header, currentTrack);
|
||||
if(trackTime.Ticks > 0) {
|
||||
label += " / " + trackTime.ToString(trackTime.TotalHours < 1 ? @"mm\:ss" : @"hh\:mm\:ss");
|
||||
}
|
||||
|
||||
string[] trackNames = header.GetTrackNames();
|
||||
if(trackNames.Length > 1 && trackNames.Length > currentTrack) {
|
||||
label += Environment.NewLine + (string.IsNullOrWhiteSpace(trackNames[currentTrack]) ? ResourceHelper.GetMessage("NsfUnnamedTrack") : trackNames[currentTrack]);
|
||||
}
|
||||
|
||||
lblTime.Text = label;
|
||||
}
|
||||
|
||||
private TimeSpan GetTrackLength(NsfHeader header, int track)
|
||||
{
|
||||
int trackLength = header.TrackLength[track];
|
||||
if(header.TotalSongs > 1 && trackLength < 0 && ConfigManager.Config.PreferenceInfo.NsfMoveToNextTrackAfterTime) {
|
||||
trackLength = (ConfigManager.Config.PreferenceInfo.NsfMoveToNextTrackTime - 1) * 1000;
|
||||
}
|
||||
|
||||
if(trackLength >= 0) {
|
||||
int trackFade = header.TrackFade[track];
|
||||
if(trackFade < 0) {
|
||||
//1 sec by default
|
||||
trackFade = 1000;
|
||||
}
|
||||
trackLength += trackFade;
|
||||
|
||||
return TimeSpan.FromSeconds((double)trackLength / 1000);
|
||||
}
|
||||
|
||||
return TimeSpan.FromSeconds(0);
|
||||
}
|
||||
|
||||
private void UpdateTrackDisplay()
|
||||
{
|
||||
NsfHeader header = InteropEmu.NsfGetHeader();
|
||||
int currentTrack = InteropEmu.NsfGetCurrentTrack();
|
||||
|
||||
string[] trackNames = header.GetTrackNames();
|
||||
|
||||
if(header.TotalSongs != cboTrack.Items.Count) {
|
||||
_trackList = new List<ComboboxItem>();
|
||||
for(int i = 0; i < header.TotalSongs; i++) {
|
||||
string trackName = (i + 1).ToString();
|
||||
if(trackNames.Length > 1 && trackNames.Length > i) {
|
||||
trackName += " - " + (string.IsNullOrWhiteSpace(trackNames[i]) ? ResourceHelper.GetMessage("NsfUnnamedTrack") : trackNames[i]);
|
||||
}
|
||||
TimeSpan trackTime = GetTrackLength(header, i);
|
||||
if(trackTime.Ticks > 0) {
|
||||
trackName += " (" + trackTime.ToString(trackTime.TotalHours < 1 ? @"mm\:ss" : @"hh\:mm\:ss") + ")";
|
||||
}
|
||||
_trackList.Add(new ComboboxItem { Value = i +1, Description = trackName });
|
||||
}
|
||||
cboTrack.DataSource = _trackList;
|
||||
cboTrack.DisplayMember = "Value";
|
||||
}
|
||||
cboTrack.SelectedIndex = currentTrack;
|
||||
lblTrackTotal.Text = "/ " + header.TotalSongs.ToString();
|
||||
}
|
||||
|
||||
public void UpdateText()
|
||||
{
|
||||
if(this.InvokeRequired) {
|
||||
this.BeginInvoke((MethodInvoker)(() => UpdateText()));
|
||||
} else {
|
||||
UpdateTrackDisplay();
|
||||
|
||||
toolTip.SetToolTip(btnNext, ResourceHelper.GetMessage("NsfNextTrack"));
|
||||
|
||||
NsfHeader header = InteropEmu.NsfGetHeader();
|
||||
trkVolume.Value = (int)ConfigManager.Config.AudioInfo.MasterVolume;
|
||||
|
||||
lblTitleValue.Text = header.GetSongName();
|
||||
lblArtistValue.Text = header.GetArtistName();
|
||||
lblCopyrightValue.Text = header.GetCopyrightHolder();
|
||||
|
||||
lblVrc6.ForeColor = (header.SoundChips & 0x01) == 0x01 ? Color.White : Color.Gray;
|
||||
lblVrc7.ForeColor = (header.SoundChips & 0x02) == 0x02 ? Color.White : Color.Gray;
|
||||
lblFds.ForeColor = (header.SoundChips & 0x04) == 0x04 ? Color.White : Color.Gray;
|
||||
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;
|
||||
|
||||
if(InteropEmu.IsPaused()) {
|
||||
btnPause.Image = Properties.Resources.Play;
|
||||
} else {
|
||||
btnPause.Image = Properties.Resources.Pause;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void btnPause_Click(object sender, EventArgs e)
|
||||
{
|
||||
if(InteropEmu.IsPaused()) {
|
||||
InteropEmu.Resume();
|
||||
btnPause.Image = Properties.Resources.Pause;
|
||||
} else {
|
||||
InteropEmu.Pause();
|
||||
btnPause.Image = Properties.Resources.Play;
|
||||
}
|
||||
}
|
||||
|
||||
private void btnNext_Click(object sender, EventArgs e)
|
||||
{
|
||||
if(!_fastForwarding) {
|
||||
int soundCount = InteropEmu.NsfGetHeader().TotalSongs;
|
||||
int currentTrack = InteropEmu.NsfGetCurrentTrack();
|
||||
currentTrack = (currentTrack + 1) % soundCount;
|
||||
InteropEmu.NsfSelectTrack((byte)currentTrack);
|
||||
_frameCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void btnPrevious_Click(object sender, EventArgs e)
|
||||
{
|
||||
int soundCount = InteropEmu.NsfGetHeader().TotalSongs;
|
||||
int currentTrack = InteropEmu.NsfGetCurrentTrack();
|
||||
if(_frameCount < 120) {
|
||||
//Reload current track if it has been playing for more than 2 seconds
|
||||
currentTrack--;
|
||||
if(currentTrack < 0) {
|
||||
currentTrack = soundCount - 1;
|
||||
}
|
||||
}
|
||||
InteropEmu.NsfSelectTrack((byte)currentTrack);
|
||||
_frameCount = 0;
|
||||
}
|
||||
|
||||
private void trkVolume_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
ConfigManager.Config.AudioInfo.MasterVolume = (uint)trkVolume.Value;
|
||||
ConfigManager.ApplyChanges();
|
||||
AudioInfo.ApplyConfig();
|
||||
}
|
||||
|
||||
private void cboTrack_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
int currentTrack = InteropEmu.NsfGetCurrentTrack();
|
||||
if(currentTrack != cboTrack.SelectedIndex) {
|
||||
InteropEmu.NsfSelectTrack((byte)cboTrack.SelectedIndex);
|
||||
_frameCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
||||
{
|
||||
if(keyData == Keys.Left) {
|
||||
btnPrevious_Click(null, null);
|
||||
return true;
|
||||
} else if(keyData == Keys.Right) {
|
||||
btnNext_Click(null, null);
|
||||
return true;
|
||||
} else if(keyData == Keys.Up) {
|
||||
trkVolume.Value = Math.Min(trkVolume.Value+5, 100);
|
||||
return true;
|
||||
} else if(keyData == Keys.Down) {
|
||||
trkVolume.Value = Math.Max(trkVolume.Value-5, 0);
|
||||
return true;
|
||||
} else if(keyData == Keys.Space) {
|
||||
btnPause_Click(null, null);
|
||||
return true;
|
||||
}
|
||||
return base.ProcessCmdKey(ref msg, keyData);
|
||||
}
|
||||
|
||||
private void ctrlNsfPlayer_VisibleChanged(object sender, EventArgs e)
|
||||
{
|
||||
btnPause.Focus();
|
||||
}
|
||||
|
||||
private void btnNext_MouseDown(object sender, MouseEventArgs e)
|
||||
{
|
||||
if(e.Button == MouseButtons.Left) {
|
||||
tmrFastForward.Start();
|
||||
_originalSpeed = ConfigManager.Config.EmulationInfo.EmulationSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
private void tmrFastForward_Tick(object sender, EventArgs e)
|
||||
{
|
||||
if(Control.MouseButtons.HasFlag(MouseButtons.Left)) {
|
||||
if(!_fastForwarding) {
|
||||
tmrFastForward.Interval = 50;
|
||||
_fastForwarding = true;
|
||||
ConfigManager.Config.EmulationInfo.EmulationSpeed = 0;
|
||||
ConfigManager.ApplyChanges();
|
||||
EmulationInfo.ApplyConfig();
|
||||
}
|
||||
} else {
|
||||
tmrFastForward.Interval = 500;
|
||||
tmrFastForward.Stop();
|
||||
ConfigManager.Config.EmulationInfo.EmulationSpeed = _originalSpeed;
|
||||
ConfigManager.ApplyChanges();
|
||||
EmulationInfo.ApplyConfig();
|
||||
_fastForwarding = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void cboTrack_DropDown(object sender, EventArgs e)
|
||||
{
|
||||
cboTrack.DisplayMember = "Description";
|
||||
int scrollBarWidth = (cboTrack.Items.Count>cboTrack.MaxDropDownItems) ? SystemInformation.VerticalScrollBarWidth : 0;
|
||||
|
||||
int width = 100;
|
||||
using(Graphics g = cboTrack.CreateGraphics()) {
|
||||
foreach(ComboboxItem item in ((ComboBox)sender).Items) {
|
||||
width = Math.Max(width, (int)g.MeasureString(item.Description, cboTrack.Font).Width + scrollBarWidth);
|
||||
}
|
||||
}
|
||||
cboTrack.DropDownWidth = Math.Min(width, 300);
|
||||
}
|
||||
|
||||
private void cboTrack_DropDownClosed(object sender, EventArgs e)
|
||||
{
|
||||
int index = cboTrack.SelectedIndex;
|
||||
cboTrack.DisplayMember = "Value";
|
||||
cboTrack.SelectedIndex = index;
|
||||
btnPause.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
public class ComboboxItem
|
||||
{
|
||||
public int Value { get; set; }
|
||||
public string Description { get; set; }
|
||||
}
|
||||
}
|
126
GUI.NET/Controls/ctrlNsfPlayer.resx
Normal file
126
GUI.NET/Controls/ctrlNsfPlayer.resx
Normal file
|
@ -0,0 +1,126 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="tmrFastForward.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>154, 17</value>
|
||||
</metadata>
|
||||
</root>
|
|
@ -5,8 +5,8 @@
|
|||
<Message ID="FilterMovie">Movie files (*.mmo)|*.mmo|All Files (*.*)|*.*</Message>
|
||||
<Message ID="FilterWave">Wave files (*.wav)|*.wav|All Files (*.*)|*.*</Message>
|
||||
<Message ID="FilterPalette">Palette Files (*.pal)|*.pal|All Files (*.*)|*.*</Message>
|
||||
<Message ID="FilterRom">All supported formats (*.nes, *.zip, *.7z, *.fds)|*.NES;*.ZIP;*.7z;*.FDS|NES Roms (*.nes)|*.NES|Famicom Disk System Roms (*.fds)|*.FDS|ZIP Archives (*.zip)|*.ZIP|7-Zip Archives (*.7z)|*.7z|All (*.*)|*.*</Message>
|
||||
<Message ID="FilterRomIps">All supported formats (*.nes, *.zip, *.7z, *.fds, *.ips)|*.NES;*.ZIP;*.7z;*.IPS;*.FDS|NES Roms (*.nes)|*.NES|Famicom Disk System Roms (*.fds)|*.FDS|ZIP Archives (*.zip)|*.ZIP|7-Zip Archives (*.7z)|*.7z|IPS Patches (*.ips)|*.IPS|All (*.*)|*.*</Message>
|
||||
<Message ID="FilterRom">All supported formats (*.nes, *.zip, *.7z, *.nsf, *.nsfe, *.fds)|*.NES;*.ZIP;*.7z;*.FDS;*.NSF;*.NSFE|NES Roms (*.nes)|*.NES|Famicom Disk System Roms (*.fds)|*.FDS|NSF files (*.nsf, *.nsfe)|*.nsf;*.nsfe|ZIP Archives (*.zip)|*.ZIP|7-Zip Archives (*.7z)|*.7z|All (*.*)|*.*</Message>
|
||||
<Message ID="FilterRomIps">All supported formats (*.nes, *.zip, *.7z, *.fds, *.nsf, *.nsfe, *.ips)|*.NES;*.ZIP;*.7z;*.IPS;*.FDS;*.NSF;*.NSFE|NES Roms (*.nes)|*.NES|Famicom Disk System Roms (*.fds)|*.FDS|NSF files (*.nsf, *.nsfe)|*.nsf;*.nsfe|ZIP Archives (*.zip)|*.ZIP|7-Zip Archives (*.7z)|*.7z|IPS Patches (*.ips)|*.IPS|All (*.*)|*.*</Message>
|
||||
<Message ID="FilterTest">Test files (*.mtp)|*.mtp|All (*.*)|*.*</Message>
|
||||
|
||||
<Message ID="Resume">Resume</Message>
|
||||
|
@ -19,6 +19,10 @@
|
|||
|
||||
<Message ID="RomsFound">{0} roms found</Message>
|
||||
|
||||
<Message ID="NsfNextTrack">Next Track (Hold to fast forward)</Message>
|
||||
<Message ID="NsfUnnamedTrack"><no name></Message>
|
||||
<Message ID="NsfUnknownField"><unknown></Message>
|
||||
|
||||
<Message ID="CouldNotInstallRuntime">The Visual Studio Runtime could not be installed properly.</Message>
|
||||
<Message ID="EmptyState"><empty></Message>
|
||||
<Message ID="ErrorWhileCheckingUpdates">An error has occurred while trying to check for updates.

Error details:
{0}</Message>
|
||||
|
|
|
@ -87,6 +87,12 @@
|
|||
<Control ID="mnuHelp">Aide</Control>
|
||||
<Control ID="mnuCheckForUpdates">Recherche de mises-à-jour</Control>
|
||||
<Control ID="mnuAbout">À propos de...</Control>
|
||||
|
||||
<!-- NSF Player -->
|
||||
<Control ID="lblTitle">Titre</Control>
|
||||
<Control ID="lblArtist">Artiste</Control>
|
||||
<Control ID="lblCopyright">Copyright</Control>
|
||||
<Control ID="lblSoundChips">Puces audio</Control>
|
||||
</Form>
|
||||
<Form ID="frmLogWindow" Title="Fenêtre de log">
|
||||
<Control ID="btnClose">Fermer</Control>
|
||||
|
@ -263,7 +269,14 @@
|
|||
<Control ID="btnResync">Resynchroniser</Control>
|
||||
|
||||
<Control ID="chkDisableGameDatabase">Désactiver la base de données des jeux</Control>
|
||||
|
||||
|
||||
<Control ID="tpgNsf">NSF / NSFe</Control>
|
||||
<Control ID="chkNsfAutoDetectSilence">Jouer la piste suivante après</Control>
|
||||
<Control ID="lblNsfMillisecondsOfSilence">millisecondes de silence</Control>
|
||||
<Control ID="chkNsfMoveToNextTrackAfterTime">Limiter la durée des pistes à</Control>
|
||||
<Control ID="lblNsfSeconds">secondes</Control>
|
||||
<Control ID="chkNsfDisableApuIrqs">Désactiver les IRQs du APU</Control>
|
||||
|
||||
<Control ID="btnOK">OK</Control>
|
||||
<Control ID="btnCancel">Annuler</Control>
|
||||
</Form>
|
||||
|
@ -344,8 +357,8 @@
|
|||
<Message ID="FilterMovie">Films (*.mmo)|*.mmo|Tous les fichiers (*.*)|*.*</Message>
|
||||
<Message ID="FilterWave">Fichiers wave (*.wav)|*.wav|Tous les fichiers (*.*)|*.*</Message>
|
||||
<Message ID="FilterPalette">Fichier de palette (*.pal)|*.pal|Tous les fichiers (*.*)|*.*</Message>
|
||||
<Message ID="FilterRom">Tous les formats supportés (*.nes, *.zip, *.7z, *.fds)|*.NES;*.ZIP;*.7z;*.FDS|Roms de NES (*.nes)|*.NES|Roms du Famicom Disk System (*.fds)|*.FDS|Fichiers ZIP (*.zip)|*.ZIP|Fichiers 7-Zip (*.7z)|*.7z|Tous les fichiers (*.*)|*.*</Message>
|
||||
<Message ID="FilterRomIps">Tous les formats supportés (*.nes, *.zip, *.7z, *.fds, *.ips)|*.NES;*.ZIP;*.7z;*.IPS;*.FDS|Roms de NES(*.nes)|*.NES|Roms du Famicom Disk System (*.fds)|*.FDS|Fichiers ZIP (*.zip)|*.ZIP|Fichiers 7-Zip (*.7z)|*.7z|Fichiers IPS (*.ips)|*.IPS|Tous les fichiers (*.*)|*.*</Message>
|
||||
<Message ID="FilterRom">Tous les formats supportés (*.nes, *.zip, *.7z, *.fds, *.nsf, *.nsfe)|*.NES;*.ZIP;*.7z;*.FDS;*.NSF;*.NSFE|Roms de NES (*.nes)|*.NES|Roms du Famicom Disk System (*.fds)|*.FDS|Fichiers NSF (*.nsf, *.nsfe)|*.NSF;*.NSFE|Fichiers ZIP (*.zip)|*.ZIP|Fichiers 7-Zip (*.7z)|*.7z|Tous les fichiers (*.*)|*.*</Message>
|
||||
<Message ID="FilterRomIps">Tous les formats supportés (*.nes, *.zip, *.7z, *.fds, *.nsf, *.nsfe, *.ips)|*.NES;*.ZIP;*.7z;*.IPS;*.FDS;*.NSF;*.NSFE|Roms de NES(*.nes)|*.NES|Roms du Famicom Disk System (*.fds)|*.FDS|Fichiers NSF (*.nsf, *.nsfe)|*.NSF;*.NSFE|Fichiers ZIP (*.zip)|*.ZIP|Fichiers 7-Zip (*.7z)|*.7z|Fichiers IPS (*.ips)|*.IPS|Tous les fichiers (*.*)|*.*</Message>
|
||||
<Message ID="FilterTest">Fichiers de test (*.mtp)|*.mtp|Tous les fichiers (*.*)|*.*</Message>
|
||||
|
||||
<Message ID="Resume">Continuer</Message>
|
||||
|
@ -358,6 +371,10 @@
|
|||
|
||||
<Message ID="RomsFound">{0} roms trouvés</Message>
|
||||
|
||||
<Message ID="NsfNextTrack">Piste Suivante (Garder enfoncé pour jouer plus rapidement)</Message>
|
||||
<Message ID="NsfUnnamedTrack">[sans nom]</Message>
|
||||
<Message ID="NsfUnknownField">[inconnu]</Message>
|
||||
|
||||
<Message ID="CouldNotInstallRuntime">Le package Redistribuable Visual C++ pour Visual Studio 2015 n'a pas été installé correctement.</Message>
|
||||
<Message ID="EmptyState"><aucune sauvegarde></Message>
|
||||
<Message ID="ErrorWhileCheckingUpdates">Une erreur s'est produite lors de la recherche de mises-à-jour.

Détails de l'erreur :
{0}</Message>
|
||||
|
|
|
@ -87,6 +87,12 @@
|
|||
<Control ID="mnuHelp">ヘルプ</Control>
|
||||
<Control ID="mnuCheckForUpdates">アップデートの確認</Control>
|
||||
<Control ID="mnuAbout">Mesenとは</Control>
|
||||
|
||||
<!-- NSF Player -->
|
||||
<Control ID="lblTitle">タイトル</Control>
|
||||
<Control ID="lblArtist">作者</Control>
|
||||
<Control ID="lblCopyright">コピーライト</Control>
|
||||
<Control ID="lblSoundChips">音源チップ</Control>
|
||||
</Form>
|
||||
<Form ID="frmLogWindow" Title="ログウィンドウ">
|
||||
<Control ID="btnClose">閉じる</Control>
|
||||
|
@ -263,6 +269,13 @@
|
|||
|
||||
<Control ID="chkDisableGameDatabase">ゲームデータベースを無効にする</Control>
|
||||
|
||||
<Control ID="tpgNsf">NSF / NSFe</Control>
|
||||
<Control ID="chkNsfAutoDetectSilence">無音検出:</Control>
|
||||
<Control ID="lblNsfMillisecondsOfSilence">ミリ秒間で無音の場合、次の曲を再生</Control>
|
||||
<Control ID="chkNsfMoveToNextTrackAfterTime">曲の最大長さを</Control>
|
||||
<Control ID="lblNsfSeconds">秒に固定する</Control>
|
||||
<Control ID="chkNsfDisableApuIrqs">APUのIRQを無効にする</Control>
|
||||
|
||||
<Control ID="btnOK">OK</Control>
|
||||
<Control ID="btnCancel">キャンセル</Control>
|
||||
</Form>
|
||||
|
@ -336,8 +349,8 @@
|
|||
<Message ID="FilterMovie">動画 (*.mmo)|*.mmo|すべてのファイル (*.*)|*.*</Message>
|
||||
<Message ID="FilterWave">WAVファイル (*.wav)|*.wav|すべてのファイル (*.*)|*.*</Message>
|
||||
<Message ID="FilterPalette">パレットファイル (*.pal)|*.pal|すべてのファイル (*.*)|*.*</Message>
|
||||
<Message ID="FilterRom">対応するすべてのファイル (*.nes, *.zip, *.7z, *.fds)|*.NES;*.ZIP;*.FDS;*.7z|ファミコンゲーム (*.nes)|*.NES|ファミコンディスクシステムのゲーム (*.fds)|*.FDS|ZIPファイル (*.zip)|*.ZIP|7-Zipファイル (*.7z)|*.7z|すべてのファイル (*.*)|*.*</Message>
|
||||
<Message ID="FilterRomIps">対応するすべてのファイル (*.nes, *.zip, *.7z, *.fds, *.ips)|*.NES;*.ZIP;*.7z;*.IPS;*.FDS|ファミコンゲーム (*.nes)|*.NES|ファミコンディスクシステムのゲーム (*.fds)|*.FDS|ZIPファイル (*.zip)|*.ZIP|7-Zipファイル (*.7z)|*.7z|IPSファイル (*.ips)|*.IPS|すべてのファイル (*.*)|*.*</Message>
|
||||
<Message ID="FilterRom">対応するすべてのファイル (*.nes, *.zip, *.7z, *.fds, *.nsf, *.nsfe)|*.NES;*.ZIP;*.FDS;*.7z;*.NSF;*.NSFE|ファミコンゲーム (*.nes)|*.NES|ファミコンディスクシステムのゲーム (*.fds)|*.FDS|NSFファイル (*.nsf, *.nsfe)|*.NSF;*.NSFE|ZIPファイル (*.zip)|*.ZIP|7-Zipファイル (*.7z)|*.7z|すべてのファイル (*.*)|*.*</Message>
|
||||
<Message ID="FilterRomIps">対応するすべてのファイル (*.nes, *.zip, *.7z, *.fds, *.nsf, *.nsfe, *.ips)|*.NES;*.ZIP;*.7z;*.IPS;*.FDS;*.NSF;*.NSFE|ファミコンゲーム (*.nes)|*.NES|ファミコンディスクシステムのゲーム (*.fds)|*.FDS|NSFファイル (*.nsf, *.nsfe)|*.NSF;*.NSFE|ZIPファイル (*.zip)|*.ZIP|7-Zipファイル (*.7z)|*.7z|IPSファイル (*.ips)|*.IPS|すべてのファイル (*.*)|*.*</Message>
|
||||
<Message ID="FilterTest">テストファイル (*.mtp)|*.mtp|すべてのファイル (*.*)|*.*</Message>
|
||||
|
||||
<Message ID="Resume">再開</Message>
|
||||
|
@ -350,6 +363,10 @@
|
|||
|
||||
<Message ID="RomsFound">{0}個</Message>
|
||||
|
||||
<Message ID="NsfNextTrack">次の曲 (長押しで早送り)</Message>
|
||||
<Message ID="NsfUnnamedTrack">[名無し]</Message>
|
||||
<Message ID="NsfUnknownField">[不明]</Message>
|
||||
|
||||
<Message ID="CouldNotInstallRuntime">Microsoft Visual Studio 2015のVisual C++再頒布可能パッケージはインストールできませんでした。</Message>
|
||||
<Message ID="EmptyState"><なし></Message>
|
||||
<Message ID="ErrorWhileCheckingUpdates">アップデートを確認する時にエラーが発生しました。

エラーの詳細:
{0}</Message>
|
||||
|
|
273
GUI.NET/Forms/Config/frmPreferences.Designer.cs
generated
273
GUI.NET/Forms/Config/frmPreferences.Designer.cs
generated
|
@ -58,19 +58,32 @@
|
|||
this.lblLastSync = new System.Windows.Forms.Label();
|
||||
this.lblLastSyncDateTime = new System.Windows.Forms.Label();
|
||||
this.btnResync = new System.Windows.Forms.Button();
|
||||
this.tpgNsf = new System.Windows.Forms.TabPage();
|
||||
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.flowLayoutPanel7 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.chkNsfAutoDetectSilence = new System.Windows.Forms.CheckBox();
|
||||
this.nudNsfAutoDetectSilenceDelay = new System.Windows.Forms.NumericUpDown();
|
||||
this.lblNsfMillisecondsOfSilence = new System.Windows.Forms.Label();
|
||||
this.flowLayoutPanel5 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.chkNsfMoveToNextTrackAfterTime = new System.Windows.Forms.CheckBox();
|
||||
this.nudNsfMoveToNextTrackTime = new System.Windows.Forms.NumericUpDown();
|
||||
this.lblNsfSeconds = new System.Windows.Forms.Label();
|
||||
this.chkNsfDisableApuIrqs = new System.Windows.Forms.CheckBox();
|
||||
this.tpgFileAssociations = new System.Windows.Forms.TabPage();
|
||||
this.grpFileAssociations = new System.Windows.Forms.GroupBox();
|
||||
this.tlpFileFormat = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.chkNsfeFormat = new System.Windows.Forms.CheckBox();
|
||||
this.chkNesFormat = new System.Windows.Forms.CheckBox();
|
||||
this.chkFdsFormat = new System.Windows.Forms.CheckBox();
|
||||
this.chkMmoFormat = new System.Windows.Forms.CheckBox();
|
||||
this.chkMstFormat = new System.Windows.Forms.CheckBox();
|
||||
this.chkNsfFormat = new System.Windows.Forms.CheckBox();
|
||||
this.tpgAdvanced = new System.Windows.Forms.TabPage();
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.chkDisableGameDatabase = new System.Windows.Forms.CheckBox();
|
||||
this.chkFdsAutoLoadDisk = new System.Windows.Forms.CheckBox();
|
||||
this.chkFdsFastForwardOnLoad = new System.Windows.Forms.CheckBox();
|
||||
this.tmrSyncDateTime = new System.Windows.Forms.Timer(this.components);
|
||||
this.chkFdsFastForwardOnLoad = new System.Windows.Forms.CheckBox();
|
||||
this.chkFdsAutoLoadDisk = new System.Windows.Forms.CheckBox();
|
||||
this.chkDisableGameDatabase = new System.Windows.Forms.CheckBox();
|
||||
this.tlpMain.SuspendLayout();
|
||||
this.flowLayoutPanel2.SuspendLayout();
|
||||
this.tabMain.SuspendLayout();
|
||||
|
@ -82,11 +95,16 @@
|
|||
this.flowLayoutPanel3.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.picOK)).BeginInit();
|
||||
this.flowLayoutPanel4.SuspendLayout();
|
||||
this.tpgNsf.SuspendLayout();
|
||||
this.tableLayoutPanel2.SuspendLayout();
|
||||
this.flowLayoutPanel7.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.nudNsfAutoDetectSilenceDelay)).BeginInit();
|
||||
this.flowLayoutPanel5.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.nudNsfMoveToNextTrackTime)).BeginInit();
|
||||
this.tpgFileAssociations.SuspendLayout();
|
||||
this.grpFileAssociations.SuspendLayout();
|
||||
this.tlpFileFormat.SuspendLayout();
|
||||
this.tpgAdvanced.SuspendLayout();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// baseConfigPanel
|
||||
|
@ -252,6 +270,7 @@
|
|||
//
|
||||
this.tabMain.Controls.Add(this.tpgGeneral);
|
||||
this.tabMain.Controls.Add(this.tpgCloudSave);
|
||||
this.tabMain.Controls.Add(this.tpgNsf);
|
||||
this.tabMain.Controls.Add(this.tpgFileAssociations);
|
||||
this.tabMain.Controls.Add(this.tpgAdvanced);
|
||||
this.tabMain.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
|
@ -440,6 +459,149 @@
|
|||
this.btnResync.UseVisualStyleBackColor = true;
|
||||
this.btnResync.Click += new System.EventHandler(this.btnResync_Click);
|
||||
//
|
||||
// tpgNsf
|
||||
//
|
||||
this.tpgNsf.Controls.Add(this.tableLayoutPanel2);
|
||||
this.tpgNsf.Location = new System.Drawing.Point(4, 22);
|
||||
this.tpgNsf.Name = "tpgNsf";
|
||||
this.tpgNsf.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tpgNsf.Size = new System.Drawing.Size(479, 256);
|
||||
this.tpgNsf.TabIndex = 4;
|
||||
this.tpgNsf.Text = "NSF / NSFe";
|
||||
this.tpgNsf.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tableLayoutPanel2
|
||||
//
|
||||
this.tableLayoutPanel2.ColumnCount = 1;
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel2.Controls.Add(this.flowLayoutPanel7, 0, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.flowLayoutPanel5, 0, 1);
|
||||
this.tableLayoutPanel2.Controls.Add(this.chkNsfDisableApuIrqs, 0, 2);
|
||||
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 3);
|
||||
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
this.tableLayoutPanel2.RowCount = 3;
|
||||
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(473, 250);
|
||||
this.tableLayoutPanel2.TabIndex = 0;
|
||||
//
|
||||
// flowLayoutPanel7
|
||||
//
|
||||
this.flowLayoutPanel7.Controls.Add(this.chkNsfAutoDetectSilence);
|
||||
this.flowLayoutPanel7.Controls.Add(this.nudNsfAutoDetectSilenceDelay);
|
||||
this.flowLayoutPanel7.Controls.Add(this.lblNsfMillisecondsOfSilence);
|
||||
this.flowLayoutPanel7.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.flowLayoutPanel7.Location = new System.Drawing.Point(0, 0);
|
||||
this.flowLayoutPanel7.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.flowLayoutPanel7.Name = "flowLayoutPanel7";
|
||||
this.flowLayoutPanel7.Size = new System.Drawing.Size(473, 24);
|
||||
this.flowLayoutPanel7.TabIndex = 5;
|
||||
//
|
||||
// chkNsfAutoDetectSilence
|
||||
//
|
||||
this.chkNsfAutoDetectSilence.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.chkNsfAutoDetectSilence.AutoSize = true;
|
||||
this.chkNsfAutoDetectSilence.Location = new System.Drawing.Point(3, 4);
|
||||
this.chkNsfAutoDetectSilence.Name = "chkNsfAutoDetectSilence";
|
||||
this.chkNsfAutoDetectSilence.Size = new System.Drawing.Size(139, 17);
|
||||
this.chkNsfAutoDetectSilence.TabIndex = 1;
|
||||
this.chkNsfAutoDetectSilence.Text = "Move to next track after";
|
||||
this.chkNsfAutoDetectSilence.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// nudNsfAutoDetectSilenceDelay
|
||||
//
|
||||
this.nudNsfAutoDetectSilenceDelay.Location = new System.Drawing.Point(145, 3);
|
||||
this.nudNsfAutoDetectSilenceDelay.Margin = new System.Windows.Forms.Padding(0, 3, 3, 3);
|
||||
this.nudNsfAutoDetectSilenceDelay.Maximum = new decimal(new int[] {
|
||||
999999,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudNsfAutoDetectSilenceDelay.Minimum = new decimal(new int[] {
|
||||
200,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudNsfAutoDetectSilenceDelay.Name = "nudNsfAutoDetectSilenceDelay";
|
||||
this.nudNsfAutoDetectSilenceDelay.Size = new System.Drawing.Size(57, 20);
|
||||
this.nudNsfAutoDetectSilenceDelay.TabIndex = 3;
|
||||
this.nudNsfAutoDetectSilenceDelay.Value = new decimal(new int[] {
|
||||
3000,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
//
|
||||
// lblNsfMillisecondsOfSilence
|
||||
//
|
||||
this.lblNsfMillisecondsOfSilence.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.lblNsfMillisecondsOfSilence.AutoSize = true;
|
||||
this.lblNsfMillisecondsOfSilence.Location = new System.Drawing.Point(205, 6);
|
||||
this.lblNsfMillisecondsOfSilence.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
|
||||
this.lblNsfMillisecondsOfSilence.Name = "lblNsfMillisecondsOfSilence";
|
||||
this.lblNsfMillisecondsOfSilence.Size = new System.Drawing.Size(111, 13);
|
||||
this.lblNsfMillisecondsOfSilence.TabIndex = 4;
|
||||
this.lblNsfMillisecondsOfSilence.Text = "milliseconds of silence";
|
||||
//
|
||||
// flowLayoutPanel5
|
||||
//
|
||||
this.flowLayoutPanel5.Controls.Add(this.chkNsfMoveToNextTrackAfterTime);
|
||||
this.flowLayoutPanel5.Controls.Add(this.nudNsfMoveToNextTrackTime);
|
||||
this.flowLayoutPanel5.Controls.Add(this.lblNsfSeconds);
|
||||
this.flowLayoutPanel5.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.flowLayoutPanel5.Location = new System.Drawing.Point(0, 24);
|
||||
this.flowLayoutPanel5.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.flowLayoutPanel5.Name = "flowLayoutPanel5";
|
||||
this.flowLayoutPanel5.Size = new System.Drawing.Size(473, 24);
|
||||
this.flowLayoutPanel5.TabIndex = 4;
|
||||
//
|
||||
// chkNsfMoveToNextTrackAfterTime
|
||||
//
|
||||
this.chkNsfMoveToNextTrackAfterTime.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.chkNsfMoveToNextTrackAfterTime.AutoSize = true;
|
||||
this.chkNsfMoveToNextTrackAfterTime.Location = new System.Drawing.Point(3, 4);
|
||||
this.chkNsfMoveToNextTrackAfterTime.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3);
|
||||
this.chkNsfMoveToNextTrackAfterTime.Name = "chkNsfMoveToNextTrackAfterTime";
|
||||
this.chkNsfMoveToNextTrackAfterTime.Size = new System.Drawing.Size(126, 17);
|
||||
this.chkNsfMoveToNextTrackAfterTime.TabIndex = 2;
|
||||
this.chkNsfMoveToNextTrackAfterTime.Text = "Limit track run time to";
|
||||
this.chkNsfMoveToNextTrackAfterTime.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// nudNsfMoveToNextTrackTime
|
||||
//
|
||||
this.nudNsfMoveToNextTrackTime.Location = new System.Drawing.Point(129, 3);
|
||||
this.nudNsfMoveToNextTrackTime.Margin = new System.Windows.Forms.Padding(0, 3, 3, 3);
|
||||
this.nudNsfMoveToNextTrackTime.Maximum = new decimal(new int[] {
|
||||
999,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudNsfMoveToNextTrackTime.Name = "nudNsfMoveToNextTrackTime";
|
||||
this.nudNsfMoveToNextTrackTime.Size = new System.Drawing.Size(44, 20);
|
||||
this.nudNsfMoveToNextTrackTime.TabIndex = 3;
|
||||
//
|
||||
// lblNsfSeconds
|
||||
//
|
||||
this.lblNsfSeconds.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.lblNsfSeconds.AutoSize = true;
|
||||
this.lblNsfSeconds.Location = new System.Drawing.Point(176, 6);
|
||||
this.lblNsfSeconds.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
|
||||
this.lblNsfSeconds.Name = "lblNsfSeconds";
|
||||
this.lblNsfSeconds.Size = new System.Drawing.Size(47, 13);
|
||||
this.lblNsfSeconds.TabIndex = 4;
|
||||
this.lblNsfSeconds.Text = "seconds";
|
||||
//
|
||||
// chkNsfDisableApuIrqs
|
||||
//
|
||||
this.chkNsfDisableApuIrqs.AutoSize = true;
|
||||
this.chkNsfDisableApuIrqs.Location = new System.Drawing.Point(3, 51);
|
||||
this.chkNsfDisableApuIrqs.Name = "chkNsfDisableApuIrqs";
|
||||
this.chkNsfDisableApuIrqs.Size = new System.Drawing.Size(113, 17);
|
||||
this.chkNsfDisableApuIrqs.TabIndex = 6;
|
||||
this.chkNsfDisableApuIrqs.Text = "Disable APU IRQs";
|
||||
this.chkNsfDisableApuIrqs.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tpgFileAssociations
|
||||
//
|
||||
this.tpgFileAssociations.Controls.Add(this.grpFileAssociations);
|
||||
|
@ -467,21 +629,33 @@
|
|||
this.tlpFileFormat.ColumnCount = 2;
|
||||
this.tlpFileFormat.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tlpFileFormat.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tlpFileFormat.Controls.Add(this.chkNsfeFormat, 0, 3);
|
||||
this.tlpFileFormat.Controls.Add(this.chkNesFormat, 0, 0);
|
||||
this.tlpFileFormat.Controls.Add(this.chkFdsFormat, 0, 1);
|
||||
this.tlpFileFormat.Controls.Add(this.chkMmoFormat, 1, 0);
|
||||
this.tlpFileFormat.Controls.Add(this.chkMstFormat, 1, 1);
|
||||
this.tlpFileFormat.Controls.Add(this.chkNsfFormat, 0, 2);
|
||||
this.tlpFileFormat.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tlpFileFormat.Location = new System.Drawing.Point(3, 16);
|
||||
this.tlpFileFormat.Name = "tlpFileFormat";
|
||||
this.tlpFileFormat.RowCount = 4;
|
||||
this.tlpFileFormat.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tlpFileFormat.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tlpFileFormat.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tlpFileFormat.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tlpFileFormat.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tlpFileFormat.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tlpFileFormat.Size = new System.Drawing.Size(467, 231);
|
||||
this.tlpFileFormat.TabIndex = 0;
|
||||
//
|
||||
// chkNsfeFormat
|
||||
//
|
||||
this.chkNsfeFormat.AutoSize = true;
|
||||
this.chkNsfeFormat.Location = new System.Drawing.Point(3, 72);
|
||||
this.chkNsfeFormat.Name = "chkNsfeFormat";
|
||||
this.chkNsfeFormat.Size = new System.Drawing.Size(226, 17);
|
||||
this.chkNsfeFormat.TabIndex = 15;
|
||||
this.chkNsfeFormat.Text = ".NSFE (Nintendo Sound Format Extended)";
|
||||
this.chkNsfeFormat.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// chkNesFormat
|
||||
//
|
||||
this.chkNesFormat.AutoSize = true;
|
||||
|
@ -523,6 +697,16 @@
|
|||
this.chkMstFormat.Text = ".MST (Mesen Savestate)";
|
||||
this.chkMstFormat.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// chkNsfFormat
|
||||
//
|
||||
this.chkNsfFormat.AutoSize = true;
|
||||
this.chkNsfFormat.Location = new System.Drawing.Point(3, 49);
|
||||
this.chkNsfFormat.Name = "chkNsfFormat";
|
||||
this.chkNsfFormat.Size = new System.Drawing.Size(171, 17);
|
||||
this.chkNsfFormat.TabIndex = 14;
|
||||
this.chkNsfFormat.Text = ".NSF (Nintendo Sound Format)";
|
||||
this.chkNsfFormat.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tpgAdvanced
|
||||
//
|
||||
this.tpgAdvanced.Controls.Add(this.tableLayoutPanel1);
|
||||
|
@ -538,9 +722,6 @@
|
|||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 1;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkDisableGameDatabase, 0, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkFdsAutoLoadDisk, 0, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkFdsFastForwardOnLoad, 0, 2);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 3);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
|
@ -555,25 +736,10 @@
|
|||
this.tableLayoutPanel1.Size = new System.Drawing.Size(473, 250);
|
||||
this.tableLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// chkDisableGameDatabase
|
||||
// tmrSyncDateTime
|
||||
//
|
||||
this.chkDisableGameDatabase.AutoSize = true;
|
||||
this.chkDisableGameDatabase.Location = new System.Drawing.Point(3, 3);
|
||||
this.chkDisableGameDatabase.Name = "chkDisableGameDatabase";
|
||||
this.chkDisableGameDatabase.Size = new System.Drawing.Size(170, 17);
|
||||
this.chkDisableGameDatabase.TabIndex = 6;
|
||||
this.chkDisableGameDatabase.Text = "Disable built-in game database";
|
||||
this.chkDisableGameDatabase.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// chkFdsAutoLoadDisk
|
||||
//
|
||||
this.chkFdsAutoLoadDisk.AutoSize = true;
|
||||
this.chkFdsAutoLoadDisk.Location = new System.Drawing.Point(3, 26);
|
||||
this.chkFdsAutoLoadDisk.Name = "chkFdsAutoLoadDisk";
|
||||
this.chkFdsAutoLoadDisk.Size = new System.Drawing.Size(303, 17);
|
||||
this.chkFdsAutoLoadDisk.TabIndex = 3;
|
||||
this.chkFdsAutoLoadDisk.Text = "Automatically insert disk 1 side A when starting FDS games";
|
||||
this.chkFdsAutoLoadDisk.UseVisualStyleBackColor = true;
|
||||
this.tmrSyncDateTime.Enabled = true;
|
||||
this.tmrSyncDateTime.Tick += new System.EventHandler(this.tmrSyncDateTime_Tick);
|
||||
//
|
||||
// chkFdsFastForwardOnLoad
|
||||
//
|
||||
|
@ -585,10 +751,25 @@
|
|||
this.chkFdsFastForwardOnLoad.Text = "Automatically fast forward FDS games when disk or BIOS is loading";
|
||||
this.chkFdsFastForwardOnLoad.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tmrSyncDateTime
|
||||
// chkFdsAutoLoadDisk
|
||||
//
|
||||
this.tmrSyncDateTime.Enabled = true;
|
||||
this.tmrSyncDateTime.Tick += new System.EventHandler(this.tmrSyncDateTime_Tick);
|
||||
this.chkFdsAutoLoadDisk.AutoSize = true;
|
||||
this.chkFdsAutoLoadDisk.Location = new System.Drawing.Point(3, 26);
|
||||
this.chkFdsAutoLoadDisk.Name = "chkFdsAutoLoadDisk";
|
||||
this.chkFdsAutoLoadDisk.Size = new System.Drawing.Size(303, 17);
|
||||
this.chkFdsAutoLoadDisk.TabIndex = 3;
|
||||
this.chkFdsAutoLoadDisk.Text = "Automatically insert disk 1 side A when starting FDS games";
|
||||
this.chkFdsAutoLoadDisk.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// chkDisableGameDatabase
|
||||
//
|
||||
this.chkDisableGameDatabase.AutoSize = true;
|
||||
this.chkDisableGameDatabase.Location = new System.Drawing.Point(3, 3);
|
||||
this.chkDisableGameDatabase.Name = "chkDisableGameDatabase";
|
||||
this.chkDisableGameDatabase.Size = new System.Drawing.Size(170, 17);
|
||||
this.chkDisableGameDatabase.TabIndex = 6;
|
||||
this.chkDisableGameDatabase.Text = "Disable built-in game database";
|
||||
this.chkDisableGameDatabase.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// frmPreferences
|
||||
//
|
||||
|
@ -621,13 +802,20 @@
|
|||
((System.ComponentModel.ISupportInitialize)(this.picOK)).EndInit();
|
||||
this.flowLayoutPanel4.ResumeLayout(false);
|
||||
this.flowLayoutPanel4.PerformLayout();
|
||||
this.tpgNsf.ResumeLayout(false);
|
||||
this.tableLayoutPanel2.ResumeLayout(false);
|
||||
this.tableLayoutPanel2.PerformLayout();
|
||||
this.flowLayoutPanel7.ResumeLayout(false);
|
||||
this.flowLayoutPanel7.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.nudNsfAutoDetectSilenceDelay)).EndInit();
|
||||
this.flowLayoutPanel5.ResumeLayout(false);
|
||||
this.flowLayoutPanel5.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.nudNsfMoveToNextTrackTime)).EndInit();
|
||||
this.tpgFileAssociations.ResumeLayout(false);
|
||||
this.grpFileAssociations.ResumeLayout(false);
|
||||
this.tlpFileFormat.ResumeLayout(false);
|
||||
this.tlpFileFormat.PerformLayout();
|
||||
this.tpgAdvanced.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
@ -649,10 +837,6 @@
|
|||
private System.Windows.Forms.CheckBox chkFdsFormat;
|
||||
private System.Windows.Forms.CheckBox chkMmoFormat;
|
||||
private System.Windows.Forms.CheckBox chkMstFormat;
|
||||
private System.Windows.Forms.TabPage tpgAdvanced;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.CheckBox chkFdsAutoLoadDisk;
|
||||
private System.Windows.Forms.CheckBox chkFdsFastForwardOnLoad;
|
||||
private System.Windows.Forms.CheckBox chkAllowBackgroundInput;
|
||||
private System.Windows.Forms.CheckBox chkPauseOnMovieEnd;
|
||||
private System.Windows.Forms.Button btnOpenMesenFolder;
|
||||
|
@ -675,6 +859,23 @@
|
|||
private System.Windows.Forms.Label lblLastSyncDateTime;
|
||||
private System.Windows.Forms.Timer tmrSyncDateTime;
|
||||
private System.Windows.Forms.Button btnResync;
|
||||
private System.Windows.Forms.CheckBox chkNsfeFormat;
|
||||
private System.Windows.Forms.CheckBox chkNsfFormat;
|
||||
private System.Windows.Forms.TabPage tpgAdvanced;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.TabPage tpgNsf;
|
||||
private System.Windows.Forms.CheckBox chkFdsFastForwardOnLoad;
|
||||
private System.Windows.Forms.CheckBox chkFdsAutoLoadDisk;
|
||||
private System.Windows.Forms.CheckBox chkDisableGameDatabase;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel5;
|
||||
private System.Windows.Forms.CheckBox chkNsfMoveToNextTrackAfterTime;
|
||||
private System.Windows.Forms.NumericUpDown nudNsfMoveToNextTrackTime;
|
||||
private System.Windows.Forms.Label lblNsfSeconds;
|
||||
private System.Windows.Forms.CheckBox chkNsfAutoDetectSilence;
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel7;
|
||||
private System.Windows.Forms.NumericUpDown nudNsfAutoDetectSilenceDelay;
|
||||
private System.Windows.Forms.Label lblNsfMillisecondsOfSilence;
|
||||
private System.Windows.Forms.CheckBox chkNsfDisableApuIrqs;
|
||||
}
|
||||
}
|
|
@ -29,6 +29,14 @@ namespace Mesen.GUI.Forms.Config
|
|||
AddBinding("AssociateFdsFiles", chkFdsFormat);
|
||||
AddBinding("AssociateMmoFiles", chkMmoFormat);
|
||||
AddBinding("AssociateMstFiles", chkMstFormat);
|
||||
AddBinding("AssociateNsfFiles", chkNsfFormat);
|
||||
AddBinding("AssociateNsfeFiles", chkNsfeFormat);
|
||||
|
||||
AddBinding("NsfAutoDetectSilence", chkNsfAutoDetectSilence);
|
||||
AddBinding("NsfMoveToNextTrackAfterTime", chkNsfMoveToNextTrackAfterTime);
|
||||
AddBinding("NsfMoveToNextTrackTime", nudNsfMoveToNextTrackTime);
|
||||
AddBinding("NsfAutoDetectSilenceDelay", nudNsfAutoDetectSilenceDelay);
|
||||
AddBinding("NsfDisableApuIrqs", chkNsfDisableApuIrqs);
|
||||
|
||||
AddBinding("FdsAutoLoadDisk", chkFdsAutoLoadDisk);
|
||||
AddBinding("FdsFastForwardOnLoad", chkFdsFastForwardOnLoad);
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace Mesen.GUI.Forms
|
|||
}
|
||||
}
|
||||
|
||||
public static string GetMessage(string id, params string[] args)
|
||||
public static string GetMessage(string id, params object[] args)
|
||||
{
|
||||
var baseNode = _resources.SelectSingleNode("/Resources/Messages/Message[@ID='" + id + "']");
|
||||
if(baseNode != null) {
|
||||
|
|
12
GUI.NET/Forms/frmMain.Designer.cs
generated
12
GUI.NET/Forms/frmMain.Designer.cs
generated
|
@ -34,6 +34,7 @@ namespace Mesen.GUI.Forms
|
|||
this.menuTimer = new System.Windows.Forms.Timer(this.components);
|
||||
this.panelRenderer = new System.Windows.Forms.Panel();
|
||||
this.ctrlRenderer = new Mesen.GUI.Controls.ctrlRenderer();
|
||||
this.ctrlNsfPlayer = new Mesen.GUI.Controls.ctrlNsfPlayer();
|
||||
this.menuStrip = new System.Windows.Forms.MenuStrip();
|
||||
this.mnuFile = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuOpen = new System.Windows.Forms.ToolStripMenuItem();
|
||||
|
@ -168,6 +169,7 @@ namespace Mesen.GUI.Forms
|
|||
// panelRenderer
|
||||
//
|
||||
this.panelRenderer.BackColor = System.Drawing.Color.Black;
|
||||
this.panelRenderer.Controls.Add(this.ctrlNsfPlayer);
|
||||
this.panelRenderer.Controls.Add(this.ctrlRenderer);
|
||||
this.panelRenderer.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.panelRenderer.Location = new System.Drawing.Point(0, 24);
|
||||
|
@ -191,6 +193,15 @@ namespace Mesen.GUI.Forms
|
|||
this.ctrlRenderer.MouseClick += new System.Windows.Forms.MouseEventHandler(this.ctrlRenderer_MouseClick);
|
||||
this.ctrlRenderer.MouseMove += new System.Windows.Forms.MouseEventHandler(this.ctrlRenderer_MouseMove);
|
||||
//
|
||||
// ctrlNsfPlayer
|
||||
//
|
||||
this.ctrlNsfPlayer.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlNsfPlayer.Location = new System.Drawing.Point(0, 0);
|
||||
this.ctrlNsfPlayer.Name = "ctrlNsfPlayer";
|
||||
this.ctrlNsfPlayer.Size = new System.Drawing.Size(304, 218);
|
||||
this.ctrlNsfPlayer.TabIndex = 2;
|
||||
this.ctrlNsfPlayer.Visible = false;
|
||||
//
|
||||
// menuStrip
|
||||
//
|
||||
this.menuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
|
@ -1350,6 +1361,7 @@ namespace Mesen.GUI.Forms
|
|||
private System.Windows.Forms.ToolStripMenuItem mnuScale6x;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuLogWindow;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuEmulationConfig;
|
||||
private Controls.ctrlNsfPlayer ctrlNsfPlayer;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ namespace Mesen.GUI.Forms
|
|||
private bool _fullscreenMode = false;
|
||||
private double _regularScale = ConfigManager.Config.VideoInfo.VideoScale;
|
||||
private bool _needScaleUpdate = false;
|
||||
private bool _isNsfPlayerMode = false;
|
||||
|
||||
public frmMain(string[] args)
|
||||
{
|
||||
|
@ -254,8 +255,9 @@ namespace Mesen.GUI.Forms
|
|||
InteropEmu.ScreenSize size = InteropEmu.GetScreenSize(false);
|
||||
|
||||
if(!_customSize && this.WindowState != FormWindowState.Maximized) {
|
||||
Size sizeGap = this.Size - this.ClientSize;
|
||||
this.Resize -= frmMain_Resize;
|
||||
this.ClientSize = new Size(size.Width, size.Height + menuStrip.Height);
|
||||
this.ClientSize = new Size(Math.Max(this.MinimumSize.Width - sizeGap.Width, size.Width), Math.Max(this.MinimumSize.Height - sizeGap.Height, size.Height + menuStrip.Height));
|
||||
this.Resize += frmMain_Resize;
|
||||
}
|
||||
|
||||
|
@ -268,6 +270,8 @@ namespace Mesen.GUI.Forms
|
|||
{
|
||||
if(this.WindowState != FormWindowState.Minimized) {
|
||||
SetScaleBasedOnWindowSize();
|
||||
ctrlRenderer.Left = (panelRenderer.Width - ctrlRenderer.Width) / 2;
|
||||
ctrlRenderer.Top = (panelRenderer.Height - ctrlRenderer.Height) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -324,6 +328,7 @@ namespace Mesen.GUI.Forms
|
|||
switch(e.NotificationType) {
|
||||
case InteropEmu.ConsoleNotificationType.GameLoaded:
|
||||
_currentGame = InteropEmu.GetRomInfo().GetRomName();
|
||||
InitializeNsfMode();
|
||||
InitializeFdsDiskMenu();
|
||||
InitializeVsSystemMenu();
|
||||
CheatInfo.ApplyCheats();
|
||||
|
@ -333,6 +338,16 @@ namespace Mesen.GUI.Forms
|
|||
this.StartEmuThread();
|
||||
break;
|
||||
|
||||
case InteropEmu.ConsoleNotificationType.PpuFrameDone:
|
||||
if(InteropEmu.IsNsf()) {
|
||||
this.ctrlNsfPlayer.CountFrame();
|
||||
}
|
||||
break;
|
||||
|
||||
case InteropEmu.ConsoleNotificationType.GameReset:
|
||||
InitializeNsfMode();
|
||||
break;
|
||||
|
||||
case InteropEmu.ConsoleNotificationType.DisconnectedFromServer:
|
||||
ConfigManager.Config.ApplyConfig();
|
||||
break;
|
||||
|
@ -353,7 +368,10 @@ namespace Mesen.GUI.Forms
|
|||
}));
|
||||
break;
|
||||
}
|
||||
UpdateMenus();
|
||||
|
||||
if(e.NotificationType != InteropEmu.ConsoleNotificationType.PpuFrameDone) {
|
||||
UpdateMenus();
|
||||
}
|
||||
}
|
||||
|
||||
private void mnuOpen_Click(object sender, EventArgs e)
|
||||
|
@ -475,6 +493,11 @@ namespace Mesen.GUI.Forms
|
|||
mnuPause.Text = InteropEmu.IsPaused() ? ResourceHelper.GetMessage("Resume") : ResourceHelper.GetMessage("Pause");
|
||||
mnuPause.Image = InteropEmu.IsPaused() ? Mesen.GUI.Properties.Resources.Play : Mesen.GUI.Properties.Resources.Pause;
|
||||
|
||||
if(InteropEmu.IsNsf()) {
|
||||
mnuSaveState.Enabled = false;
|
||||
mnuLoadState.Enabled = false;
|
||||
}
|
||||
|
||||
bool netPlay = InteropEmu.IsServerRunning() || isNetPlayClient;
|
||||
|
||||
mnuStartServer.Enabled = !isNetPlayClient;
|
||||
|
@ -588,6 +611,8 @@ namespace Mesen.GUI.Forms
|
|||
} else {
|
||||
InteropEmu.Pause();
|
||||
}
|
||||
|
||||
ctrlNsfPlayer.UpdateText();
|
||||
}
|
||||
|
||||
private void ResetEmu()
|
||||
|
@ -644,7 +669,7 @@ namespace Mesen.GUI.Forms
|
|||
ToolStripMenuItem item = (ToolStripMenuItem)menu.DropDownItems.Add(label);
|
||||
uint stateIndex = i;
|
||||
item.Click += (object sender, EventArgs e) => {
|
||||
if(_emuThread != null) {
|
||||
if(_emuThread != null && !InteropEmu.IsNsf()) {
|
||||
if(forSave) {
|
||||
InteropEmu.SaveState(stateIndex);
|
||||
} else {
|
||||
|
@ -938,12 +963,14 @@ namespace Mesen.GUI.Forms
|
|||
|
||||
private void mnuPreferences_Click(object sender, EventArgs e)
|
||||
{
|
||||
new frmPreferences().ShowDialog(sender);
|
||||
ResourceHelper.LoadResources(ConfigManager.Config.PreferenceInfo.DisplayLanguage);
|
||||
ResourceHelper.UpdateEmuLanguage();
|
||||
ResourceHelper.ApplyResources(this);
|
||||
UpdateMenus();
|
||||
InitializeFdsDiskMenu();
|
||||
if(new frmPreferences().ShowDialog(sender) == DialogResult.OK) {
|
||||
ResourceHelper.LoadResources(ConfigManager.Config.PreferenceInfo.DisplayLanguage);
|
||||
ResourceHelper.UpdateEmuLanguage();
|
||||
ResourceHelper.ApplyResources(this);
|
||||
UpdateMenus();
|
||||
InitializeFdsDiskMenu();
|
||||
InitializeNsfMode();
|
||||
}
|
||||
}
|
||||
|
||||
private void mnuRegion_Click(object sender, EventArgs e)
|
||||
|
@ -1300,10 +1327,14 @@ namespace Mesen.GUI.Forms
|
|||
|
||||
private void InitializeVsSystemMenu()
|
||||
{
|
||||
sepVsSystem.Visible = InteropEmu.IsVsSystem();
|
||||
mnuInsertCoin1.Visible = InteropEmu.IsVsSystem();
|
||||
mnuInsertCoin2.Visible = InteropEmu.IsVsSystem();
|
||||
mnuVsGameConfig.Visible = InteropEmu.IsVsSystem();
|
||||
if(this.InvokeRequired) {
|
||||
this.BeginInvoke((MethodInvoker)(() => InitializeVsSystemMenu()));
|
||||
} else {
|
||||
sepVsSystem.Visible = InteropEmu.IsVsSystem();
|
||||
mnuInsertCoin1.Visible = InteropEmu.IsVsSystem();
|
||||
mnuInsertCoin2.Visible = InteropEmu.IsVsSystem();
|
||||
mnuVsGameConfig.Visible = InteropEmu.IsVsSystem();
|
||||
}
|
||||
}
|
||||
|
||||
private void mnuInsertCoin1_Click(object sender, EventArgs e)
|
||||
|
@ -1352,5 +1383,32 @@ namespace Mesen.GUI.Forms
|
|||
new frmEmulationConfig().ShowDialog(sender);
|
||||
UpdateEmulationSpeedMenu();
|
||||
}
|
||||
|
||||
|
||||
private void InitializeNsfMode()
|
||||
{
|
||||
if(this.InvokeRequired) {
|
||||
this.BeginInvoke((MethodInvoker)(() => this.InitializeNsfMode()));
|
||||
} else {
|
||||
if(InteropEmu.IsNsf()) {
|
||||
if(!this._isNsfPlayerMode) {
|
||||
this.Size = new Size(380, 320);
|
||||
this.MinimumSize = new Size(380, 320);
|
||||
}
|
||||
this._isNsfPlayerMode = true;
|
||||
this.ctrlNsfPlayer.UpdateText();
|
||||
this.ctrlNsfPlayer.ResetCount();
|
||||
this.ctrlNsfPlayer.Visible = true;
|
||||
this.ctrlNsfPlayer.Focus();
|
||||
|
||||
_currentGame = InteropEmu.NsfGetHeader().GetSongName();
|
||||
} else {
|
||||
this.MinimumSize = new Size(335, 320);
|
||||
this.SetScale(_regularScale);
|
||||
this._isNsfPlayerMode = false;
|
||||
this.ctrlNsfPlayer.Visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -227,6 +227,12 @@
|
|||
<Compile Include="Controls\ctrlHorizontalTrackbar.Designer.cs">
|
||||
<DependentUpon>ctrlHorizontalTrackbar.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ctrlNsfPlayer.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ctrlNsfPlayer.Designer.cs">
|
||||
<DependentUpon>ctrlNsfPlayer.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ctrlTrackbar.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
|
@ -508,6 +514,9 @@
|
|||
<EmbeddedResource Include="Controls\ctrlHorizontalTrackbar.resx">
|
||||
<DependentUpon>ctrlHorizontalTrackbar.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Controls\ctrlNsfPlayer.resx">
|
||||
<DependentUpon>ctrlNsfPlayer.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Controls\ctrlTrackbar.resx">
|
||||
<DependentUpon>ctrlTrackbar.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
@ -715,6 +724,9 @@
|
|||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Icon.ico" />
|
||||
<None Include="Resources\NsfBackground.png" />
|
||||
<None Include="Resources\PrevTrack.png" />
|
||||
<None Include="Resources\NextTrack.png" />
|
||||
<None Include="Resources\LogWindow.png" />
|
||||
<None Include="Resources\format-justify-fill.png" />
|
||||
<None Include="Resources\Record.png" />
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace Mesen.GUI
|
|||
[DllImport(DLLPath)] public static extern void AddKnowGameFolder([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string folder);
|
||||
|
||||
[DllImport(DLLPath, EntryPoint = "GetArchiveRomList")] private static extern IntPtr GetArchiveRomListWrapper([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string filename);
|
||||
public static List<string> GetArchiveRomList(string filename) { return new List<string>(PtrToStringUtf8(InteropEmu.GetArchiveRomListWrapper(filename)).Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries)); }
|
||||
public static List<string> GetArchiveRomList(string filename) { return new List<string>(PtrToStringUtf8(InteropEmu.GetArchiveRomListWrapper(filename)).Split(new string[] { "[!|!]" }, StringSplitOptions.RemoveEmptyEntries)); }
|
||||
|
||||
[DllImport(DLLPath)] public static extern void SetMousePosition(double x, double y);
|
||||
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool HasZapper();
|
||||
|
@ -96,6 +96,12 @@ namespace Mesen.GUI
|
|||
[DllImport(DLLPath)] public static extern void LoadState(UInt32 stateIndex);
|
||||
[DllImport(DLLPath)] public static extern Int64 GetStateInfo(UInt32 stateIndex);
|
||||
|
||||
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool IsNsf();
|
||||
[DllImport(DLLPath)] public static extern void NsfSelectTrack(Byte trackNumber);
|
||||
[DllImport(DLLPath)] public static extern Int32 NsfGetCurrentTrack();
|
||||
[DllImport(DLLPath, EntryPoint = "NsfGetHeader")] private static extern void NsfGetHeaderWrapper(out NsfHeader header);
|
||||
[DllImport(DLLPath)] public static extern void NsfSetNsfConfig(Int32 autoDetectSilenceDelay, Int32 moveToNextTrackTime, [MarshalAs(UnmanagedType.I1)]bool disableApuIrqs);
|
||||
|
||||
[DllImport(DLLPath)] public static extern UInt32 FdsGetSideCount();
|
||||
[DllImport(DLLPath)] public static extern void FdsEjectDisk();
|
||||
[DllImport(DLLPath)] public static extern void FdsInsertDisk(UInt32 diskNumber);
|
||||
|
@ -260,6 +266,13 @@ namespace Mesen.GUI
|
|||
}
|
||||
}
|
||||
|
||||
public static NsfHeader NsfGetHeader()
|
||||
{
|
||||
NsfHeader header = new NsfHeader();
|
||||
NsfGetHeaderWrapper(out header);
|
||||
return header;
|
||||
}
|
||||
|
||||
public static RomInfo GetRomInfo(string filename = "", Int32 archiveFileIndex = -1)
|
||||
{
|
||||
InteropRomInfo romInfo = new InteropRomInfo();
|
||||
|
@ -644,6 +657,93 @@ namespace Mesen.GUI
|
|||
public byte[] Condition;
|
||||
}
|
||||
|
||||
public struct NsfHeader
|
||||
{
|
||||
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 5)]
|
||||
public Byte[] Header;
|
||||
|
||||
public Byte Version;
|
||||
public Byte TotalSongs;
|
||||
public Byte StartingSong;
|
||||
public UInt16 LoadAddress;
|
||||
public UInt16 InitAddress;
|
||||
public UInt16 PlayAddress;
|
||||
|
||||
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 256)]
|
||||
public Byte[] SongName;
|
||||
|
||||
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 256)]
|
||||
public Byte[] ArtistName;
|
||||
|
||||
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 256)]
|
||||
public Byte[] CopyrightHolder;
|
||||
|
||||
public UInt16 PlaySpeedNtsc;
|
||||
|
||||
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public Byte[] BankSetup;
|
||||
|
||||
public UInt16 PlaySpeedPal;
|
||||
public Byte Flags;
|
||||
public Byte SoundChips;
|
||||
|
||||
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public Byte[] Padding;
|
||||
|
||||
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 256)]
|
||||
public Byte[] RipperName;
|
||||
|
||||
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 20000)]
|
||||
public Byte[] TrackName;
|
||||
|
||||
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 256)]
|
||||
public Int32[] TrackLength;
|
||||
|
||||
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 256)]
|
||||
public Int32[] TrackFade;
|
||||
|
||||
private string ConvertString(Byte[] input)
|
||||
{
|
||||
string output = Encoding.UTF8.GetString(input, 0, Array.IndexOf(input, (Byte)0));
|
||||
if(output[0] == 0xFFFD) {
|
||||
//Patch to convert an invalid character at index 0 to a copyright sign
|
||||
//This is usually the case for NSFe files (not sure what the encoding for NSF/NSFe is meant to be. Is it properly defined?)
|
||||
return "©" + output.Substring(1);
|
||||
}
|
||||
|
||||
if(output == "<?>") {
|
||||
return ResourceHelper.GetMessage("NsfUnknownField");
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public string GetSongName()
|
||||
{
|
||||
return ConvertString(this.SongName);
|
||||
}
|
||||
|
||||
public string GetArtistName()
|
||||
{
|
||||
return ConvertString(this.ArtistName);
|
||||
}
|
||||
|
||||
public string GetCopyrightHolder()
|
||||
{
|
||||
return ConvertString(this.CopyrightHolder);
|
||||
}
|
||||
|
||||
public string GetRipperName()
|
||||
{
|
||||
return ConvertString(this.RipperName);
|
||||
}
|
||||
|
||||
public string[] GetTrackNames()
|
||||
{
|
||||
return Encoding.UTF8.GetString(this.TrackName, 0, Array.IndexOf(this.TrackName, (Byte)0)).Split(new string[] { "[!|!]" }, StringSplitOptions.None);
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum BreakpointType
|
||||
{
|
||||
|
|
30
GUI.NET/Properties/Resources.Designer.cs
generated
30
GUI.NET/Properties/Resources.Designer.cs
generated
|
@ -290,6 +290,26 @@ namespace Mesen.GUI.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap NextTrack {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("NextTrack", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap NsfBackground {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("NsfBackground", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
|
@ -320,6 +340,16 @@ namespace Mesen.GUI.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap PrevTrack {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("PrevTrack", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
|
|
|
@ -214,4 +214,13 @@
|
|||
<data name="LogWindow" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\LogWindow.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="NextTrack" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\NextTrack.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="NsfBackground" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\NsfBackground.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="PrevTrack" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\PrevTrack.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
BIN
GUI.NET/Resources/NextTrack.png
Normal file
BIN
GUI.NET/Resources/NextTrack.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 618 B |
BIN
GUI.NET/Resources/NsfBackground.png
Normal file
BIN
GUI.NET/Resources/NsfBackground.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.9 KiB |
BIN
GUI.NET/Resources/PrevTrack.png
Normal file
BIN
GUI.NET/Resources/PrevTrack.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 618 B |
|
@ -2,9 +2,6 @@
|
|||
|
||||
#include "../Core/MessageManager.h"
|
||||
#include "../Core/Console.h"
|
||||
#include "../Windows/Renderer.h"
|
||||
#include "../Windows/SoundManager.h"
|
||||
#include "../Windows/WindowsKeyManager.h"
|
||||
#include "../Core/GameServer.h"
|
||||
#include "../Core/GameClient.h"
|
||||
#include "../Core/ClientConnectionData.h"
|
||||
|
@ -17,6 +14,10 @@
|
|||
#include "../Core/VsControlManager.h"
|
||||
#include "../Core/SoundMixer.h"
|
||||
#include "../Core/RomLoader.h"
|
||||
#include "../Core/NsfMapper.h"
|
||||
#include "../Windows/Renderer.h"
|
||||
#include "../Windows/SoundManager.h"
|
||||
#include "../Windows/WindowsKeyManager.h"
|
||||
|
||||
NES::Renderer *_renderer = nullptr;
|
||||
SoundManager *_soundManager = nullptr;
|
||||
|
@ -82,7 +83,7 @@ namespace InteropEmu {
|
|||
DllExport const char* __stdcall GetArchiveRomList(char* filename) {
|
||||
std::ostringstream out;
|
||||
for(string romName : RomLoader::GetArchiveRomList(filename)) {
|
||||
out << romName << "/";
|
||||
out << romName << "[!|!]";
|
||||
}
|
||||
_returnString = out.str();
|
||||
return _returnString.c_str();
|
||||
|
@ -325,6 +326,28 @@ namespace InteropEmu {
|
|||
|
||||
DllExport void __stdcall GetScreenSize(ScreenSize &size, bool ignoreScale) { VideoDecoder::GetInstance()->GetScreenSize(size, ignoreScale); }
|
||||
|
||||
//NSF functions
|
||||
DllExport bool __stdcall IsNsf() { return NsfMapper::GetInstance() != nullptr; }
|
||||
DllExport void __stdcall NsfSelectTrack(uint8_t trackNumber) {
|
||||
if(NsfMapper::GetInstance()) {
|
||||
NsfMapper::GetInstance()->SelectTrack(trackNumber);
|
||||
}
|
||||
}
|
||||
DllExport int32_t __stdcall NsfGetCurrentTrack(uint8_t trackNumber) {
|
||||
if(NsfMapper::GetInstance()) {
|
||||
return NsfMapper::GetInstance()->GetCurrentTrack();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
DllExport void __stdcall NsfGetHeader(NsfHeader* header) {
|
||||
if(NsfMapper::GetInstance()) {
|
||||
*header = NsfMapper::GetInstance()->GetNsfHeader();
|
||||
}
|
||||
}
|
||||
DllExport void __stdcall NsfSetNsfConfig(int32_t autoDetectSilenceDelay, int32_t moveToNextTrackTime, bool disableApuIrqs) {
|
||||
EmulationSettings::SetNsfConfig(autoDetectSilenceDelay, moveToNextTrackTime, disableApuIrqs);
|
||||
}
|
||||
|
||||
//FDS functions
|
||||
DllExport uint32_t __stdcall FdsGetSideCount() { return FDS::GetSideCount(); }
|
||||
DllExport void __stdcall FdsEjectDisk() { FDS::EjectDisk(); }
|
||||
|
|
Loading…
Add table
Reference in a new issue