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: victor@4: #include "../../include/render.h" victor@4: #include victor@4: #include // neon library victor@4: #include victor@4: andrewm@5: int gFFTSize; andrewm@5: float gFFTScaleFactor = 0; victor@4: int gNumChannels; 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: victor@4: // initialise_render() 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: victor@4: bool initialise_render(int numChannels, int numMatrixFramesPerPeriod, victor@4: int numAudioFramesPerPeriod, float matrixSampleRate, victor@4: float audioSampleRate, 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: gNumChannels = numChannels; 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: victor@4: void render(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut, victor@4: uint16_t *matrixIn, uint16_t *matrixOut) victor@4: { victor@4: for(int n = 0; n < numAudioFrames; n++) { andrewm@5: timeDomainIn[gReadPointer].r = (ne10_float32_t) ((audioIn[n*gNumChannels] + audioIn[n*gNumChannels+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: victor@4: for(int channel = 0; channel < gNumChannels; channel++) andrewm@5: audioOut[n * gNumChannels + channel] = (float) timeDomainOut[gWritePointer].r * gFFTScaleFactor; andrewm@5: gWritePointer++; victor@4: } victor@4: } victor@4: victor@4: // cleanup_render() is called once at the end, after the audio has stopped. victor@4: // Release any resources that were allocated in initialise_render(). victor@4: victor@4: void cleanup_render() victor@4: { andrewm@5: NE10_FREE(timeDomainIn); andrewm@5: NE10_FREE(timeDomainOut); victor@4: NE10_FREE(frequencyDomain); victor@4: NE10_FREE(cfg); victor@4: }