diff --git a/Core/BaseSoundFilter.cpp b/Core/BaseSoundFilter.cpp new file mode 100644 index 00000000..92e92554 --- /dev/null +++ b/Core/BaseSoundFilter.cpp @@ -0,0 +1,21 @@ +#include "stdafx.h" +#include "BaseSoundFilter.h" + +void BaseSoundFilter::UpdateBufferSize(size_t sampleCount, bool isStereo) +{ + if(_maxSampleCount < sampleCount) { + if(_filterBuffer) { + delete[] _filterBuffer; + } + _maxSampleCount = sampleCount; + _filterBuffer = new int16_t[_maxSampleCount * (isStereo ? 2 : 1)]; + memset(_filterBuffer, 0, _maxSampleCount * sizeof(int16_t) * (isStereo ? 2 : 1)); + } +} + +BaseSoundFilter::~BaseSoundFilter() +{ + if(_filterBuffer) { + delete[] _filterBuffer; + } +} \ No newline at end of file diff --git a/Core/BaseSoundFilter.h b/Core/BaseSoundFilter.h new file mode 100644 index 00000000..cf3a7a71 --- /dev/null +++ b/Core/BaseSoundFilter.h @@ -0,0 +1,14 @@ +#pragma once +#include "stdafx.h" + +class BaseSoundFilter +{ +protected: + int16_t* _filterBuffer = nullptr; + size_t _maxSampleCount = 0; + + void UpdateBufferSize(size_t sampleCount, bool isStereo); + +public: + virtual ~BaseSoundFilter(); +}; \ No newline at end of file diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 9ea90e8e..90fcd047 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -362,6 +362,7 @@ + @@ -410,6 +411,7 @@ + @@ -493,6 +495,8 @@ + + @@ -525,6 +529,7 @@ + @@ -545,6 +550,7 @@ + @@ -565,6 +571,8 @@ Create Create + + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index cab4fa93..e390700d 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -66,6 +66,9 @@ {acd315c2-48ad-4243-a997-bb9a970c24bd} + + {783f3638-4293-480f-b525-2485c4209ff5} + @@ -551,6 +554,18 @@ Nes\Controllers + + Nes\APU\Filters + + + Nes\APU\Filters + + + Nes\APU\Filters + + + Nes\APU\Filters + @@ -679,5 +694,17 @@ Nes\Controllers + + Nes\APU\Filters + + + Nes\APU\Filters + + + Nes\APU\Filters + + + Nes\APU\Filters + \ No newline at end of file diff --git a/Core/EmulationSettings.cpp b/Core/EmulationSettings.cpp index 5ef2f034..d73b942f 100644 --- a/Core/EmulationSettings.cpp +++ b/Core/EmulationSettings.cpp @@ -30,6 +30,11 @@ uint32_t EmulationSettings::_audioLatency = 20000; double EmulationSettings::_channelVolume[11] = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 }; double EmulationSettings::_masterVolume = 1.0; uint32_t EmulationSettings::_sampleRate = 44100; +StereoFilter EmulationSettings::_stereoFilter = StereoFilter::None; +int32_t EmulationSettings::_stereoDelay = 0; +double EmulationSettings::_stereoAngle = 0; +double EmulationSettings::_reverbStrength = 0; +double EmulationSettings::_reverbDelay = 0; NesModel EmulationSettings::_model = NesModel::Auto; diff --git a/Core/EmulationSettings.h b/Core/EmulationSettings.h index b375878d..18423cd1 100644 --- a/Core/EmulationSettings.h +++ b/Core/EmulationSettings.h @@ -152,6 +152,13 @@ enum class Language Japanese = 3 }; +enum class StereoFilter +{ + None = 0, + Delay = 1, + Panning = 2, +}; + class EmulationSettings { private: @@ -167,9 +174,13 @@ private: static uint32_t _audioLatency; static double _channelVolume[11]; static double _masterVolume; - static uint32_t _sampleRate; - + static StereoFilter _stereoFilter; + static int32_t _stereoDelay; + static double _stereoAngle; + static double _reverbStrength; + static double _reverbDelay; + static NesModel _model; static uint32_t _emulationSpeed; @@ -262,6 +273,52 @@ public: _audioLatency = msLatency; } + static void SetStereoFilter(StereoFilter stereoFilter) + { + _stereoFilter = stereoFilter; + } + + static void SetStereoDelay(int32_t delay) + { + _stereoDelay = delay; + } + + static void SetStereoPanningAngle(double angle) + { + _stereoAngle = angle; + } + + static void SetReverbParameters(double strength, double delay) + { + _reverbStrength = strength; + _reverbDelay = delay; + } + + static StereoFilter GetStereoFilter() + { + return _stereoFilter; + } + + static int32_t GetStereoDelay() + { + return _stereoDelay; + } + + static double GetStereoPanningAngle() + { + return _stereoAngle; + } + + static double GetReverbStrength() + { + return _reverbStrength; + } + + static double GetReverbDelay() + { + return _reverbDelay; + } + //0: No limit, Number: % of default speed (50/60fps) static void SetEmulationSpeed(uint32_t emulationSpeed) { diff --git a/Core/IAudioDevice.h b/Core/IAudioDevice.h index 151ee8ec..871da912 100644 --- a/Core/IAudioDevice.h +++ b/Core/IAudioDevice.h @@ -5,7 +5,7 @@ class IAudioDevice { public: - virtual void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate) = 0; + virtual void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo) = 0; virtual void Stop() = 0; virtual void Pause() = 0; }; \ No newline at end of file diff --git a/Core/ReverbFilter.cpp b/Core/ReverbFilter.cpp new file mode 100644 index 00000000..eac69eee --- /dev/null +++ b/Core/ReverbFilter.cpp @@ -0,0 +1,31 @@ +#include "stdafx.h" +#include "ReverbFilter.h" + +void ReverbFilter::ResetFilter() +{ + for(int i = 0; i < 5; i++) { + _delay[i].Reset(); + } +} + +int16_t* ReverbFilter::ApplyFilter(int16_t* monoBuffer, size_t sampleCount, uint32_t sampleRate, double reverbStrength, double reverbDelay) +{ + _delay[0].SetParameters(550 * reverbDelay, 0.25 * reverbStrength, sampleRate); + _delay[1].SetParameters(330 * reverbDelay, 0.15 * reverbStrength, sampleRate); + _delay[2].SetParameters(485 * reverbDelay, 0.12 * reverbStrength, sampleRate); + _delay[3].SetParameters(150 * reverbDelay, 0.20 * reverbStrength, sampleRate); + _delay[4].SetParameters(285 * reverbDelay, 0.05 * reverbStrength, sampleRate); + + UpdateBufferSize(sampleCount, false); + + memcpy(_filterBuffer, monoBuffer, sampleCount * sizeof(int16_t)); + + for(int i = 0; i < 5; i++) { + _delay[i].ApplyReverb(_filterBuffer, sampleCount); + } + for(int i = 0; i < 5; i++) { + _delay[i].AddSamples(_filterBuffer, sampleCount); + } + + return _filterBuffer; +} \ No newline at end of file diff --git a/Core/ReverbFilter.h b/Core/ReverbFilter.h new file mode 100644 index 00000000..e4733b5c --- /dev/null +++ b/Core/ReverbFilter.h @@ -0,0 +1,57 @@ +#pragma once +#include "stdafx.h" +#include "BaseSoundFilter.h" +#include + +class ReverbDelay +{ +private: + std::deque _samples; + uint32_t _delay = 0; + double _decay = 0; + +public: + void SetParameters(double delay, double decay, int32_t sampleRate) + { + uint32_t delaySampleCount = (uint32_t)(delay / 1000 * sampleRate); + if(delaySampleCount != _delay || decay != _decay) { + _delay = delaySampleCount; + _decay = decay; + _samples.clear(); + } + } + + void Reset() + { + _samples.clear(); + } + + void AddSamples(int16_t* buffer, size_t sampleCount) + { + for(size_t i = 0; i < sampleCount; i++) { + _samples.push_back(buffer[i]); + } + } + + void ApplyReverb(int16_t* buffer, size_t sampleCount) + { + if(_samples.size() > _delay) { + size_t samplesToInsert = std::min(_samples.size() - _delay, sampleCount); + + for(size_t j = sampleCount - samplesToInsert; j < sampleCount; j++) { + buffer[j] += (int16_t)((double)_samples.front() * _decay); + _samples.pop_front(); + } + } + } +}; + +class ReverbFilter : public BaseSoundFilter +{ +private: + ReverbDelay _delay[5]; + +public: + void ResetFilter(); + int16_t* ApplyFilter(int16_t* monoBuffer, size_t sampleCount, uint32_t sampleRate, double reverbStrength, double reverbDelay); +}; \ No newline at end of file diff --git a/Core/SoundMixer.cpp b/Core/SoundMixer.cpp index fce5b932..a2806db6 100644 --- a/Core/SoundMixer.cpp +++ b/Core/SoundMixer.cpp @@ -82,9 +82,29 @@ void SoundMixer::PlayAudioBuffer(uint32_t time) } } - SoundMixer::AudioDevice->PlayBuffer(_outputBuffer, (uint32_t)(sampleCount * SoundMixer::BitsPerSample / 8), _sampleRate); + int16_t* soundBuffer = _outputBuffer; + if(EmulationSettings::GetReverbStrength() > 0) { + soundBuffer = _reverbFilter.ApplyFilter(soundBuffer, sampleCount, _sampleRate, EmulationSettings::GetReverbStrength(), EmulationSettings::GetReverbDelay()); + } else { + _reverbFilter.ResetFilter(); + } + + bool isStereo = false; + switch(EmulationSettings::GetStereoFilter()) { + case StereoFilter::Delay: + soundBuffer = _stereoDelay.ApplyFilter(soundBuffer, sampleCount, _sampleRate); + isStereo = true; + break; + + case StereoFilter::Panning: + soundBuffer = _stereoPanning.ApplyFilter(soundBuffer, sampleCount); + isStereo = true; + break; + } + + SoundMixer::AudioDevice->PlayBuffer(soundBuffer, (uint32_t)sampleCount, _sampleRate, isStereo); } - + if(EmulationSettings::GetSampleRate() != _sampleRate) { //Update sample rate for next frame if setting changed _sampleRate = EmulationSettings::GetSampleRate(); diff --git a/Core/SoundMixer.h b/Core/SoundMixer.h index f1e64680..72d3810a 100644 --- a/Core/SoundMixer.h +++ b/Core/SoundMixer.h @@ -5,6 +5,9 @@ #include "../BlipBuffer/blip_buf.h" #include "IAudioDevice.h" #include "Snapshotable.h" +#include "StereoPanningFilter.h" +#include "StereoDelayFilter.h" +#include "ReverbFilter.h" class SoundMixer : public Snapshotable { @@ -21,6 +24,9 @@ private: AudioChannel _expansionAudioType; LowPassFilter _lowPassFilter; + StereoPanningFilter _stereoPanning; + StereoDelayFilter _stereoDelay; + ReverbFilter _reverbFilter; int16_t _previousOutput = 0; diff --git a/Core/StereoDelayFilter.cpp b/Core/StereoDelayFilter.cpp new file mode 100644 index 00000000..a1c5c258 --- /dev/null +++ b/Core/StereoDelayFilter.cpp @@ -0,0 +1,35 @@ +#include "stdafx.h" +#include "StereoDelayFilter.h" + +int16_t* StereoDelayFilter::ApplyFilter(int16_t* monoBuffer, size_t sampleCount, uint32_t sampleRate) +{ + UpdateBufferSize(sampleCount, true); + + int32_t delay = EmulationSettings::GetStereoDelay(); + if(delay != _lastDelay) { + _delayedSamples.clear(); + } + _lastDelay = delay; + + int32_t delaySampleCount = (int32_t)((double)delay / 1000 * sampleRate); + + for(size_t i = 0; i < sampleCount; i++) { + _delayedSamples.push_back(monoBuffer[i]); + } + + for(int i = 0; i < sampleCount; i++) { + _filterBuffer[i * 2] = monoBuffer[i]; + _filterBuffer[i * 2 + 1] = 0; + } + + if(_delayedSamples.size() > delaySampleCount) { + size_t samplesToInsert = std::max(_delayedSamples.size() - delaySampleCount, sampleCount); + + for(size_t i = sampleCount - samplesToInsert; i < sampleCount; i++) { + _filterBuffer[i * 2 + 1] = _delayedSamples.front(); + _delayedSamples.pop_front(); + } + } + + return _filterBuffer; +} diff --git a/Core/StereoDelayFilter.h b/Core/StereoDelayFilter.h new file mode 100644 index 00000000..179ce0a3 --- /dev/null +++ b/Core/StereoDelayFilter.h @@ -0,0 +1,16 @@ +#pragma once +#include "stdafx.h" +#include +#include +#include "EmulationSettings.h" +#include "BaseSoundFilter.h" + +class StereoDelayFilter : public BaseSoundFilter +{ +private: + std::deque _delayedSamples; + int32_t _lastDelay; + +public: + int16_t* ApplyFilter(int16_t* monoBuffer, size_t sampleCount, uint32_t sampleRate); +}; \ No newline at end of file diff --git a/Core/StereoPanningFilter.cpp b/Core/StereoPanningFilter.cpp new file mode 100644 index 00000000..4f696a52 --- /dev/null +++ b/Core/StereoPanningFilter.cpp @@ -0,0 +1,24 @@ +#include "stdafx.h" +#include "StereoPanningFilter.h" +#include "EmulationSettings.h" +#include + +void StereoPanningFilter::UpdateFactors() +{ + double angle = EmulationSettings::GetStereoPanningAngle(); + _leftChannelFactor = _baseFactor * (std::cos(angle) - std::sin(angle)); + _rightChannelFactor = _baseFactor * (std::cos(angle) + std::sin(angle)); +} + +int16_t* StereoPanningFilter::ApplyFilter(int16_t* monoBuffer, size_t sampleCount) +{ + UpdateFactors(); + UpdateBufferSize(sampleCount, true); + + for(size_t i = 0; i < sampleCount; i++) { + _filterBuffer[i * 2] = (int16_t)(_leftChannelFactor * (double)monoBuffer[i]); + _filterBuffer[i * 2 + 1] = (int16_t)(_rightChannelFactor * (double)monoBuffer[i]); + } + + return _filterBuffer; +} \ No newline at end of file diff --git a/Core/StereoPanningFilter.h b/Core/StereoPanningFilter.h new file mode 100644 index 00000000..fe018726 --- /dev/null +++ b/Core/StereoPanningFilter.h @@ -0,0 +1,16 @@ +#pragma once +#include "stdafx.h" +#include "BaseSoundFilter.h" + +class StereoPanningFilter : public BaseSoundFilter +{ +private: + const double _baseFactor = 0.70710678118654752440084436210485; // == sqrt(2)/2 + double _leftChannelFactor = 0; + double _rightChannelFactor = 0; + + void UpdateFactors(); + +public: + int16_t* ApplyFilter(int16_t* monoBuffer, size_t sampleCount); +}; \ No newline at end of file diff --git a/GUI.NET/Config/AudioInfo.cs b/GUI.NET/Config/AudioInfo.cs index af0f2a92..364a6a24 100644 --- a/GUI.NET/Config/AudioInfo.cs +++ b/GUI.NET/Config/AudioInfo.cs @@ -30,6 +30,12 @@ namespace Mesen.GUI.Config public bool ReduceSoundInBackground = true; public bool MuteSoundInBackground = false; public bool SwapDutyCycles = false; + public InteropEmu.StereoFilter StereoFilter; + public Int32 StereoDelay = 15; + public Int32 StereoPanningAngle = 15; + public bool ReverbEnabled = false; + public UInt32 ReverbStrength = 5; + public UInt32 ReverbDelay = 10; public AudioInfo() { @@ -67,6 +73,16 @@ namespace Mesen.GUI.Config InteropEmu.SetFlag(EmulationFlags.ReduceSoundInBackground, audioInfo.ReduceSoundInBackground); InteropEmu.SetFlag(EmulationFlags.SwapDutyCycles, audioInfo.SwapDutyCycles); + + InteropEmu.SetStereoFilter(audioInfo.StereoFilter); + InteropEmu.SetStereoPanningAngle((double)audioInfo.StereoPanningAngle/180*Math.PI); + InteropEmu.SetStereoDelay(audioInfo.StereoDelay); + + if(audioInfo.ReverbEnabled) { + InteropEmu.SetReverbParameters(audioInfo.ReverbStrength/10.0, audioInfo.ReverbDelay/10.0); + } else { + InteropEmu.SetReverbParameters(0, 0); + } } } } diff --git a/GUI.NET/Dependencies/resources.fr.xml b/GUI.NET/Dependencies/resources.fr.xml index 1610af48..55cd8250 100644 --- a/GUI.NET/Dependencies/resources.fr.xml +++ b/GUI.NET/Dependencies/resources.fr.xml @@ -83,6 +83,17 @@ Général Avancé Inverser le rapport cyclique des canaux Square 1 et Square 2 + Effets + Stéréo + Désactivé + Délai + Panoramique + ms + (angle en degrés) + Réverbération + Activer la réverbération + Délai : + Force : Fermer le son lorsque Mesen est en arrière-plan Réduire le volume lorsque Mesen est en arrière-plan Activer le son diff --git a/GUI.NET/Dependencies/resources.ja.xml b/GUI.NET/Dependencies/resources.ja.xml index a9fc21a8..0255ff41 100644 --- a/GUI.NET/Dependencies/resources.ja.xml +++ b/GUI.NET/Dependencies/resources.ja.xml @@ -83,6 +83,17 @@ 全般 詳細設定 Squareチャンネルのデューティサイクルをスワップする + エフェクト + ステレオ + 無効 + ディレイ + パニング + ミリ秒 + (角度) + 残響 + 残響を有効にする + ディレイ: + 強度: Mesenが最前面ではない時、音声をミュートにする Mesenが最前面ではない時、音声を低くする 音声オン diff --git a/GUI.NET/Forms/BaseConfigForm.cs b/GUI.NET/Forms/BaseConfigForm.cs index ae3cda31..92d0450d 100644 --- a/GUI.NET/Forms/BaseConfigForm.cs +++ b/GUI.NET/Forms/BaseConfigForm.cs @@ -181,7 +181,9 @@ namespace Mesen.GUI.Forms NumericUpDown nud = kvp.Value as NumericUpDown; decimal val; if(field.FieldType == typeof(UInt32)) { - val = (uint)value; + val = (UInt32)value; + } else if(field.FieldType == typeof(Int32)) { + val = (Int32)value; } else { val = (decimal)(double)value; } @@ -251,6 +253,8 @@ namespace Mesen.GUI.Forms } else if(kvp.Value is NumericUpDown) { if(field.FieldType == typeof(UInt32)) { field.SetValue(Entity, (UInt32)((NumericUpDown)kvp.Value).Value); + } else if(field.FieldType == typeof(Int32)) { + field.SetValue(Entity, (Int32)((NumericUpDown)kvp.Value).Value); } else { field.SetValue(Entity, (double)((NumericUpDown)kvp.Value).Value); } diff --git a/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs b/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs index c0e06e4a..47f58042 100644 --- a/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs +++ b/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs @@ -57,6 +57,26 @@ this.tabMain = new System.Windows.Forms.TabControl(); this.tpgGeneral = new System.Windows.Forms.TabPage(); this.tpgVolume = new System.Windows.Forms.TabPage(); + this.tpgEffects = new System.Windows.Forms.TabPage(); + this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); + this.grpStereo = new System.Windows.Forms.GroupBox(); + this.tlpStereoFilter = new System.Windows.Forms.TableLayoutPanel(); + this.flowLayoutPanel3 = new System.Windows.Forms.FlowLayoutPanel(); + this.nudStereoDelay = new System.Windows.Forms.NumericUpDown(); + this.lblStereoDelayMs = new System.Windows.Forms.Label(); + this.radStereoDisabled = new System.Windows.Forms.RadioButton(); + this.radStereoDelay = new System.Windows.Forms.RadioButton(); + this.radStereoPanning = new System.Windows.Forms.RadioButton(); + this.flowLayoutPanel4 = new System.Windows.Forms.FlowLayoutPanel(); + this.nudStereoPanning = new System.Windows.Forms.NumericUpDown(); + this.lblStereoPanningAngle = new System.Windows.Forms.Label(); + this.grpReverb = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel5 = new System.Windows.Forms.TableLayoutPanel(); + this.chkReverbEnabled = new System.Windows.Forms.CheckBox(); + this.lblReverbStrength = new System.Windows.Forms.Label(); + this.lblReverbDelay = new System.Windows.Forms.Label(); + this.trkReverbDelay = new System.Windows.Forms.TrackBar(); + this.trkReverbStrength = new System.Windows.Forms.TrackBar(); this.tpgAdvanced = new System.Windows.Forms.TabPage(); this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); this.chkSwapDutyCycles = new System.Windows.Forms.CheckBox(); @@ -69,6 +89,18 @@ this.tabMain.SuspendLayout(); this.tpgGeneral.SuspendLayout(); this.tpgVolume.SuspendLayout(); + this.tpgEffects.SuspendLayout(); + this.tableLayoutPanel4.SuspendLayout(); + this.grpStereo.SuspendLayout(); + this.tlpStereoFilter.SuspendLayout(); + this.flowLayoutPanel3.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.nudStereoDelay)).BeginInit(); + this.flowLayoutPanel4.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.nudStereoPanning)).BeginInit(); + this.grpReverb.SuspendLayout(); + this.tableLayoutPanel5.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.trkReverbDelay)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.trkReverbStrength)).BeginInit(); this.tpgAdvanced.SuspendLayout(); this.tableLayoutPanel3.SuspendLayout(); this.SuspendLayout(); @@ -124,7 +156,6 @@ // trkDmcVol // this.trkDmcVol.Anchor = System.Windows.Forms.AnchorStyles.Top; - this.trkDmcVol.Text = "DMC"; this.trkDmcVol.Location = new System.Drawing.Point(384, 0); this.trkDmcVol.Margin = new System.Windows.Forms.Padding(0); this.trkDmcVol.Maximum = 100; @@ -133,12 +164,12 @@ this.trkDmcVol.Name = "trkDmcVol"; this.trkDmcVol.Size = new System.Drawing.Size(63, 160); this.trkDmcVol.TabIndex = 16; + this.trkDmcVol.Text = "DMC"; this.trkDmcVol.Value = 50; // // trkNoiseVol // this.trkNoiseVol.Anchor = System.Windows.Forms.AnchorStyles.Top; - this.trkNoiseVol.Text = "Noise"; this.trkNoiseVol.Location = new System.Drawing.Point(306, 0); this.trkNoiseVol.Margin = new System.Windows.Forms.Padding(0); this.trkNoiseVol.Maximum = 100; @@ -147,12 +178,12 @@ this.trkNoiseVol.Name = "trkNoiseVol"; this.trkNoiseVol.Size = new System.Drawing.Size(63, 160); this.trkNoiseVol.TabIndex = 15; + this.trkNoiseVol.Text = "Noise"; this.trkNoiseVol.Value = 50; // // trkTriangleVol // this.trkTriangleVol.Anchor = System.Windows.Forms.AnchorStyles.Top; - this.trkTriangleVol.Text = "Triangle"; this.trkTriangleVol.Location = new System.Drawing.Point(231, 0); this.trkTriangleVol.Margin = new System.Windows.Forms.Padding(0); this.trkTriangleVol.Maximum = 100; @@ -161,12 +192,12 @@ this.trkTriangleVol.Name = "trkTriangleVol"; this.trkTriangleVol.Size = new System.Drawing.Size(63, 160); this.trkTriangleVol.TabIndex = 14; + this.trkTriangleVol.Text = "Triangle"; this.trkTriangleVol.Value = 50; // // trkSquare2Vol // this.trkSquare2Vol.Anchor = System.Windows.Forms.AnchorStyles.Top; - this.trkSquare2Vol.Text = "Square 2"; this.trkSquare2Vol.Location = new System.Drawing.Point(156, 0); this.trkSquare2Vol.Margin = new System.Windows.Forms.Padding(0); this.trkSquare2Vol.Maximum = 100; @@ -175,12 +206,12 @@ this.trkSquare2Vol.Name = "trkSquare2Vol"; this.trkSquare2Vol.Size = new System.Drawing.Size(63, 160); this.trkSquare2Vol.TabIndex = 13; + this.trkSquare2Vol.Text = "Square 2"; this.trkSquare2Vol.Value = 50; // // trkSquare1Vol // this.trkSquare1Vol.Anchor = System.Windows.Forms.AnchorStyles.Top; - this.trkSquare1Vol.Text = "Square 1"; this.trkSquare1Vol.Location = new System.Drawing.Point(81, 0); this.trkSquare1Vol.Margin = new System.Windows.Forms.Padding(0); this.trkSquare1Vol.Maximum = 100; @@ -189,12 +220,12 @@ this.trkSquare1Vol.Name = "trkSquare1Vol"; this.trkSquare1Vol.Size = new System.Drawing.Size(63, 160); this.trkSquare1Vol.TabIndex = 12; + this.trkSquare1Vol.Text = "Square 1"; this.trkSquare1Vol.Value = 50; // // trkMaster // this.trkMaster.Anchor = System.Windows.Forms.AnchorStyles.Top; - this.trkMaster.Text = "Master"; this.trkMaster.Location = new System.Drawing.Point(6, 0); this.trkMaster.Margin = new System.Windows.Forms.Padding(0); this.trkMaster.Maximum = 100; @@ -203,12 +234,12 @@ this.trkMaster.Name = "trkMaster"; this.trkMaster.Size = new System.Drawing.Size(63, 160); this.trkMaster.TabIndex = 11; + this.trkMaster.Text = "Master"; this.trkMaster.Value = 50; // // trkFdsVol // this.trkFdsVol.Anchor = System.Windows.Forms.AnchorStyles.Top; - this.trkFdsVol.Text = "FDS"; this.trkFdsVol.Location = new System.Drawing.Point(6, 160); this.trkFdsVol.Margin = new System.Windows.Forms.Padding(0); this.trkFdsVol.Maximum = 100; @@ -217,12 +248,12 @@ this.trkFdsVol.Name = "trkFdsVol"; this.trkFdsVol.Size = new System.Drawing.Size(63, 160); this.trkFdsVol.TabIndex = 17; + this.trkFdsVol.Text = "FDS"; this.trkFdsVol.Value = 50; // // trkMmc5Vol // this.trkMmc5Vol.Anchor = System.Windows.Forms.AnchorStyles.Top; - this.trkMmc5Vol.Text = "MMC5"; this.trkMmc5Vol.Enabled = false; this.trkMmc5Vol.Location = new System.Drawing.Point(81, 160); this.trkMmc5Vol.Margin = new System.Windows.Forms.Padding(0); @@ -232,12 +263,12 @@ this.trkMmc5Vol.Name = "trkMmc5Vol"; this.trkMmc5Vol.Size = new System.Drawing.Size(63, 160); this.trkMmc5Vol.TabIndex = 18; + this.trkMmc5Vol.Text = "MMC5"; this.trkMmc5Vol.Value = 50; // // trkVrc6Vol // this.trkVrc6Vol.Anchor = System.Windows.Forms.AnchorStyles.Top; - this.trkVrc6Vol.Text = "VRC6"; this.trkVrc6Vol.Enabled = false; this.trkVrc6Vol.Location = new System.Drawing.Point(156, 160); this.trkVrc6Vol.Margin = new System.Windows.Forms.Padding(0); @@ -247,12 +278,12 @@ this.trkVrc6Vol.Name = "trkVrc6Vol"; this.trkVrc6Vol.Size = new System.Drawing.Size(63, 160); this.trkVrc6Vol.TabIndex = 19; + this.trkVrc6Vol.Text = "VRC6"; this.trkVrc6Vol.Value = 50; // // trkVrc7Vol // this.trkVrc7Vol.Anchor = System.Windows.Forms.AnchorStyles.Top; - this.trkVrc7Vol.Text = "VRC7"; this.trkVrc7Vol.Enabled = false; this.trkVrc7Vol.Location = new System.Drawing.Point(231, 160); this.trkVrc7Vol.Margin = new System.Windows.Forms.Padding(0); @@ -262,12 +293,12 @@ this.trkVrc7Vol.Name = "trkVrc7Vol"; this.trkVrc7Vol.Size = new System.Drawing.Size(63, 160); this.trkVrc7Vol.TabIndex = 20; + this.trkVrc7Vol.Text = "VRC7"; this.trkVrc7Vol.Value = 50; // // trkNamco163Vol // this.trkNamco163Vol.Anchor = System.Windows.Forms.AnchorStyles.Top; - this.trkNamco163Vol.Text = "Namco"; this.trkNamco163Vol.Enabled = false; this.trkNamco163Vol.Location = new System.Drawing.Point(306, 160); this.trkNamco163Vol.Margin = new System.Windows.Forms.Padding(0); @@ -277,12 +308,12 @@ this.trkNamco163Vol.Name = "trkNamco163Vol"; this.trkNamco163Vol.Size = new System.Drawing.Size(63, 160); this.trkNamco163Vol.TabIndex = 21; + this.trkNamco163Vol.Text = "Namco"; this.trkNamco163Vol.Value = 50; // // trkSunsoft5b // this.trkSunsoft5b.Anchor = System.Windows.Forms.AnchorStyles.Top; - this.trkSunsoft5b.Text = "Sunsoft"; this.trkSunsoft5b.Enabled = false; this.trkSunsoft5b.Location = new System.Drawing.Point(384, 160); this.trkSunsoft5b.Margin = new System.Windows.Forms.Padding(0); @@ -292,6 +323,7 @@ this.trkSunsoft5b.Name = "trkSunsoft5b"; this.trkSunsoft5b.Size = new System.Drawing.Size(63, 160); this.trkSunsoft5b.TabIndex = 22; + this.trkSunsoft5b.Text = "Sunsoft"; this.trkSunsoft5b.Value = 50; // // tableLayoutPanel2 @@ -468,6 +500,7 @@ // this.tabMain.Controls.Add(this.tpgGeneral); this.tabMain.Controls.Add(this.tpgVolume); + this.tabMain.Controls.Add(this.tpgEffects); this.tabMain.Controls.Add(this.tpgAdvanced); this.tabMain.Dock = System.Windows.Forms.DockStyle.Fill; this.tabMain.Location = new System.Drawing.Point(0, 0); @@ -498,6 +531,252 @@ this.tpgVolume.Text = "Volume"; this.tpgVolume.UseVisualStyleBackColor = true; // + // tpgEffects + // + this.tpgEffects.Controls.Add(this.tableLayoutPanel4); + this.tpgEffects.Location = new System.Drawing.Point(4, 22); + this.tpgEffects.Name = "tpgEffects"; + this.tpgEffects.Padding = new System.Windows.Forms.Padding(3); + this.tpgEffects.Size = new System.Drawing.Size(469, 349); + this.tpgEffects.TabIndex = 3; + this.tpgEffects.Text = "Effects"; + this.tpgEffects.UseVisualStyleBackColor = true; + // + // tableLayoutPanel4 + // + this.tableLayoutPanel4.ColumnCount = 1; + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel4.Controls.Add(this.grpStereo, 0, 0); + this.tableLayoutPanel4.Controls.Add(this.grpReverb, 0, 1); + this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 3); + this.tableLayoutPanel4.Name = "tableLayoutPanel4"; + this.tableLayoutPanel4.RowCount = 3; + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel4.Size = new System.Drawing.Size(463, 343); + this.tableLayoutPanel4.TabIndex = 0; + // + // grpStereo + // + this.grpStereo.Controls.Add(this.tlpStereoFilter); + this.grpStereo.Dock = System.Windows.Forms.DockStyle.Fill; + this.grpStereo.Location = new System.Drawing.Point(3, 3); + this.grpStereo.Name = "grpStereo"; + this.grpStereo.Size = new System.Drawing.Size(457, 95); + this.grpStereo.TabIndex = 0; + this.grpStereo.TabStop = false; + this.grpStereo.Text = "Stereo"; + // + // tlpStereoFilter + // + this.tlpStereoFilter.ColumnCount = 2; + this.tlpStereoFilter.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tlpStereoFilter.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tlpStereoFilter.Controls.Add(this.flowLayoutPanel3, 1, 1); + this.tlpStereoFilter.Controls.Add(this.radStereoDisabled, 0, 0); + this.tlpStereoFilter.Controls.Add(this.radStereoDelay, 0, 1); + this.tlpStereoFilter.Controls.Add(this.radStereoPanning, 0, 2); + this.tlpStereoFilter.Controls.Add(this.flowLayoutPanel4, 1, 2); + this.tlpStereoFilter.Dock = System.Windows.Forms.DockStyle.Fill; + this.tlpStereoFilter.Location = new System.Drawing.Point(3, 16); + this.tlpStereoFilter.Name = "tlpStereoFilter"; + this.tlpStereoFilter.RowCount = 4; + this.tlpStereoFilter.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tlpStereoFilter.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tlpStereoFilter.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tlpStereoFilter.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tlpStereoFilter.Size = new System.Drawing.Size(451, 76); + this.tlpStereoFilter.TabIndex = 0; + // + // flowLayoutPanel3 + // + this.flowLayoutPanel3.Controls.Add(this.nudStereoDelay); + this.flowLayoutPanel3.Controls.Add(this.lblStereoDelayMs); + this.flowLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill; + this.flowLayoutPanel3.Location = new System.Drawing.Point(72, 23); + this.flowLayoutPanel3.Margin = new System.Windows.Forms.Padding(0); + this.flowLayoutPanel3.Name = "flowLayoutPanel3"; + this.flowLayoutPanel3.Size = new System.Drawing.Size(379, 26); + this.flowLayoutPanel3.TabIndex = 1; + // + // nudStereoDelay + // + this.nudStereoDelay.Location = new System.Drawing.Point(3, 3); + this.nudStereoDelay.Name = "nudStereoDelay"; + this.nudStereoDelay.Size = new System.Drawing.Size(45, 20); + this.nudStereoDelay.TabIndex = 1; + // + // lblStereoDelayMs + // + this.lblStereoDelayMs.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblStereoDelayMs.AutoSize = true; + this.lblStereoDelayMs.Location = new System.Drawing.Point(54, 6); + this.lblStereoDelayMs.Name = "lblStereoDelayMs"; + this.lblStereoDelayMs.Size = new System.Drawing.Size(20, 13); + this.lblStereoDelayMs.TabIndex = 1; + this.lblStereoDelayMs.Text = "ms"; + // + // radStereoDisabled + // + this.radStereoDisabled.AutoSize = true; + this.radStereoDisabled.Location = new System.Drawing.Point(3, 3); + this.radStereoDisabled.Name = "radStereoDisabled"; + this.radStereoDisabled.Size = new System.Drawing.Size(66, 17); + this.radStereoDisabled.TabIndex = 1; + this.radStereoDisabled.TabStop = true; + this.radStereoDisabled.Tag = "None"; + this.radStereoDisabled.Text = "Disabled"; + this.radStereoDisabled.UseVisualStyleBackColor = true; + // + // radStereoDelay + // + this.radStereoDelay.AutoSize = true; + this.radStereoDelay.Location = new System.Drawing.Point(3, 26); + this.radStereoDelay.Name = "radStereoDelay"; + this.radStereoDelay.Size = new System.Drawing.Size(52, 17); + this.radStereoDelay.TabIndex = 2; + this.radStereoDelay.TabStop = true; + this.radStereoDelay.Tag = "Delay"; + this.radStereoDelay.Text = "Delay"; + this.radStereoDelay.UseVisualStyleBackColor = true; + // + // radStereoPanning + // + this.radStereoPanning.AutoSize = true; + this.radStereoPanning.Location = new System.Drawing.Point(3, 52); + this.radStereoPanning.Name = "radStereoPanning"; + this.radStereoPanning.Size = new System.Drawing.Size(64, 17); + this.radStereoPanning.TabIndex = 3; + this.radStereoPanning.TabStop = true; + this.radStereoPanning.Tag = "Panning"; + this.radStereoPanning.Text = "Panning"; + this.radStereoPanning.UseVisualStyleBackColor = true; + // + // flowLayoutPanel4 + // + this.flowLayoutPanel4.Controls.Add(this.nudStereoPanning); + this.flowLayoutPanel4.Controls.Add(this.lblStereoPanningAngle); + this.flowLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill; + this.flowLayoutPanel4.Location = new System.Drawing.Point(72, 49); + this.flowLayoutPanel4.Margin = new System.Windows.Forms.Padding(0); + this.flowLayoutPanel4.Name = "flowLayoutPanel4"; + this.flowLayoutPanel4.Size = new System.Drawing.Size(379, 26); + this.flowLayoutPanel4.TabIndex = 4; + // + // nudStereoPanning + // + this.nudStereoPanning.Location = new System.Drawing.Point(3, 3); + this.nudStereoPanning.Maximum = new decimal(new int[] { + 180, + 0, + 0, + 0}); + this.nudStereoPanning.Minimum = new decimal(new int[] { + 180, + 0, + 0, + -2147483648}); + this.nudStereoPanning.Name = "nudStereoPanning"; + this.nudStereoPanning.Size = new System.Drawing.Size(45, 20); + this.nudStereoPanning.TabIndex = 1; + // + // lblStereoPanningAngle + // + this.lblStereoPanningAngle.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblStereoPanningAngle.AutoSize = true; + this.lblStereoPanningAngle.Location = new System.Drawing.Point(54, 6); + this.lblStereoPanningAngle.Name = "lblStereoPanningAngle"; + this.lblStereoPanningAngle.Size = new System.Drawing.Size(92, 13); + this.lblStereoPanningAngle.TabIndex = 1; + this.lblStereoPanningAngle.Text = "(Angle in degrees)"; + // + // grpReverb + // + this.grpReverb.Controls.Add(this.tableLayoutPanel5); + this.grpReverb.Dock = System.Windows.Forms.DockStyle.Fill; + this.grpReverb.Location = new System.Drawing.Point(3, 104); + this.grpReverb.Name = "grpReverb"; + this.grpReverb.Size = new System.Drawing.Size(457, 109); + this.grpReverb.TabIndex = 1; + this.grpReverb.TabStop = false; + this.grpReverb.Text = "Reverb"; + // + // tableLayoutPanel5 + // + this.tableLayoutPanel5.ColumnCount = 2; + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel5.Controls.Add(this.chkReverbEnabled, 0, 0); + this.tableLayoutPanel5.Controls.Add(this.lblReverbStrength, 0, 1); + this.tableLayoutPanel5.Controls.Add(this.lblReverbDelay, 0, 2); + this.tableLayoutPanel5.Controls.Add(this.trkReverbDelay, 1, 2); + this.tableLayoutPanel5.Controls.Add(this.trkReverbStrength, 1, 1); + this.tableLayoutPanel5.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel5.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel5.Name = "tableLayoutPanel5"; + this.tableLayoutPanel5.RowCount = 4; + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 32F)); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 32F)); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel5.Size = new System.Drawing.Size(451, 90); + this.tableLayoutPanel5.TabIndex = 0; + // + // chkReverbEnabled + // + this.chkReverbEnabled.AutoSize = true; + this.tableLayoutPanel5.SetColumnSpan(this.chkReverbEnabled, 2); + this.chkReverbEnabled.Location = new System.Drawing.Point(3, 3); + this.chkReverbEnabled.Name = "chkReverbEnabled"; + this.chkReverbEnabled.Size = new System.Drawing.Size(97, 17); + this.chkReverbEnabled.TabIndex = 0; + this.chkReverbEnabled.Text = "Enable Reverb"; + this.chkReverbEnabled.UseVisualStyleBackColor = true; + // + // lblReverbStrength + // + this.lblReverbStrength.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblReverbStrength.AutoSize = true; + this.lblReverbStrength.Location = new System.Drawing.Point(3, 32); + this.lblReverbStrength.Name = "lblReverbStrength"; + this.lblReverbStrength.Size = new System.Drawing.Size(50, 13); + this.lblReverbStrength.TabIndex = 2; + this.lblReverbStrength.Text = "Strength:"; + // + // lblReverbDelay + // + this.lblReverbDelay.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblReverbDelay.AutoSize = true; + this.lblReverbDelay.Location = new System.Drawing.Point(3, 64); + this.lblReverbDelay.Name = "lblReverbDelay"; + this.lblReverbDelay.Size = new System.Drawing.Size(37, 13); + this.lblReverbDelay.TabIndex = 3; + this.lblReverbDelay.Text = "Delay:"; + // + // trkReverbDelay + // + this.trkReverbDelay.BackColor = System.Drawing.SystemColors.ControlLightLight; + this.trkReverbDelay.Location = new System.Drawing.Point(59, 58); + this.trkReverbDelay.Maximum = 30; + this.trkReverbDelay.Minimum = 1; + this.trkReverbDelay.Name = "trkReverbDelay"; + this.trkReverbDelay.Size = new System.Drawing.Size(104, 26); + this.trkReverbDelay.TabIndex = 4; + this.trkReverbDelay.TickFrequency = 3; + this.trkReverbDelay.Value = 1; + // + // trkReverbStrength + // + this.trkReverbStrength.BackColor = System.Drawing.SystemColors.ControlLightLight; + this.trkReverbStrength.Location = new System.Drawing.Point(59, 26); + this.trkReverbStrength.Minimum = 1; + this.trkReverbStrength.Name = "trkReverbStrength"; + this.trkReverbStrength.Size = new System.Drawing.Size(104, 26); + this.trkReverbStrength.TabIndex = 1; + this.trkReverbStrength.Value = 1; + // // tpgAdvanced // this.tpgAdvanced.Controls.Add(this.tableLayoutPanel3); @@ -559,6 +838,22 @@ this.tabMain.ResumeLayout(false); this.tpgGeneral.ResumeLayout(false); this.tpgVolume.ResumeLayout(false); + this.tpgEffects.ResumeLayout(false); + this.tableLayoutPanel4.ResumeLayout(false); + this.grpStereo.ResumeLayout(false); + this.tlpStereoFilter.ResumeLayout(false); + this.tlpStereoFilter.PerformLayout(); + this.flowLayoutPanel3.ResumeLayout(false); + this.flowLayoutPanel3.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.nudStereoDelay)).EndInit(); + this.flowLayoutPanel4.ResumeLayout(false); + this.flowLayoutPanel4.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.nudStereoPanning)).EndInit(); + this.grpReverb.ResumeLayout(false); + this.tableLayoutPanel5.ResumeLayout(false); + this.tableLayoutPanel5.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.trkReverbDelay)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.trkReverbStrength)).EndInit(); this.tpgAdvanced.ResumeLayout(false); this.tableLayoutPanel3.ResumeLayout(false); this.tableLayoutPanel3.PerformLayout(); @@ -601,5 +896,25 @@ private System.Windows.Forms.TabPage tpgAdvanced; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; private System.Windows.Forms.CheckBox chkSwapDutyCycles; + private System.Windows.Forms.TabPage tpgEffects; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; + private System.Windows.Forms.GroupBox grpStereo; + private System.Windows.Forms.TableLayoutPanel tlpStereoFilter; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel3; + private System.Windows.Forms.NumericUpDown nudStereoDelay; + private System.Windows.Forms.Label lblStereoDelayMs; + private System.Windows.Forms.RadioButton radStereoDisabled; + private System.Windows.Forms.RadioButton radStereoDelay; + private System.Windows.Forms.RadioButton radStereoPanning; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel4; + private System.Windows.Forms.NumericUpDown nudStereoPanning; + private System.Windows.Forms.Label lblStereoPanningAngle; + private System.Windows.Forms.GroupBox grpReverb; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel5; + private System.Windows.Forms.CheckBox chkReverbEnabled; + private System.Windows.Forms.Label lblReverbStrength; + private System.Windows.Forms.Label lblReverbDelay; + private System.Windows.Forms.TrackBar trkReverbDelay; + private System.Windows.Forms.TrackBar trkReverbStrength; } } \ No newline at end of file diff --git a/GUI.NET/Forms/Config/frmAudioConfig.cs b/GUI.NET/Forms/Config/frmAudioConfig.cs index 3d747566..b6641a48 100644 --- a/GUI.NET/Forms/Config/frmAudioConfig.cs +++ b/GUI.NET/Forms/Config/frmAudioConfig.cs @@ -44,6 +44,18 @@ namespace Mesen.GUI.Forms.Config AddBinding("MuteSoundInBackground", chkMuteSoundInBackground); AddBinding("SwapDutyCycles", chkSwapDutyCycles); + + radStereoDisabled.Tag = InteropEmu.StereoFilter.None; + radStereoDelay.Tag = InteropEmu.StereoFilter.Delay; + radStereoPanning.Tag = InteropEmu.StereoFilter.Panning; + + AddBinding("StereoFilter", tlpStereoFilter); + AddBinding("StereoDelay", nudStereoDelay); + AddBinding("StereoPanningAngle", nudStereoPanning); + + AddBinding("ReverbEnabled", chkReverbEnabled); + AddBinding("ReverbDelay", trkReverbDelay); + AddBinding("ReverbStrength", trkReverbStrength); } protected override void OnFormClosed(FormClosedEventArgs e) diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index 6d0c8942..a2ea800c 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -102,6 +102,10 @@ namespace Mesen.GUI [DllImport(DLLPath)] public static extern void SetChannelVolume(AudioChannel channel, double volume); [DllImport(DLLPath)] public static extern void SetSampleRate(UInt32 sampleRate); [DllImport(DLLPath)] public static extern void SetAudioLatency(UInt32 msLatency); + [DllImport(DLLPath)] public static extern void SetStereoFilter(StereoFilter stereoFilter); + [DllImport(DLLPath)] public static extern void SetStereoDelay(Int32 delay); + [DllImport(DLLPath)] public static extern void SetStereoPanningAngle(double angle); + [DllImport(DLLPath)] public static extern void SetReverbParameters(double strength, double delay); [DllImport(DLLPath)] public static extern void SetNesModel(NesModel model); [DllImport(DLLPath)] public static extern void SetEmulationSpeed(UInt32 emulationSpeed); [DllImport(DLLPath)] public static extern void SetOverscanDimensions(UInt32 left, UInt32 right, UInt32 top, UInt32 bottom); @@ -361,6 +365,13 @@ namespace Mesen.GUI public UInt32 TurboSelect; } + public enum StereoFilter + { + None = 0, + Delay = 1, + Panning = 2, + } + public struct ScreenSize { public Int32 Width; diff --git a/InteropDLL/ConsoleWrapper.cpp b/InteropDLL/ConsoleWrapper.cpp index 1b92a69d..38c5386e 100644 --- a/InteropDLL/ConsoleWrapper.cpp +++ b/InteropDLL/ConsoleWrapper.cpp @@ -254,6 +254,11 @@ namespace InteropEmu { DllExport void __stdcall SetMasterVolume(double volume) { EmulationSettings::SetMasterVolume(volume); } DllExport void __stdcall SetSampleRate(uint32_t sampleRate) { EmulationSettings::SetSampleRate(sampleRate); } DllExport void __stdcall SetAudioLatency(uint32_t msLatency) { EmulationSettings::SetAudioLatency(msLatency); } + DllExport void __stdcall SetStereoFilter(StereoFilter stereoFilter) { EmulationSettings::SetStereoFilter(stereoFilter); } + DllExport void __stdcall SetStereoDelay(int32_t delay) { EmulationSettings::SetStereoDelay(delay); } + DllExport void __stdcall SetStereoPanningAngle(double angle) { EmulationSettings::SetStereoPanningAngle(angle); } + DllExport void __stdcall SetReverbParameters(double strength, double delay) { EmulationSettings::SetReverbParameters(strength, delay); } + DllExport void __stdcall SetNesModel(uint32_t model) { EmulationSettings::SetNesModel((NesModel)model); } DllExport void __stdcall SetOverscanDimensions(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) { EmulationSettings::SetOverscanDimensions(left, right, top, bottom); } DllExport void __stdcall SetEmulationSpeed(uint32_t emulationSpeed) { EmulationSettings::SetEmulationSpeed(emulationSpeed); } diff --git a/Windows/SoundManager.cpp b/Windows/SoundManager.cpp index e75e3732..7c7189c9 100644 --- a/Windows/SoundManager.cpp +++ b/Windows/SoundManager.cpp @@ -12,7 +12,7 @@ SoundManager::SoundManager(HWND hwnd) memset(&_audioDeviceID, 0, sizeof(_audioDeviceID)); - if(InitializeDirectSound(44100)) { + if(InitializeDirectSound(44100, false)) { SoundMixer::RegisterAudioDevice(this); } else { MessageManager::DisplayMessage("Error", "Could not initialize audio system"); @@ -69,7 +69,7 @@ void SoundManager::SetAudioDevice(string deviceName) } } -bool SoundManager::InitializeDirectSound(uint32_t sampleRate) +bool SoundManager::InitializeDirectSound(uint32_t sampleRate, bool isStereo) { HRESULT result; DSBUFFERDESC bufferDesc; @@ -103,11 +103,12 @@ bool SoundManager::InitializeDirectSound(uint32_t sampleRate) // Setup the format of the primary sound bufffer. _sampleRate = sampleRate; + _isStereo = isStereo; waveFormat.wFormatTag = WAVE_FORMAT_PCM; waveFormat.nSamplesPerSec = _sampleRate; waveFormat.wBitsPerSample = 16; - waveFormat.nChannels = 1; + waveFormat.nChannels = isStereo ? 2 : 1; waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels; waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; waveFormat.cbSize = 0; @@ -225,14 +226,21 @@ void SoundManager::Play() } } -void SoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t soundBufferSize, uint32_t sampleRate) +void SoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t sampleCount, uint32_t sampleRate, bool isStereo) { - if(_sampleRate != sampleRate || _needReset) { + uint32_t bytesPerSample = (SoundMixer::BitsPerSample / 8); + if(_sampleRate != sampleRate || _isStereo != isStereo || _needReset) { Release(); - InitializeDirectSound(sampleRate); + InitializeDirectSound(sampleRate, isStereo); } - int32_t byteLatency = (int32_t)((float)(sampleRate * EmulationSettings::GetAudioLatency()) / 1000.0f * (SoundMixer::BitsPerSample / 8)); + if(isStereo) { + bytesPerSample *= 2; + } + + uint32_t soundBufferSize = sampleCount * bytesPerSample; + + int32_t byteLatency = (int32_t)((float)(sampleRate * EmulationSettings::GetAudioLatency()) / 1000.0f * bytesPerSample); if(byteLatency != _previousLatency) { Stop(); _previousLatency = byteLatency; diff --git a/Windows/SoundManager.h b/Windows/SoundManager.h index 275c3c12..b175638c 100644 --- a/Windows/SoundManager.h +++ b/Windows/SoundManager.h @@ -16,7 +16,7 @@ public: ~SoundManager(); void Release(); - void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate); + void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo); void Play(); void Pause(); void Stop(); @@ -27,7 +27,7 @@ public: private: vector GetAvailableDeviceInfo(); static bool CALLBACK DirectSoundEnumProc(LPGUID lpGUID, LPCWSTR lpszDesc, LPCSTR lpszDrvName, LPVOID lpContext); - bool InitializeDirectSound(uint32_t sampleRate); + bool InitializeDirectSound(uint32_t sampleRate, bool isStereo); void ShutdownDirectSound(); void ClearSecondaryBuffer(); void CopyToSecondaryBuffer(uint8_t *data, uint32_t size); @@ -40,6 +40,7 @@ private: uint16_t _lastWriteOffset = 0; uint16_t _previousLatency = 0; uint32_t _sampleRate = 0; + bool _isStereo = false; IDirectSound8* _directSound; IDirectSoundBuffer* _primaryBuffer;