Skip to content
This repository
Browse code

[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 authored September 04, 2013
10  language/English/strings.po
@@ -14337,6 +14337,11 @@ msgctxt "#36542"
14337 14337
 msgid "Output to both analogue (headphones) and HDMI"
14338 14338
 msgstr ""
14339 14339
 
  14340
+#: system/settings/rbp.xml
  14341
+msgctxt "#36543"
  14342
+msgid "Enable this to make dialogue louder compared to background sounds when downmixing multichannel audio"
  14343
+msgstr ""
  14344
+
14340 14345
 #reserved strings 365XX
14341 14346
 
14342 14347
 #: xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamNavigator.cpp
@@ -14390,3 +14395,8 @@ msgstr ""
14390 14395
 msgctxt "#37017"
14391 14396
 msgid "Dual audio output"
14392 14397
 msgstr ""
  14398
+
  14399
+#: system/settings/rbp.xml
  14400
+msgctxt "#37018"
  14401
+msgid "Boost centre channel when downmixing"
  14402
+msgstr ""
4  system/settings/rbp.xml
@@ -88,6 +88,10 @@
88 88
           <level>2</level>
89 89
           <default>false</default>
90 90
         </setting>
  91
+        <setting id="audiooutput.boostcentre" type="boolean" label="37018" help="36543">
  92
+          <level>2</level>
  93
+          <default>false</default>
  94
+        </setting>
91 95
       </group>
92 96
       <group id="2">
93 97
         <visible>false</visible>
180  xbmc/cores/omxplayer/OMXAudio.cpp
@@ -89,6 +89,19 @@ const float downmixing_coefficients_8[OMX_AUDIO_MAXCHANNELS] = {
89 89
   /* Rr */  0,      0.7071
90 90
 };
91 91
 
  92
+// 7.1 downmixing coefficients with boosted centre channel
  93
+const float downmixing_coefficients_8_boostcentre[OMX_AUDIO_MAXCHANNELS] = {
  94
+  //        L       R
  95
+  /* L */   0.7071, 0,
  96
+  /* R */   0,      0.7071,
  97
+  /* C */   1,      1,
  98
+  /* LFE */ 0.7071, 0.7071,
  99
+  /* Ls */  0.7071, 0,
  100
+  /* Rs */  0,      0.7071,
  101
+  /* Lr */  0.7071, 0,
  102
+  /* Rr */  0,      0.7071
  103
+};
  104
+
92 105
 //////////////////////////////////////////////////////////////////////
93 106
 // Construction/Destruction
94 107
 //////////////////////////////////////////////////////////////////////
@@ -106,6 +119,10 @@ COMXAudio::COMXAudio() :
106 119
   m_ChunkLen        (0      ),
107 120
   m_OutputChannels  (0      ),
108 121
   m_BitsPerSample   (0      ),
  122
+  m_maxLevel        (0.0f   ),
  123
+  m_amplification   (1.0f   ),
  124
+  m_attenuation     (1.0f   ),
  125
+  m_desired_attenuation(1.0f),
109 126
   m_omx_clock       (NULL   ),
110 127
   m_av_clock        (NULL   ),
111 128
   m_settings_changed(false  ),
@@ -200,6 +217,7 @@ bool COMXAudio::PortSettingsChanged()
200 217
       return false;
201 218
   }
202 219
 
  220
+  SetDynamicRangeCompression((long)(CMediaSettings::Get().GetCurrentVideoSettings().m_VolumeAmplification * 100));
203 221
   ApplyVolume();
204 222
 
205 223
   if( m_omx_mixer.IsInitialized() )
@@ -518,7 +536,10 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
518 536
   memset(&m_wave_header, 0x0, sizeof(m_wave_header));
519 537
 
520 538
   for(int i = 0; i < OMX_AUDIO_MAXCHANNELS; i++)
  539
+  {
521 540
     m_pcm_input.eChannelMapping[i] = OMX_AUDIO_ChannelNone;
  541
+    m_input_channels[i] = OMX_AUDIO_ChannelMax;
  542
+  }
522 543
 
523 544
   m_output_channels[0] = OMX_AUDIO_ChannelLF;
524 545
   m_output_channels[1] = OMX_AUDIO_ChannelRF;
@@ -846,6 +867,10 @@ void COMXAudio::Flush()
846 867
 //***********************************************************************************************
847 868
 void COMXAudio::SetDynamicRangeCompression(long drc)
848 869
 {
  870
+  CSingleLock lock (m_critSection);
  871
+  m_amplification = powf(10.0f, (float)drc / 2000.0f);
  872
+  if (m_settings_changed)
  873
+    ApplyVolume();
849 874
 }
850 875
 
851 876
 //***********************************************************************************************
@@ -876,87 +901,68 @@ bool COMXAudio::ApplyVolume(void)
876 901
 
877 902
   float fVolume = m_Mute ? VOLUME_MINIMUM : m_CurrentVolume;
878 903
 
  904
+  // the analogue volume is too quiet for some. Allow use of an advancedsetting to boost this (at risk of distortion) (deprecated)
879 905
   double gain = pow(10, (g_advancedSettings.m_ac3Gain - 12.0f) / 20.0);
  906
+  double r = 1.0;
  907
+  const float* coeff = downmixing_coefficients_8;
880 908
 
881  
-  if (m_format.m_channelLayout.Count() > 2)
882  
-  {
883  
-    double r = fVolume;
884  
-    const float* coeff = downmixing_coefficients_8;
  909
+  // alternate coffeciciants that boost centre channel more
  910
+  if(!CSettings::Get().GetBool("audiooutput.boostcentre"))
  911
+    coeff = downmixing_coefficients_8_boostcentre;
885 912
 
886  
-    // normally we normalalise the levels, can be skipped (boosted) at risk of distortion
887  
-    if(!CSettings::Get().GetBool("audiooutput.normalizelevels"))
  913
+  // normally we normalise the levels, can be skipped (boosted) at risk of distortion
  914
+  if(!CSettings::Get().GetBool("audiooutput.normalizelevels"))
  915
+  {
  916
+    double sum_L = 0;
  917
+    double sum_R = 0;
  918
+    for(size_t i = 0; i < OMX_AUDIO_MAXCHANNELS; ++i)
888 919
     {
889  
-      double sum_L = 0;
890  
-      double sum_R = 0;
  920
+      if (m_input_channels[i] == OMX_AUDIO_ChannelMax)
  921
+        break;
  922
+      if(i & 1)
  923
+        sum_R += coeff[i];
  924
+      else
  925
+        sum_L += coeff[i];
  926
+    }
891 927
 
892  
-      for(size_t i = 0; i < OMX_AUDIO_MAXCHANNELS; ++i)
893  
-      {
894  
-        if (m_input_channels[i] == OMX_AUDIO_ChannelMax)
895  
-          break;
896  
-        if(i & 1)
897  
-          sum_R += coeff[i];
898  
-        else
899  
-          sum_L += coeff[i];
900  
-      }
  928
+    r /= max(sum_L, sum_R);
  929
+  }
  930
+  r *= gain;
901 931
 
902  
-      r /= max(sum_L, sum_R);
903  
-    }
  932
+  OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS mix;
  933
+  OMX_INIT_STRUCTURE(mix);
  934
+  OMX_ERRORTYPE omx_err;
904 935
 
905  
-    // the analogue volume is too quiet for some. Allow use of an advancedsetting to boost this (at risk of distortion)
906  
-    r *= gain;
  936
+  assert(sizeof(mix.coeff)/sizeof(mix.coeff[0]) == 16);
907 937
 
908  
-    OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS mix;
909  
-    OMX_INIT_STRUCTURE(mix);
910  
-    mix.nPortIndex = m_omx_mixer.GetInputPort();
  938
+  // reduce scaling so overflow can be seen
  939
+  for(size_t i = 0; i < 16; ++i)
  940
+    mix.coeff[i] = static_cast<unsigned int>(0x10000 * (coeff[i] * r * 0.01f));
911 941
 
912  
-    assert(sizeof(mix.coeff)/sizeof(mix.coeff[0]) == 16);
  942
+  mix.nPortIndex = m_omx_decoder.GetInputPort();
  943
+  omx_err = m_omx_decoder.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients, &mix);
  944
+  if(omx_err != OMX_ErrorNone)
  945
+  {
  946
+    CLog::Log(LOGERROR, "%s::%s - error setting decoder OMX_IndexConfigBrcmAudioDownmixCoefficients, error 0x%08x\n",
  947
+              CLASSNAME, __func__, omx_err);
  948
+    return false;
  949
+  }
913 950
 
  951
+  if (m_amplification != 1.0)
  952
+  {
914 953
     for(size_t i = 0; i < 16; ++i)
915  
-      mix.coeff[i] = static_cast<unsigned int>(0x10000 * (coeff[i] * r));
916  
-
917  
-    OMX_ERRORTYPE omx_err =
918  
-      m_omx_mixer.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients, &mix);
  954
+      mix.coeff[i] = static_cast<unsigned int>(0x10000 * (coeff[i] * r * fVolume * m_amplification * m_attenuation));
919 955
 
  956
+    mix.nPortIndex = m_omx_mixer.GetInputPort();
  957
+    omx_err = m_omx_mixer.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients, &mix);
920 958
     if(omx_err != OMX_ErrorNone)
921 959
     {
922  
-      CLog::Log(LOGERROR, "%s::%s - error setting OMX_IndexConfigBrcmAudioDownmixCoefficients, error 0x%08x\n",
  960
+      CLog::Log(LOGERROR, "%s::%s - error setting mixer OMX_IndexConfigBrcmAudioDownmixCoefficients, error 0x%08x\n",
923 961
                 CLASSNAME, __func__, omx_err);
924 962
       return false;
925 963
     }
926 964
   }
927  
-  else
928  
-  {
929  
-    OMX_AUDIO_CONFIG_VOLUMETYPE volume;
930  
-    OMX_INIT_STRUCTURE(volume);
931  
-
932  
-    volume.bLinear    = OMX_TRUE;
933  
-    float hardwareVolume = fVolume * gain * 100.0f;
934  
-    volume.sVolume.nValue = (int)(hardwareVolume + 0.5f);
935  
-
936  
-    if(m_omx_render_analog.IsInitialized())
937  
-    {
938  
-      volume.nPortIndex = m_omx_render_analog.GetInputPort();
939  
-      OMX_ERRORTYPE omx_err = m_omx_render_analog.SetConfig(OMX_IndexConfigAudioVolume, &volume);
940  
-      if(omx_err != OMX_ErrorNone)
941  
-      {
942  
-        CLog::Log(LOGERROR, "%s::%s - error setting OMX_IndexConfigAudioVolume, error 0x%08x\n",
943  
-                CLASSNAME, __func__, omx_err);
944  
-        return false;
945  
-      }
946  
-    }
947  
-    if(m_omx_render_hdmi.IsInitialized())
948  
-    {
949  
-      volume.nPortIndex = m_omx_render_hdmi.GetInputPort();
950  
-      OMX_ERRORTYPE omx_err = m_omx_render_hdmi.SetConfig(OMX_IndexConfigAudioVolume, &volume);
951  
-      if(omx_err != OMX_ErrorNone)
952  
-      {
953  
-        CLog::Log(LOGERROR, "%s::%s - error setting OMX_IndexConfigAudioVolume, error 0x%08x\n",
954  
-                CLASSNAME, __func__, omx_err);
955  
-        return false;
956  
-      }
957  
-    }
958  
-  }
959  
-  CLog::Log(LOGINFO, "%s::%s - Volume=%.2f\n", CLASSNAME, __func__, fVolume);
  965
+  CLog::Log(LOGINFO, "%s::%s - Volume=%.2f (* %.2f * %.2f)\n", CLASSNAME, __func__, fVolume, m_amplification, m_attenuation);
960 966
   return true;
961 967
 }
962 968
 
@@ -1171,6 +1177,27 @@ unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dt
1171 1177
     }
1172 1178
   }
1173 1179
 
  1180
+  if (m_amplification != 1.0)
  1181
+  {
  1182
+    double level_pts = 0.0;
  1183
+    float level = GetMaxLevel(level_pts);
  1184
+    if (level_pts != 0.0)
  1185
+    {
  1186
+      float alpha_h = -1.0f/(0.025f*log10f(0.999f));
  1187
+      float alpha_r = -1.0f/(0.100f*log10f(0.900f));
  1188
+      float hold    = powf(10.0f, -1.0f / (alpha_h * g_advancedSettings.m_limiterHold));
  1189
+      float release = powf(10.0f, -1.0f / (alpha_r * g_advancedSettings.m_limiterRelease));
  1190
+      m_maxLevel = level > m_maxLevel ? level : hold * m_maxLevel + (1.0f-hold) * level;
  1191
+
  1192
+      float amp = m_amplification * m_desired_attenuation;
  1193
+
  1194
+      // want m_maxLevel * amp -> 1.0
  1195
+      m_desired_attenuation = std::min(1.0f, std::max(m_desired_attenuation / (amp * m_maxLevel), 1.0f/m_amplification));
  1196
+      m_attenuation = release * m_attenuation + (1.0f-release) * m_desired_attenuation;
  1197
+
  1198
+      ApplyVolume();
  1199
+    }
  1200
+  }
1174 1201
   return len;
1175 1202
 }
1176 1203
 
@@ -1269,6 +1296,33 @@ unsigned int COMXAudio::GetAudioRenderingLatency()
1269 1296
   return param.nU32;
1270 1297
 }
1271 1298
 
  1299
+float COMXAudio::GetMaxLevel(double &pts)
  1300
+{
  1301
+  CSingleLock lock (m_critSection);
  1302
+
  1303
+  if(!m_Initialized)
  1304
+    return 0;
  1305
+
  1306
+  OMX_CONFIG_BRCMAUDIOMAXSAMPLE param;
  1307
+  OMX_INIT_STRUCTURE(param);
  1308
+
  1309
+  if(m_omx_decoder.IsInitialized())
  1310
+  {
  1311
+    param.nPortIndex = m_omx_decoder.GetInputPort();
  1312
+
  1313
+    OMX_ERRORTYPE omx_err = m_omx_decoder.GetConfig(OMX_IndexConfigBrcmAudioMaxSample, &param);
  1314
+
  1315
+    if(omx_err != OMX_ErrorNone)
  1316
+    {
  1317
+      CLog::Log(LOGERROR, "%s::%s - error getting OMX_IndexConfigBrcmAudioMaxSample error 0x%08x\n",
  1318
+        CLASSNAME, __func__, omx_err);
  1319
+      return 0;
  1320
+    }
  1321
+  }
  1322
+  pts = FromOMXTime(param.nTimeStamp);
  1323
+  return (float)param.nMaxSample * (100.0f / (1<<15));
  1324
+}
  1325
+
1272 1326
 void COMXAudio::SubmitEOS()
1273 1327
 {
1274 1328
   CSingleLock lock (m_critSection);
6  xbmc/cores/omxplayer/OMXAudio.h
@@ -72,6 +72,7 @@ class COMXAudio
72 72
   void SetVolume(float nVolume);
73 73
   void SetMute(bool bOnOff);
74 74
   void SetDynamicRangeCompression(long drc);
  75
+  float GetDynamicRangeAmplification() { return 20.0f * log10f(m_amplification * m_attenuation); }
75 76
   bool ApplyVolume();
76 77
   int SetPlaySpeed(int iSpeed);
77 78
   void SubmitEOS();
@@ -94,6 +95,7 @@ class COMXAudio
94 95
 
95 96
   bool BadState() { return !m_Initialized; };
96 97
   unsigned int GetAudioRenderingLatency();
  98
+  float GetMaxLevel(double &pts);
97 99
   void VizPacket(const void* data, unsigned int len, double pts);
98 100
 
99 101
 private:
@@ -109,6 +111,10 @@ class COMXAudio
109 111
   unsigned int  m_ChunkLen;
110 112
   unsigned int  m_OutputChannels;
111 113
   unsigned int  m_BitsPerSample;
  114
+  float         m_maxLevel;
  115
+  float         m_amplification;
  116
+  float         m_attenuation;
  117
+  float         m_desired_attenuation;
112 118
   COMXCoreComponent *m_omx_clock;
113 119
   OMXClock       *m_av_clock;
114 120
   bool          m_settings_changed;
6  xbmc/cores/omxplayer/OMXPlayer.cpp
@@ -2875,7 +2875,7 @@ void COMXPlayer::GetGeneralInfo(CStdString& strGeneralInfo)
2875 2875
         strBuf.AppendFormat(" %d sec", DVD_TIME_TO_SEC(m_State.cache_delay));
2876 2876
     }
2877 2877
 
2878  
-    strGeneralInfo.Format("C( ad:% 6.3f, a/v:% 6.3f%s, dcpu:%2i%% acpu:%2i%% vcpu:%2i%%%s af:%d%% vf:%d%% )"
  2878
+    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 )"
2879 2879
                          , m_omxPlayerAudio.GetDelay()
2880 2880
                          , dDiff
2881 2881
                          , strEDL.c_str()
@@ -2884,7 +2884,8 @@ void COMXPlayer::GetGeneralInfo(CStdString& strGeneralInfo)
2884 2884
                          , (int)(m_omxPlayerVideo.GetRelativeUsage()*100)
2885 2885
                          , strBuf.c_str()
2886 2886
                          , m_audio_fifo
2887  
-                         , m_video_fifo);
  2887
+                         , m_video_fifo
  2888
+                         , m_omxPlayerAudio.GetDynamicRangeAmplification());
2888 2889
 
2889 2890
   }
2890 2891
 }
@@ -4464,6 +4465,7 @@ void COMXPlayer::GetAudioCapabilities(std::vector<int> &audioCaps)
4464 4465
   audioCaps.push_back(IPC_AUD_OFFSET);
4465 4466
   audioCaps.push_back(IPC_AUD_SELECT_STREAM);
4466 4467
   audioCaps.push_back(IPC_AUD_SELECT_OUTPUT);
  4468
+  audioCaps.push_back(IPC_AUD_AMP);
4467 4469
 }
4468 4470
 
4469 4471
 void COMXPlayer::GetSubtitleCapabilities(std::vector<int> &subCaps)
1  xbmc/cores/omxplayer/OMXPlayerAudio.h
@@ -112,6 +112,7 @@ class OMXPlayerAudio : public CThread
112 112
   void SetVolume(float fVolume)                          { m_omxAudio.SetVolume(fVolume); }
113 113
   void SetMute(bool bOnOff)                              { m_omxAudio.SetMute(bOnOff); }
114 114
   void SetDynamicRangeCompression(long drc)              { m_omxAudio.SetDynamicRangeCompression(drc); }
  115
+  float GetDynamicRangeAmplification()                   { return m_omxAudio.GetDynamicRangeAmplification(); }
115 116
   void SetSpeed(int iSpeed);
116 117
   int  GetAudioBitrate();
117 118
   std::string GetPlayerInfo();

0 notes on commit 6e4103b

Please sign in to comment.
Something went wrong with that request. Please try again.