0

I am amplifying an audio file frame-by-frame via the following algorithm:

  1. Find maximum value among all the samples in a frame
  2. Find the amplification factor to make the maximum value equal to 0 dB
  3. Multiply the entire frame by the above amplification factor

The above algorithm makes many samples close to 0 dB in the signal (as expected). However, when played, those samples which are close to 0 dB create a very sharp tick or click. The signal is full of such sharp ticks/clicks drastically deteriorating the listening experience.

How to avoid generating such ticks/clicks?

Edit: Tetsujin's method given in the 1st comment (to change the amplitude from 0 dB to -0.3 dB) seems to have reduced some of the clicks. But there are abundant clicks remaining at frame boundaries. I changed the amplitude from 0 dB to -0.3 dB to -1 dB to -3 dB to -10 dB but the clicks do not seem to go away. What should I do now? I have tried to read and look up what all of you were discussing but due to my limited knowledge, I couldn't see how should I go about implementing those things in my code. Could you please help me with what exactly should I do to reduce the "intersample/interframe clipping"?

12
  • 1
    Don't normalise to 0dB, normalise to -0.3
    – Tetsujin
    Feb 21, 2017 at 13:22
  • 1
    Also, amplifying by frame leaves you with an issue at frame borders - your process adds in high freq, potentially high amplitude signals...
    – Rory Alsop
    Feb 21, 2017 at 13:47
  • @Tetsujin Thanks a lot, it worked. Could you please explain why it works? Also, I would be grateful if you could add your comment as an Answer so that I can accept it. Feb 21, 2017 at 14:00
  • @RoryAlsop Thanks for your expert comments, I am new to Audio Processing. Could you please help me with what I should do instead? I want as high amplification as possible and the different parts of the signal have different amplitudes. Feb 21, 2017 at 14:01
  • 1
    Clicks occur whenever a sudden, extreme change in amplitude occurs over a one or a few samples. To avoid clicking, you need to make your volume changes gradual by, say, having all your frames overlap by 100 samples and crossfading them. Still, I'll repeat what everyone else is saying: use a compressor. Even if you manage to eliminate the clicking, this method will still produce (sonically) bad results.
    – Linuxios
    Feb 23, 2017 at 17:03

2 Answers 2

2

firstly your normalization factor will be different frame to frame. I cannot think of the application you will be using this for as it will create discontinuities across frame boundaries and introduce artifacts.

Additionally, your method doesn't take into account inter-sample peaks. You are normalizing only the visible peaks but in reality - once the audio has been converted back to analogue - you may experience clipping in the audio waveform between the samples. You need to up-sample your audio to at least 4x the original sampling rate in order to cover for inter-sample peaks.

You should not change the normalization factor on a frame-by-frame basis but you should scan all the audio and then apply a gross normalization factor across the whole file.

In my honest opinion your efforts are pointless. There is no reason to do what you are doing. You should not be normalizing audio to the highest possible level as all you are doing is increasing overall loudness and increasing the noise floor along with the signal.

A more useful exercise would be to normalize to a known loudness (LKFS) factor.

1
  • 1
    Plus, if you really want to adjust the dynamic range, use a dynamic range compressor. Much easier.
    – n00dles
    Feb 23, 2017 at 15:00
1

ffmpeg has a module called loudnorm which nearly does what you are describing. However, the change is applied incrementally on a frame of 100ms. So the gain factor will change only a little bit one way or the other between each 100ms of audio samples.

The module is capable of detecting the loudness of the samples found so far in the file. It does so with an energy histogram. The pertinent line is:

// found in libavfilter/ebur128.c
++st->d->block_energy_histogram[find_histogram_index(sum)];

The issue here is that this histogram does not ever decay... so near the end of the file, it adjusts the loudness as if the whole file was measured first and it means the beginning of the file was adjusted improperly.

However, I think that you could apply an energy decay on the energy histogram. A simple decrement once every 100ms after some time as passed (i.e. after 3 sec., for example). This would require you to memorize the increments 3 sec. earlier so as to be able to apply the decrements later (i.e. cancel the effects of the noise generated 3 sec. ago).

Further, if you look at the acceptable parameters, this algorithm will allow you to specify a level between -5dB and -70dB. They do not let you increase the volume to 0dB. That's a crazy value anyway (and even -0.3dB is way too high).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.