title: How to amplify sounds without distortion in Python
body: <p>I am trying to do naive volume adjustment of a sound file. I am using python 2.7 and the following </p>
  
  <p>libraries:</p>
  
  <pre><code>import numpy as np
  
  import scipy.io.wavfile as wv
  
  import matplotlib.pyplot as plt
  
  import pyaudio  
  
  import wave  
  </code></pre>
  
  <p>I have tried 2 approaches, I am trying to amplify the sound by 2, ie. n=2. The first is a altered dyanmic range limiter approach from here (<a href="http://bastibe.de/2012-11-02-real-time-signal-processing-in-python.html" rel="nofollow">http://bastibe.de/2012-11-02-real-time-signal-processing-in-python.html</a>):</p>
  
  <pre><code>def limiter(self, n):
  
      #best version so far
  
      signal=self.snd_array
  
      attack_coeff = 0.01
  
      framemax=2**15-1
  
      threshold=framemax
  
      for i in np.arange(len(signal)):
  
      #if amplitude value * amplitude gain factor is &gt; threshold set an interval to decrease the amplitude            
  
          if signal[i]*n &gt; threshold:
  
              gain=1
  
              jmin=0
  
              jmax=0                
  
              if i-100&gt;0: 
  
                  jmin=i-100
  
              else:
  
                  jmin=0
  
              if i+100&lt;len(signal):
  
                  jmax=i+100
  
              else:
  
                  jmax=len(signal)
  
              for j in range(jmin,jmax):    
  
                  #target gain is amplitude factor times exponential to smoothly decrease the amp factor (n)
  
                  target_gain = n*np.exp(-10*(j-jmin))
  
                  gain = (gain*attack_coeff + target_gain*(1-attack_coeff))
  
                  signal[j]=signal[j]*gain
  
          else:
  
              signal[i] = signal[i]*n
  
      print max(signal),min(signal)
  
      plt.figure(3)
  
      plt.plot(signal)
  
      return signal
  </code></pre>
  
  <p>The second is a method where I do hard knee compression to decrease the amplitude of sound values above a threshold and then I amplify the whole signal by an amplitude gain factor.</p>
  
  <pre><code>def compress(self,n):
  
       print 'start compress'
  
       threshold=2**15/n+1000
  
       #compress all values above the threshold, therefore limiting the audio amplitude range
  
       for i in np.arange(len(self.snd_array)):         
  
           if abs(self.snd_array[i])&gt;threshold:
  
               factor=1+(threshold-abs(self.snd_array[i]))/threshold
  
           else:
  
               factor=1.0
  
       #apply compression factor and amp gain factor (n)
  
           self.snd_array[i] = self.snd_array[i]*factor*n
  
       print np.min(self.snd_array),np.max(self.snd_array)
  
       plt.figure(2)
  
       plt.plot(self.snd_array,'k')
  
       return self.snd_array
  </code></pre>
  
  <p>In both methods the file sounds distorted. At points whose amplitudes are near the threshold the music sounds clipped and crackly. I think this is because it "flattens" out near the threshold value. I tried applying an exponential in the limiter function but it does not remove the crackling sound completely even when I make it decrease very quickly. If I change n=1.5 the sound is not distorted. If anyone could give me any pointers on how to remove crackling distortion or links to other volume modulation code that would be much appreciated.</p>