Menu

#7 Tap Scaling Limiter error adds sharp peaks to audio

closed-fixed
nobody
None
5
2012-07-08
2012-03-11
No

Hi again :)

This bugreport is related to my previous one. I was not able to correct the bug. My previous solution seemed to work until I made some more tests.

It seems that Tap Scaling Limiter has a bug that causes it to make a miscalculation that causes sharp peaks in the audio. The interval of these peaks is always sample rate divided by 80 which by coincidence is what is defined on line 94 in the source code. This results in errors in every 552 samples in 44100 Hz audio and if I change the divider to 50 the errors occur at 882 sample intervals (44100 / 50 = 882.

My lack of ladspa and C knowledge stops me from finding the bug (tried hard :)

How to reproduce:

- Create a sine wave with Audacity 1.3.13, frequency 200 Hz, Amplitude 0.95, duration 30 seconds, save audio to "sine_wave.wav"
- Use sox 14.3.2 to limit the sine wave with command: sox sine_wave.wav sine_wave-scaling_limiter.wav ladspa /usr/lib/ladspa/tap_limiter.so -4 3

Tap Scaling Limiter adds peaks to the sine wave that were not originally there.

You can confirm that sox 14.3.2 is ok, by limiting the same file with "hard_limiter" from swh_plugins (command: sox sine_wave.wav sine_wave-hard_limiter.wav ladspa /usr/lib/ladspa/hard_limiter_1413.so -4 1 0 gain 3

This time there are no errors in the limited audio. The result sounds ugly, but this is just how hard_limiter is designed to work.

My guess is that the error happens at buffer boundary or when you change audio buffers. May also be a mismatch between limiters buffer and the host applications (sox) buffer.

I hope you correct this bug soon, since your limiter is the best out there, and I need it badly :) Sorry for not being able to locate the bug :)

Mikael Hartzell

Discussion

  • Taku YAMAMOTO

    Taku YAMAMOTO - 2012-06-04

    Oh, this is the bug I've got occasionally bitten!
    Thanks for your insight!

    I'll look into the source and try fixing it if at all possible.

    Post scriptum: I usually work-around this bug by preprocessing with SC4 to reduce peak RMS.

     
  • Taku YAMAMOTO

    Taku YAMAMOTO - 2012-06-04

    Ok, I found the cause of this bug and made a possible fix.
    I'll post the URL of my patch because I don't know how to submit a patch directly to this project.

    http://www.tackymt.homeip.net/tap_limiter-boundary_fix.patch

    This bug came from the way how this plugin works against host's audio buffer.

    This plugin calculates scaling factors for each zero-cross to zero-cross chunks.
    The problem arise when the last zero-cross point crosses the limiter's internal buffer boundary;
    without my patch, it insists working on the internal buffer size at a time,
    thus ends up with fragmented chunks of different scaling factors.

    With my patch, if the last chunk wraps the internal buffer, it emits the already calculated chunks sans the last fragmented chunk and tries to fill up the internal buffer with the counterpart fragment.
    (See my patch for more correct details.)

     
  • Mikael Hartzell

    Mikael Hartzell - 2012-06-23

    Hi :)

    Thanks for the patch, I just tried it out. Unfortunately if you create a sine wave like I describe in my bug report, and use scaling limiter on it (with the patch applied) and then open the limited wave in audacity and listen to it, you can hear periodic clicks in it. The original error is greatly reduced so I think you have hit the spot where the bug is, but some problem still escapes us :)

     
  • Taku YAMAMOTO

    Taku YAMAMOTO - 2012-06-23

    Hi,

    First of all, I'm happy to hear that our problem got reduced to the architectural limit.

    Unfortunately, the remaining problem is unavoidable due to the nature of the block-by-block operation performed by LADSPA hosts (sox, audacity, ardour or whatever).

    Speaking with sox, we can decrease the problem further by giving --buffer 131072
    (or any number greater than default 8192; the more buffer, the less clicks),
    but we can't eliminate the problem completely unless having the LADSPA host to operate on the whole clip as a block.
    (Fortunately we can give sox a couple of hundreds of megabytes without a pain these days;
    try insanely large size such as 1048576000 which should be enough for usual 5 minutes tune :)

     
  • Mikael Hartzell

    Mikael Hartzell - 2012-07-08

    Hi :)

    Thanks for looking into the problem :) I've managed to get a working solution for our purposes using sox compand function. You can get quite nice results adding 3 stages on compand, each with shorter attack than previous and a final fourth stage with a hard-limiter. It works for us for the time being :)

    I think the buffering problem in scaling limiter might be solved by using two buffers, one would be twice the size of the other. When reading in audio it would be written in the bigger buffer, two reads would be needed to fill it. Then limiting would be done on this big buffer. Limited audio could be written to the smaller buffer and sent back to host.

    This would introduce silence at the beginning of the file equaling the length of the smaller buffer since the first time audio is given back to sox it would be silence.

    I don't know how you use scaling limiter, but if you only need the plugin to process files with sox, then you might wan't to take a look at sox's compand function.

    Here is the algorithm I use, save it as limiter.sh

    #!/bin/bash

    if [ "$1" = "" ] && [ "$2" = "" ] && [ "$3" = "" ]; then echo ; echo "Usage: ./limiter.sh INFILE OUTFILE GAIN" ; echo ; exit ; fi

    INFILE=$1
    OUTFILE=$2
    GAIN=$3
    let GAIN_SIGN_REVERSED="$GAIN * -1"
    let MAX_PEAKS="GAIN_SIGN_REVERSED + -4"

    # Print sox commandline and make a limited version of the audiofile.
    echo "sox $INFILE $OUTFILE compand 0.005,0.3 1:$(($MAX_PEAKS + -3)),$(($MAX_PEAKS + -3)),0,$(($MAX_PEAKS + -2)) compand 0.002,0.15 1:$(($MAX_PEAKS + -2)),$(($MAX_PEAKS + -2)),0,$(($MAX_PEAKS + -1)) compand 0.001,0.075 1:$(($MAX_PEAKS + -1)),$(($MAX_PEAKS + -1)),0,$(($MAX_PEAKS + -0)) compand 0,0 4:$(($MAX_PEAKS + -4)),$(($MAX_PEAKS + -4)),0,$(($MAX_PEAKS + -0)) gain $GAIN"
    sox $INFILE $OUTFILE compand 0.005,0.3 1:$(($MAX_PEAKS + -3)),$(($MAX_PEAKS + -3)),0,$(($MAX_PEAKS + -2)) compand 0.002,0.15 1:$(($MAX_PEAKS + -2)),$(($MAX_PEAKS + -2)),0,$(($MAX_PEAKS + -1)) compand 0.001,0.075 1:$(($MAX_PEAKS + -1)),$(($MAX_PEAKS + -1)),0,$(($MAX_PEAKS + -0)) compand 0,0 4:$(($MAX_PEAKS + -2)),$(($MAX_PEAKS + -2)),0,$(($MAX_PEAKS + 2)) gain $GAIN

     
  • Mikael Hartzell

    Mikael Hartzell - 2012-07-08

    Hmmm. The commenting system hosed my code :)

    Here is a link to the code. It is a short bash-script that demonstrates the functionality: http://dl.dropbox.com/u/2071830/limiter.sh

    Usage: ./limiter.sh INFILE.wav OUTFILE.wav Gain

    Example: ./limiter testfile.wav limited_testfile.wav 10

    The example adds 10 dB gain to the file, but before doing it it limits the peaks so that no distortion is introduced. Peaks are limited to max -4 dBFS, but you can change it in the script. By giving large gain numbers you can test what the limiter does to the singal in extreme cases :)

     
  • Tom Szilagyi

    Tom Szilagyi - 2012-07-08
    • status: open --> closed-fixed
     
  • Tom Szilagyi

    Tom Szilagyi - 2012-07-08

    I applied the patch by tackymt (thanks!) and released tap-plugins-0.7.2 based on this modified version.

     

Log in to post a comment.