victor@2: /* victor@2: * render.cpp victor@2: * victor@2: * Created on: Oct 24, 2014 victor@2: * Author: Andrew McPherson and Victor Zappi victor@2: */ victor@2: victor@2: andrewm@56: #include victor@2: #include victor@2: #include // neon library victor@2: #include "SampleData.h" victor@2: #include "FIRfilter.h" victor@2: victor@2: SampleData gSampleData; // User defined structure to get complex data from main victor@2: int gReadPtr; // Position of last read sample from file victor@2: victor@2: // filter vars victor@2: ne10_fir_instance_f32_t gFIRfilter; victor@2: ne10_float32_t *gFIRfilterIn; victor@2: ne10_float32_t *gFIRfilterOut; victor@2: ne10_uint32_t blockSize; victor@2: ne10_float32_t *gFIRfilterState; victor@2: andrewm@52: void initialise_filter(BeagleRTContext *context); victor@2: victor@2: // Task for handling the update of the frequencies using the matrix victor@2: AuxiliaryTask gTriggerSamplesTask; victor@2: victor@2: bool initialise_trigger(); victor@2: void trigger_samples(); victor@2: andrewm@56: // setup() is called once before the audio rendering starts. victor@2: // Use it to perform any initialisation and allocation which is dependent victor@2: // on the period size or sample rate. victor@2: // victor@2: // userData holds an opaque pointer to a data structure that was passed victor@2: // in from the call to initAudio(). victor@2: // victor@2: // Return true on success; returning false halts the program. victor@2: andrewm@56: bool setup(BeagleRTContext *context, void *userData) victor@2: { victor@2: victor@2: // Retrieve a parameter passed in from the initAudio() call victor@2: gSampleData = *(SampleData *)userData; victor@2: victor@2: gReadPtr = -1; victor@2: andrewm@52: initialise_filter(context); victor@2: victor@2: // Initialise auxiliary tasks victor@2: if(!initialise_trigger()) victor@2: return false; victor@2: victor@2: return true; victor@2: } victor@2: victor@2: // render() is called regularly at the highest priority by the audio engine. victor@2: // Input and output are given from the audio hardware and the other victor@2: // ADCs and DACs (if available). If only audio is available, numMatrixFrames victor@2: // will be 0. victor@2: andrewm@52: void render(BeagleRTContext *context, void *userData) victor@2: { andrewm@52: for(unsigned int n = 0; n < context->audioFrames; n++) { victor@2: float in = 0; victor@2: victor@2: // If triggered... victor@2: if(gReadPtr != -1) victor@2: in += gSampleData.samples[gReadPtr++]; // ...read each sample... victor@2: victor@2: if(gReadPtr >= gSampleData.sampleLen) victor@2: gReadPtr = -1; victor@2: victor@2: gFIRfilterIn[n] = in; victor@2: } victor@2: victor@2: ne10_fir_float_neon(&gFIRfilter, gFIRfilterIn, gFIRfilterOut, blockSize); victor@2: andrewm@52: for(unsigned int n = 0; n < context->audioFrames; n++) { andrewm@52: for(unsigned int channel = 0; channel < context->audioChannels; channel++) andrewm@52: context->audioOut[n * context->audioChannels + channel] = gFIRfilterOut[n]; // ...and put it in both left and right channel victor@2: } victor@2: victor@2: victor@2: // Request that the lower-priority task run at next opportunity andrewm@52: BeagleRT_scheduleAuxiliaryTask(gTriggerSamplesTask); victor@2: } victor@2: victor@2: // Initialise NE10 data structures to define FIR filter victor@2: andrewm@52: void initialise_filter(BeagleRTContext *context) victor@2: { andrewm@52: blockSize = context->audioFrames; victor@2: gFIRfilterState = (ne10_float32_t *) NE10_MALLOC ((FILTER_TAP_NUM+blockSize-1) * sizeof (ne10_float32_t)); victor@2: gFIRfilterIn = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); victor@2: gFIRfilterOut = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); victor@2: ne10_fir_init_float(&gFIRfilter, FILTER_TAP_NUM, filterTaps, gFIRfilterState, blockSize); victor@2: } victor@2: victor@2: victor@2: // Initialise the auxiliary task victor@2: // and print info victor@2: victor@2: bool initialise_trigger() victor@2: { andrewm@52: if((gTriggerSamplesTask = BeagleRT_createAuxiliaryTask(&trigger_samples, 50, "beaglert-trigger-samples")) == 0) victor@2: return false; victor@2: victor@2: rt_printf("Press 'a' to trigger sample, 's' to stop\n"); victor@2: rt_printf("Press 'q' to quit\n"); victor@2: victor@2: return true; victor@2: } victor@2: victor@2: // This is a lower-priority call to periodically read keyboard input victor@2: // and trigger samples. By placing it at a lower priority, victor@2: // it has minimal effect on the audio performance but it will take longer to victor@2: // complete if the system is under heavy audio load. victor@2: victor@2: void trigger_samples() victor@2: { victor@2: // This is not a real-time task! victor@2: // Cos getchar is a system call, not handled by Xenomai. victor@2: // This task will be automatically down graded. victor@2: victor@2: char keyStroke = '.'; victor@2: victor@2: keyStroke = getchar(); victor@2: while(getchar()!='\n'); // to read the first stroke victor@2: victor@2: switch (keyStroke) victor@2: { victor@2: case 'a': victor@2: gReadPtr = 0; victor@2: break; victor@2: case 's': victor@2: gReadPtr = -1; victor@2: break; victor@2: case 'q': victor@2: gShouldStop = true; victor@2: break; victor@2: default: victor@2: break; victor@2: } victor@2: } victor@2: victor@2: victor@2: 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@2: andrewm@56: void cleanup(BeagleRTContext *context, void *userData) victor@2: { victor@2: delete[] gSampleData.samples; victor@2: victor@2: NE10_FREE(gFIRfilterState); victor@2: NE10_FREE(gFIRfilterIn); victor@2: NE10_FREE(gFIRfilterOut); victor@2: }