Efficient Audio Clip function Ideas?

Technical questions regarding the XTC tools and programming with XMOS.
bearcat
Respected Member
Posts: 283
Joined: Fri Mar 19, 2010 4:49 am

Efficient Audio Clip function Ideas?

Post by bearcat »

All, need the ability to clip an audio value to a maximum and minimum value if greater than a certain number of bits. Looking for the most effecient way to do this. In this example the audio sample has been >> 4 (ASHR), to provides for headroom in calculations. After the calculations are complete, then need to clip it, if above / below, and put it back to full range. If you don't clip it, it turns into full volume noise, as it causes overflows.

Here's the best I have been able to come up with (not debugged yet, so may have errors):

Code: Select all

inline void Clip(int &sample)
//Clips an audio value in 4.28 format to max of 1
{
    int temp;
    asm("clz %0, %1" : "=r" (temp) : "r" (sample));
    if(temp)
    {
        //Signal positive, test for overflow
        if(temp < 4)
        {
            sample = 0x7FFFFFF;
        }
        else
        {
            sample <<= 4;
        }
    }
    else
    {
        //Signal negative
        asm("not %0, %1" : "=r" (temp) : "r" (sample));
        asm("clz %0, %0" : "=r" (temp) :);
        if(temp < 4)
        {
            sample = 0xF8000001;
        }
        else
        {
            sample <<= 4;
        }
    }
}


User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

Probably not the most confused programmer anymore on the XCORE forum.
User avatar
davelacey
Experienced Member
Posts: 104
Joined: Fri Dec 11, 2009 8:29 pm

Post by davelacey »

lilltroll wrote:Check out this doc as well
http://github.xcore.com/doc_tips_and_tr ... saturation
I wonder if:

Code: Select all

a = 0x7fffffff + ((unsigned) h >> 31);
is more efficient than:

Code: Select all

if (h > 0) {
    a = 0x7fffffff;
} else {
    a = 0x80000000;
}
I expect it probably is.

Dave
bearcat
Respected Member
Posts: 283
Joined: Fri Mar 19, 2010 4:49 am

Post by bearcat »

Thanks for the replies. Hadn't realized the sext instruction could work also.

Here's the latest version, shortened without the need to << 4 after all:

Code: Select all

inline void Clip(int &sample)
//Clips an audio value in 4.28 format
{
    if (sext(sample,28) != sample)
    {
    	if (sample > 0)
    	{
    		sample = 0x7FFFFFF;
    	}
    	else
    	{
    		sample = 0xF8000001;
    	}
    }
}
Since I am using 4.28 format, there is no literal for 28 bits, so that adds an extra load.

Compiled down to only 6 instructions! I do not understand the code yet. I will have to debug it to see exactly how that works. There are no constants in the compiled code for 0x7FFFFFF or 0xF8000001???
User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

Code: Select all

#define MIN 0xf0000000
#define MAX 0x0fffffff
long magic[16] = { 0, MAX, MAX, MAX, MAX, MAX, MAX, MAX,
  MIN, MIN, MIN, MIN, MIN, MIN, MIN, 0 };

long clamp(long x)
{
  long y;
  magic[0] = magic[15] = x;
  y = bitrev(x) & 15;
  return magic[y];
}
5 insns if I counted right. Do I get a cookie, or can someone beat this? :-)
User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

Oh, and 4 cycles if you can have 28 in a reg (load it outside a loop for example).
bearcat
Respected Member
Posts: 283
Joined: Fri Mar 19, 2010 4:49 am

Post by bearcat »

Excellent work segher. Will try that routine soon.

Here you go..
You do not have the required permissions to view the files attached to this post.
bearcat
Respected Member
Posts: 283
Joined: Fri Mar 19, 2010 4:49 am

Post by bearcat »

Well segher's suggestion didn't pan out. The array caused index's to be calculated, and ended up around 13 instructions. I will have to take the cookies back.

The prior routine is actually only 5 instructions, if the value does not have to be clipped.

Thanks all.
User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

bearcat wrote:Well segher's suggestion didn't pan out. The array caused index's to be calculated, and ended up around 13 instructions.
So write it in asm:

Code: Select all

int shift = 28;
asm("stw %0,0[%1] ; stw %0,15[%1] ; shr %0,%0,%2 ; ldw %0,%0[%1]" : "+&r"(x) : "r"(magic), "r"(shift));\
or something like that.
I will have to take the cookies back.
Are you sure? I alread ated them.
The prior routine is actually only 5 instructions, if the value does not have to be clipped.
Erm, the only thing this does is clipping. Now I'm confused.
User avatar
Ross
XCore Expert
Posts: 968
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

Code: Select all

/* Perform saturation */
    l = sext(h, 25);

    if(l != h)
    {
        if(h>>32)  
            h = (0x80000000>>7);
        else
            h = (0x7fffff00>>7);
    }
 return h<<7;
obviously replace shifts with your desired output (from USB Audio code)