1

I am mixing four buffers and applying panning. However, when I trigger a change of pan I hear a clip. Can any body see what is potentially wrong with the following code:-

for (int i = 0 ; i < numFrames; i++) {
    //Convert buffer to float
    float s1 = track1[0][i] / 32768.0f;
    float s2 = track2[0][i] / 32768.0f;;
    float s3 = track3[0][i] / 32768.0f;;
    float s4 = track4[0][i] / 32768.0f;;

    //Apply pan on track one
    float s1R = s1 * sqrt( 1 - panA ); 
    float s1L = s1 * sqrt( panA ); 

    //Apply pan on track two
    float s2R = s2 * sqrt( 1 - panB ); 
    float s2L = s2 * sqrt( panB ); 

    //Apply pan on track three
    float s3R = s3 * sqrt( 1 - panC ); 
    float s3L = s3 * sqrt( panC );

    //Apply pan on track four
    float s4R = s4 * sqrt( 1 - panD ); 
    float s4L = s4 * sqrt( panD );

    //Mix the right channel
    float mixedR = s1R + s2R + s3R + s4R;

    mixedR *= 0.6f;
    if(mixedR > 1.0f) mixedR = 1.0f; 
    if(mixedR < -1.0f) mixedR = -1.0f;

    //Mix the Left channel
    float mixedL = s1L + s2L + s3L + s4L;

    mixedL *= 0.6f;
    if(mixedL > 1.0f) mixedL = 1.0f; 
    if(mixedL < -1.0f) mixedL = -1.0f;

    //Apply the Left channel 
    audioIn[0][i] = (short) (mixedL * 32768.0f);

    //Apply the right channel
    audioIn[1][i] = (short) (mixedR * 32768.0f);
}

The panning algorithm could be improved, I lifted it from here:-

http://www.kvraudio.com/forum/viewtopic.php?t=181222&postdays=0&postorder=asc&start=0

NumFrames is 512; once the audio has been mixed I am applying a time-stretching algorithm using Dirac.

The clipping occurs without processing by Dirac.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Carl
  • 209
  • 1
  • 3
  • 13

3 Answers3

2

You are taking 4 potentially full-scale signals, adding them together and then scaling by 0.6 prior to saturating the resulting output signal. So prior to saturation your maximum range is +/- 4 * 0.6 = +/- 2.4. Hence it's not too surprising that you hear some clipping. If you multiply by 0.25 instead of 0.6 then that should eliminate clipping in even the most extreme cases, but the output signal level may be a little low in the general case.

To verify this you could add some debug logging in your saturation code, e.g.

#if DEBUG
    if (mixedR > 1.0f || mixedR < -1.0f)
        fprintf(stderr, "Clipping occurred for mixedR = %g\n", mixedR);
#endif
    if(mixedR > 1.0f) mixedR = 1.0f; 
    if(mixedR < -1.0f) mixedR = -1.0f;
Paul R
  • 208,748
  • 37
  • 389
  • 560
  • @peter - Thanks for your reply. I have just tried multiplying by 0.25 and I get the same clip. This only happens when I change the panning dynamically. – Carl Oct 13 '11 at 09:23
  • OK - is it possible that your pan values are ever out of range, i.e. < 0 or > 1 ? – Paul R Oct 13 '11 at 09:26
  • @peter - Never, I am hard-coding them as floats, 1 or 0 as a test. – Carl Oct 13 '11 at 09:48
  • 1
    Are you changing the pan values smoothly or instantaneously ? – Paul R Oct 13 '11 at 09:50
  • I am changing them instantaneously -- i.e going from 0 then 1.0. How would you suggest I do it smoothly? --- I've created a control for this --- let me test, it sounds like your right! :) Thanks – Carl Oct 13 '11 at 09:58
  • 3
    OK - it's probably not clipping then - it's just that you are introducing transients when you change the pan values instantaneously. You should probably ramp them over a period of say 50 ms. – Paul R Oct 13 '11 at 10:15
  • Thanks -- your right, theres a tiny bit of noise but I'll work on it. Cheers again :) – Carl Oct 13 '11 at 10:25
0

Your "Convert buffer to float" function is wrong. You must divide by 32767 instead of 32768, otherwise you will get clipping due to flipping of the MSB.

Matze
  • 1
0

What you hear is probably not clipping but popping from discontinuities every 4096 samples (or whatever your buffer length is). You need to smoothly interpolate your panning values to avoid abrupt changes. Two easy ways to do this: 1) define a maximum change per sample or 2) interpolate to the new value over the entire buffer length.

Either way, the essential innovation is to store the current actual pan value and destination pan value to move toward.

Matt Montag
  • 7,105
  • 8
  • 41
  • 47