From 67f850dd37893de6ef1544b024ea298033047dfd Mon Sep 17 00:00:00 2001 From: mylek4 Date: Fri, 12 Nov 2010 03:39:07 +0000 Subject: [PATCH] DSPHLE: Added an option for 48khz output and supporting upsampling code. Games that have higher frequency sounds and music should sound a bit better using 48k. I don't have any games that use DTKMusic so that upsampling code untested. If you get strange sounds only at 48k try toggling dtk music to see if that isolates the problem and let me know. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6383 8ced0084-cf51-0410-be5f-012b33b47a6e --- .../AudioCommon/Src/AudioCommonConfig.cpp | 6 + .../Core/AudioCommon/Src/AudioCommonConfig.h | 2 + Source/Core/AudioCommon/Src/Mixer.cpp | 109 ++++++------------ Source/Core/AudioCommon/Src/Mixer.h | 7 +- Source/Core/Core/Src/HW/AudioInterface.cpp | 81 +++++++++---- .../Plugins/Plugin_DSP_HLE/Src/ConfigDlg.cpp | 36 +++++- Source/Plugins/Plugin_DSP_HLE/Src/ConfigDlg.h | 3 + Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.h | 4 +- Source/Plugins/Plugin_DSP_HLE/Src/main.cpp | 10 +- 9 files changed, 149 insertions(+), 109 deletions(-) diff --git a/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp b/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp index ebec56e41d..f97b0ba75d 100644 --- a/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp +++ b/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp @@ -26,14 +26,19 @@ void AudioCommonConfig::Load(IniFile &file) { file.Get("Config", "Volume", &m_Volume, 75); #ifdef _WIN32 file.Get("Config", "Backend", &sBackend, BACKEND_DIRECTSOUND); + file.Get("Config", "Frequency", &sFrequency, "32,000 Hz"); #elif defined __APPLE__ std::string temp; file.Get("Config", "Backend", &temp, BACKEND_COREAUDIO); strncpy(sBackend, temp.c_str(), 128); + file.Get("Config", "Frequency", &temp, "32,000 Hz"); + strncpy(sFrequency, temp.c_str(), 128); #elif defined __linux__ file.Get("Config", "Backend", &sBackend, BACKEND_ALSA); + file.Get("Config", "Frequency", &sFrequency, "32,000 Hz"); #else file.Get("Config", "Backend", &sBackend, BACKEND_OPENAL); + file.Get("Config", "Frequency", &sFrequency, "32,000 Hz"); #endif } @@ -43,6 +48,7 @@ void AudioCommonConfig::Set(IniFile &file) { file.Set("Config", "EnableThrottle", m_EnableThrottle); file.Set("Config", "EnableJIT", m_EnableJIT); file.Set("Config", "Backend", sBackend); + file.Set("Config", "Frequency", sFrequency); file.Set("Config", "Volume", m_Volume); } diff --git a/Source/Core/AudioCommon/Src/AudioCommonConfig.h b/Source/Core/AudioCommon/Src/AudioCommonConfig.h index 1267b320b8..524251bb86 100644 --- a/Source/Core/AudioCommon/Src/AudioCommonConfig.h +++ b/Source/Core/AudioCommon/Src/AudioCommonConfig.h @@ -39,8 +39,10 @@ struct AudioCommonConfig int m_Volume; #ifdef __APPLE__ char sBackend[128]; + char sFrequency[128]; #else std::string sBackend; + std::string sFrequency; #endif // Load from given file diff --git a/Source/Core/AudioCommon/Src/Mixer.cpp b/Source/Core/AudioCommon/Src/Mixer.cpp index b4f1be935d..d914f634c5 100644 --- a/Source/Core/AudioCommon/Src/Mixer.cpp +++ b/Source/Core/AudioCommon/Src/Mixer.cpp @@ -57,74 +57,39 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples) samples[i] = Common::swap16(m_buffer[(m_indexR + i) & INDEX_MASK]); m_indexR += numLeft * 2; } - else + else //linear interpolation { - // AyuanX: Up-sampling is not implemented yet - PanicAlert("Mixer: Up-sampling is not implemented yet!"); -/* - static int PV1l=0,PV2l=0,PV3l=0,PV4l=0; - static int PV1r=0,PV2r=0,PV3r=0,PV4r=0; - static int acc=0; + //render numleft sample pairs to samples[] + //advance m_indexR with sample position + //remember fractional offset - while (num_stereo_samples) { - acc += core_sample_rate; - while (num_stereo_samples && (acc >= 48000)) { - PV4l=PV3l; - PV3l=PV2l; - PV2l=PV1l; - PV1l=*(samples++); //32bit processing - PV4r=PV3r; - PV3r=PV2r; - PV2r=PV1r; - PV1r=*(samples++); //32bit processing - num_stereo_samples--; - acc-=48000; - } - - // defaults to nearest - s32 DataL = PV1l; - s32 DataR = PV1r; - - if (m_mode == 1) { //linear - - DataL = PV1l + ((PV2l - PV1l)*acc)/48000; - DataR = PV1r + ((PV2r - PV1r)*acc)/48000; - } - else if (m_mode == 2) {//cubic - s32 a0l = PV1l - PV2l - PV4l + PV3l; - s32 a0r = PV1r - PV2r - PV4r + PV3r; - s32 a1l = PV4l - PV3l - a0l; - s32 a1r = PV4r - PV3r - a0r; - s32 a2l = PV1l - PV4l; - s32 a2r = PV1r - PV4r; - s32 a3l = PV2l; - s32 a3r = PV2r; - - s32 t0l = ((a0l )*acc)/48000; - s32 t0r = ((a0r )*acc)/48000; - s32 t1l = ((t0l+a1l)*acc)/48000; - s32 t1r = ((t0r+a1r)*acc)/48000; - s32 t2l = ((t1l+a2l)*acc)/48000; - s32 t2r = ((t1r+a2r)*acc)/48000; - s32 t3l = ((t2l+a3l)); - s32 t3r = ((t2r+a3r)); - - DataL = t3l; - DataR = t3r; - } - - int l = DataL, r = DataR; - if (l < -32767) l = -32767; - if (r < -32767) r = -32767; - if (l > 32767) l = 32767; - if (r > 32767) r = 32767; - sample_queue.push(l); - sample_queue.push(r); - m_queueSize += 2; - } -*/ + static u32 frac = 0; + const u32 ratio = (u32)( 65536.0f * 32000.0f / (float)m_sampleRate ); + + for (u32 i = 0; i < numLeft * 2; i+=2) { + u32 m_indexR2 = m_indexR + 2; //next sample + if ((m_indexR2 & INDEX_MASK) == (m_indexW & INDEX_MASK)) //..if it exists + m_indexR2 = m_indexR; + + + s16 l1 = Common::swap16(m_buffer[m_indexR & INDEX_MASK]); //current + s16 l2 = Common::swap16(m_buffer[m_indexR2 & INDEX_MASK]); //next + int sampleL = (l1 << 16) + (l2 - l1) * (u16)frac >> 16; + samples[i] = sampleL; + + s16 r1 = Common::swap16(m_buffer[(m_indexR + 1) & INDEX_MASK]); //current + s16 r2 = Common::swap16(m_buffer[(m_indexR2 + 1) & INDEX_MASK]); //next + int sampleR = (r1 << 16) + (r2 - r1) * (u16)frac >> 16; + samples[i+1] = sampleR; + + frac += ratio; + m_indexR += 2 * (u16)(frac >> 16); + frac &= 0xffff; + } } + + } else { numLeft = 0; } @@ -154,7 +119,7 @@ void CMixer::PushSamples(short *samples, unsigned int num_samples) if (m_throttle) { // The auto throttle function. This loop will put a ceiling on the CPU MHz. - while (Common::AtomicLoad(m_numSamples) >= MAX_SAMPLES - RESERVED_SAMPLES) + while (Common::AtomicLoad(m_numSamples) + RESERVED_SAMPLES >= MAX_SAMPLES) { if (g_dspInitialize.pEmulatorState) { @@ -171,7 +136,7 @@ void CMixer::PushSamples(short *samples, unsigned int num_samples) } // Check if we have enough free space - if (num_samples > MAX_SAMPLES - Common::AtomicLoad(m_numSamples)) + if (num_samples + Common::AtomicLoad(m_numSamples) > MAX_SAMPLES) return; // AyuanX: Actual re-sampling work has been moved to sound thread @@ -190,12 +155,12 @@ void CMixer::PushSamples(short *samples, unsigned int num_samples) m_indexW += num_samples * 2; - if (m_sampleRate != 32000) - { - PanicAlert("Mixer: Up-sampling is not implemented yet!"); - } - - Common::AtomicAdd(m_numSamples, num_samples); + if (m_sampleRate == 32000) + Common::AtomicAdd(m_numSamples, num_samples); + else if (m_sampleRate == 48000) + Common::AtomicAdd(m_numSamples, num_samples * 1.5); + else + PanicAlert("Mixer: Unsupported sample rate."); return; } diff --git a/Source/Core/AudioCommon/Src/Mixer.h b/Source/Core/AudioCommon/Src/Mixer.h index dfa4d41828..984ec1c211 100644 --- a/Source/Core/AudioCommon/Src/Mixer.h +++ b/Source/Core/AudioCommon/Src/Mixer.h @@ -26,7 +26,7 @@ class CMixer { public: - CMixer(unsigned int AISampleRate = 48000, unsigned int DACSampleRate = 48000) + CMixer(unsigned int AISampleRate = 48000, unsigned int DACSampleRate = 48000, unsigned int BackendSampleRate = 32000) : m_aiSampleRate(AISampleRate) , m_dacSampleRate(DACSampleRate) , m_bits(16) @@ -39,9 +39,8 @@ public: { // AyuanX: The internal (Core & DSP) sample rate is fixed at 32KHz // So when AI/DAC sample rate differs than 32KHz, we have to do re-sampling - // I prefer speed so let's do down-sampling instead of up-sampling - // If you like better sound than speed, feel free to implement the up-sampling code - m_sampleRate = 32000; + m_sampleRate = BackendSampleRate; + INFO_LOG(AUDIO_INTERFACE, "Mixer is initialized (AISampleRate:%i, DACSampleRate:%i)", AISampleRate, DACSampleRate); } diff --git a/Source/Core/Core/Src/HW/AudioInterface.cpp b/Source/Core/Core/Src/HW/AudioInterface.cpp index 2a3bfdfcdd..1aceee6653 100644 --- a/Source/Core/Core/Src/HW/AudioInterface.cpp +++ b/Source/Core/Core/Src/HW/AudioInterface.cpp @@ -281,17 +281,11 @@ unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples const int lvolume = g_AudioRegister.m_Volume.leftVolume; const int rvolume = g_AudioRegister.m_Volume.rightVolume; - if (g_AISampleRate == 48000 && _sampleRate == 32000) { _dbg_assert_msg_(AUDIO_INTERFACE, !(_numSamples & 1), "Number of Samples: %i must be even!", _numSamples); _numSamples = _numSamples * 3 / 2; } - else if (g_AISampleRate == 32000 && _sampleRate == 48000) - { - // AyuanX: Up-sampling is not implemented yet - PanicAlert("AUDIO_INTERFACE: Up-sampling is not implemented yet!"); - } int pcm_l = 0, pcm_r = 0; for (unsigned int i = 0; i < _numSamples; i++) @@ -299,45 +293,82 @@ unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples if (pos == 0) ReadStreamBlock(pcm); - if (g_AISampleRate == 48000 && _sampleRate == 32000) + if (g_AISampleRate == 48000 && _sampleRate == 32000) //downsample 48>32 { if (i % 3) { pcm_l = (((pcm_l + (int)pcm[pos*2]) / 2 * lvolume) >> 8) + (int)(*_pDestBuffer); - if (pcm_l > 32767) - pcm_l = 32767; - else if (pcm_l < -32767) - pcm_l = -32767; + if (pcm_l > 32767) pcm_l = 32767; + else if (pcm_l < -32767) pcm_l = -32767; *_pDestBuffer++ = pcm_l; pcm_r = (((pcm_r + (int)pcm[pos*2+1]) / 2 * rvolume) >> 8) + (int)(*_pDestBuffer); - if (pcm_r > 32767) - pcm_r = 32767; - else if (pcm_r < -32767) - pcm_r = -32767; + if (pcm_r > 32767) pcm_r = 32767; + else if (pcm_r < -32767) pcm_r = -32767; *_pDestBuffer++ = pcm_r; } pcm_l = pcm[pos*2]; pcm_r = pcm[pos*2+1]; + + pos++; } - else + else if (g_AISampleRate == 32000 && _sampleRate == 48000) //upsample 32>48 { + //starts with one sample of 0 + const u32 ratio = (u32)( 65536.0f * 32000.0f / (float)_sampleRate ); + static u32 frac = 0; + + static s16 l1 = 0; + static s16 l2 = 0; + static s16 r1 = 0; + static s16 r2 = 0; + + + if ( frac >= 0x10000 || frac == 0) + { + frac &= 0xffff; + + l1 = l2; //current + l2 = pcm[pos * 2]; //next + + r1 = r2; //current + r2 = pcm[pos * 2 + 1]; //next + } + + pcm_l = (l1 << 16) + (l2 - l1) * (u16)frac >> 16; + pcm_r = (l1 << 16) + (l2 - l1) * (u16)frac >> 16; + + + pcm_l = (pcm_l * lvolume >> 8) + (int)(*_pDestBuffer); + if (pcm_l > 32767) pcm_l = 32767; + else if (pcm_l < -32767) pcm_l = -32767; + *_pDestBuffer++ = pcm_l; + + pcm_r = (pcm_r * lvolume >> 8) + (int)(*_pDestBuffer); + if (pcm_r > 32767) pcm_r = 32767; + else if (pcm_r < -32767) pcm_r = -32767; + *_pDestBuffer++ = pcm_r; + + frac += ratio; + pos += frac >> 16; + + } + else //1:1 no resampling + { pcm_l = (((int)pcm[pos*2] * lvolume) >> 8) + (int)(*_pDestBuffer); - if (pcm_l > 32767) - pcm_l = 32767; - else if (pcm_l < -32767) - pcm_l = -32767; + if (pcm_l > 32767) pcm_l = 32767; + else if (pcm_l < -32767) pcm_l = -32767; *_pDestBuffer++ = pcm_l; pcm_r = (((int)pcm[pos*2+1] * rvolume) >> 8) + (int)(*_pDestBuffer); - if (pcm_r > 32767) - pcm_r = 32767; - else if (pcm_r < -32767) - pcm_r = -32767; + if (pcm_r > 32767) pcm_r = 32767; + else if (pcm_r < -32767) pcm_r = -32767; *_pDestBuffer++ = pcm_r; + + pos++; } - if (++pos == 28) + if (pos == 28) pos = 0; } } diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/ConfigDlg.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/ConfigDlg.cpp index 8619a25118..ab9d810b8b 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/ConfigDlg.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/ConfigDlg.cpp @@ -23,6 +23,7 @@ BEGIN_EVENT_TABLE(DSPConfigDialogHLE, wxDialog) EVT_CHECKBOX(ID_ENABLE_HLE_AUDIO, DSPConfigDialogHLE::SettingsChanged) EVT_CHECKBOX(ID_ENABLE_DTK_MUSIC, DSPConfigDialogHLE::SettingsChanged) EVT_CHECKBOX(ID_ENABLE_THROTTLE, DSPConfigDialogHLE::SettingsChanged) + EVT_CHOICE(ID_FREQUENCY, DSPConfigDialogHLE::SettingsChanged) EVT_CHOICE(ID_BACKEND, DSPConfigDialogHLE::BackendChanged) EVT_COMMAND_SCROLL(ID_VOLUME, DSPConfigDialogHLE::VolumeChanged) END_EVENT_TABLE() @@ -44,6 +45,12 @@ DSPConfigDialogHLE::DSPConfigDialogHLE(wxWindow *parent, wxWindowID id, wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_buttonEnableThrottle = new wxCheckBox(this, ID_ENABLE_THROTTLE, wxT("Enable Audio Throttle"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + + wxStaticText *FrequencyText = new wxStaticText(this, wxID_ANY, wxT("Sample Rate"), + wxDefaultPosition, wxDefaultSize, 0); + m_FrequencySelection = new wxChoice(this, ID_FREQUENCY, wxDefaultPosition, wxSize(110, 20), + wxArrayRates, 0, wxDefaultValidator, wxEmptyString); + wxStaticText *BackendText = new wxStaticText(this, wxID_ANY, wxT("Audio Backend"), wxDefaultPosition, wxDefaultSize, 0); m_BackendSelection = new wxChoice(this, ID_BACKEND, wxDefaultPosition, wxSize(110, 20), @@ -67,22 +74,41 @@ DSPConfigDialogHLE::DSPConfigDialogHLE(wxWindow *parent, wxWindowID id, wxT("Disabling this could cause abnormal game speed, such as too fast.\n") wxT("But sometimes enabling this could cause constant noise.\n") wxT("\nKeyboard Shortcut : Hold down to instantly disable Throttle.")); + m_FrequencySelection-> + SetToolTip(wxT("Changing this will have no effect while the emulator is running!")); m_BackendSelection-> SetToolTip(wxT("Changing this will have no effect while the emulator is running!")); - m_volumeSlider->SetToolTip(wxT("This setting only affects DSound, OpenAL, and PulseAudio.")); + m_volumeSlider->SetToolTip(wxT("This setting only affects DSound, OpenAL, XAudio2, and PulseAudio.")); // Create sizer and add items to dialog wxBoxSizer *sMain = new wxBoxSizer(wxVERTICAL); wxBoxSizer *sSettings = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer *sBackend = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer *sBackend = new wxBoxSizer(wxVERTICAL); + wxBoxSizer *sFrequency = new wxBoxSizer(wxVERTICAL); wxBoxSizer *sButtons = new wxBoxSizer(wxHORIZONTAL); sbSettings->Add(m_buttonEnableHLEAudio, 0, wxALL, 5); sbSettings->Add(m_buttonEnableDTKMusic, 0, wxALL, 5); sbSettings->Add(m_buttonEnableThrottle, 0, wxALL, 5); - sBackend->Add(BackendText, 0, wxALIGN_CENTER|wxALL, 5); + + sFrequency->Add(FrequencyText, 0, wxALIGN_LEFT|wxALL, 1); + sFrequency->Add(m_FrequencySelection, 0, wxALL, 1); + + m_FrequencySelection->Append(wxString::FromAscii("48,000 Hz")); + m_FrequencySelection->Append(wxString::FromAscii("32,000 Hz")); + #ifdef __APPLE__ + int num = m_FrequencySelection->FindString(wxString::FromAscii(ac_Config.sFrequency)); + #else + int num = m_FrequencySelection->FindString(wxString::FromAscii(ac_Config.sFrequency.c_str())); + #endif + m_FrequencySelection->SetSelection(num); + + sbSettings->Add(sFrequency, 0, wxALL, 7); + + + sBackend->Add(BackendText, 0, wxALIGN_LEFT|wxALL, 1); sBackend->Add(m_BackendSelection, 0, wxALL, 1); - sbSettings->Add(sBackend, 0, wxALL, 2); + sbSettings->Add(sBackend, 0, wxALL, 7); sbSettingsV->Add(m_volumeSlider, 1, wxLEFT|wxRIGHT|wxALIGN_CENTER, 6); sbSettingsV->Add(m_volumeText, 0, wxALL|wxALIGN_LEFT, 4); @@ -138,8 +164,10 @@ void DSPConfigDialogHLE::SettingsChanged(wxCommandEvent& event) #ifdef __APPLE__ strncpy(ac_Config.sBackend, m_BackendSelection->GetStringSelection().mb_str(), 128); + strncpy(ac_Config.sFrequency, m_FrequencySelection->GetStringSelection().mb_str(), 128); #else ac_Config.sBackend = m_BackendSelection->GetStringSelection().mb_str(); + ac_Config.sFrequency = m_FrequencySelection->GetStringSelection().mb_str(); #endif ac_Config.Update(); g_Config.Save(); diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/ConfigDlg.h b/Source/Plugins/Plugin_DSP_HLE/Src/ConfigDlg.h index 7c606333ab..48634699cc 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/ConfigDlg.h +++ b/Source/Plugins/Plugin_DSP_HLE/Src/ConfigDlg.h @@ -46,13 +46,16 @@ private: wxCheckBox* m_buttonEnableDTKMusic; wxCheckBox* m_buttonEnableThrottle; wxArrayString wxArrayBackends; + wxArrayString wxArrayRates; wxChoice* m_BackendSelection; + wxChoice* m_FrequencySelection; enum { ID_ENABLE_HLE_AUDIO, ID_ENABLE_DTK_MUSIC, ID_ENABLE_THROTTLE, + ID_FREQUENCY, ID_BACKEND, ID_VOLUME }; diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.h b/Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.h index 575ea618e6..a407147373 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.h +++ b/Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.h @@ -6,8 +6,8 @@ class HLEMixer : public CMixer { public: - HLEMixer(unsigned int AISampleRate = 48000, unsigned int DACSampleRate = 48000) - : CMixer(AISampleRate, DACSampleRate) {}; + HLEMixer(unsigned int AISampleRate = 48000, unsigned int DACSampleRate = 48000, unsigned int BackendSampleRate = 32000) + : CMixer(AISampleRate, DACSampleRate, BackendSampleRate) {}; virtual void Premix(short *samples, unsigned int numSamples); }; diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/main.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/main.cpp index 4482c2370b..0cc39408de 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/main.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/main.cpp @@ -250,9 +250,15 @@ unsigned short DSP_WriteControlRegister(unsigned short _Value) { if (!Temp.DSPHalt && Temp.DSPInit) { - unsigned int AISampleRate, DACSampleRate; + unsigned int AISampleRate, DACSampleRate, BackendSampleRate; g_dspInitialize.pGetSampleRate(AISampleRate, DACSampleRate); - soundStream = AudioCommon::InitSoundStream(new HLEMixer(AISampleRate, DACSampleRate)); + std::string frequency = ac_Config.sFrequency; + if (frequency == "48,000 Hz") + BackendSampleRate = 48000; + else + BackendSampleRate = 32000; + + soundStream = AudioCommon::InitSoundStream(new HLEMixer(AISampleRate, DACSampleRate, BackendSampleRate)); if(!soundStream) PanicAlert("Error starting up sound stream"); // Mixer is initialized g_InitMixer = true;