This sketch shows how to playback audio samples from a buffer using onset detection of strikes detected by a piezo sensor.
The piezo is connected to Bela through a simple voltage divider circuit.
In order to get a coherent trigger from the piezo disk we have to go through a few stages of signal taming. The first is a DC offset filter which recentres the signal around 0. This is necessary as our voltage divider circuit pushes the piezo input signal to half the input voltage range, allowing us to read the piezo's full output.
As a piezo disk behaves like a microphone it outputs both negative and positive values. A second step we have to take before detecting strikes is to fullwave rectify the signal, this gives us only positive values.
Next we perform the onset detection. We do this by looking for a downwards trend in the sensor data after a rise. Once we've identified this we can say that a peak has occured and trigger the sample to play. We do this by setting gReadPtr = 0;.
This type of onset detection is by no means perfect. Really we should lowpass filter the piezo signal before performing the onset detection algorithm and implement some kind of debounce on the stikes to avoid multiple strikes being detected for a single strike.
#include <libraries/Scope/Scope.h>
#include <libraries/AudioFile/AudioFile.h>
#include <vector>
std::string gFilename = "sample.wav";
std::vector<std::vector<float> > gSampleData;
int gReadPtr;
float gPiezoInput;
float prevReadingDCOffset = 0;
float prevPiezoReading = 0;
float readingDCOffset = 0;
float R = 0.99;
float peakValue = 0;
float thresholdToTrigger = 0.001;
float amountBelowPeak = 0.001;
float rolloffRate = 0.00005;
int triggered = 0;
int gAudioFramesPerAnalogFrame = 0;
{
{
fprintf(stderr, "Error: for this project the sampling rate of the analog inputs has to be <= the audio sample rate\n");
return false;
}
gReadPtr = -1;
return true;
}
{
float currentSample;
float out = 0;
for(
unsigned int n = 0; n < context->
audioFrames; n++) {
if(gAudioFramesPerAnalogFrame && !(n % gAudioFramesPerAnalogFrame)) {
gPiezoInput =
analogRead(context, n % gAudioFramesPerAnalogFrame, 0);
}
readingDCOffset = gPiezoInput - prevPiezoReading + (R * prevReadingDCOffset);
prevPiezoReading = gPiezoInput;
prevReadingDCOffset = readingDCOffset;
currentSample = readingDCOffset;
if(currentSample < 0)
currentSample *= -1.0f;
if(currentSample >= peakValue) {
peakValue = currentSample;
triggered = 0;
}
else if(peakValue >= rolloffRate)
peakValue -= rolloffRate;
if(currentSample < peakValue - amountBelowPeak && peakValue >= thresholdToTrigger && !triggered) {
rt_printf("%f\n", peakValue);
triggered = 1;
gReadPtr = 0;
}
if(gReadPtr != -1)
out = gSampleData[channel % gSampleData.size()][gReadPtr++];
if(gReadPtr >= (int)gSampleData[channel % gSampleData.size()].size())
gReadPtr = -1;
}
}
scope.log(gPiezoInput, peakValue, out);
}
{
}
An oscilloscope which allows data to be visualised in a browser in real time.
Definition Scope.h:23
static float analogRead(BelaContext *context, int frame, int channel)
Read an analog input, specifying the frame number (when to read) and the channel.
Definition Bela.h:1480
static void audioWrite(BelaContext *context, int frame, int channel, float value)
Write an audio output, specifying the frame number (when to write) and the channel.
Definition Bela.h:1469
void render(BelaContext *context, void *userData)
User-defined callback function to process audio and sensor data.
Definition render.cpp:68
bool setup(BelaContext *context, void *userData)
User-defined initialisation function which runs before audio rendering begins.
Definition render.cpp:51
void cleanup(BelaContext *context, void *userData)
User-defined cleanup function which runs when the program finishes.
Definition render.cpp:96
std::vector< std::vector< float > > load(const std::string &filename, int maxCount=-1, unsigned int start=0)
Definition AudioFileUtilities.cpp:135
Structure holding audio and sensor settings and pointers to I/O data buffers.
Definition Bela.h:231
const uint32_t audioOutChannels
The number of audio output channels.
Definition Bela.h:326
const uint32_t audioFrames
The number of audio frames per block.
Definition Bela.h:322
const float audioSampleRate
The audio sample rate in Hz (currently always 44100.0).
Definition Bela.h:328
const uint32_t analogFrames
The number of analog frames per block.
Definition Bela.h:341
const float analogSampleRate
Analog sample rate in Hz.
Definition Bela.h:362