andrewm@89: /* andrewm@89: * render.cpp andrewm@89: * andrewm@89: * Created on: Oct 24, 2014 andrewm@89: * Author: parallels andrewm@89: */ andrewm@89: andrewm@89: giuliomoro@301: #include andrewm@89: #include andrewm@89: andrewm@89: int gBufferSize = 8192; andrewm@89: andrewm@91: // Double buffers to hold samples for noise analysis andrewm@91: float *gReadBuffers[10], *gWriteBuffers[10]; andrewm@91: float *gBuffers0[10], *gBuffers1[10]; andrewm@89: andrewm@91: int gWriteBufferPointers[10], gReadBufferPointers[10]; andrewm@89: andrewm@91: // Task to analyse and print results which would otherwise be too slow for render() andrewm@91: AuxiliaryTask gAnalysisTask; andrewm@89: andrewm@91: void analyseResults(); andrewm@89: andrewm@89: // setup() is called once before the audio rendering starts. andrewm@89: // Use it to perform any initialisation and allocation which is dependent andrewm@89: // on the period size or sample rate. andrewm@89: // andrewm@89: // userData holds an opaque pointer to a data structure that was passed andrewm@89: // in from the call to initAudio(). andrewm@89: // andrewm@89: // Return true on success; returning false halts the program. andrewm@89: giuliomoro@301: bool setup(BelaContext *context, void *userData) andrewm@89: { andrewm@89: // Clear the filter data structures andrewm@89: for(int i = 0; i < 10; i++) { andrewm@91: gReadBufferPointers[i] = gWriteBufferPointers[i] = 0; andrewm@91: gBuffers0[i] = new float[gBufferSize]; andrewm@91: gBuffers1[i] = new float[gBufferSize]; andrewm@91: gWriteBuffers[i] = gBuffers0[i]; andrewm@91: gReadBuffers[i] = gBuffers1[i]; andrewm@91: if(gBuffers0[i] == 0 || gBuffers1[i] == 0) { andrewm@89: rt_printf("Error allocating buffer %d\n", i); andrewm@89: return false; andrewm@89: } andrewm@89: } andrewm@89: andrewm@303: gAnalysisTask = Bela_createAuxiliaryTask(analyseResults, 50, "bela-analyse-results"); andrewm@89: andrewm@89: return true; andrewm@89: } andrewm@89: andrewm@89: // render() is called regularly at the highest priority by the audio engine. andrewm@89: // Input and output are given from the audio hardware and the other andrewm@89: // ADCs and DACs (if available). If only audio is available, numMatrixFrames andrewm@89: // will be 0. andrewm@89: giuliomoro@301: void render(BelaContext *context, void *userData) andrewm@89: { andrewm@89: bool bufferIsFull = false; // Whether at least one buffer has filled andrewm@89: andrewm@89: for(unsigned int n = 0; n < context->audioFrames; n++) { andrewm@89: // Store audio inputs in buffer andrewm@89: for(unsigned int ch = 0; ch < context->audioChannels; ch++) { andrewm@91: if(gWriteBufferPointers[ch] < gBufferSize) { andrewm@91: gWriteBuffers[ch][gWriteBufferPointers[ch]] = andrewm@89: context->audioIn[n * context->audioChannels + ch]; andrewm@91: gWriteBufferPointers[ch]++; andrewm@91: if(gWriteBufferPointers[ch] >= gBufferSize) andrewm@89: bufferIsFull = true; andrewm@89: } andrewm@89: } andrewm@89: } andrewm@89: andrewm@89: if(context->analogChannels != 0) { andrewm@89: for(unsigned int n = 0; n < context->analogFrames; n++) { andrewm@89: // Store analog inputs in buffer, starting at channel 2 andrewm@89: for(unsigned int ch = 0; ch < context->analogChannels; ch++) { andrewm@91: if(gWriteBufferPointers[ch + 2] < gBufferSize) { andrewm@91: gWriteBuffers[ch + 2][gWriteBufferPointers[ch + 2]] = andrewm@89: context->analogIn[n * context->analogChannels + ch]; andrewm@91: gWriteBufferPointers[ch + 2]++; andrewm@91: if(gWriteBufferPointers[ch + 2] >= gBufferSize) andrewm@89: bufferIsFull = true; andrewm@89: } andrewm@91: andrewm@91: // Set all analog outputs to halfway point so they can be more andrewm@91: // easily measured for noise andrewm@91: context->analogOut[n * context->analogChannels + ch] = 0.5; andrewm@89: } andrewm@89: } andrewm@89: } andrewm@91: andrewm@89: andrewm@89: if(bufferIsFull) { andrewm@91: // Swap buffers and reset write pointers andrewm@89: for(int ch = 0; ch < 10; ch++) { andrewm@91: gReadBufferPointers[ch] = gWriteBufferPointers[ch]; andrewm@91: gWriteBufferPointers[ch] = 0; andrewm@89: andrewm@91: if(gReadBuffers[ch] == gBuffers0[ch]) { andrewm@91: gReadBuffers[ch] = gBuffers1[ch]; andrewm@91: gWriteBuffers[ch] = gBuffers0[ch]; andrewm@89: } andrewm@91: else { andrewm@91: gReadBuffers[ch] = gBuffers0[ch]; andrewm@91: gWriteBuffers[ch] = gBuffers1[ch]; andrewm@91: } andrewm@89: } andrewm@89: giuliomoro@301: Bela_scheduleAuxiliaryTask(gAnalysisTask); andrewm@89: } andrewm@89: } andrewm@89: andrewm@91: void analyseResults() andrewm@89: { andrewm@89: rt_printf("\e[1;1H\e[2J"); // Command to clear the screen andrewm@91: andrewm@89: // Print the analysis results. channels 0-1 are audio, channels 2-9 are analog andrewm@89: for(int ch = 0; ch < 10; ch++) { andrewm@91: // Skip unused channels andrewm@91: if(gReadBufferPointers[ch] == 0) andrewm@89: continue; andrewm@89: andrewm@91: float mean = 0; andrewm@91: for(int n = 0; n < gReadBufferPointers[ch]; n++) { andrewm@91: mean += gReadBuffers[ch][n]; andrewm@91: } andrewm@91: mean /= (float)gReadBufferPointers[ch]; andrewm@91: andrewm@91: float rms = 0; andrewm@91: for(int n = 0; n < gReadBufferPointers[ch]; n++) { andrewm@91: rms += (gReadBuffers[ch][n] - mean) * (gReadBuffers[ch][n] - mean); andrewm@91: } andrewm@91: rms = sqrtf(rms / (float)gReadBufferPointers[ch]); andrewm@91: andrewm@89: if(ch == 0) andrewm@89: rt_printf("Audio In L: "); andrewm@89: else if(ch == 1) andrewm@89: rt_printf("Audio In R: "); andrewm@89: else andrewm@89: rt_printf("Analog In %d: ", ch - 2); andrewm@89: andrewm@89: rt_printf("Noise %6.1fdB DC offset %6.4f (%6.1fdB) window size: %d\n", andrewm@91: 20.0f * log10f(rms), andrewm@91: mean, andrewm@91: 20.0f * log10f(fabsf(mean)), andrewm@91: gReadBufferPointers[ch]); andrewm@89: } andrewm@89: } andrewm@89: andrewm@89: // cleanup() is called once at the end, after the audio has stopped. andrewm@89: // Release any resources that were allocated in setup(). andrewm@89: giuliomoro@301: void cleanup(BelaContext *context, void *userData) andrewm@89: { andrewm@91: for(int i = 0; i < 10; i++) { andrewm@91: delete gBuffers0[i]; andrewm@91: delete gBuffers1[i]; andrewm@91: } andrewm@89: }