Demo: Frequency Analysis Using Integrated Performance Primitives Share your comment!

Part of an ongoing series showing what parallel tools can do

Let’s pick up three neat tools from the Intel parallel arsenal. The first is cilk_spawn, which spins up a new thread to do some work. The second, cilk::reducer_opadd, provides a safe way to signal other parts of an application. The third — and for me the coolest — is the Fast Fourier Transform (FFT), which comes with the Intel Integrated Performance Primitives (IPP).

An FFT converts data from time domain to frequency domain.   It might not be completely obvious why it is important to transform data from the time domain to the frequency domain. To explain this, let’s consider raw audio data. It is in the form of amplitudes that change over time such as what is shown in Figure 1. It is not obvious from the raw wave data what the component frequencies are. In order to derive the component frequencies along with their relative strength, you can do a Fourier Transform.  The Intel Fast Fourier Transform (FFT) code transforms audio data to the frequency domain and provides an array which contains the output data. I wrote a simple demo program in which the FFT takes incoming audio data and converts it to frequencies. Let’s see how we do…

Figure 1: Audio data pictured graphically.

Ok, Let’s Roll Audio…

The first thing that I did was to create a C++ class that records a second of audio from the microphone. This is straightforward; if you look at the demo program’s source code you can see it in the CAudioIn class. The GetSample() method returns an array of short (16-bit) values.

The next step was to create to a C++ class that wraps the IPP FFT code. I named the C++ class CFFT and the method that performs an FFT on the audio data DoIt(). I often used FFTs, which always involved significant amounts of code — not only to perform the FFTs, but to set up and call the FFT code. Intel has made this pretty easy. The following code shows you how I call IPP FFT functionality.

int power = 12;

Ipp32fc* pFilterCCS;

IppsFFTSpec_R_32f *pFFTSpec;

// allocate space for FFT

pFilterCCS = (Ipp32fc*)ippsMalloc_32f(nNumSamples+2);

// FFT configure

Ipp32fc one = {1.0, 0.0};

// zero initialize the FFT space

ippsZero_32fc( pFilterCCS, nNumSamples/2+1 );

//initialize the FFT

ippsFFTInitAlloc_R_32f( &pFFTSpec,

power, IPP_FFT_DIV_BY_SQRTN, ippAlgHintFast );

// do the FFT

ippsFFTFwd_RToPerm_32f(pAudioIn,(Ipp32f*)_pDataOut, pFFTSpec,0);

// free up the FFT space

ippsFree(pFFTSpec);

ippsFree( pAudioIn );

Implement Smartly, Please

Now that we’re set up to record audio and analyze it, the application needs to implement smartly. To manage the sequence of necessary events, a cilk::reducer_opadd was implemented. The following values signal each application aspect about when to perform its task.

enum{ IDLE, READY_TO_RECORD, CURRENTLY_RECORDING,

  READY_TO_ANALYZE, CURRENTLY_ANALYZING, READY_TO_REDRAW };

A cilk::reducer_opadd essentially performs the same function as a simple variable, except that it is thread-safe. This avoids and conflicts or race conditions. While a simple integer variable could be used, there’s a chance access to it will experience race conditions, in which multiple threads attempt access.

Finally, calls to the methods  that record the audio and analyze it are done in newly spawned threads with the cilk_spawn keyword. Performing these functions from within a separate thread prevents the user interface from hanging up – (or any other application functions, for that matter).

When the application runs, after the audio has been recorded and analyzed, the first ten data points of the FFT output are graphed in the application window as shown in Figure 1.

 FrequencyAnalysis

Figure 1: The application graphs the first ten data points from the FFT analysis.

This is impressive functionality to be implemented so easily. The Intel IPP adds a lot of extremely useful and efficient functions such as the FFT used in this demo program. FFTs are very computationally intensive, but I must say the Intel IPP technology handled it with ease and efficiency.The cilk extensions give you an extremely simple way to spin up a thread in which work can be done. And other tools such as cilk::reducer_opadd provide ways to synchronize application functionality.

Please leave your comments and questions below. I’ll be writing similar articles in the future to illustrate different tools in the well-packed Intel Parallel Studio toolbox. If you’re interested in the demo program in this blog, you can download it here.

Posted on June 4, 2013 by Rick Leinecker, Slashdot Media Contributing Editor