diff --git a/Core/SPC_DSP.cpp b/Core/SPC_DSP.cpp index 5a2ed97..b56e6f1 100644 --- a/Core/SPC_DSP.cpp +++ b/Core/SPC_DSP.cpp @@ -20,6 +20,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "blargg_source.h" #include "Spc.h" +#include "EmuSettings.h" #ifdef BLARGG_ENABLE_OPTIMIZER #include BLARGG_ENABLE_OPTIMIZER @@ -131,6 +132,25 @@ static short const gauss [512] = 1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305, }; +inline int SPC_DSP::interpolate_cubic(voice_t const* v) +{ + int const* in = &v->buf[(v->interp_pos >> 12) + v->buf_pos]; + + float v0 = in[0] / 32768.0; + float v1 = in[1] / 32768.0; + float v2 = in[2] / 32768.0; + float v3 = in[3] / 32768.0; + + float a = (v3 - v2) - (v0 - v1); + float b = (v0 - v1) - a; + float c = v2 - v0; + float d = v1; + + float ratio = (double)(v->interp_pos & 0xFFF) / 0x1000; + + return (int)((d + ratio * (c + ratio * (b + ratio * a))) * 32768); +} + inline int SPC_DSP::interpolate( voice_t const* v ) { // Make pointers into gaussian based on fractional position between samples @@ -451,7 +471,7 @@ VOICE_CLOCK( V3c ) // Gaussian interpolation { - int output = interpolate( v ); + int output = _settings->GetAudioConfig().EnableCubicInterpolation ? interpolate_cubic(v) : interpolate( v ); // Noise if ( m.t_non & v->vbit ) @@ -812,9 +832,10 @@ inline void SPC_DSP::writeRam(uint16_t addr, uint8_t value) { _spc->DspWriteRam( //// Setup -void SPC_DSP::init( Spc *spc, void* ram_64k ) +void SPC_DSP::init( Spc *spc, EmuSettings *settings, void* ram_64k ) { _spc = spc; + _settings = settings; m.ram = (uint8_t*) ram_64k; mute_voices( 0 ); disable_surround( false ); diff --git a/Core/SPC_DSP.h b/Core/SPC_DSP.h index 5ab3b28..8d80220 100644 --- a/Core/SPC_DSP.h +++ b/Core/SPC_DSP.h @@ -8,6 +8,7 @@ extern "C" { typedef void (*dsp_copy_func_t)( unsigned char** io, void* state, size_t ); } class Spc; +class EmuSettings; class SPC_DSP { public: typedef BOOST::uint8_t uint8_t; @@ -15,7 +16,7 @@ public: // Setup // Initializes DSP and has it use the 64K RAM provided - void init( Spc* spc, void* ram_64k ); + void init( Spc* spc, EmuSettings* settings, void* ram_64k ); // Sets destination for output samples. If out is NULL or out_size is 0, // doesn't generate any. @@ -191,11 +192,13 @@ private: }; state_t m; Spc* _spc; + EmuSettings* _settings; void init_counter(); void run_counters(); unsigned read_counter( int rate ); + int interpolate_cubic(voice_t const* v); int interpolate( voice_t const* v ); void run_envelope( voice_t* const v ); void decode_brr( voice_t* v ); diff --git a/Core/SettingTypes.h b/Core/SettingTypes.h index 7cb2a4e..23c77eb 100644 --- a/Core/SettingTypes.h +++ b/Core/SettingTypes.h @@ -119,6 +119,8 @@ struct AudioConfig uint32_t SampleRate = 48000; uint32_t AudioLatency = 60; + bool EnableCubicInterpolation = true; + bool MuteSoundInBackground = false; bool ReduceSoundInBackground = true; bool ReduceSoundInFastForward = false; diff --git a/Core/Spc.cpp b/Core/Spc.cpp index bc5da1c..178f419 100644 --- a/Core/Spc.cpp +++ b/Core/Spc.cpp @@ -25,7 +25,7 @@ Spc::Spc(Console* console) _dsp.reset(new SPC_DSP()); #ifndef DUMMYSPC - _dsp->init(this, _ram); + _dsp->init(this, _console->GetSettings().get(), _ram); #endif _dsp->reset(); _dsp->set_output(_soundBuffer, Spc::SampleBufferSize >> 1); diff --git a/Libretro/libretro.cpp b/Libretro/libretro.cpp index da7b2a1..4efb7cd 100644 --- a/Libretro/libretro.cpp +++ b/Libretro/libretro.cpp @@ -42,6 +42,7 @@ static constexpr const char* MesenNtscFilter = "mesen-s_ntsc_filter"; static constexpr const char* MesenRegion = "mesen-s_region"; static constexpr const char* MesenAspectRatio = "mesen-s_aspect_ratio"; static constexpr const char* MesenBlendHighRes = "mesen-s_blend_high_res"; +static constexpr const char* MesenCubicInterpolation = "mesen-s_cubic_interpolation"; static constexpr const char* MesenOverscanVertical = "mesen-s_overscan_vertical"; static constexpr const char* MesenOverscanHorizontal = "mesen-s_overscan_horizontal"; static constexpr const char* MesenRamState = "mesen-s_ramstate"; @@ -114,6 +115,7 @@ extern "C" { { MesenOverscanHorizontal, "Horizontal Overscan; None|8px|16px" }, { MesenAspectRatio, "Aspect Ratio; Auto|No Stretching|NTSC|PAL|4:3|16:9" }, { MesenBlendHighRes, "Blend Hi-Res Modes; disabled|enabled" }, + { MesenCubicInterpolation, "Cubic Interpolation (Audio); disabled|enabled" }, { MesenOverclock, "Overclock; None|Low|Medium|High|Very High" }, { MesenOverclockType, "Overclock Type; Before NMI|After NMI" }, { MesenSuperFxOverclock, "Super FX Clock Speed; 100%|200%|300%|400%|500%|1000%" }, @@ -208,6 +210,7 @@ extern "C" { { struct retro_variable var = { }; VideoConfig video = _console->GetSettings()->GetVideoConfig(); + AudioConfig audio = _console->GetSettings()->GetAudioConfig(); EmulationConfig emulation = _console->GetSettings()->GetEmulationConfig(); InputConfig input = _console->GetSettings()->GetInputConfig(); video.Brightness = 0; @@ -378,6 +381,11 @@ extern "C" { string value = string(var.value); video.BlendHighResolutionModes = (value == "enabled"); } + + if(readVariable(MesenCubicInterpolation, var)) { + string value = string(var.value); + audio.EnableCubicInterpolation = (value == "enabled"); + } auto getKeyCode = [=](int port, int retroKey) { return (port << 8) | (retroKey + 1); @@ -412,6 +420,7 @@ extern "C" { _console->GetSettings()->SetVideoConfig(video); _console->GetSettings()->SetEmulationConfig(emulation); _console->GetSettings()->SetInputConfig(input); + _console->GetSettings()->SetAudioConfig(audio); retro_system_av_info avInfo = {}; _renderer->GetSystemAudioVideoInfo(avInfo); diff --git a/UI/Config/AudioConfig.cs b/UI/Config/AudioConfig.cs index 21bea01..67f1248 100644 --- a/UI/Config/AudioConfig.cs +++ b/UI/Config/AudioConfig.cs @@ -18,6 +18,8 @@ namespace Mesen.GUI.Config [ValidValues(11025, 22050, 32000, 44100, 48000, 96000)] public UInt32 SampleRate = 48000; [MinMax(15, 300)] public UInt32 AudioLatency = 60; + [MarshalAs(UnmanagedType.I1)] public bool EnableCubicInterpolation = true; + [MarshalAs(UnmanagedType.I1)] public bool MuteSoundInBackground = false; [MarshalAs(UnmanagedType.I1)] public bool ReduceSoundInBackground = true; [MarshalAs(UnmanagedType.I1)] public bool ReduceSoundInFastForward = false; diff --git a/UI/Dependencies/resources.en.xml b/UI/Dependencies/resources.en.xml index 5baff4d..fde5d29 100644 --- a/UI/Dependencies/resources.en.xml +++ b/UI/Dependencies/resources.en.xml @@ -119,32 +119,13 @@ General Advanced Disable dynamic sample rate - Swap square channels duty cycles (Mimics old clones) - Mute ultrasonic frequencies on triangle channel (reduces popping) - Reduce popping sounds on the DMC channel - Disable noise channel mode flag - Effects - Stereo - Disabled - Delay - Panning - ms - (Angle in degrees) - Comb Filter - ms - Delay: - Strength: - Enable Crossfeed: - Reverb - Enable Reverb - Delay: - Strength: Mute sound when in background Reduce volume when in background Reduce volume during fast forward/rewind Volume Reduction (%) Volume Reduction Settings Enable Audio + Enable cubic interpolation Sample Rate: ms Low values may cause sound problems diff --git a/UI/Forms/Config/frmAudioConfig.Designer.cs b/UI/Forms/Config/frmAudioConfig.Designer.cs index 3e3e9e8..c392b9f 100644 --- a/UI/Forms/Config/frmAudioConfig.Designer.cs +++ b/UI/Forms/Config/frmAudioConfig.Designer.cs @@ -76,6 +76,7 @@ this.tpgAdvanced = new System.Windows.Forms.TabPage(); this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this.chkDisableDynamicSampleRate = new Mesen.GUI.Controls.ctrlRiskyOption(); + this.chkEnableCubicInterpolation = new System.Windows.Forms.CheckBox(); this.tabControl1.SuspendLayout(); this.tpgGeneral.SuspendLayout(); this.tableLayoutPanel2.SuspendLayout(); @@ -298,6 +299,7 @@ 0, 0, 0}); + this.nudLatency.IsHex = false; this.nudLatency.Location = new System.Drawing.Point(3, 3); this.nudLatency.Maximum = new decimal(new int[] { 300, @@ -890,11 +892,13 @@ // this.tableLayoutPanel1.ColumnCount = 1; this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel1.Controls.Add(this.chkDisableDynamicSampleRate, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.chkDisableDynamicSampleRate, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.chkEnableCubicInterpolation, 0, 0); this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 3); this.tableLayoutPanel1.Name = "tableLayoutPanel1"; - this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowCount = 3; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel1.Size = new System.Drawing.Size(478, 346); @@ -903,12 +907,22 @@ // chkDisableDynamicSampleRate // this.chkDisableDynamicSampleRate.Checked = false; - this.chkDisableDynamicSampleRate.Location = new System.Drawing.Point(0, 0); + this.chkDisableDynamicSampleRate.Location = new System.Drawing.Point(0, 23); this.chkDisableDynamicSampleRate.Name = "chkDisableDynamicSampleRate"; this.chkDisableDynamicSampleRate.Size = new System.Drawing.Size(463, 24); this.chkDisableDynamicSampleRate.TabIndex = 5; this.chkDisableDynamicSampleRate.Text = "Disable dynamic sample rate"; // + // chkEnableCubicInterpolation + // + this.chkEnableCubicInterpolation.AutoSize = true; + this.chkEnableCubicInterpolation.Location = new System.Drawing.Point(3, 3); + this.chkEnableCubicInterpolation.Name = "chkEnableCubicInterpolation"; + this.chkEnableCubicInterpolation.Size = new System.Drawing.Size(148, 17); + this.chkEnableCubicInterpolation.TabIndex = 6; + this.chkEnableCubicInterpolation.Text = "Enable cubic interpolation"; + this.chkEnableCubicInterpolation.UseVisualStyleBackColor = true; + // // frmAudioConfig // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -938,6 +952,7 @@ this.tlpEqualizer.ResumeLayout(false); this.tpgAdvanced.ResumeLayout(false); this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -994,5 +1009,6 @@ private System.Windows.Forms.TabPage tpgAdvanced; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; private Controls.ctrlRiskyOption chkDisableDynamicSampleRate; - } + private System.Windows.Forms.CheckBox chkEnableCubicInterpolation; + } } \ No newline at end of file diff --git a/UI/Forms/Config/frmAudioConfig.cs b/UI/Forms/Config/frmAudioConfig.cs index 4c0ce9e..5d3fd6b 100644 --- a/UI/Forms/Config/frmAudioConfig.cs +++ b/UI/Forms/Config/frmAudioConfig.cs @@ -30,6 +30,8 @@ namespace Mesen.GUI.Forms.Config AddBinding(nameof(AudioConfig.SampleRate), cboSampleRate); AddBinding(nameof(AudioConfig.AudioDevice), cboAudioDevice); AddBinding(nameof(AudioConfig.DisableDynamicSampleRate), chkDisableDynamicSampleRate); + + AddBinding(nameof(AudioConfig.EnableCubicInterpolation), chkEnableCubicInterpolation); AddBinding(nameof(AudioConfig.EnableEqualizer), chkEnableEqualizer); AddBinding(nameof(AudioConfig.Band1Gain), trkBand1Gain);