This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[OMAP-L137] FFT Problem in Audio Sample Project

Other Parts Discussed in Thread: CCSTUDIO

Hi,

I am trying to take fft in audio sample project given in pspdrivers_01_30_01. I am using OMAP L137 EVM and I am new in TI DSPs. As you know, in audio sample project the audio input is taken from line in jack and the output is given from the headphone out without any change. I have tried to take fft first and then take inverse fft in order to hear the input signal again, but strange sounds were heard from the output.

The first thing I have tried is to add the real fft function with a modification. This example is taken from the following link;

http://processors.wiki.ti.com/index.php/Efficient_FFT_Computation_of_Real_Input

This function is modified as follows;

void Real_FFT (float *input, float *output)
{
 int i, rad, nTemp = N / 2;
 float *twiddle;

 if (nTemp == 16 || nTemp == 64 || nTemp == 256 || nTemp == 1024 || nTemp == 4096 || nTemp == 16384)
  rad = 4;
 else if (nTemp == 8 || nTemp == 32 || nTemp == 128 || nTemp == 512 || nTemp == 2048 || nTemp == 8192)
  rad = 2;
 else
 {
  printf ("%d Value of N is not supported \n", N);
  exit (0);
 } 

 // Real FFT of length N/2

 for (i = 0; i < N/2; i++)
 {
  pRFFT_In[2 * i] = input[2*i];            //arrange real input sequence to
  pRFFT_In[2 * i + 1] =input[2*i+1];   //N/2 complex sequence..
  //printf("input[%d] = %15.4f\n",2*i,input[2*i]);

 }
 tw_gen (w, N / 2);
 split_gen (A, B, N / 2);

 twiddle = (float *) w;

 DSPF_sp_fftSPxSP (N / 2, pRFFT_In, twiddle, pTemp, brev, rad, 0, N / 2);
 // FFT Split call to get complex FFT out of length N..
 FFT_Split (N / 2, pTemp, A, B, pRFFT_Out);

 IFFT_Split (N / 2, pRFFT_Out, A, B, pTemp);
 // Inverse FFT Calculation using N/2 complex IFFT..
 DSPF_sp_ifftSPxSP (N / 2, pTemp, twiddle, output, brev, rad, 0, N / 2);
}

And it was called inside Audio_echo_Task() as;

Real_FFT((float *)&rcv,(float *)&xmt);

1) I have decreased the "BUFLEN" from 2560 to 1024 to be compatible with the FFT size (The fft size N = 1024)

2) I have changed .far in .cmd file from IRAM to SDRAM in order to solve the link error.

3) After the is compiled and linked with success, there are two remarks remain as shown below;

"D:/Program Files/Texas Instruments/C6000 Code Generation Tools 6.1.9/include/math.h", line 63: remark: function "_FMOD" was declared but never referenced
"D:/Program Files/Texas Instruments/C6000 Code Generation Tools 6.1.9/include/mathf.h", line 141: remark: function "_FMODF" was declared but never referenced

The second thing I have tried is to call the complex fft functions with the same logic, but the result does not change. Again I heard strange sounds or no sound.

What can be wrong? Can you give an idea about this issue? Is there any setting in order to use DSPLIB together with DSP/BIOS?

Thanks&Best Regards,

Fikret

  • Hi,

    Nobody knows this? I want to be able to take FFT and inverse FFT on audio sample project and to hear the audio without any problem. Is this so hard? I have tried several things but I dont know the reason why I can't hear the input audio at headphone out. Appreciated for your helps.

    Best Regards,

    Fikret

  • Fikret,

    You may want to try a simple test to narrow down where the problem is coming from.  I would recommend doing a complex FFT/IFFT pair without worrying about the real FFT trick.  Obviously, the FFT data won't be meaningful if you look at it, but the IFFT will still get you back to the original input signal.

    Also: the audio driver gives you data in a packed (stereo) 16-bit, fixed point format.  Are you converting this to single-precision floating point before calling the FFT function?  You need to cast and normalize these values to workable floating point values before you start processing.  After processing, you need to bring everything back to the fixed point domain.  Here's what that might look like:

    // float *left_buffer, *right_buffer; Int16 *audio_in_buffer, audio_out_buffer;
    for (i = 0; i < length; i++)
    {
        left_buffer[i]  = (float)audio_in_buffer[i * 2] / 32768.0f;
        right_buffer[i] = (float)audio_in_buffer[i * 2 + 1] / 32768.0f;
    }
    // processing on left_buffer, right_buffer...
    for (i = 0; i < length; i++)
    {
        audio_out_buffer[i * 2] = (Int16)(left_buffer[i] * 32768.0f);
        audio_out_buffer[i * 2 + 1] = (Int16)(right_buffer[i] * 32768.0f);
    }

    In the above code, the floating point values should be kept in the +/- 1 range.

    Hope this helps.

  • Dear Joe,

    Thank you for your reply. I didn't know the procedure that you explained. I was trying to use the audio driver output directly.

    For the first step, I forgot FFT. I have just wanted to apply the steps you explained without any processing and to hear the input audio at output again. But I didn't hear the audio, when I printed the left_buffer and right buffer, they are printed as zero. I have applied a 250 Hz sinusoid signal at the input. I can read "rcv" variable as shown in the below code, but the left_buffer and right_buffer are obtained as zero. I am working with pspdrivers_01_30_01. I am adding the audioSample_io.c below. What can be wrong?

    If I create the variables you mentioned outside Audio_Echo_Task() as global variables, instead of creating them inside the function, the result is same. But I noted that the addresses of four of that variables are 0xFFFFFFF. Is there any extra adjustments required, for example inside the cmd file? Thank you for your interest.

    Best Regards,

    Fikret

     

    #include "stdio.h"

    #include "std.h"

    #include "sio.h"

    #include "iom.h"

    #include "mem.h"

    #include "log.h"

    #include "ti/pspiom/platforms/evmOMAPL137/audio/Audio.h"

    #include "ti/pspiom/mcasp/Mcasp.h"

    #include "ti/sdo/edma3/drv/edma3_drv.h"

     

    /* ========================================================================== */

    /*                          IMPORTED VARIABLES                                */

    /* ========================================================================== */

     

    extern Int edma3init();

    extern EDMA3_DRV_Handle hEdma;

    extern LOG_Obj trace;

     

    /* ========================================================================== */

    /*                          MACRO DEFINITIONS                                 */

    /* ========================================================================== */

     

    /*

     * Buffers placed in external memory are aligned on a 128 bytes boundary.

     * In addition, the buffer should be of a size multiple of 128 bytes for

     * the cache work optimally on the C6x.

     */

    #define BUFLEN                  2560         /* number of samples in the frame */

    #define BUFALIGN                128 /* alignment of buffer for use of L2 cache */

     

     

    /** Number of serializers configured for record */

    #define RX_NUM_SERIALIZER       (1u)

    #define TX_NUM_SERIALIZER       (1u)

     

    #define BUFSIZE                 (BUFLEN * sizeof(Int16))

     

    #define NUM_BUFS                4   /* Num Bufs to be issued and reclaimed */

     

    /* inStream and outStream are stream handles created in main */

    static SIO_Handle inStream, outStream;

     

    /* Function prototype */

    static Void createStreams();

    static Void prime();

     

    Ptr buf[NUM_BUFS * 2];

     

    Mcasp_HwSetupData mcaspRcvSetup = {

            /* .rmask    = */ 0xFFFFFFFF, /* All the data bits are to be used     */

            /* .rfmt     = */ 0x000080F0, /*

                                           * 0 bit delay from framsync

                                           * MSB first

                                           * No extra bit padding

                                           * Padding bit (ignore)

                                           * slot Size is 32

                                           * Reads from DMA port

                                           * NO rotation

                                           */

            /* .afsrctl  = */ 0x00000000, /* burst mode,

                                           * Frame sync is one bit

                                           * Rising edge is start of frame

                                           * externally generated frame sync

                                           */

            /* .rtdm     = */ 0x00000001, /* slot 1 is active (DSP)               */

            /* .rintctl  = */ 0x00000003, /* sync error and overrun error         */

            /* .rstat    = */ 0x000001FF, /* reset any existing status bits       */

            /* .revtctl  = */ 0x00000000, /* DMA request is enabled or disabled   */

            {

                 /* .aclkrctl  = */ 0x00000000,

                 /* .ahclkrctl = */ 0x00000000,

                 /* .rclkchk   = */ 0x00000000

            }

    } ;

     

    Mcasp_HwSetupData mcaspXmtSetup = {

            /* .xmask    = */ 0xFFFFFFFF, /* All the data bits are to be used     */

            /* .xfmt     = */ 0x000080F0, /*

                                           * 0 bit delay from framsync

                                           * MSB first

                                           * No extra bit padding

                                           * Padding bit (ignore)

                                           * slot Size is 32

                                           * Reads from DMA port

                                           * NO rotation

                                           */

            /* .afsxctl  = */ 0x00000000, /* burst mode,

                                           * Frame sync is one bit

                                           * Rising edge is start of frame

                                           * externally generated frame sync

                                           */

            /* .xtdm     = */ 0x00000001, /* slot 1 is active (DSP)               */

            /* .xintctl  = */ 0x00000007, /* sync error,overrun error,clK error   */

            /* .xstat    = */ 0x000001FF, /* reset any existing status bits       */

            /* .xevtctl  = */ 0x00000000, /* DMA request is enabled or disabled   */

            {

                 /* .aclkxctl  = */ 0x00000000,

                 /* .ahclkxctl = */ 0x00000000,

                 /* .xclkchk   = */ 0x00000000

            },

     

    };

     

     

    /* McBsp channel parameters                                  */

    Mcasp_ChanParams  mcasp_chanparam[Audio_NUM_CHANS]=

    {

        {

            0x0001,                    /* number of serialisers      */

            {Mcasp_SerializerNum_0, }, /* serialiser index           */

            &mcaspRcvSetup,

            TRUE,

            Mcasp_OpMode_TDM,          /* Mode (TDM/DIT)             */

            Mcasp_WordLength_32,

            NULL,

            0,

            NULL,

            NULL,

            1,                        /* number of TDM channels      */

            Mcasp_BufferFormat_1SER_1SLOT,

            TRUE,

            TRUE

        },

        {

            0x0001,                   /* number of serialisers       */

            {Mcasp_SerializerNum_5,},

            &mcaspXmtSetup,

            TRUE,

            Mcasp_OpMode_TDM,

            Mcasp_WordLength_32,      /* word width                  */

            NULL,

            0,

            NULL,

            NULL,

            1,                        /* number of TDM channels      */

            Mcasp_BufferFormat_1SER_1SLOT,

            TRUE,

            TRUE

        }

    };

     

    Audio_ChannelConfig audioChanParamsIN =

    {

       /*  channel 0 (RX)                                            */

        (Ptr)&mcasp_chanparam[0], 

        {   /* codec [0]                                              */

            {

                44100,  /* sampling rate for codec */

      30,  /* gain (%) for codec      */

                 0x00,

                 0x00

            }

        }

    };

     

    Audio_ChannelConfig audioChanParamsOUT =

    {        

        /*  channel 1 (TX)                                            */

        (Ptr)&mcasp_chanparam[1],      

        {

            /* codec [1]                           */

            {

                44100,  /* sampling rate           */

      70,  /* gain (%) for codec      */

                 0x00,

                 0x00

            }

        }

    };

     

    /*

     * ======== createStreams ========

     */

    static Void createStreams()

    {

        SIO_Attrs sioAttrs;

     

        sioAttrs   = SIO_ATTRS;

        sioAttrs.nbufs = NUM_BUFS;

        sioAttrs.align = BUFALIGN;

        sioAttrs.model = SIO_ISSUERECLAIM;

     

    mcasp_chanparam[0].edmaHandle = hEdma;

        mcasp_chanparam[1].edmaHandle = hEdma;

     

        /* open the I/O streams */

        outStream = SIO_create("/dioAudioOUT", SIO_OUTPUT, BUFSIZE, &sioAttrs);

     

        if (outStream == NULL)

        {

            LOG_printf(&trace,"\r\nCreate output stream FAILED.\n");

            return;

        }

     

        inStream = SIO_create("/dioAudioIN", SIO_INPUT, BUFSIZE, &sioAttrs);

     

        if (inStream == NULL)

        {

            LOG_printf(&trace,"\r\nCreate input stream FAILED.\n");

            return;

        }

    }

     

    /*

     * ======== prime ========

     */

    static Void prime()

    {

        Int32        count = 0;

     

        /* Allocate buffers for the SIO buffer exchanges */

        for(count = 0; count < (NUM_BUFS ); count ++)

        {

            buf[count] = (Ptr)MEM_calloc(0, BUFSIZE * RX_NUM_SERIALIZER, BUFALIGN);

            if(NULL == buf[count])

            {

                LOG_printf(&trace,"\r\nMEM_calloc failed.\n");

            }

        }

     

        /* Allocate buffers for the SIO buffer exchanges */

        for(count = NUM_BUFS; count < (NUM_BUFS * 2); count ++)

        {

            buf[count] = (Ptr)MEM_calloc(0, BUFSIZE * TX_NUM_SERIALIZER, BUFALIGN);

            if(NULL == buf[count])

            {

                LOG_printf(&trace,"\r\nMEM_calloc failed.\n");

            }

        }

     

        for(count = 0; count < NUM_BUFS; count ++)

        {

            /* Issue the first & second empty buffers to the input stream */

            SIO_issue(inStream, buf[count], BUFSIZE * RX_NUM_SERIALIZER, NULL);

        }

     

        for(count = NUM_BUFS; count < (NUM_BUFS * 2); count ++)

        {

            SIO_issue(outStream, buf[count], BUFSIZE * TX_NUM_SERIALIZER,NULL);

        }

    }

     

     

    /*

     * ======== echo ========

     * This function copies from the input SIO to the output SIO. You could

     * easily replace the copy function with a signal processing algorithm.

     */

    Void Audio_echo_Task()

    {

        volatile int i32Count;

        Int nmadus = 0;

        float *left_buffer, *right_buffer; 

    Int16 *audio_in_buffer, *audio_out_buffer;

    Int16 *rcv,*xmt;

     

    int i;

        /* initialise the edma library                                            */

        edma3init();

     

        /* Call createStream function to create I/O streams                       */

        createStreams();

     

        /* Call prime function to do priming                                      */

        prime();

     

        /* Forever loop to continously receviec and transmit audio data           */

        for (i32Count = 0; i32Count >= 0; i32Count++)

        {

            nmadus = SIO_reclaim(inStream, (Ptr *)&rcv, NULL);

     

            /* Reclaim full buffer from the input stream */

            if (nmadus < 0)

            {

                LOG_printf(&trace,"\r\nError reclaiming full buffer from the input stream\n");

            }

     

            /* Reclaim empty buffer from the output stream to be reused */

            nmadus = SIO_reclaim(outStream, (Ptr *)&xmt, NULL);

            if (nmadus < 0)

            {

                LOG_printf(&trace,"\r\nError reclaiming empty buffer from the output stream\n");

            }

    for (i = 0; i < BUFLEN; i++)

    {

    printf("\n rcv[%d]= %d",2*i,rcv[2*i]);

       left_buffer[i]  = (float)rcv[i * 2] / 32768.0f;

       right_buffer[i] = (float)rcv[i * 2 + 1] / 32768.0f;

    printf("\n left_buffer[%d] = %f ",i,left_buffer[i]);

    printf("\n right_buffer[%d] = %f ",i,right_buffer[i]);

    }

    // processing on left_buffer, right_buffer...

    for (i = 0; i < BUFLEN; i++)

    {

       audio_out_buffer[i * 2] = (Int16)(left_buffer[i] * 32768.0f);

       audio_out_buffer[i * 2 + 1] = (Int16)(right_buffer[i] * 32768.0f);

    }

            /* copy the receive information to the transmit buffer                */

            memcpy(xmt,audio_out_buffer,BUFSIZE * RX_NUM_SERIALIZER);

     

            /* Issue full buffer to the output stream    */

            if (SIO_issue(outStream, xmt, BUFSIZE * TX_NUM_SERIALIZER, NULL)

       != SYS_OK)

            {

                LOG_printf(&trace,"\r\nFailed to issue empty buffer to stream\n");

            }

     

     

            /* Issue an empty buffer to the input stream */

            if (SIO_issue(inStream, rcv, BUFSIZE * RX_NUM_SERIALIZER, NULL)

       != SYS_OK)

            {

                LOG_printf(&trace,"\r\nFailed to issue empty buffer to stream\n");

            }

        }

    }

     

     

     

     

  • Fikret,

    It looks like you may have neglected to allocate your floating point buffers.  You've only created pointers, not buffers, so you can't de-reference them (i.e. name[index]) as-is.  You can statically allocate buffers like this:

    float left_buffer[BUFLEN], right_buffer[BUFLEN];

    Or you can do it dynamically, like the audio buffers are done elsewhere in your code:

    float *left_buffer, *right_buffer;
    left_buffer  = MEM_alloc(0, BUFLEN * sizeof(float), BUFALIGN);
    right_buffer = MEM_alloc(0, BUF
    LEN * sizeof(float), BUFALIGN);

    Also, you may have too many audio buffer pointers in the Audio_echo_Task function.  I see two sets of pointers, rcv/xmt and audio_in_buffer/audio_out_buffer, but the second set seems redundant.  The only one that's used is audio_out_buffer, but its contents are simply copied to xmt using memcpy.  If you want to keep this second set of buffers, you will need to allocate them as with the floating point buffers, above.

    Hope this helps.

  • Dear Joe,

    I added the settings to the code, I also added FFT and inverse FFT. Now it works fine. Thank very much you for your support, really appreciated.

    I take FFT separately for left channel and right channel and inverse FFT in the same way as follows;

    DSPF_sp_fftSPxSP (N, pCFFT_InLeft, twiddle, pCFFT_OutLeft, brev, rad, 0, N);

    DSPF_sp_fftSPxSP (N, pCFFT_InRight, twiddle, pCFFT_OutRight, brev, rad, 0, N);

    // Inverse FFT Calculation..

    DSPF_sp_ifftSPxSP (N, pCFFT_OutLeft, twiddle, pCFFT_InvOutLeft, brev, rad, 0, N);

    DSPF_sp_ifftSPxSP (N, pCFFT_OutRight, twiddle, pCFFT_InvOutRight, brev, rad, 0, N);

    This can not be performed for both channels at the same time right?

    My last question is about the compile remarks. 

    [audioSample_io.c] "D:\Program Files\Texas Instruments\C6000 Code Generation Tools 6.1.9\bin\cl6x" -g -pdr -fr"D:/Program Files/Texas Instruments/pspdrivers_01_30_01/packages/ti/pspiom/examples/evm6747/audio/build/ccs3/Debug" -i"D:/Program Files/Texas Instruments/pspdrivers_01_30_01/packages/ti/pspiom/examples/evm6747/audio/build/ccs3/../../../../../../../" -i"D:/C674x_dsp_1_00_00_11/edma3_lld_01_10_00_01/packages" -i"D:/CCStudio_v3.3/c674x/dsplib_v12" -mv6740 -@"../build/ccs3/Debug.lkf" "audioSample_io.c"

    "D:/Program Files/Texas Instruments/C6000 Code Generation Tools 6.1.9/include/math.h", line 63: remark: function "_FMOD" was declared but never referenced

    "D:/Program Files/Texas Instruments/C6000 Code Generation Tools 6.1.9/include/mathf.h", line 141: remark: function "_FMODF" was declared but never referenced

    When I build the code, the above remarks are created. They didn't cause any problems for the execution of the program, but are they important? How can they be solved. 
    And last thing I want ask is about the cmd file, I changed .far from IRAM to SDRAM in the cmd file in order to fix the compile errors, but I did this with trial and error. Is there any document of TI about memory management and/or cmd file?
    Thank you for your helps again.
    Best Regards,
    Fikret

  • Fikret,

    Don't worry about those remarks; they will appear in any application that uses math.h.  A remark is not harmful; it generally points out somewhere that your code (in this case, TI's code) could be cleaner.  On the other hand, a warning will inform you if there's a problem that could potentially lead to unintended consequences in your program.  A warning should generally be fixed, but a remark is usually safe enough as-is.

    As for memory segments, the most likely reason that a program will successfully build and run in IRAM but not SDRAM is that your code and/or buffers are too big to fit in IRAM.  Look at the datasheet for your device to see how much IRAM you have to work with.  (For OMAP-L1x, IRAM is another name for L2RAM, which is 256 KB in size.)  This is something you can't really get away from in embedded programming.

    I'm glad that I could help you with your application.