Audio Slice Kit Not Good For Real Time Audio Processing

New to XMOS and XCore? Get started here.
Post Reply
rmammina
Member
Posts: 9
Joined: Thu Mar 20, 2014 7:24 pm

Audio Slice Kit Not Good For Real Time Audio Processing

Post by rmammina »

Hey, I'm working on an audio project.

I've been doing some audio processing, where I have no way around but to use doubles. I know they are awfully slow.

For example:

I've tried using the xmos biquad filter lib (which uses doubles to calculate the biquad coefficients), but I can't find a way to update the cutoff frequency without getting pops. I tried to split up the coefficient calculation by doing them on a separate core. I switch back and forth by outputting audio through one biquad filter with the new coefficients, and update the older filter with the separate core. But now there's an issue with synchronization. The double calculation on the separate core makes it so that dsp stream core is waiting to synchronize with the coefficient core. I tried using a timer for timing out, but that still doesn't work. I'm running out of options, and am starting to feel that the xmos product is just not cut out to do any realtime audio processing.

Are there any better biquad filter libraries that work well with variable filter cutoff?
Is there a better way of timing-out a synchronized channel communication?
Has anyone had luck with processing doubles on a separate core?

Much would be appreciated.


rmammina
Member
Posts: 9
Joined: Thu Mar 20, 2014 7:24 pm

Post by rmammina »

To further explain the synchronization issues, I'll show you a simple example.

I have one tile, with four separate threads. This is the set up in my main function.

Code: Select all

int main (void) {
	streaming chan c_aud_dsp;
	interface adc_interface adc;
	chan param;

	par {
		on tile[1]: audio_io( c_aud_dsp ); // Audio I/O core
      on tile[1] : filter_coeff ( adc, param );
		on tile[1]: dsp_biquad( c_aud_dsp, 0, param); // BiQuad filter core
		on tile[1] : gpio ( adc );
	}

	return 0;
}
So I'm streaming the audio from the audio_io thread to the dsp_biquad thread.
The dsp biquad thread runs a simple loop as follows.

Code: Select all

void dsp_biquad( streaming chanend c_dsp, int biquad_id, chanend parameter) {
	int inp_samps[BUFF_SIZE];	// Unequalised input audio sample buffer
	int out_samps[BUFF_SIZE];	// Output audio sample buffer

	// For Filter
	timer tmr;
	int time;
	int param_temp;

	// initialise samples buffers
	for (int chan_cnt = 0; chan_cnt < BUFF_SIZE; chan_cnt++) {
		inp_samps[chan_cnt] = 0;
		out_samps[chan_cnt] = 0;
	}

	while(1) {
	    tmr :> time;
	    time += MILLISECOND;

		// Send/Receive samples over Audio core channel
#pragma loop unroll
		for (int chan_cnt = 0; chan_cnt < BUFF_SIZE; chan_cnt++) {
		   c_dsp :> inp_samps[chan_cnt];
			c_dsp <: out_samps[chan_cnt];
		}

		select {
		    case tmr when timerafter(time) :> void :
		    break;
		    case parameter :> param_temp:
		    break;
		}

		for(int i = 0; i < 4; i++) {
		    out_samps[i] = inp_samps[i];
		}

	}
}
1. Take the current time and update a variable called time (increment the time by one millisecond).

2. Process all channels by saving the current audio stream into the inp_samps buffer, and output the
previous stream from out_samps to the audio stream.

3. Enter the select statement. If the timerafter of time runs out, then exit the select statement, otherwise if parameter stores something into param_temp, exit.

4. Process the audio output stream.

This is a simplified version of what I've been working on. I'll explain after this code segment why it's still an issue though.

In the next thread code block, I sample a gpio value (from a rotary potentiometer). I've verified that it works, and have tested it thoroughly.

Here's how it works.

Code: Select all

void set_f(int filter_cutoff) {
    double f = 2 * sin(PI*filter_cutoff/48000);
}

void filter_coeff(interface adc_interface server adc, chanend parameter) {
    int filter_cutoff = 0;
    int param_number = 1;
    select {
        case adc.get_value(int value):
            filter_cutoff = value;
            break;
    }

    while (1) {
        parameter <: param_number;
        select {
              case adc.get_value(int value):
                 if( value >= filter_cutoff + 10 ||
                     value <= filter_cutoff - 10 ) {
                      filter_cutoff = value;
                      set_f(filter_cutoff);
                      parameter <: param_number;
                 }
                  break;
        }
    }
}
1. In the main body of the while loop, send the output channel of the current param_number. Interestingly, if I comment this part out, I can't seem to get the audio stream to continue playing. So I keep this line here.

2. Grab a new value from the adc. If its changed past a certain threshold, then process the data.

3. Here's the annoying part. When I run the set_f function, It clearly takes some x amount of cpu cycles. After this is done, I send a signal to the other core with the parameter channel. Even with this, I get pops and clicks with the audio. As soon as I comment this set_f function out, no more pops.

I really hope there is some sort of solution to this. Is there a better way to synchronize the two threads?
Thanks.
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

I might have a solution.

I have written a filter toolbox with extended precision for fixed numbers in asm for XMOS.
It uses a 96 bit long MAC, and it supports filter updates on the fly.
Since it is optimised in asm the speed is about the same as the standard filter lib without the extended precision.

The limited cycles error is less than ½ LSB of 24 bit data for all realistic filters I have tested, even at high fs and high Q-values.

Long time since I updated this online. A lot more has been done since 2012.
http://www.xcore.com/projects/high-end- ... ir-filters

I will see if I can update the page later.
User avatar
infiniteimprobability
XCore Legend
Posts: 1126
Joined: Thu May 27, 2010 10:08 am
Contact:

Post by infiniteimprobability »

I have written a filter toolbox with extended precision for fixed numbers in asm for XMOS.
This is great. Good work lilltroll!!
Post Reply