10*log10(sum(audioFrame.2)) is shorthand for computing the power in the frame. Here's the code. My main problem is that I can get the scope to display at the audio sample rate, which is not what I want, but I cannot get it to display at the frame rate. It never triggers. I'm not sure if the problem is somehow with the update rate, or with the triggering. Thanks.
#include <Bela.h>
#include <algorithm> // possibly not needed
#include <assert.h>
#include <cmath>
#include <string.h>
#include <libraries/Scope/Scope.h>
int gAudioNumChannels; // number of audio channels to iterate over
int gAudioBufferSize;
int gInputBufferPointer = 0;
int gRenderCounter = 0;
int gStartSample;
float *gInputBufferL = NULL;
float *gInputBufferR = NULL;
float gPowerL = 0.0;
float gPowerR = 0.0;
float gFs; // sample rate
//Instantiate a scope
Scope scope;
bool setup(BelaContext *context, void *userData)
{
// Number of audio channels
gAudioNumChannels = context->audioInChannels;
assert(gAudioChannelNum == 2);
// Number of samples per input buffer
gAudioBufferSize = context->audioFrames;
// Sample rate
gFs = context->audioSampleRate;
// Allocate the input buffers
gInputBufferL = (float *)malloc(2 * gAudioBufferSize * sizeof(float)); // x2 to allow for overlap in processing
gInputBufferR = (float *)malloc(2 * gAudioBufferSize * sizeof(float)); // x2 to allow for overlap in processing
if(gInputBufferL == 0 || gInputBufferR == 0) {
rt_printf("Failed to allocate gInputBuffer (L or R) in setup().\n");
return false;
}
// Initialize to 0
memset(gInputBufferL, 0, 2 * gAudioBufferSize * sizeof(float));
memset(gInputBufferR, 0, 2 * gAudioBufferSize * sizeof(float));
// Always write data into the second half of the buffer, which is
// twice as long as the frame.
gStartSample = (int)(gAudioBufferSize);
// Set up the scope: 2 channels, update at the frame rate
scope.setup(2, (float)(gFs/gAudioBufferSize));
//scope.setup(2, gFs); // for testing scope at audio sample rate, not what I want
return true;
}
void render(BelaContext *context, void *userData)
{
float powerL, powerR;
// Manually trigger the scope (THIS DOESN'T WORK)
if (gRenderCounter == 0)
scope.trigger();
// Copy the 2nd half of the buffer to the first
memcpy(gInputBufferL, &gInputBufferL[gAudioBufferSize], sizeof(float) * gAudioBufferSize); // copy second half to first
memcpy(gInputBufferR, &gInputBufferR[gAudioBufferSize], sizeof(float) * gAudioBufferSize); // copy second half to first
// Now read from the mics and write into the 2nd half of the main buffers (L and R)
for(unsigned int n = 0; n < gAudioBufferSize; n++) {
gInputBufferL[gStartSample + n] = audioRead(context, n, 0);
gInputBufferR[gStartSample + n] = audioRead(context, n, 1);
// This scope.log call works (at the audio sample rate) but is not what I want
//scope.log(gInputBufferL[gStartSample + n], gInputBufferR[gStartSample + n]);
} // end n loop over frames (samples)
// Compute the power in the buffer
powerL = powerR = 0.0;
for(unsigned int n = 0; n < 2*gAudioBufferSize; n++) {
powerL += gInputBufferL[n]*gInputBufferL[n];
powerR += gInputBufferR[n]*gInputBufferR[n];
}
powerL = 10*log10(powerL);
powerR = 10*log10(powerR);
// Log the two power levels to the scope (THIS NEVER TRIGGERS THE SCOPE)
scope.log(powerL, powerR); // uncomment when testing is done
// Update the global frame counter
gRenderCounter++;
} // end render()