From 266ca82a0668f8ad450a4e8cb16c052499d3fa1c Mon Sep 17 00:00:00 2001 From: Souryo Date: Fri, 17 Jul 2015 20:58:57 -0400 Subject: [PATCH] Added basic audio settings --- Core/APU.cpp | 16 +- Core/APU.h | 2 +- Core/ApuEnvelope.h | 2 +- Core/ApuLengthCounter.h | 2 +- Core/BaseApuChannel.h | 25 +- Core/Console.cpp | 29 +- Core/Console.h | 11 - Core/Core.vcxproj | 2 + Core/Core.vcxproj.filters | 6 + Core/DeltaModulationChannel.h | 2 +- Core/EmulationSettings.cpp | 6 + Core/EmulationSettings.h | 63 ++++ Core/GameClientConnection.cpp | 5 +- Core/GameServerConnection.cpp | 3 +- Core/NoiseChannel.h | 2 +- Core/SquareChannel.h | 2 +- Core/TriangleChannel.h | 2 +- Core/VirtualController.cpp | 5 +- GUI.NET/Config/AudioInfo.cs | 47 +++ GUI.NET/Config/Configuration.cs | 2 + GUI.NET/Controls/ctrlTrackbar.Designer.cs | 117 +++++++ GUI.NET/Controls/ctrlTrackbar.cs | 47 +++ GUI.NET/Controls/ctrlTrackbar.resx | 120 +++++++ GUI.NET/Forms/BaseConfigForm.Designer.cs | 63 ++-- GUI.NET/Forms/BaseConfigForm.cs | 34 +- GUI.NET/Forms/BaseConfigForm.resx | 3 - GUI.NET/Forms/Cheats/frmCheat.cs | 1 - .../Forms/Config/frmAudioConfig.Designer.cs | 310 ++++++++++++++++++ GUI.NET/Forms/Config/frmAudioConfig.cs | 61 ++++ GUI.NET/Forms/Config/frmAudioConfig.resx | 120 +++++++ GUI.NET/Forms/frmMain.Designer.cs | 2 +- GUI.NET/Forms/frmMain.cs | 7 + GUI.NET/GUI.NET.csproj | 19 ++ GUI.NET/InteropEmu.cs | 7 +- InteropDLL/ConsoleWrapper.cpp | 15 +- Windows/Renderer.cpp | 13 +- Windows/SoundManager.cpp | 13 +- Windows/SoundManager.h | 2 +- 38 files changed, 1074 insertions(+), 114 deletions(-) create mode 100644 Core/EmulationSettings.cpp create mode 100644 Core/EmulationSettings.h create mode 100644 GUI.NET/Config/AudioInfo.cs create mode 100644 GUI.NET/Controls/ctrlTrackbar.Designer.cs create mode 100644 GUI.NET/Controls/ctrlTrackbar.cs create mode 100644 GUI.NET/Controls/ctrlTrackbar.resx create mode 100644 GUI.NET/Forms/Config/frmAudioConfig.Designer.cs create mode 100644 GUI.NET/Forms/Config/frmAudioConfig.cs create mode 100644 GUI.NET/Forms/Config/frmAudioConfig.resx diff --git a/Core/APU.cpp b/Core/APU.cpp index 06748677..271ed734 100644 --- a/Core/APU.cpp +++ b/Core/APU.cpp @@ -7,6 +7,7 @@ #include "NoiseChannel.h" #include "DeltaModulationChannel.h" #include "ApuFrameCounter.h" +#include "EmulationSettings.h" APU* APU::Instance = nullptr; IAudioDevice* APU::AudioDevice = nullptr; @@ -16,17 +17,17 @@ APU::APU(MemoryManager* memoryManager) APU::Instance = this; _memoryManager = memoryManager; - _blipBuffer = new Blip_Buffer(); + _blipBuffer.reset(new Blip_Buffer()); _blipBuffer->sample_rate(APU::SampleRate); _blipBuffer->clock_rate(CPU::ClockRate); _outputBuffer = new int16_t[APU::SamplesPerFrame]; - _squareChannel.push_back(unique_ptr(new SquareChannel(_blipBuffer, true))); - _squareChannel.push_back(unique_ptr(new SquareChannel(_blipBuffer, false))); - _triangleChannel.reset(new TriangleChannel(_blipBuffer)); - _noiseChannel.reset(new NoiseChannel(_blipBuffer)); - _deltaModulationChannel.reset(new DeltaModulationChannel(_blipBuffer, _memoryManager)); + _squareChannel.push_back(unique_ptr(new SquareChannel(AudioChannel::Square1, _blipBuffer.get(), true))); + _squareChannel.push_back(unique_ptr(new SquareChannel(AudioChannel::Square2, _blipBuffer.get(), false))); + _triangleChannel.reset(new TriangleChannel(AudioChannel::Triangle, _blipBuffer.get())); + _noiseChannel.reset(new NoiseChannel(AudioChannel::Noise, _blipBuffer.get())); + _deltaModulationChannel.reset(new DeltaModulationChannel(AudioChannel::DMC, _blipBuffer.get(), _memoryManager)); _frameCounter.reset(new ApuFrameCounter(&APU::FrameCounterTick)); _memoryManager->RegisterIODevice(_squareChannel[0].get()); @@ -146,7 +147,7 @@ void APU::ExecStatic() void APU::Exec() { _currentCycle++; - if(_currentCycle == 20000) { + if(_currentCycle == 10000) { Run(); _squareChannel[0]->EndFrame(); @@ -158,7 +159,6 @@ void APU::Exec() _blipBuffer->end_frame(_currentCycle); // Read some samples out of Blip_Buffer if there are enough to fill our output buffer - uint32_t availableSampleCount = _blipBuffer->samples_avail(); size_t sampleCount = _blipBuffer->read_samples(_outputBuffer, APU::SamplesPerFrame); if(APU::AudioDevice) { APU::AudioDevice->PlayBuffer(_outputBuffer, (uint32_t)(sampleCount * BitsPerSample / 8)); diff --git a/Core/APU.h b/Core/APU.h index 52f8015e..ad52ed97 100644 --- a/Core/APU.h +++ b/Core/APU.h @@ -30,7 +30,7 @@ class APU : public Snapshotable, public IMemoryHandler unique_ptr _frameCounter; - Blip_Buffer* _blipBuffer; + unique_ptr _blipBuffer; int16_t* _outputBuffer; MemoryManager* _memoryManager; diff --git a/Core/ApuEnvelope.h b/Core/ApuEnvelope.h index e38099f7..c46f8bbb 100644 --- a/Core/ApuEnvelope.h +++ b/Core/ApuEnvelope.h @@ -15,7 +15,7 @@ private: uint8_t _counter = 0; protected: - ApuEnvelope(Blip_Buffer* buffer) : ApuLengthCounter(buffer) + ApuEnvelope(AudioChannel channel, Blip_Buffer* buffer) : ApuLengthCounter(channel, buffer) { } diff --git a/Core/ApuLengthCounter.h b/Core/ApuLengthCounter.h index a56b091e..15fdecc2 100644 --- a/Core/ApuLengthCounter.h +++ b/Core/ApuLengthCounter.h @@ -25,7 +25,7 @@ protected: } public: - ApuLengthCounter(Blip_Buffer* buffer) : BaseApuChannel(buffer) + ApuLengthCounter(AudioChannel channel, Blip_Buffer* buffer) : BaseApuChannel(channel, buffer) { } diff --git a/Core/BaseApuChannel.h b/Core/BaseApuChannel.h index 35776e40..93731da3 100644 --- a/Core/BaseApuChannel.h +++ b/Core/BaseApuChannel.h @@ -2,6 +2,7 @@ #include "stdafx.h" #include "IMemoryHandler.h" #include "../BlipBuffer/Blip_Buffer.h" +#include "EmulationSettings.h" template class BaseApuChannel : public IMemoryHandler, public Snapshotable @@ -11,18 +12,32 @@ private: uint16_t _lastOutput = 0; uint32_t _previousCycle = 0; Blip_Buffer *_buffer; + AudioChannel _channel; + double _baseVolume; protected: uint16_t _timer = 0; uint16_t _period = 0; uint32_t _clockDivider = 2; //All channels except triangle clock overy other cpu clock + void SetVolume(double volume) + { + _baseVolume = volume; + UpdateSynthVolume(); + } + + void UpdateSynthVolume() + { + _synth->volume(_baseVolume * EmulationSettings::GetChannelVolume(_channel) * 2); + } + public: virtual void Clock() = 0; virtual bool GetStatus() = 0; - BaseApuChannel(Blip_Buffer *buffer) + BaseApuChannel(AudioChannel channel, Blip_Buffer *buffer) { + _channel = channel; _buffer = buffer; _synth.reset(new Blip_Synth()); @@ -50,11 +65,6 @@ public: } } - void SetVolume(double volume) - { - _synth->volume(volume); - } - virtual void Run(uint32_t targetCycle) { while(_previousCycle < targetCycle) { @@ -91,5 +101,8 @@ public: void EndFrame() { _previousCycle = 0; + + //Update options at the end of the cycle + UpdateSynthVolume(); } }; \ No newline at end of file diff --git a/Core/Console.cpp b/Core/Console.cpp index e86e79b3..347f0f62 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -4,12 +4,12 @@ #include "BaseMapper.h" #include "MapperFactory.h" #include "Debugger.h" +#include "MessageManager.h" +#include "EmulationSettings.h" #include "../Utilities/Timer.h" #include "../Utilities/FolderUtilities.h" -#include "../Core/MessageManager.h" shared_ptr Console::Instance(new Console()); -uint32_t Console::Flags = 0; Console::Console() { @@ -127,7 +127,7 @@ void Console::ResetComponents(bool softReset) void Console::Stop() { _stop = true; - Console::ClearFlags(EmulationFlags::Paused); + EmulationSettings::ClearFlags(EmulationFlags::Paused); _stopLock.Acquire(); _stopLock.Release(); } @@ -145,26 +145,11 @@ void Console::Resume() Console::Instance->_pauseLock.Release(); } -void Console::SetFlags(int flags) -{ - Console::Flags |= flags; -} - -void Console::ClearFlags(int flags) -{ - Console::Flags &= ~flags; -} - -bool Console::CheckFlag(int flag) -{ - return (Console::Flags & flag) == flag; -} - void Console::Run() { Timer clockTimer; double elapsedTime = 0; - double targetTime = 16.6666666666666666; + double targetTime = 16.63926405550947; //~60.0988fps _runLock.Acquire(); _stopLock.Acquire(); @@ -177,7 +162,7 @@ void Console::Run() lastFrameNumber = currentFrameNumber; _cpu->EndFrame(); - if(CheckFlag(EmulationFlags::LimitFPS)) { + if(EmulationSettings::CheckFlag(EmulationFlags::LimitFPS)) { elapsedTime = clockTimer.GetElapsedMS(); while(targetTime > elapsedTime) { if(targetTime - elapsedTime > 2) { @@ -197,14 +182,14 @@ void Console::Run() _runLock.Acquire(); } - if(CheckFlag(EmulationFlags::Paused) && !_stop) { + if(EmulationSettings::CheckFlag(EmulationFlags::Paused) && !_stop) { MessageManager::SendNotification(ConsoleNotificationType::GamePaused); _runLock.Release(); //Prevent audio from looping endlessly while game is paused _apu->StopAudio(); - while(CheckFlag(EmulationFlags::Paused)) { + while(EmulationSettings::CheckFlag(EmulationFlags::Paused)) { //Sleep until emulation is resumed std::this_thread::sleep_for(std::chrono::duration(100)); } diff --git a/Core/Console.h b/Core/Console.h index c00ae9fa..396ae1b1 100644 --- a/Core/Console.h +++ b/Core/Console.h @@ -8,12 +8,6 @@ #include "ControlManager.h" #include "../Utilities/SimpleLock.h" -enum EmulationFlags -{ - LimitFPS = 0x01, - Paused = 0x02, -}; - class Debugger; class BaseMapper; @@ -21,7 +15,6 @@ class Console { private: static shared_ptr Instance; - static uint32_t Flags; SimpleLock _pauseLock; SimpleLock _runLock; SimpleLock _stopLock; @@ -67,9 +60,5 @@ class Console static string FindMatchingRomInFolder(string folder, string romFilename, uint32_t crc32Hash); static string GetROMPath(); - static bool CheckFlag(int flag); - static void SetFlags(int flags); - static void ClearFlags(int flags); - static shared_ptr GetInstance(); }; diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 567751cf..092c2283 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -282,6 +282,7 @@ + @@ -336,6 +337,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 1fa2998a..10706663 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -218,6 +218,9 @@ Header Files\APU + + Header Files + @@ -289,5 +292,8 @@ Source Files\APU + + Source Files + \ No newline at end of file diff --git a/Core/DeltaModulationChannel.h b/Core/DeltaModulationChannel.h index fd4fcb90..45a49dab 100644 --- a/Core/DeltaModulationChannel.h +++ b/Core/DeltaModulationChannel.h @@ -86,7 +86,7 @@ protected: } public: - DeltaModulationChannel(Blip_Buffer *buffer, MemoryManager* memoryManager) : BaseApuChannel(buffer) + DeltaModulationChannel(AudioChannel channel, Blip_Buffer *buffer, MemoryManager* memoryManager) : BaseApuChannel(channel, buffer) { _memoryManager = memoryManager; _clockDivider = 1; diff --git a/Core/EmulationSettings.cpp b/Core/EmulationSettings.cpp new file mode 100644 index 00000000..660dd5a2 --- /dev/null +++ b/Core/EmulationSettings.cpp @@ -0,0 +1,6 @@ +#include "stdafx.h" +#include "EmulationSettings.h" + +uint32_t EmulationSettings::Flags = 0; +uint32_t EmulationSettings::AudioLatency = 20000; +double EmulationSettings::ChannelVolume[5] = { 0.5f, 0.5f, 0.5f, 0.5f, 0.5f }; \ No newline at end of file diff --git a/Core/EmulationSettings.h b/Core/EmulationSettings.h new file mode 100644 index 00000000..6752200e --- /dev/null +++ b/Core/EmulationSettings.h @@ -0,0 +1,63 @@ +#pragma once + +#include "stdafx.h" + +enum EmulationFlags +{ + LimitFPS = 0x01, + Paused = 0x02, +}; + +enum class AudioChannel +{ + Square1 = 0, + Square2 = 1, + Triangle = 2, + Noise = 3, + DMC = 4 +}; + +class EmulationSettings +{ +private: + static uint32_t Flags; + static uint32_t AudioLatency; + static double ChannelVolume[5]; + +public: + static void SetFlags(uint32_t flags) + { + Flags |= flags; + } + + static void ClearFlags(uint32_t flags) + { + Flags &= ~flags; + } + + static bool CheckFlag(uint32_t flag) + { + return (Flags & flag) == flag; + } + + //0: Muted, 0.5: Default, 1.0: Max volume + static void SetChannelVolume(AudioChannel channel, double volume) + { + ChannelVolume[(int)channel] = volume; + } + + static void SetAudioLatency(uint32_t msLatency) + { + AudioLatency = msLatency; + } + + static double GetChannelVolume(AudioChannel channel) + { + return ChannelVolume[(int)channel]; + } + + static uint32_t GetAudioLatency() + { + return AudioLatency; + } +}; diff --git a/Core/GameClientConnection.cpp b/Core/GameClientConnection.cpp index bcce8c3c..fc12f674 100644 --- a/Core/GameClientConnection.cpp +++ b/Core/GameClientConnection.cpp @@ -7,6 +7,7 @@ #include "GameInformationMessage.h" #include "SaveStateMessage.h" #include "Console.h" +#include "EmulationSettings.h" #include "ControlManager.h" #include "VirtualController.h" #include "ClientConnectionData.h" @@ -84,9 +85,9 @@ void GameClientConnection::ProcessMessage(NetMessage* message) _gameLoaded = gameInfo->AttemptLoadGame(); if(gameInfo->IsPaused()) { - Console::SetFlags(EmulationFlags::Paused); + EmulationSettings::SetFlags(EmulationFlags::Paused); } else { - Console::ClearFlags(EmulationFlags::Paused); + EmulationSettings::ClearFlags(EmulationFlags::Paused); } break; diff --git a/Core/GameServerConnection.cpp b/Core/GameServerConnection.cpp index 699b5511..8e3d8489 100644 --- a/Core/GameServerConnection.cpp +++ b/Core/GameServerConnection.cpp @@ -10,6 +10,7 @@ #include "Console.h" #include "ControlManager.h" #include "ClientConnectionData.h" +#include "EmulationSettings.h" GameServerConnection::GameServerConnection(shared_ptr socket, int controllerPort, IGameBroadcaster* gameBroadcaster) : GameConnection(socket, nullptr) { @@ -54,7 +55,7 @@ void GameServerConnection::SendGameState() void GameServerConnection::SendGameInformation() { - SendNetMessage(GameInformationMessage(Console::GetROMPath(), _controllerPort, Console::CheckFlag(EmulationFlags::Paused))); + SendNetMessage(GameInformationMessage(Console::GetROMPath(), _controllerPort, EmulationSettings::CheckFlag(EmulationFlags::Paused))); } void GameServerConnection::SendMovieData(uint8_t state, uint8_t port) diff --git a/Core/NoiseChannel.h b/Core/NoiseChannel.h index 8754c3c0..1dc699c5 100644 --- a/Core/NoiseChannel.h +++ b/Core/NoiseChannel.h @@ -37,7 +37,7 @@ protected: } public: - NoiseChannel(Blip_Buffer* buffer) : ApuEnvelope(buffer) + NoiseChannel(AudioChannel channel, Blip_Buffer* buffer) : ApuEnvelope(channel, buffer) { SetVolume(0.0741); } diff --git a/Core/SquareChannel.h b/Core/SquareChannel.h index 5609a4f2..ddae8505 100644 --- a/Core/SquareChannel.h +++ b/Core/SquareChannel.h @@ -77,7 +77,7 @@ protected: } public: - SquareChannel(Blip_Buffer *buffer, bool isChannel1) : ApuEnvelope(buffer) + SquareChannel(AudioChannel channel, Blip_Buffer *buffer, bool isChannel1) : ApuEnvelope(channel, buffer) { SetVolume(0.1128); _isChannel1 = isChannel1; diff --git a/Core/TriangleChannel.h b/Core/TriangleChannel.h index 8f68e687..02c18fa7 100644 --- a/Core/TriangleChannel.h +++ b/Core/TriangleChannel.h @@ -29,7 +29,7 @@ protected: } public: - TriangleChannel(Blip_Buffer* buffer) : ApuLengthCounter(buffer) + TriangleChannel(AudioChannel channel, Blip_Buffer* buffer) : ApuLengthCounter(channel, buffer) { _clockDivider = 1; //Triangle clocks at the same speed as the cpu SetVolume(0.12765); diff --git a/Core/VirtualController.cpp b/Core/VirtualController.cpp index dac33b3a..8b56ec69 100644 --- a/Core/VirtualController.cpp +++ b/Core/VirtualController.cpp @@ -3,6 +3,7 @@ #include "VirtualController.h" #include "ControlManager.h" #include "Console.h" +#include "EmulationSettings.h" VirtualController::VirtualController(uint8_t port) { @@ -44,9 +45,9 @@ ButtonState VirtualController::GetButtonState() _queueSize--; if(_queueSize.load() > _minimumBuffer) { - Console::ClearFlags(EmulationFlags::LimitFPS); + EmulationSettings::ClearFlags(EmulationFlags::LimitFPS); } else { - Console::SetFlags(EmulationFlags::LimitFPS); + EmulationSettings::SetFlags(EmulationFlags::LimitFPS); } _writeLock.Release(); diff --git a/GUI.NET/Config/AudioInfo.cs b/GUI.NET/Config/AudioInfo.cs new file mode 100644 index 00000000..2183af97 --- /dev/null +++ b/GUI.NET/Config/AudioInfo.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Mesen.GUI.Config +{ + public class AudioInfo + { + public bool EnableAudio = true; + public UInt32 AudioLatency = 150; + public UInt32 MasterVolume = 50; + public UInt32 Square1Volume = 50; + public UInt32 Square2Volume = 50; + public UInt32 TriangleVolume = 50; + public UInt32 NoiseVolume = 50; + public UInt32 DmcVolume = 50; + + public AudioInfo() + { + } + + static private double ConvertVolume(UInt32 volume) + { + if(ConfigManager.Config.AudioInfo.EnableAudio) { + return ((double)volume / 100d) * (double)ConfigManager.Config.AudioInfo.MasterVolume * 2 / 100d; + } else { + return 0; + } + } + + static public void ApplyConfig() + { + AudioInfo audioInfo = ConfigManager.Config.AudioInfo; + InteropEmu.SetAudioLatency(audioInfo.AudioLatency); + InteropEmu.SetChannelVolume(0, ConvertVolume(audioInfo.Square1Volume)); + InteropEmu.SetChannelVolume(1, ConvertVolume(audioInfo.Square2Volume)); + InteropEmu.SetChannelVolume(2, ConvertVolume(audioInfo.TriangleVolume)); + InteropEmu.SetChannelVolume(3, ConvertVolume(audioInfo.NoiseVolume)); + InteropEmu.SetChannelVolume(4, ConvertVolume(audioInfo.DmcVolume)); + } + } +} diff --git a/GUI.NET/Config/Configuration.cs b/GUI.NET/Config/Configuration.cs index 01557f19..1b10b8cf 100644 --- a/GUI.NET/Config/Configuration.cs +++ b/GUI.NET/Config/Configuration.cs @@ -15,6 +15,7 @@ namespace Mesen.GUI.Config public PlayerProfile Profile; public ClientConnectionInfo ClientConnectionInfo; public ServerInfo ServerInfo; + public AudioInfo AudioInfo; public List RecentFiles; public List Cheats; public List Controllers; @@ -25,6 +26,7 @@ namespace Mesen.GUI.Config Profile = new PlayerProfile(); ClientConnectionInfo = new ClientConnectionInfo(); ServerInfo = new ServerInfo(); + AudioInfo = new AudioInfo(); RecentFiles = new List(); Controllers = new List(); } diff --git a/GUI.NET/Controls/ctrlTrackbar.Designer.cs b/GUI.NET/Controls/ctrlTrackbar.Designer.cs new file mode 100644 index 00000000..cb90036e --- /dev/null +++ b/GUI.NET/Controls/ctrlTrackbar.Designer.cs @@ -0,0 +1,117 @@ +namespace Mesen.GUI.Controls +{ + partial class ctrlTrackbar + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if(disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.lblText = new System.Windows.Forms.Label(); + this.trackBar = new System.Windows.Forms.TrackBar(); + this.txtValue = new System.Windows.Forms.TextBox(); + this.tableLayoutPanel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.trackBar)).BeginInit(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Controls.Add(this.lblText, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.trackBar, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.txtValue, 0, 1); + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 3; + 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.Size = new System.Drawing.Size(62, 160); + this.tableLayoutPanel1.TabIndex = 0; + // + // lblText + // + this.lblText.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.lblText.AutoSize = true; + this.lblText.Location = new System.Drawing.Point(3, 147); + this.lblText.Name = "lblText"; + this.lblText.Size = new System.Drawing.Size(56, 13); + this.lblText.TabIndex = 14; + this.lblText.Text = "Text"; + this.lblText.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // trackBar + // + this.trackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.trackBar.Location = new System.Drawing.Point(17, 0); + this.trackBar.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0); + this.trackBar.Maximum = 100; + this.trackBar.Name = "trackBar"; + this.trackBar.Orientation = System.Windows.Forms.Orientation.Vertical; + this.trackBar.Size = new System.Drawing.Size(45, 124); + this.trackBar.TabIndex = 13; + this.trackBar.TickFrequency = 10; + this.trackBar.Value = 50; + this.trackBar.ValueChanged += new System.EventHandler(this.trackBar_ValueChanged); + // + // txtValue + // + this.txtValue.Anchor = System.Windows.Forms.AnchorStyles.None; + this.txtValue.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtValue.Location = new System.Drawing.Point(15, 127); + this.txtValue.Multiline = true; + this.txtValue.Name = "txtValue"; + this.txtValue.Size = new System.Drawing.Size(31, 17); + this.txtValue.TabIndex = 15; + this.txtValue.Text = "100"; + this.txtValue.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + // + // ctrlTrackbar + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tableLayoutPanel1); + this.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0); + this.MaximumSize = new System.Drawing.Size(63, 160); + this.MinimumSize = new System.Drawing.Size(63, 160); + this.Name = "ctrlTrackbar"; + this.Size = new System.Drawing.Size(63, 160); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.trackBar)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label lblText; + private System.Windows.Forms.TrackBar trackBar; + private System.Windows.Forms.TextBox txtValue; + } +} diff --git a/GUI.NET/Controls/ctrlTrackbar.cs b/GUI.NET/Controls/ctrlTrackbar.cs new file mode 100644 index 00000000..48ed380a --- /dev/null +++ b/GUI.NET/Controls/ctrlTrackbar.cs @@ -0,0 +1,47 @@ +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; + +namespace Mesen.GUI.Controls +{ + public partial class ctrlTrackbar : UserControl + { + public event EventHandler ValueChanged + { + add { trackBar.ValueChanged += value; } + remove { trackBar.ValueChanged -= value; } + } + + public ctrlTrackbar() + { + InitializeComponent(); + } + + public string Caption + { + get { return lblText.Text; } + set { lblText.Text = value; } + } + + public int Value + { + get { return trackBar.Value; } + set + { + trackBar.Value = value; + txtValue.Text = trackBar.Value.ToString() + "%"; + } + } + + private void trackBar_ValueChanged(object sender, EventArgs e) + { + txtValue.Text = trackBar.Value.ToString() + "%"; + } + } +} diff --git a/GUI.NET/Controls/ctrlTrackbar.resx b/GUI.NET/Controls/ctrlTrackbar.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/GUI.NET/Controls/ctrlTrackbar.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/GUI.NET/Forms/BaseConfigForm.Designer.cs b/GUI.NET/Forms/BaseConfigForm.Designer.cs index c61d198c..07d42046 100644 --- a/GUI.NET/Forms/BaseConfigForm.Designer.cs +++ b/GUI.NET/Forms/BaseConfigForm.Designer.cs @@ -37,39 +37,19 @@ namespace Mesen.GUI.Forms /// private void InitializeComponent() { - this.panel1 = new System.Windows.Forms.Panel(); - this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); this.btnCancel = new System.Windows.Forms.Button(); this.btnOK = new System.Windows.Forms.Button(); - this.panel1.SuspendLayout(); + this.baseConfigPanel = new System.Windows.Forms.Panel(); + this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + this.baseConfigPanel.SuspendLayout(); this.flowLayoutPanel1.SuspendLayout(); this.SuspendLayout(); // - // panel1 - // - this.panel1.Controls.Add(this.flowLayoutPanel1); - this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom; - this.panel1.Location = new System.Drawing.Point(0, 232); - this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(284, 30); - this.panel1.TabIndex = 0; - // - // flowLayoutPanel1 - // - this.flowLayoutPanel1.Controls.Add(this.btnCancel); - this.flowLayoutPanel1.Controls.Add(this.btnOK); - this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; - this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft; - this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0); - this.flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(0); - this.flowLayoutPanel1.Name = "flowLayoutPanel1"; - this.flowLayoutPanel1.Size = new System.Drawing.Size(284, 30); - this.flowLayoutPanel1.TabIndex = 4; - // // btnCancel // + this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.btnCancel.Location = new System.Drawing.Point(206, 3); + this.btnCancel.Location = new System.Drawing.Point(84, 3); this.btnCancel.Name = "btnCancel"; this.btnCancel.Size = new System.Drawing.Size(75, 23); this.btnCancel.TabIndex = 0; @@ -79,8 +59,9 @@ namespace Mesen.GUI.Forms // // btnOK // + this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; - this.btnOK.Location = new System.Drawing.Point(125, 3); + this.btnOK.Location = new System.Drawing.Point(3, 3); this.btnOK.Name = "btnOK"; this.btnOK.Size = new System.Drawing.Size(75, 23); this.btnOK.TabIndex = 1; @@ -88,14 +69,34 @@ namespace Mesen.GUI.Forms this.btnOK.UseVisualStyleBackColor = true; this.btnOK.Click += new System.EventHandler(this.btnOK_Click); // + // baseConfigPanel + // + this.baseConfigPanel.Controls.Add(this.flowLayoutPanel1); + this.baseConfigPanel.Dock = System.Windows.Forms.DockStyle.Bottom; + this.baseConfigPanel.Location = new System.Drawing.Point(0, 233); + this.baseConfigPanel.Name = "baseConfigPanel"; + this.baseConfigPanel.Size = new System.Drawing.Size(327, 29); + this.baseConfigPanel.TabIndex = 1; + // + // flowLayoutPanel1 + // + this.flowLayoutPanel1.Controls.Add(this.btnOK); + this.flowLayoutPanel1.Controls.Add(this.btnCancel); + this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Right; + this.flowLayoutPanel1.Location = new System.Drawing.Point(162, 0); + this.flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0); + this.flowLayoutPanel1.Name = "flowLayoutPanel1"; + this.flowLayoutPanel1.Size = new System.Drawing.Size(165, 29); + this.flowLayoutPanel1.TabIndex = 2; + // // BaseConfigForm // this.AcceptButton = this.btnOK; this.CancelButton = this.btnCancel; - this.ClientSize = new System.Drawing.Size(284, 262); - this.Controls.Add(this.panel1); + this.ClientSize = new System.Drawing.Size(327, 262); + this.Controls.Add(this.baseConfigPanel); this.Name = "BaseConfigForm"; - this.panel1.ResumeLayout(false); + this.baseConfigPanel.ResumeLayout(false); this.flowLayoutPanel1.ResumeLayout(false); this.ResumeLayout(false); @@ -103,9 +104,9 @@ namespace Mesen.GUI.Forms #endregion - private System.Windows.Forms.Panel panel1; - protected System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; protected Button btnCancel; protected Button btnOK; + protected Panel baseConfigPanel; + private FlowLayoutPanel flowLayoutPanel1; } } diff --git a/GUI.NET/Forms/BaseConfigForm.cs b/GUI.NET/Forms/BaseConfigForm.cs index 9a91be69..82f22adb 100644 --- a/GUI.NET/Forms/BaseConfigForm.cs +++ b/GUI.NET/Forms/BaseConfigForm.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using Mesen.GUI.Config; +using Mesen.GUI.Controls; namespace Mesen.GUI.Forms { @@ -15,7 +16,7 @@ namespace Mesen.GUI.Forms private Dictionary _fieldInfo = null; private object _entity; private Timer _validateTimer; - + public BaseConfigForm() { InitializeComponent(); @@ -26,6 +27,13 @@ namespace Mesen.GUI.Forms _validateTimer.Start(); } + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + + UpdateUI(); + } + private void OnValidateInput(object sender, EventArgs e) { btnOK.Enabled = ValidateInput(); @@ -47,6 +55,7 @@ namespace Mesen.GUI.Forms protected override void OnFormClosed(FormClosedEventArgs e) { if(this.DialogResult == System.Windows.Forms.DialogResult.OK) { + UpdateObject(); UpdateConfig(); if(ApplyChangesOnOK) { ConfigManager.ApplyChanges(); @@ -66,6 +75,12 @@ namespace Mesen.GUI.Forms { } + protected bool Updating + { + get; + private set; + } + protected object Entity { get { return _entity; } @@ -99,6 +114,7 @@ namespace Mesen.GUI.Forms protected void UpdateUI() { + this.Updating = true; foreach(KeyValuePair kvp in _bindings) { if(!_fieldInfo.ContainsKey(kvp.Key)) { throw new Exception("Invalid binding key"); @@ -122,9 +138,17 @@ namespace Mesen.GUI.Forms } else { throw new Exception("No radio button matching value found"); } + } else if(kvp.Value is ctrlTrackbar) { + ((ctrlTrackbar)kvp.Value).Value = (int)(uint)value; + } else if(kvp.Value is NumericUpDown) { + NumericUpDown nud = kvp.Value as NumericUpDown; + decimal val = (decimal)(uint)value; + val = Math.Min(Math.Max(val, nud.Minimum), nud.Maximum); + nud.Value = val; } } - } + } + this.Updating = false; } protected void UpdateObject() @@ -146,9 +170,13 @@ namespace Mesen.GUI.Forms field.SetValue(Entity, ((CheckBox)kvp.Value).Checked); } else if(kvp.Value is Panel) { field.SetValue(Entity, kvp.Value.Controls.OfType().FirstOrDefault(r => r.Checked).Tag); + } else if(kvp.Value is ctrlTrackbar) { + field.SetValue(Entity, (UInt32)((ctrlTrackbar)kvp.Value).Value); + } else if(kvp.Value is NumericUpDown) { + field.SetValue(Entity, (UInt32)((NumericUpDown)kvp.Value).Value); } } - } + } } private void btnOK_Click(object sender, EventArgs e) diff --git a/GUI.NET/Forms/BaseConfigForm.resx b/GUI.NET/Forms/BaseConfigForm.resx index b94d2c98..1af7de15 100644 --- a/GUI.NET/Forms/BaseConfigForm.resx +++ b/GUI.NET/Forms/BaseConfigForm.resx @@ -117,7 +117,4 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - True - \ No newline at end of file diff --git a/GUI.NET/Forms/Cheats/frmCheat.cs b/GUI.NET/Forms/Cheats/frmCheat.cs index 6e5e1458..aec99709 100644 --- a/GUI.NET/Forms/Cheats/frmCheat.cs +++ b/GUI.NET/Forms/Cheats/frmCheat.cs @@ -46,7 +46,6 @@ namespace Mesen.GUI.Forms.Cheats AddBinding("CompareValue", txtCompare); AddBinding("IsRelativeAddress", radRelativeAddress.Parent); - UpdateUI(); UpdateOKButton(); } diff --git a/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs b/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs new file mode 100644 index 00000000..0ec100e8 --- /dev/null +++ b/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs @@ -0,0 +1,310 @@ +namespace Mesen.GUI.Forms.Config +{ + partial class frmAudioConfig + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if(disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.grpVolume = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.trkDmcVol = new Mesen.GUI.Controls.ctrlTrackbar(); + this.trkNoiseVol = new Mesen.GUI.Controls.ctrlTrackbar(); + this.trkTriangleVol = new Mesen.GUI.Controls.ctrlTrackbar(); + this.trkSquare2Vol = new Mesen.GUI.Controls.ctrlTrackbar(); + this.trkSquare1Vol = new Mesen.GUI.Controls.ctrlTrackbar(); + this.trkMaster = new Mesen.GUI.Controls.ctrlTrackbar(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.chkEnableAudio = new System.Windows.Forms.CheckBox(); + this.flowLayoutPanel2 = new System.Windows.Forms.FlowLayoutPanel(); + this.lblAudioLatency = new System.Windows.Forms.Label(); + this.nudLatency = new System.Windows.Forms.NumericUpDown(); + this.lblLatencyMs = new System.Windows.Forms.Label(); + this.btnReset = new System.Windows.Forms.Button(); + this.baseConfigPanel.SuspendLayout(); + this.grpVolume.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + this.flowLayoutPanel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.nudLatency)).BeginInit(); + this.SuspendLayout(); + // + // baseConfigPanel + // + this.baseConfigPanel.Controls.Add(this.btnReset); + this.baseConfigPanel.Location = new System.Drawing.Point(0, 245); + this.baseConfigPanel.Size = new System.Drawing.Size(470, 29); + this.baseConfigPanel.Controls.SetChildIndex(this.btnReset, 0); + // + // grpVolume + // + this.grpVolume.Controls.Add(this.tableLayoutPanel1); + this.grpVolume.Location = new System.Drawing.Point(3, 29); + this.grpVolume.Name = "grpVolume"; + this.grpVolume.Size = new System.Drawing.Size(462, 185); + this.grpVolume.TabIndex = 2; + this.grpVolume.TabStop = false; + this.grpVolume.Text = "Volume"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 6; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.Controls.Add(this.trkDmcVol, 5, 0); + this.tableLayoutPanel1.Controls.Add(this.trkNoiseVol, 4, 0); + this.tableLayoutPanel1.Controls.Add(this.trkTriangleVol, 3, 0); + this.tableLayoutPanel1.Controls.Add(this.trkSquare2Vol, 2, 0); + this.tableLayoutPanel1.Controls.Add(this.trkSquare1Vol, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.trkMaster, 0, 0); + this.tableLayoutPanel1.Location = new System.Drawing.Point(6, 19); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 1; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 160F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(451, 160); + this.tableLayoutPanel1.TabIndex = 2; + // + // trkDmcVol + // + this.trkDmcVol.Anchor = System.Windows.Forms.AnchorStyles.Top; + this.trkDmcVol.Caption = "DMC"; + this.trkDmcVol.Location = new System.Drawing.Point(381, 0); + this.trkDmcVol.Margin = new System.Windows.Forms.Padding(0); + this.trkDmcVol.MaximumSize = new System.Drawing.Size(63, 160); + this.trkDmcVol.MinimumSize = new System.Drawing.Size(63, 160); + this.trkDmcVol.Name = "trkDmcVol"; + this.trkDmcVol.Size = new System.Drawing.Size(63, 160); + this.trkDmcVol.TabIndex = 16; + this.trkDmcVol.Value = 50; + // + // trkNoiseVol + // + this.trkNoiseVol.Anchor = System.Windows.Forms.AnchorStyles.Top; + this.trkNoiseVol.Caption = "Noise"; + this.trkNoiseVol.Location = new System.Drawing.Point(306, 0); + this.trkNoiseVol.Margin = new System.Windows.Forms.Padding(0); + this.trkNoiseVol.MaximumSize = new System.Drawing.Size(63, 160); + this.trkNoiseVol.MinimumSize = new System.Drawing.Size(63, 160); + this.trkNoiseVol.Name = "trkNoiseVol"; + this.trkNoiseVol.Size = new System.Drawing.Size(63, 160); + this.trkNoiseVol.TabIndex = 15; + this.trkNoiseVol.Value = 50; + // + // trkTriangleVol + // + this.trkTriangleVol.Anchor = System.Windows.Forms.AnchorStyles.Top; + this.trkTriangleVol.Caption = "Triangle"; + this.trkTriangleVol.Location = new System.Drawing.Point(231, 0); + this.trkTriangleVol.Margin = new System.Windows.Forms.Padding(0); + this.trkTriangleVol.MaximumSize = new System.Drawing.Size(63, 160); + this.trkTriangleVol.MinimumSize = new System.Drawing.Size(63, 160); + this.trkTriangleVol.Name = "trkTriangleVol"; + this.trkTriangleVol.Size = new System.Drawing.Size(63, 160); + this.trkTriangleVol.TabIndex = 14; + this.trkTriangleVol.Value = 50; + // + // trkSquare2Vol + // + this.trkSquare2Vol.Anchor = System.Windows.Forms.AnchorStyles.Top; + this.trkSquare2Vol.Caption = "Square 2"; + this.trkSquare2Vol.Location = new System.Drawing.Point(156, 0); + this.trkSquare2Vol.Margin = new System.Windows.Forms.Padding(0); + this.trkSquare2Vol.MaximumSize = new System.Drawing.Size(63, 160); + this.trkSquare2Vol.MinimumSize = new System.Drawing.Size(63, 160); + this.trkSquare2Vol.Name = "trkSquare2Vol"; + this.trkSquare2Vol.Size = new System.Drawing.Size(63, 160); + this.trkSquare2Vol.TabIndex = 13; + this.trkSquare2Vol.Value = 50; + // + // trkSquare1Vol + // + this.trkSquare1Vol.Anchor = System.Windows.Forms.AnchorStyles.Top; + this.trkSquare1Vol.Caption = "Square 1"; + this.trkSquare1Vol.Location = new System.Drawing.Point(81, 0); + this.trkSquare1Vol.Margin = new System.Windows.Forms.Padding(0); + this.trkSquare1Vol.MaximumSize = new System.Drawing.Size(63, 160); + this.trkSquare1Vol.MinimumSize = new System.Drawing.Size(63, 160); + this.trkSquare1Vol.Name = "trkSquare1Vol"; + this.trkSquare1Vol.Size = new System.Drawing.Size(63, 160); + this.trkSquare1Vol.TabIndex = 12; + this.trkSquare1Vol.Value = 50; + // + // trkMaster + // + this.trkMaster.Anchor = System.Windows.Forms.AnchorStyles.Top; + this.trkMaster.Caption = "Master"; + this.trkMaster.Location = new System.Drawing.Point(6, 0); + this.trkMaster.Margin = new System.Windows.Forms.Padding(0); + this.trkMaster.MaximumSize = new System.Drawing.Size(63, 160); + this.trkMaster.MinimumSize = new System.Drawing.Size(63, 160); + this.trkMaster.Name = "trkMaster"; + this.trkMaster.Size = new System.Drawing.Size(63, 160); + this.trkMaster.TabIndex = 11; + this.trkMaster.Value = 50; + // + // 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.grpVolume, 0, 1); + this.tableLayoutPanel2.Controls.Add(this.chkEnableAudio, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.flowLayoutPanel2, 0, 2); + this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 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(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(470, 274); + this.tableLayoutPanel2.TabIndex = 3; + // + // chkEnableAudio + // + this.chkEnableAudio.AutoSize = true; + this.chkEnableAudio.Location = new System.Drawing.Point(6, 6); + this.chkEnableAudio.Margin = new System.Windows.Forms.Padding(6, 6, 6, 3); + this.chkEnableAudio.Name = "chkEnableAudio"; + this.chkEnableAudio.Size = new System.Drawing.Size(89, 17); + this.chkEnableAudio.TabIndex = 3; + this.chkEnableAudio.Text = "Enable Audio"; + this.chkEnableAudio.UseVisualStyleBackColor = true; + this.chkEnableAudio.CheckedChanged += new System.EventHandler(this.AudioConfig_ValueChanged); + // + // flowLayoutPanel2 + // + this.flowLayoutPanel2.Controls.Add(this.lblAudioLatency); + this.flowLayoutPanel2.Controls.Add(this.nudLatency); + this.flowLayoutPanel2.Controls.Add(this.lblLatencyMs); + this.flowLayoutPanel2.Location = new System.Drawing.Point(3, 220); + this.flowLayoutPanel2.Name = "flowLayoutPanel2"; + this.flowLayoutPanel2.Size = new System.Drawing.Size(200, 24); + this.flowLayoutPanel2.TabIndex = 4; + // + // lblAudioLatency + // + this.lblAudioLatency.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblAudioLatency.AutoSize = true; + this.lblAudioLatency.Location = new System.Drawing.Point(3, 6); + this.lblAudioLatency.Name = "lblAudioLatency"; + this.lblAudioLatency.Size = new System.Drawing.Size(48, 13); + this.lblAudioLatency.TabIndex = 0; + this.lblAudioLatency.Text = "Latency:"; + // + // nudLatency + // + this.nudLatency.Location = new System.Drawing.Point(57, 3); + this.nudLatency.Maximum = new decimal(new int[] { + 300, + 0, + 0, + 0}); + this.nudLatency.Minimum = new decimal(new int[] { + 100, + 0, + 0, + 0}); + this.nudLatency.Name = "nudLatency"; + this.nudLatency.Size = new System.Drawing.Size(45, 20); + this.nudLatency.TabIndex = 1; + this.nudLatency.Value = new decimal(new int[] { + 100, + 0, + 0, + 0}); + // + // lblLatencyMs + // + this.lblLatencyMs.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblLatencyMs.AutoSize = true; + this.lblLatencyMs.Location = new System.Drawing.Point(108, 6); + this.lblLatencyMs.Name = "lblLatencyMs"; + this.lblLatencyMs.Size = new System.Drawing.Size(20, 13); + this.lblLatencyMs.TabIndex = 2; + this.lblLatencyMs.Text = "ms"; + // + // btnReset + // + this.btnReset.AutoSize = true; + this.btnReset.Location = new System.Drawing.Point(6, 3); + this.btnReset.Name = "btnReset"; + this.btnReset.Size = new System.Drawing.Size(99, 23); + this.btnReset.TabIndex = 3; + this.btnReset.Text = "Reset to Defaults"; + this.btnReset.UseVisualStyleBackColor = true; + this.btnReset.Click += new System.EventHandler(this.btnReset_Click); + // + // frmAudioConfig + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(470, 274); + this.Controls.Add(this.tableLayoutPanel2); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "frmAudioConfig"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Audio Options"; + this.Controls.SetChildIndex(this.tableLayoutPanel2, 0); + this.Controls.SetChildIndex(this.baseConfigPanel, 0); + this.baseConfigPanel.ResumeLayout(false); + this.baseConfigPanel.PerformLayout(); + this.grpVolume.ResumeLayout(false); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel2.PerformLayout(); + this.flowLayoutPanel2.ResumeLayout(false); + this.flowLayoutPanel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.nudLatency)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.GroupBox grpVolume; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.CheckBox chkEnableAudio; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel2; + private System.Windows.Forms.Label lblAudioLatency; + private System.Windows.Forms.NumericUpDown nudLatency; + private System.Windows.Forms.Label lblLatencyMs; + private System.Windows.Forms.Button btnReset; + private Controls.ctrlTrackbar trkMaster; + private Controls.ctrlTrackbar trkDmcVol; + private Controls.ctrlTrackbar trkNoiseVol; + private Controls.ctrlTrackbar trkTriangleVol; + private Controls.ctrlTrackbar trkSquare2Vol; + private Controls.ctrlTrackbar trkSquare1Vol; + + } +} \ No newline at end of file diff --git a/GUI.NET/Forms/Config/frmAudioConfig.cs b/GUI.NET/Forms/Config/frmAudioConfig.cs new file mode 100644 index 00000000..287f9aab --- /dev/null +++ b/GUI.NET/Forms/Config/frmAudioConfig.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Mesen.GUI.Config; + +namespace Mesen.GUI.Forms.Config +{ + public partial class frmAudioConfig : BaseConfigForm + { + public frmAudioConfig() + { + InitializeComponent(); + + Entity = ConfigManager.Config.AudioInfo; + + AddBinding("EnableAudio", chkEnableAudio); + AddBinding("MasterVolume", trkMaster); + AddBinding("Square1Volume", trkSquare1Vol); + AddBinding("Square2Volume", trkSquare2Vol); + AddBinding("TriangleVolume", trkTriangleVol); + AddBinding("NoiseVolume", trkNoiseVol); + AddBinding("DmcVolume", trkDmcVol); + AddBinding("AudioLatency", nudLatency); + } + + protected override void OnFormClosed(FormClosedEventArgs e) + { + base.OnFormClosed(e); + AudioInfo.ApplyConfig(); + } + + private void AudioConfig_ValueChanged(object sender, EventArgs e) + { + if(!this.Updating) { + UpdateObject(); + AudioInfo.ApplyConfig(); + } + } + + private void btnReset_Click(object sender, EventArgs e) + { + AudioInfo config = Entity as AudioInfo; + config.EnableAudio = true; + config.AudioLatency = 100; + config.MasterVolume = 50; + config.Square2Volume = 50; + config.Square1Volume = 50; + config.TriangleVolume = 50; + config.NoiseVolume = 50; + config.DmcVolume = 50; + UpdateUI(); + AudioInfo.ApplyConfig(); + } + } +} diff --git a/GUI.NET/Forms/Config/frmAudioConfig.resx b/GUI.NET/Forms/Config/frmAudioConfig.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/GUI.NET/Forms/Config/frmAudioConfig.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/GUI.NET/Forms/frmMain.Designer.cs b/GUI.NET/Forms/frmMain.Designer.cs index 9e404400..2a43cc99 100644 --- a/GUI.NET/Forms/frmMain.Designer.cs +++ b/GUI.NET/Forms/frmMain.Designer.cs @@ -248,10 +248,10 @@ // // mnuAudioConfig // - this.mnuAudioConfig.Enabled = false; this.mnuAudioConfig.Name = "mnuAudioConfig"; this.mnuAudioConfig.Size = new System.Drawing.Size(152, 22); this.mnuAudioConfig.Text = "Audio"; + this.mnuAudioConfig.Click += new System.EventHandler(this.mnuAudioConfig_Click); // // mnuTools // diff --git a/GUI.NET/Forms/frmMain.cs b/GUI.NET/Forms/frmMain.cs index 97447739..bda13915 100644 --- a/GUI.NET/Forms/frmMain.cs +++ b/GUI.NET/Forms/frmMain.cs @@ -56,6 +56,7 @@ namespace Mesen.GUI.Forms } ControllerInfo.ApplyConfig(); + AudioInfo.ApplyConfig(); InteropEmu.SetFlags((int)EmulationFlags.LimitFPS); } @@ -395,5 +396,11 @@ namespace Mesen.GUI.Forms frmInputConfig frm = new frmInputConfig(); frm.ShowDialog(); } + + private void mnuAudioConfig_Click(object sender, EventArgs e) + { + frmAudioConfig frm = new frmAudioConfig(); + frm.ShowDialog(); + } } } diff --git a/GUI.NET/GUI.NET.csproj b/GUI.NET/GUI.NET.csproj index fd7d855f..f9b3aea6 100644 --- a/GUI.NET/GUI.NET.csproj +++ b/GUI.NET/GUI.NET.csproj @@ -79,9 +79,16 @@ + + + UserControl + + + ctrlTrackbar.cs + UserControl @@ -157,6 +164,12 @@ frmInputConfig.cs + + Form + + + frmAudioConfig.cs + Form @@ -196,6 +209,9 @@ + + ctrlTrackbar.cs + ctrlConsoleStatus.cs @@ -226,6 +242,9 @@ frmInputConfig.cs + + frmAudioConfig.cs + frmVideoConfig.cs diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index 3c36fd53..ea09d24d 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -31,8 +31,6 @@ namespace Mesen.GUI [DllImport(DLLPath)] public static extern void Stop(); [DllImport(DLLPath, EntryPoint="GetROMPath")] private static extern IntPtr GetROMPathWrapper(); [DllImport(DLLPath)] public static extern void Reset(); - [DllImport(DLLPath)] public static extern void SetFlags(int flags); - [DllImport(DLLPath)] public static extern void ClearFlags(int flags); [DllImport(DLLPath)] public static extern void StartServer(UInt16 port); [DllImport(DLLPath)] public static extern void StopServer(); [DllImport(DLLPath)] public static extern bool IsServerRunning(); @@ -63,6 +61,11 @@ namespace Mesen.GUI [DllImport(DLLPath)] public static extern void CheatAddProActionRocky(UInt32 code); [DllImport(DLLPath)] public static extern void CheatClear(); + [DllImport(DLLPath)] public static extern void SetFlags(UInt32 flags); + [DllImport(DLLPath)] public static extern void ClearFlags(UInt32 flags); + [DllImport(DLLPath)] public static extern void SetChannelVolume(UInt32 channel, double volume); + [DllImport(DLLPath)] public static extern void SetAudioLatency(UInt32 msLatency); + [DllImport(DLLPath)] public static extern void DebugInitialize(); [DllImport(DLLPath)] public static extern void DebugRelease(); [DllImport(DLLPath)] public static extern void DebugGetState(ref DebugState state); diff --git a/InteropDLL/ConsoleWrapper.cpp b/InteropDLL/ConsoleWrapper.cpp index 80b88d76..965ee987 100644 --- a/InteropDLL/ConsoleWrapper.cpp +++ b/InteropDLL/ConsoleWrapper.cpp @@ -11,6 +11,7 @@ #include "../Core/SaveStateManager.h" #include "../Core/CheatManager.h" #include "../Core/StandardController.h" +#include "../Core/EmulationSettings.h" static NES::Renderer *_renderer = nullptr; static SoundManager *_soundManager = nullptr; @@ -79,8 +80,8 @@ namespace InteropEmu { } } - DllExport void __stdcall Resume() { Console::ClearFlags(EmulationFlags::Paused); } - DllExport int __stdcall IsPaused() { return Console::CheckFlag(EmulationFlags::Paused); } + DllExport void __stdcall Resume() { EmulationSettings::ClearFlags(EmulationFlags::Paused); } + DllExport int __stdcall IsPaused() { return EmulationSettings::CheckFlag(EmulationFlags::Paused); } DllExport void __stdcall Stop() { if(Console::GetInstance()) { @@ -94,8 +95,6 @@ namespace InteropEmu { } DllExport void __stdcall Reset() { Console::Reset(); } - DllExport void __stdcall SetFlags(int flags) { Console::SetFlags(flags); } - DllExport void __stdcall ClearFlags(int flags) { Console::ClearFlags(flags); } DllExport void __stdcall StartServer(uint16_t port) { GameServer::StartServer(port); } DllExport void __stdcall StopServer() { GameServer::StopServer(); } @@ -120,7 +119,7 @@ namespace InteropEmu { DllExport void __stdcall Pause() { if(!IsConnected()) { - Console::SetFlags(EmulationFlags::Paused); + EmulationSettings::SetFlags(EmulationFlags::Paused); } } @@ -160,5 +159,11 @@ namespace InteropEmu { DllExport void __stdcall CheatAddGameGenie(char* code) { CheatManager::AddGameGenieCode(code); } DllExport void __stdcall CheatAddProActionRocky(uint32_t code) { CheatManager::AddProActionRockyCode(code); } DllExport void __stdcall CheatClear() { CheatManager::ClearCodes(); } + + DllExport void __stdcall SetFlags(uint32_t flags) { EmulationSettings::SetFlags(flags); } + DllExport void __stdcall ClearFlags(uint32_t flags) { EmulationSettings::ClearFlags(flags); } + DllExport void __stdcall SetChannelVolume(uint32_t channel, double volume) { EmulationSettings::SetChannelVolume((AudioChannel)channel, volume); } + DllExport void __stdcall SetAudioLatency(uint32_t msLatency) { EmulationSettings::SetAudioLatency(msLatency); } + } } \ No newline at end of file diff --git a/Windows/Renderer.cpp b/Windows/Renderer.cpp index 3cc40047..c6cfd6ce 100644 --- a/Windows/Renderer.cpp +++ b/Windows/Renderer.cpp @@ -5,7 +5,7 @@ #include "DirectXTK/DDSTextureLoader.h" #include "DirectXTK/WICTextureLoader.h" #include "../Core/PPU.h" -#include "../Core/Console.h" +#include "../Core/EmulationSettings.h" #include "../Core/MessageManager.h" #include "../Utilities/UTF8Util.h" @@ -369,6 +369,11 @@ namespace NES sourceRect.top = 8; sourceRect.bottom = _screenHeight - 8; + RECT destRect; + destRect.left = 0; + destRect.top = 0; + destRect.right = _screenWidth * 4; + destRect.bottom = (_screenHeight - 16) * 4; XMVECTOR position{ { 0, 0 } }; D3D11_MAPPED_SUBRESOURCE dd; @@ -383,7 +388,7 @@ namespace NES _pDeviceContext->Unmap(_pTexture, 0); ID3D11ShaderResourceView *nesOutputBuffer = GetShaderResourceView(_pTexture); - _spriteBatch->Draw(nesOutputBuffer, position, &sourceRect, Colors::White, 0.0f, position, 4.0f); + _spriteBatch->Draw(nesOutputBuffer, destRect, &sourceRect); nesOutputBuffer->Release(); } @@ -418,7 +423,7 @@ namespace NES void Renderer::Render() { - if(_frameChanged || Console::CheckFlag(EmulationFlags::Paused) || !_toasts.empty()) { + if(_frameChanged || EmulationSettings::CheckFlag(EmulationFlags::Paused) || !_toasts.empty()) { _frameChanged = false; // Clear the back buffer _pDeviceContext->ClearRenderTargetView(_pRenderTargetView, Colors::Black); @@ -434,7 +439,7 @@ namespace NES _spriteBatch->Begin(SpriteSortMode_Deferred, nullptr, _samplerState);*/ - if(Console::CheckFlag(EmulationFlags::Paused)) { + if(EmulationSettings::CheckFlag(EmulationFlags::Paused)) { DrawPauseScreen(); } else { //Draw FPS counter diff --git a/Windows/SoundManager.cpp b/Windows/SoundManager.cpp index 4202164a..613c13e5 100644 --- a/Windows/SoundManager.cpp +++ b/Windows/SoundManager.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "SoundManager.h" +#include "../Core/EmulationSettings.h" SoundManager::SoundManager(HWND hwnd) { @@ -165,7 +166,11 @@ void SoundManager::Reset() void SoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t soundBufferSize) { - static const int32_t byteLatency = _latency * (APU::BitsPerSample / 8); + int32_t byteLatency = (int32_t)((float)(APU::SampleRate * EmulationSettings::GetAudioLatency()) / 1000.0f * (APU::BitsPerSample / 8)); + if(byteLatency != _previousLatency) { + Reset(); + _previousLatency = byteLatency; + } DWORD status; _secondaryBuffer->GetStatus(&status); @@ -180,7 +185,7 @@ void SoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t soundBufferSize) _secondaryBuffer->GetCurrentPosition(¤tPlayCursor, nullptr); int32_t playWriteByteLatency = (_lastWriteOffset - currentPlayCursor); - if(playWriteByteLatency < -byteLatency * 2) { + if(playWriteByteLatency < 0) { playWriteByteLatency = 0xFFFF - currentPlayCursor + _lastWriteOffset; } @@ -189,10 +194,10 @@ void SoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t soundBufferSize) //Out of sync, move back to where we should be (start of the latency buffer) _secondaryBuffer->SetFrequency(44100); _secondaryBuffer->SetCurrentPosition(_lastWriteOffset - byteLatency); - } else if(latencyGap < -200) { + } else if(latencyGap < -byteLatency/35) { //Playing too fast, slow down playing _secondaryBuffer->SetFrequency(43900); - } else if(latencyGap > 200) { + } else if(latencyGap > byteLatency/35) { //Playing too slow, speed up _secondaryBuffer->SetFrequency(44300); } else { diff --git a/Windows/SoundManager.h b/Windows/SoundManager.h index 9b44c6a0..e636db79 100644 --- a/Windows/SoundManager.h +++ b/Windows/SoundManager.h @@ -23,7 +23,7 @@ private: private: uint16_t _lastWriteOffset = 0; - const uint16_t _latency = APU::SampleRate / (1000 / 150); // == 150ms latency + uint16_t _previousLatency = 0; IDirectSound8* _directSound; IDirectSoundBuffer* _primaryBuffer;