Bela
Real-time, ultra-low-latency audio and sensor processing system for BeagleBone Black
Loading...
Searching...
No Matches
Audio/record-audio/render.cpp

Recording the audio input and output to file

This example records the inputs and outputs of Bela to an audio file of a fixed length on disk.

When the program begins it will attempt to allocate enough memory to store gDurationSec seconds of audio data for each of the input and output channels. If you request an excessive amount of RAM then the program may fail when starting or while running.

The program processes the input audio and it stores the input samples into the array gInputs[]. In order to generate something to send to the outputs we apply a filter to the input audio and store this as the output samples into the array gOutputs.

Ã…fter running for gDurationSec this program will automatically stop and write a two .wav files to disk. If you have more audio input or output channels then these .wav files will be multichannel.

These .wav files will be created in the Resources section of the Project explorer amongst your other project files.

/*
____ _____ _ _
| __ )| ____| | / \
| _ \| _| | | / _ \
| |_) | |___| |___ / ___ \
|____/|_____|_____/_/ \_\
http://bela.io
*/
#include <Bela.h>
#include <libraries/AudioFile/AudioFile.h>
#include <libraries/Biquad/Biquad.h>
#include <vector>
#include <string>
#include <algorithm>
std::vector<std::vector<float>> gInputs;
std::vector<std::vector<float>> gOutputs;
std::string gFilenameOutputs = "outputs.wav";
std::string gFilenameInputs = "inputs.wav";
const double gDurationSec = 20; // how many seconds to record.
unsigned int gWrittenFrames = 0; // how many frame have actually been written to gInputs and gOutputs
std::vector<Biquad> gBiquads; // filters to process the inputs
bool setup(BelaContext *context, void *userData)
{
// pre-allocate all the memory needed to store the audio data
unsigned int numFrames = context->audioSampleRate * gDurationSec;
gInputs.resize(context->audioInChannels);
gOutputs.resize(context->audioOutChannels);
// If we have too many channels or too many frames to store, we may run out of RAM and
// the program will fail to start.
try {
for(auto& c : gInputs)
c.resize(numFrames);
for(auto& c : gOutputs)
c.resize(numFrames);
} catch (std::exception& e) {
fprintf(stderr, "Error while allocating memory. Maybe you are asking to record too many frames and/or too many channels\n");
return false;
}
Biquad::Settings settings {
.fs = context->audioSampleRate,
.type = Biquad::lowpass,
.cutoff = 200,
.q = 0.707,
.peakGainDb = 0,
};
// create some filters to process the input
gBiquads.resize(std::min(context->audioInChannels, context->audioOutChannels), Biquad(settings));
return true;
}
void render(BelaContext *context, void *userData)
{
for(unsigned int n = 0; n < context->audioFrames; ++n)
{
// store audio inputs
for(unsigned int c = 0; c < context->audioInChannels; ++c)
gInputs[c][gWrittenFrames] = audioRead(context, n, c);
unsigned int c;
// process audio inputs through the filter, write to the audio outputs and store the audio outputs
for(c = 0; c < gBiquads.size(); ++c) {
float in = audioRead(context, n, c);
float out = gBiquads[c].process(in);
gOutputs[c][gWrittenFrames] = out;
audioWrite(context, n, c, out);
}
++gWrittenFrames;
if(gWrittenFrames >= gOutputs[0].size()) {
// if we have processed enough samples an we have filled the pre-allocated buffer,
// stop the program
return;
}
}
}
void cleanup(BelaContext *context, void *userData)
{
// ensure we don't write any more frames than those that have actually been processed
// this way if the program is stopped by the user before its natural end we don't end up
// with a lot of empty samples at the end of each file.
for(auto& i : gInputs)
i.resize(gWrittenFrames);
for(auto& o : gOutputs)
o.resize(gWrittenFrames);
AudioFileUtilities::write(gFilenameInputs, gInputs, context->audioSampleRate);
AudioFileUtilities::write(gFilenameOutputs, gOutputs, context->audioSampleRate);
}
Main Bela public API.
Definition Biquad.h:99
void Bela_requestStop()
Tell the Bela program to stop.
static float audioRead(BelaContext *context, int frame, int channel)
Read an audio input, specifying the frame number (when to read) and the channel.
Definition Bela.h:1458
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
int write(const std::string &filename, float *buf, unsigned int channels, unsigned int frames, unsigned int samplerate)
Definition AudioFileUtilities.cpp:79
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 uint32_t audioInChannels
The number of audio input channels.
Definition Bela.h:324
const float audioSampleRate
The audio sample rate in Hz (currently always 44100.0).
Definition Bela.h:328
Definition Biquad.h:34