Please consider registering

sp_LogInOut Log In sp_Registration Register

Register | Lost password?
Advanced Search

— Forum Scope —

— Match —

— Forum Options —

Minimum search word length is 3 characters - maximum search word length is 84 characters

sp_Feed sp_TopicIcon
Stuttering in RackAFX audio output: computational complexity limits
No permission to create posts
August 19, 2014
12:22 am
Forum Posts: 11
Member Since:
February 26, 2014
sp_UserOfflineSmall Offline

In a nutshell, my question in very generally how much processing is one able to do within the processAudioFrame() function before RackAFX will start to stutter when producing audio output (i.e. not to a file)?

More specifically:
I'm creating a plugin in RAFX that's emulating the analog processing performed by a certain guitar distortion pedal. This requires me, in the processAudioFrame() function to do the following for each incoming sample:

(1) upsample and perform anti-imaging filtering -> (2) process with simple low-order filter #1 -> (3) process with simple low-order FIR filter #2 -> (4) process through simulation of non-linear analog circuitry (where I use the iterative Newton-Raphson method) -> (5) perform anti-aliasing filtering and decimation.

Step (1), and subsequently step (5), are performed to change a lower sampling rate (say 44.1khz) to a higher one in order to create a "buffer" so that higher harmonics created by the nonlinear processing in (4) will not create aliasing distortion.

My problem is that if I do what I describe above with 4xs up/down-sampling at (1) and (5) and specify a maximum of 75000 iterations in step (4) (which seems to be what's needed for a good solution) things hang for an indefinitely long time. If I choose a lower number of max iterations like ~100 I get horrible stuttering in the audio output, but if I save the output to a wav file instead it'll sound great on playback.

I've found that I can get the audio output (when NOT sent to a wav file) to start to sound smooth if I lower the max number of iterations down to some very small number, like < 10, which is insufficient. Removing the up/down-sampling entirely helps me boost the number to perhaps 15-20, but that's about all that buys me. Either case, this is very low # of iterations and not enough to allow for a good solution to be found.

So far this seems like a normal engineering trade-off since, clearly, there are computational limitations to what RAFX can do and still produce smooth sounding audio output (not to a file). However, the sorts of computations I'm doing inside each iteration of the non-linear loop are really quite simple, so I'm unsure why it shouldn't allow for a much larger number of iterations and still produce smooth audio output (not to a file). I'm sure that what I'm doing is within normal bounds of what many non-trivial plugins do.

To point, I'm copying the code below from the inside of the code that I iterate over to solve the non-linear equations below. There's not a lot going on (no function calls, etc...just a few simple operations). I'm not sure why doing that as few times as even 50 should cause such computational hickups (audio stuttering) to occur.

I'm running this with V6.2.6 with VS2013 on a late-2013 Macbook Pro (Mavericks) running Windows 7 via Parallels.

Anyway, if anyone has experience something like this and has any thoughts/suggestions I'd love to hear 'em. Thanks in advance!



// main NR iteration loop
while (!NRConverged && (NRCnt < NRCntLimit)) {

Geq_D2 = (Is/VT)*exp(-Vp_out[inputChannelCount]/VT); // D2
Ieq_D2 = Ip_D2[inputChannelCount] + Vp_out[inputChannelCount]*Geq_D2;
Geq_D1 = (Is/VT)*exp(Vp_out[inputChannelCount]/VT); // D1
Ieq_D1 = Ip_D1[inputChannelCount] - Vp_out[inputChannelCount]*Geq_D1;

Vn_out[inputChannelCount] = (Ieq_D2 - Ieq_D1 + Ieq_C4)*(Req_C5 + R1) +
(upSampledInputBuffer[2*upSampleCount + inputChannelCount] - Veq_C5);
Vn_out[inputChannelCount] /= (1 + (Geq_D2 + Geq_D1 + Geq_C4 + Go)*(Req_C5 + R1));

if (NRDampingMethod == 1) { // simple
Vn_out[inputChannelCount] = Vp_out[inputChannelCount] + NRDampingParam*(Vn_out[inputChannelCount] -
} else if (NRDampingMethod == 2) { // hyperbolic tangent
Vn_out[inputChannelCount] = Vp_out[inputChannelCount] + 10*VT*tanh((Vn_out[inputChannelCount] -
} // else no damping at all

In_D2[inputChannelCount] = Is*(exp(-Vn_out[inputChannelCount]/VT) - 1);
In_D1[inputChannelCount] = Is*(exp(Vn_out[inputChannelCount]/VT) - 1);

if (abs(Vp_out[inputChannelCount] - Vn_out[inputChannelCount]) < Vp_out[inputChannelCount]*RelTol +
VolAbsTol) {
NRConverged = TRUE;

Vp_out[inputChannelCount] = Vn_out[inputChannelCount];
Ip_D2[inputChannelCount] = In_D2[inputChannelCount];
Ip_D1[inputChannelCount] = In_D1[inputChannelCount];

August 26, 2014
6:07 pm
W Pirkle
Forum Posts: 247
Member Since:
January 29, 2017
sp_UserOfflineSmall Offline

Hi Michael

Sorry for the late reply; classes just started at the University and we're just getting settled.

The audio processing loop runs on a single thread which handles the callbacks from the audio sub-system. The CPU meter you see at the upper right of RAFX monitors this single thread and does not reflect any CPU operations in RAFX (nor does anything in RAFX affect that callback/thread). You will hear stuttering/choppy audio as soon as that CPU meter hits the top red "LED." And, as you noticed, offline processing into a WAV file works fine even if the real-time version maxes out the CPU.

Ordinarily, I would have tagged the tanh() and exp() functions and a few others as problematic, but the sheer number of iterations you require (75000!) is the main culprit. There are several optimization methods out there (and that is a whole other topic in programming) that you might look into.

However, if you can parallelize your code, you can use worker threads and split the code into a set of parallel thread processes. The CPU doles out time to each thread, not each process so you can grab some extra CPU time by using parallel worker threads. A good example of this is in my App Note 2 on Parallel FFT Processing. It shows how to use a worker thread to run the FFT processing in parallel with the audio processing. Note that the CPU meter in RAFX only shows the audio callback thread, so the FFT's are "invisible" to that thread. If you download the project and play around with it, you can watch the parallel action occur and you can adjust the size of the FFT until FFT frames get dropped when the thread is maxed out.

But, the use of the worker threads hinges on your ability to split the algorithm into parallel processing branches (another kind of algorithm optimization technique).

Hope that helps and sheds some light on whats going on in the audio processing.

- Will

September 6, 2014
8:05 pm
Forum Posts: 11
Member Since:
February 26, 2014
sp_UserOfflineSmall Offline

Hi Will,

Thanks again for the detailed and very helpful reply. Apologies for the belated follow-up on my end.

It turns out that the reason why I was requiring so many iterations was that there was a subtle but quite relevant bug in one of my routines that, when fixed, lead to MUCH fewer iterations being necessary. The algorithm I've been developing now runs very well. All that you said was really helpful to learn about and I think that code parallelization will become relevant for another project I'm likely going to delve into soon.


Forum Timezone: America/New_York

Most Users Ever Online: 36

Currently Online:
6 Guest(s)

Currently Browsing this Page:
1 Guest(s)

Top Posters:

Skyler: 48

Derek: 46

Peter: 41

Frodson: 40

clau_ste: 39

Gwen: 32

JimmyM: 30

TheSmile: 27

EZB: 24

lppier: 23

Member Stats:

Guest Posters: 1

Members: 522

Moderators: 1

Admins: 4

Forum Stats:

Groups: 11

Forums: 31

Topics: 545

Posts: 2134

Newest Members:

Bill, hill william, NAUN_SONAR, sufy, Diane, Richard, drvenkman, venkman, Jfx, drorh

Moderators: W Pirkle: 247

Administrators: Tom: 67, JD Young: 80, Will Pirkle: 0, W Pirkle: 247