victor@4: /* victor@4: * render.cpp victor@4: * victor@4: * Created on: Oct 24, 2014 victor@4: * Author: parallels victor@4: */ victor@4: victor@4: giuliomoro@301: #include victor@4: #include victor@4: #include // neon library victor@4: #include victor@4: andrewm@5: int gFFTSize; andrewm@5: float gFFTScaleFactor = 0; victor@4: victor@4: int gReadPointer = 0; victor@4: int gWritePointer = 0; victor@4: victor@4: // FFT vars andrewm@5: ne10_fft_cpx_float32_t* timeDomainIn; andrewm@5: ne10_fft_cpx_float32_t* timeDomainOut; victor@4: ne10_fft_cpx_float32_t* frequencyDomain; victor@4: ne10_fft_cfg_float32_t cfg; victor@4: andrewm@56: // setup() is called once before the audio rendering starts. victor@4: // Use it to perform any initialisation and allocation which is dependent victor@4: // on the period size or sample rate. victor@4: // victor@4: // userData holds an opaque pointer to a data structure that was passed victor@4: // in from the call to initAudio(). victor@4: // victor@4: // Return true on success; returning false halts the program. victor@4: giuliomoro@301: bool setup(BelaContext *context, void *userData) victor@4: { victor@4: // Retrieve a parameter passed in from the initAudio() call andrewm@5: gFFTSize = *(int *)userData; andrewm@5: gFFTScaleFactor = 1.0f / (float)gFFTSize; victor@4: andrewm@5: timeDomainIn = (ne10_fft_cpx_float32_t*) NE10_MALLOC (gFFTSize * sizeof (ne10_fft_cpx_float32_t)); andrewm@5: timeDomainOut = (ne10_fft_cpx_float32_t*) NE10_MALLOC (gFFTSize * sizeof (ne10_fft_cpx_float32_t)); andrewm@5: frequencyDomain = (ne10_fft_cpx_float32_t*) NE10_MALLOC (gFFTSize * sizeof (ne10_fft_cpx_float32_t)); andrewm@5: cfg = ne10_fft_alloc_c2c_float32 (gFFTSize); victor@4: andrewm@5: memset(timeDomainOut, 0, gFFTSize * sizeof (ne10_fft_cpx_float32_t)); victor@4: victor@4: return true; victor@4: } victor@4: victor@4: // render() is called regularly at the highest priority by the audio engine. victor@4: // Input and output are given from the audio hardware and the other victor@4: // ADCs and DACs (if available). If only audio is available, numMatrixFrames victor@4: // will be 0. victor@4: giuliomoro@301: void render(BelaContext *context, void *userData) victor@4: { andrewm@52: for(unsigned int n = 0; n < context->audioFrames; n++) { andrewm@52: timeDomainIn[gReadPointer].r = (ne10_float32_t) ((context->audioIn[n*context->audioChannels] + andrewm@52: context->audioIn[n*context->audioChannels+1]) * 0.5); andrewm@5: timeDomainIn[gReadPointer].i = 0; victor@4: andrewm@5: if(++gReadPointer >= gFFTSize) andrewm@5: { andrewm@5: //FFT andrewm@5: ne10_fft_c2c_1d_float32_neon (frequencyDomain, timeDomainIn, cfg->twiddles, cfg->factors, gFFTSize, 0); victor@4: andrewm@5: //Do frequency domain stuff victor@4: andrewm@5: //IFFT andrewm@5: ne10_fft_c2c_1d_float32_neon (timeDomainOut, frequencyDomain, cfg->twiddles, cfg->factors, gFFTSize, 1); victor@4: andrewm@5: gReadPointer = 0; andrewm@5: gWritePointer = 0; andrewm@5: } victor@4: andrewm@56: for(unsigned int channel = 0; channel < context->audioChannels; channel++) andrewm@52: context->audioOut[n * context->audioChannels + channel] = (float) timeDomainOut[gWritePointer].r * gFFTScaleFactor; andrewm@5: gWritePointer++; victor@4: } victor@4: } victor@4: andrewm@56: // cleanup() is called once at the end, after the audio has stopped. andrewm@56: // Release any resources that were allocated in setup(). victor@4: giuliomoro@301: void cleanup(BelaContext *context, void *userData) victor@4: { andrewm@5: NE10_FREE(timeDomainIn); andrewm@5: NE10_FREE(timeDomainOut); victor@4: NE10_FREE(frequencyDomain); victor@4: NE10_FREE(cfg); victor@4: }