diff options
-rw-r--r-- | language/English/strings.po | 10 | ||||
-rw-r--r-- | system/settings/rbp.xml | 4 | ||||
-rw-r--r-- | xbmc/cores/omxplayer/OMXAudio.cpp | 180 | ||||
-rw-r--r-- | xbmc/cores/omxplayer/OMXAudio.h | 6 | ||||
-rw-r--r-- | xbmc/cores/omxplayer/OMXPlayer.cpp | 6 | ||||
-rw-r--r-- | xbmc/cores/omxplayer/OMXPlayerAudio.h | 1 |
6 files changed, 142 insertions, 65 deletions
diff --git a/language/English/strings.po b/language/English/strings.po index 3f957b07d7..0e7ecd5529 100644 --- a/language/English/strings.po +++ b/language/English/strings.po @@ -14337,6 +14337,11 @@ msgctxt "#36542" msgid "Output to both analogue (headphones) and HDMI" msgstr "" +#: system/settings/rbp.xml +msgctxt "#36543" +msgid "Enable this to make dialogue louder compared to background sounds when downmixing multichannel audio" +msgstr "" + #reserved strings 365XX #: xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamNavigator.cpp @@ -14390,3 +14395,8 @@ msgstr "" msgctxt "#37017" msgid "Dual audio output" msgstr "" + +#: system/settings/rbp.xml +msgctxt "#37018" +msgid "Boost centre channel when downmixing" +msgstr "" diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml index 5293091a0f..ddd6635bb6 100644 --- a/system/settings/rbp.xml +++ b/system/settings/rbp.xml @@ -88,6 +88,10 @@ <level>2</level> <default>false</default> </setting> + <setting id="audiooutput.boostcentre" type="boolean" label="37018" help="36543"> + <level>2</level> + <default>false</default> + </setting> </group> <group id="2"> <visible>false</visible> diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp index d2864b947e..cbf04ef648 100644 --- a/xbmc/cores/omxplayer/OMXAudio.cpp +++ b/xbmc/cores/omxplayer/OMXAudio.cpp @@ -89,6 +89,19 @@ const float downmixing_coefficients_8[OMX_AUDIO_MAXCHANNELS] = { /* Rr */ 0, 0.7071 }; +// 7.1 downmixing coefficients with boosted centre channel +const float downmixing_coefficients_8_boostcentre[OMX_AUDIO_MAXCHANNELS] = { + // L R + /* L */ 0.7071, 0, + /* R */ 0, 0.7071, + /* C */ 1, 1, + /* LFE */ 0.7071, 0.7071, + /* Ls */ 0.7071, 0, + /* Rs */ 0, 0.7071, + /* Lr */ 0.7071, 0, + /* Rr */ 0, 0.7071 +}; + ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// @@ -106,6 +119,10 @@ COMXAudio::COMXAudio() : m_ChunkLen (0 ), m_OutputChannels (0 ), m_BitsPerSample (0 ), + m_maxLevel (0.0f ), + m_amplification (1.0f ), + m_attenuation (1.0f ), + m_desired_attenuation(1.0f), m_omx_clock (NULL ), m_av_clock (NULL ), m_settings_changed(false ), @@ -200,6 +217,7 @@ bool COMXAudio::PortSettingsChanged() return false; } + SetDynamicRangeCompression((long)(CMediaSettings::Get().GetCurrentVideoSettings().m_VolumeAmplification * 100)); ApplyVolume(); if( m_omx_mixer.IsInitialized() ) @@ -518,7 +536,10 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo memset(&m_wave_header, 0x0, sizeof(m_wave_header)); for(int i = 0; i < OMX_AUDIO_MAXCHANNELS; i++) + { m_pcm_input.eChannelMapping[i] = OMX_AUDIO_ChannelNone; + m_input_channels[i] = OMX_AUDIO_ChannelMax; + } m_output_channels[0] = OMX_AUDIO_ChannelLF; m_output_channels[1] = OMX_AUDIO_ChannelRF; @@ -846,6 +867,10 @@ void COMXAudio::Flush() //*********************************************************************************************** void COMXAudio::SetDynamicRangeCompression(long drc) { + CSingleLock lock (m_critSection); + m_amplification = powf(10.0f, (float)drc / 2000.0f); + if (m_settings_changed) + ApplyVolume(); } //*********************************************************************************************** @@ -876,87 +901,68 @@ bool COMXAudio::ApplyVolume(void) float fVolume = m_Mute ? VOLUME_MINIMUM : m_CurrentVolume; + // the analogue volume is too quiet for some. Allow use of an advancedsetting to boost this (at risk of distortion) (deprecated) double gain = pow(10, (g_advancedSettings.m_ac3Gain - 12.0f) / 20.0); + double r = 1.0; + const float* coeff = downmixing_coefficients_8; - if (m_format.m_channelLayout.Count() > 2) - { - double r = fVolume; - const float* coeff = downmixing_coefficients_8; + // alternate coffeciciants that boost centre channel more + if(!CSettings::Get().GetBool("audiooutput.boostcentre")) + coeff = downmixing_coefficients_8_boostcentre; - // normally we normalalise the levels, can be skipped (boosted) at risk of distortion - if(!CSettings::Get().GetBool("audiooutput.normalizelevels")) + // normally we normalise the levels, can be skipped (boosted) at risk of distortion + if(!CSettings::Get().GetBool("audiooutput.normalizelevels")) + { + double sum_L = 0; + double sum_R = 0; + for(size_t i = 0; i < OMX_AUDIO_MAXCHANNELS; ++i) { - double sum_L = 0; - double sum_R = 0; + if (m_input_channels[i] == OMX_AUDIO_ChannelMax) + break; + if(i & 1) + sum_R += coeff[i]; + else + sum_L += coeff[i]; + } - for(size_t i = 0; i < OMX_AUDIO_MAXCHANNELS; ++i) - { - if (m_input_channels[i] == OMX_AUDIO_ChannelMax) - break; - if(i & 1) - sum_R += coeff[i]; - else - sum_L += coeff[i]; - } + r /= max(sum_L, sum_R); + } + r *= gain; - r /= max(sum_L, sum_R); - } + OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS mix; + OMX_INIT_STRUCTURE(mix); + OMX_ERRORTYPE omx_err; - // the analogue volume is too quiet for some. Allow use of an advancedsetting to boost this (at risk of distortion) - r *= gain; + assert(sizeof(mix.coeff)/sizeof(mix.coeff[0]) == 16); - OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS mix; - OMX_INIT_STRUCTURE(mix); - mix.nPortIndex = m_omx_mixer.GetInputPort(); + // reduce scaling so overflow can be seen + for(size_t i = 0; i < 16; ++i) + mix.coeff[i] = static_cast<unsigned int>(0x10000 * (coeff[i] * r * 0.01f)); - assert(sizeof(mix.coeff)/sizeof(mix.coeff[0]) == 16); + mix.nPortIndex = m_omx_decoder.GetInputPort(); + omx_err = m_omx_decoder.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients, &mix); + if(omx_err != OMX_ErrorNone) + { + CLog::Log(LOGERROR, "%s::%s - error setting decoder OMX_IndexConfigBrcmAudioDownmixCoefficients, error 0x%08x\n", + CLASSNAME, __func__, omx_err); + return false; + } + if (m_amplification != 1.0) + { for(size_t i = 0; i < 16; ++i) - mix.coeff[i] = static_cast<unsigned int>(0x10000 * (coeff[i] * r)); - - OMX_ERRORTYPE omx_err = - m_omx_mixer.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients, &mix); + mix.coeff[i] = static_cast<unsigned int>(0x10000 * (coeff[i] * r * fVolume * m_amplification * m_attenuation)); + mix.nPortIndex = m_omx_mixer.GetInputPort(); + omx_err = m_omx_mixer.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients, &mix); if(omx_err != OMX_ErrorNone) { - CLog::Log(LOGERROR, "%s::%s - error setting OMX_IndexConfigBrcmAudioDownmixCoefficients, error 0x%08x\n", + CLog::Log(LOGERROR, "%s::%s - error setting mixer OMX_IndexConfigBrcmAudioDownmixCoefficients, error 0x%08x\n", CLASSNAME, __func__, omx_err); return false; } } - else - { - OMX_AUDIO_CONFIG_VOLUMETYPE volume; - OMX_INIT_STRUCTURE(volume); - - volume.bLinear = OMX_TRUE; - float hardwareVolume = fVolume * gain * 100.0f; - volume.sVolume.nValue = (int)(hardwareVolume + 0.5f); - - if(m_omx_render_analog.IsInitialized()) - { - volume.nPortIndex = m_omx_render_analog.GetInputPort(); - OMX_ERRORTYPE omx_err = m_omx_render_analog.SetConfig(OMX_IndexConfigAudioVolume, &volume); - if(omx_err != OMX_ErrorNone) - { - CLog::Log(LOGERROR, "%s::%s - error setting OMX_IndexConfigAudioVolume, error 0x%08x\n", - CLASSNAME, __func__, omx_err); - return false; - } - } - if(m_omx_render_hdmi.IsInitialized()) - { - volume.nPortIndex = m_omx_render_hdmi.GetInputPort(); - OMX_ERRORTYPE omx_err = m_omx_render_hdmi.SetConfig(OMX_IndexConfigAudioVolume, &volume); - if(omx_err != OMX_ErrorNone) - { - CLog::Log(LOGERROR, "%s::%s - error setting OMX_IndexConfigAudioVolume, error 0x%08x\n", - CLASSNAME, __func__, omx_err); - return false; - } - } - } - CLog::Log(LOGINFO, "%s::%s - Volume=%.2f\n", CLASSNAME, __func__, fVolume); + CLog::Log(LOGINFO, "%s::%s - Volume=%.2f (* %.2f * %.2f)\n", CLASSNAME, __func__, fVolume, m_amplification, m_attenuation); return true; } @@ -1171,6 +1177,27 @@ unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dt } } + if (m_amplification != 1.0) + { + double level_pts = 0.0; + float level = GetMaxLevel(level_pts); + if (level_pts != 0.0) + { + float alpha_h = -1.0f/(0.025f*log10f(0.999f)); + float alpha_r = -1.0f/(0.100f*log10f(0.900f)); + float hold = powf(10.0f, -1.0f / (alpha_h * g_advancedSettings.m_limiterHold)); + float release = powf(10.0f, -1.0f / (alpha_r * g_advancedSettings.m_limiterRelease)); + m_maxLevel = level > m_maxLevel ? level : hold * m_maxLevel + (1.0f-hold) * level; + + float amp = m_amplification * m_desired_attenuation; + + // want m_maxLevel * amp -> 1.0 + m_desired_attenuation = std::min(1.0f, std::max(m_desired_attenuation / (amp * m_maxLevel), 1.0f/m_amplification)); + m_attenuation = release * m_attenuation + (1.0f-release) * m_desired_attenuation; + + ApplyVolume(); + } + } return len; } @@ -1269,6 +1296,33 @@ unsigned int COMXAudio::GetAudioRenderingLatency() return param.nU32; } +float COMXAudio::GetMaxLevel(double &pts) +{ + CSingleLock lock (m_critSection); + + if(!m_Initialized) + return 0; + + OMX_CONFIG_BRCMAUDIOMAXSAMPLE param; + OMX_INIT_STRUCTURE(param); + + if(m_omx_decoder.IsInitialized()) + { + param.nPortIndex = m_omx_decoder.GetInputPort(); + + OMX_ERRORTYPE omx_err = m_omx_decoder.GetConfig(OMX_IndexConfigBrcmAudioMaxSample, ¶m); + + if(omx_err != OMX_ErrorNone) + { + CLog::Log(LOGERROR, "%s::%s - error getting OMX_IndexConfigBrcmAudioMaxSample error 0x%08x\n", + CLASSNAME, __func__, omx_err); + return 0; + } + } + pts = FromOMXTime(param.nTimeStamp); + return (float)param.nMaxSample * (100.0f / (1<<15)); +} + void COMXAudio::SubmitEOS() { CSingleLock lock (m_critSection); diff --git a/xbmc/cores/omxplayer/OMXAudio.h b/xbmc/cores/omxplayer/OMXAudio.h index 09993e6ba0..f287b0a277 100644 --- a/xbmc/cores/omxplayer/OMXAudio.h +++ b/xbmc/cores/omxplayer/OMXAudio.h @@ -72,6 +72,7 @@ public: void SetVolume(float nVolume); void SetMute(bool bOnOff); void SetDynamicRangeCompression(long drc); + float GetDynamicRangeAmplification() { return 20.0f * log10f(m_amplification * m_attenuation); } bool ApplyVolume(); int SetPlaySpeed(int iSpeed); void SubmitEOS(); @@ -94,6 +95,7 @@ public: bool BadState() { return !m_Initialized; }; unsigned int GetAudioRenderingLatency(); + float GetMaxLevel(double &pts); void VizPacket(const void* data, unsigned int len, double pts); private: @@ -109,6 +111,10 @@ private: unsigned int m_ChunkLen; unsigned int m_OutputChannels; unsigned int m_BitsPerSample; + float m_maxLevel; + float m_amplification; + float m_attenuation; + float m_desired_attenuation; COMXCoreComponent *m_omx_clock; OMXClock *m_av_clock; bool m_settings_changed; diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp index dbe8ba5682..6c13e35ce5 100644 --- a/xbmc/cores/omxplayer/OMXPlayer.cpp +++ b/xbmc/cores/omxplayer/OMXPlayer.cpp @@ -2875,7 +2875,7 @@ void COMXPlayer::GetGeneralInfo(CStdString& strGeneralInfo) strBuf.AppendFormat(" %d sec", DVD_TIME_TO_SEC(m_State.cache_delay)); } - strGeneralInfo.Format("C( ad:% 6.3f, a/v:% 6.3f%s, dcpu:%2i%% acpu:%2i%% vcpu:%2i%%%s af:%d%% vf:%d%% )" + strGeneralInfo.Format("C( ad:% 6.3f a/v:% 6.3f%s, dcpu:%2i%% acpu:%2i%% vcpu:%2i%%%s af:%d%% vf:%d%% amp:% 5.2f )" , m_omxPlayerAudio.GetDelay() , dDiff , strEDL.c_str() @@ -2884,7 +2884,8 @@ void COMXPlayer::GetGeneralInfo(CStdString& strGeneralInfo) , (int)(m_omxPlayerVideo.GetRelativeUsage()*100) , strBuf.c_str() , m_audio_fifo - , m_video_fifo); + , m_video_fifo + , m_omxPlayerAudio.GetDynamicRangeAmplification()); } } @@ -4464,6 +4465,7 @@ void COMXPlayer::GetAudioCapabilities(std::vector<int> &audioCaps) audioCaps.push_back(IPC_AUD_OFFSET); audioCaps.push_back(IPC_AUD_SELECT_STREAM); audioCaps.push_back(IPC_AUD_SELECT_OUTPUT); + audioCaps.push_back(IPC_AUD_AMP); } void COMXPlayer::GetSubtitleCapabilities(std::vector<int> &subCaps) diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.h b/xbmc/cores/omxplayer/OMXPlayerAudio.h index fd8873bccd..19f50f7b7f 100644 --- a/xbmc/cores/omxplayer/OMXPlayerAudio.h +++ b/xbmc/cores/omxplayer/OMXPlayerAudio.h @@ -112,6 +112,7 @@ public: void SetVolume(float fVolume) { m_omxAudio.SetVolume(fVolume); } void SetMute(bool bOnOff) { m_omxAudio.SetMute(bOnOff); } void SetDynamicRangeCompression(long drc) { m_omxAudio.SetDynamicRangeCompression(drc); } + float GetDynamicRangeAmplification() { return m_omxAudio.GetDynamicRangeAmplification(); } void SetSpeed(int iSpeed); int GetAudioBitrate(); std::string GetPlayerInfo(); |