Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[rbp/omxplayer] Add Dynamic Range Compression scheme

This adds a DRC scheme. A number of dBs of amplification can be chosen.
The audio_decode component is setup to do the usual downmix operation early
before most of the audio buffering. This means we get a second or two to
detect if the downmix would overflow. This allows the amplification to be
attenuated in time to avoid the clipping.
The attenuation gradually decays when overflow condition stops.

Also adds a gui setting to boost centre channel.

Requires updated firmware
  • Loading branch information...
commit 6e4103ba98d8fa2b5c91c59e477a77691fc6c53b 1 parent 5f6255f
popcornmix popcornmix authored
10 language/English/strings.po
View
@@ -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 ""
4 system/settings/rbp.xml
View
@@ -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>
180 xbmc/cores/omxplayer/OMXAudio.cpp
View
@@ -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, &param);
+
+ 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);
6 xbmc/cores/omxplayer/OMXAudio.h
View
@@ -72,6 +72,7 @@ class COMXAudio
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 @@ class COMXAudio
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 @@ class COMXAudio
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;
6 xbmc/cores/omxplayer/OMXPlayer.cpp
View
@@ -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)
1  xbmc/cores/omxplayer/OMXPlayerAudio.h
View
@@ -112,6 +112,7 @@ class OMXPlayerAudio : public CThread
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();
Please sign in to comment.
Something went wrong with that request. Please try again.