Merge pull request #1788 from bobo1on1/volampfix
authorbobo1on1 <bob@xbmc.org>
Thu, 15 Nov 2012 23:24:43 +0000 (15:24 -0800)
committerbobo1on1 <bob@xbmc.org>
Thu, 15 Nov 2012 23:24:43 +0000 (15:24 -0800)
Re-added volume amplification for softae and coreae, xcode build and windows build will need updating.

xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.cpp
xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.h
xbmc/cores/AudioEngine/Engines/PulseAE/PulseAEStream.h
xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp
xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.cpp
xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.h
xbmc/cores/AudioEngine/Interfaces/AEStream.h
xbmc/cores/AudioEngine/Makefile.in
xbmc/cores/AudioEngine/Utils/AELimiter.cpp [new file with mode: 0644]
xbmc/cores/AudioEngine/Utils/AELimiter.h [new file with mode: 0644]
xbmc/cores/dvdplayer/DVDAudio.cpp

index 9be515b..6eec3dd 100644 (file)
@@ -132,6 +132,7 @@ CCoreAudioAEStream::CCoreAudioAEStream(enum AEDataFormat dataFormat, unsigned in
   m_vizRemapBuffer                = (uint8_t *)_aligned_malloc(m_vizRemapBufferSize,16);
 
   m_isRaw                         = COREAUDIO_IS_RAW(dataFormat);
+  m_limiter.SetSamplerate(AE.GetSampleRate());
 }
 
 CCoreAudioAEStream::~CCoreAudioAEStream()
@@ -453,6 +454,7 @@ unsigned int CCoreAudioAEStream::GetFrames(uint8_t *buffer, unsigned int size)
   {
     float *floatBuffer   = (float *)buffer;
     unsigned int samples = readsize / m_OutputBytesPerSample;
+    unsigned int frames         = samples / m_chLayoutCountOutput;
 
     // we have a frame, if we have a viz we need to hand the data to it.
     // Keep in mind that our buffer is already in output format.
@@ -460,7 +462,6 @@ unsigned int CCoreAudioAEStream::GetFrames(uint8_t *buffer, unsigned int size)
     if (m_OutputFormat.m_dataFormat == AE_FMT_FLOAT)
     {
       // TODO : Why the hell is vizdata limited ?
-      unsigned int frames         = samples / m_chLayoutCountOutput;
       unsigned int samplesClamped = (samples > 512) ? 512 : samples;
       if (samplesClamped)
       {
@@ -498,6 +499,24 @@ unsigned int CCoreAudioAEStream::GetFrames(uint8_t *buffer, unsigned int size)
 #endif
       CAEUtil::ClampArray(floatBuffer, samples);
     }
+    // apply volume amplification by using the sogt limiter
+    // TODO - maybe reinvent the coreaudio compressor for this after frodo
+    else if (GetAmplification() != 1.0f)
+    {
+      for(unsigned int i = 0; i < frames; i++)
+      {
+        int frameIdx = i*m_chLayoutCountOutput;
+        float amplification = RunLimiter(&floatBuffer[frameIdx], m_chLayoutCountOutput);
+        float *frameStart = &floatBuffer[frameIdx];
+#ifdef __SSE___
+        CAEUtil::SSEMulArray(frameStart, amplification, m_chLayoutCountOutput);
+#else
+        for(unsigned int n = 0; n < m_chLayoutCountOutput; n++)
+          frameStart[n] *= amplification;
+#endif
+        
+      }
+    }
   }
 
   return readsize;
index 02969d5..f6af16f 100644 (file)
@@ -28,6 +28,7 @@
 #include "cores/AudioEngine/Interfaces/AEStream.h"
 #include "cores/AudioEngine/Utils/AEConvert.h"
 #include "cores/AudioEngine/Utils/AERemap.h"
+#include "Utils/AELimiter.h"
 
 #if defined(TARGET_DARWIN_IOS)
 # include "CoreAudioAEHALIOS.h"
@@ -77,8 +78,12 @@ public:
 
   virtual float GetVolume();
   virtual float GetReplayGain();
+  virtual float GetAmplification() { return m_limiter.GetAmplification(); }
   virtual void  SetVolume(float volume);
   virtual void  SetReplayGain(float factor);
+  virtual void  SetAmplification(float amplify){ m_limiter.SetAmplification(amplify); }
+  
+  virtual float RunLimiter(float* frame, int channels) { return m_limiter.Run(frame, channels); }
 
   virtual const unsigned int      GetChannelCount() const;
   virtual const unsigned int      GetSampleRate() const;
@@ -129,6 +134,7 @@ private:
   CAERemap                m_remap;         /* the remapper */
   float                   m_volume;        /* the volume level */
   float                   m_rgain;         /* replay gain level */
+  CAELimiter              m_limiter;       /* volume amplification/limiter*/
   IAEStream               *m_slave;        /* slave aestream */
 
   CAEConvert::AEConvertToFn m_convertFn;
index 0444c19..89bf74b 100644 (file)
@@ -53,8 +53,10 @@ public:
 
   virtual float GetVolume    ();
   virtual float GetReplayGain();
+  virtual float GetAmplification() { return 1.0f; }
   virtual void  SetVolume    (float volume);
   virtual void  SetReplayGain(float factor);
+  virtual void  SetAmplification(float amplify){}
   void SetMute(const bool muted);
 
   virtual const unsigned int      GetFrameSize   () const;
index b73b43e..abbe55f 100644 (file)
@@ -1362,7 +1362,7 @@ unsigned int CSoftAE::RunStreamStage(unsigned int channelCount, void *out, bool
     if (!frame)
       continue;
 
-    float volume = stream->GetVolume() * stream->GetReplayGain();
+    float volume = stream->GetVolume() * stream->GetReplayGain() * stream->RunLimiter(frame, channelCount);
     #ifdef __SSE__
     if (channelCount > 1)
       CAEUtil::SSEMulAddArray(dst, frame, volume, channelCount);
index 8a56c7b..cabcd40 100644 (file)
@@ -198,6 +198,8 @@ void CSoftAEStream::Initialize()
     m_ssrcData.end_of_input  = 0;
   }
 
+  m_limiter.SetSamplerate(AE.GetSampleRate());
+
   m_chLayoutCount = m_format.m_channelLayout.Count();
   m_valid = true;
 }
index 13b0356..7e93215 100644 (file)
@@ -29,6 +29,7 @@
 #include "Utils/AEConvert.h"
 #include "Utils/AERemap.h"
 #include "Utils/AEBuffer.h"
+#include "Utils/AELimiter.h"
 
 class IAEPostProc;
 class CSoftAEStream : public IAEStream
@@ -65,8 +66,12 @@ public:
 
   virtual float             GetVolume       ()             { return m_volume; }
   virtual float             GetReplayGain   ()             { return m_rgain ; }
+  virtual float             GetAmplification()             { return m_limiter.GetAmplification(); }
   virtual void              SetVolume       (float volume) { m_volume = std::max( 0.0f, std::min(1.0f, volume)); }
   virtual void              SetReplayGain   (float factor) { m_rgain  = std::max( 0.0f, factor); }
+  virtual void              SetAmplification(float amplify){ m_limiter.SetAmplification(amplify); }
+
+  virtual float             RunLimiter(float* frame, int channels) { return m_limiter.Run(frame, channels); }
 
   virtual const unsigned int      GetFrameSize   () const  { return m_format.m_frameSize; }
   virtual const unsigned int      GetChannelCount() const  { return m_initChannelLayout.Count(); }
@@ -135,6 +140,7 @@ private:
   bool                m_paused;
   bool                m_autoStart;
   bool                m_draining;
+  CAELimiter          m_limiter;
 
   /* vizualization internals */
   CAERemap           m_vizRemap;
index a245300..b2b8b41 100644 (file)
@@ -139,6 +139,26 @@ public:
   virtual void SetReplayGain(float factor) = 0;
 
   /**
+   * Gets the stream's volume amplification in linear units.
+   * @return The volume amplification factor between 1.0 and 1000.0
+   */
+  virtual float GetAmplification() = 0;
+
+  /**
+   * Sets the stream's volume amplification in linear units.
+   * @param The volume amplification factor between 1.0 and 1000.0
+   */
+  virtual void SetAmplification(float amplify) = 0;
+
+  /**
+   * Runs the limiter over one frame
+   * @param pointer to the frame
+   * @param number of channels
+   * @return amplification factor that should be applied
+   */
+  virtual float RunLimiter(float* frame, int channels) = 0;
+
+  /**
    * Returns the size of one audio frame in bytes (channelCount * resolution)
    * @return The size in bytes of one frame
   */
index 5fee468..833dfab 100644 (file)
@@ -67,6 +67,7 @@ SRCS += Utils/AEBitstreamPacker.cpp
 SRCS += Utils/AEWAVLoader.cpp
 SRCS += Utils/AEELDParser.cpp
 SRCS += Utils/AEDeviceInfo.cpp
+SRCS += Utils/AELimiter.cpp
 
 SRCS += Encoders/AEEncoderFFmpeg.cpp
 
diff --git a/xbmc/cores/AudioEngine/Utils/AELimiter.cpp b/xbmc/cores/AudioEngine/Utils/AELimiter.cpp
new file mode 100644 (file)
index 0000000..1de88bc
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *      Copyright (C) 2010-2012 Team XBMC
+ *      http://xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "system.h"
+#include "AELimiter.h"
+#include "settings/AdvancedSettings.h"
+#include "utils/MathUtils.h"
+#include <algorithm>
+#include <math.h>
+
+CAELimiter::CAELimiter()
+{
+  m_amplify = 1.0f;
+  m_attenuation = 1.0f;
+  m_samplerate = 48000.0f;
+  m_holdcounter = 0;
+  m_increase = 0.0f;
+}
+
+float CAELimiter::Run(float* frame, int channels)
+{
+  float* end = frame + channels;
+  float highest = 0.0f;
+  while (frame != end)
+    highest = std::max(highest, fabsf(*(frame++)));
+
+  float sample = highest * m_amplify;
+  if (sample * m_attenuation > 1.0f)
+  {
+    m_attenuation = 1.0f / sample;
+    m_holdcounter = MathUtils::round_int(m_samplerate * g_advancedSettings.m_limiterHold);
+    m_increase = powf(std::min(sample, 10000.0f), 1.0f / (g_advancedSettings.m_limiterRelease * m_samplerate));
+  }
+
+  float attenuation = m_attenuation;
+
+  if (m_holdcounter > 0)
+  {
+    m_holdcounter--;
+  }
+  else
+  {
+    if (m_increase > 0.0f)
+    {
+      m_attenuation *= m_increase;
+      if (m_attenuation > 1.0f)
+      {
+        m_increase = 0.0f;
+        m_attenuation = 1.0f;
+      }
+    }
+  }
+
+  return attenuation * m_amplify;
+}
+
diff --git a/xbmc/cores/AudioEngine/Utils/AELimiter.h b/xbmc/cores/AudioEngine/Utils/AELimiter.h
new file mode 100644 (file)
index 0000000..8b3f364
--- /dev/null
@@ -0,0 +1,52 @@
+#pragma once
+/*
+ *      Copyright (C) 2010-2012 Team XBMC
+ *      http://xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <algorithm>
+
+class CAELimiter
+{
+  private:
+    float m_amplify;
+    float m_attenuation;
+    float m_samplerate;
+    int   m_holdcounter;
+    float m_increase;
+
+  public:
+    CAELimiter();
+
+    void SetAmplification(float amplify)
+    {
+      m_amplify = std::max(std::min(amplify, 1000.0f), 1.0f);
+    }
+
+    float GetAmplification()
+    {
+      return m_amplify;
+    }
+
+    void SetSamplerate(int samplerate)
+    {
+      m_samplerate = samplerate;
+    }
+
+    float Run(float* frame, int channels);
+};
index de04389..bdb9c2a 100644 (file)
@@ -327,7 +327,9 @@ void CDVDAudio::SetVolume(float volume)
 
 void CDVDAudio::SetDynamicRangeCompression(long drc)
 {
-
+  CSingleLock lock (m_critSection);
+  if (m_pAudioStream)
+    m_pAudioStream->SetAmplification(powf(10.0f, (float)drc / 2000.0f));
 }
 
 float CDVDAudio::GetCurrentAttenuation()