andrewm@13: /* robert@269: ____ _____ _ _ robert@269: | __ )| ____| | / \ robert@269: | _ \| _| | | / _ \ robert@269: | |_) | |___| |___ / ___ \ robert@269: |____/|_____|_____/_/ \_\.io robert@269: robert@269: */ robert@269: robert@269: /* andrewm@13: * render.cpp andrewm@13: * andrewm@13: * Created on: Oct 24, 2014 andrewm@13: * Author: parallels andrewm@13: */ andrewm@13: robert@269: /** robert@285: \example 1_basic_audio_analog_passthrough robert@269: robert@285: Audio and analog passthrough: input to output robert@269: ----------------------------------------- robert@269: robert@285: This sketch demonstrates how to read from and write to the audio and analog input and output buffers. robert@269: robert@285: In `render()` you'll see a nested for loop structure. You'll see this in all Bela projects. robert@285: The first for loop cycles through `audioFrames`, the second through robert@285: `audioChannels` (in this case left 0 and right 1). robert@269: robert@285: You can access any information about current audio and sensor settings you can do the following: robert@285: `context->name_of_item`. For example `context->audioChannels` returns current number of channels, robert@285: `context->audioFrames` returns the current number of audio frames, robert@285: `context->audioSampleRate` returns the audio sample rate. robert@269: robert@285: You can look at all the information you can access in ::BeagleRTContext. robert@269: robert@285: Reading and writing from the audio buffers robert@285: ------------------------------------------ robert@269: robert@285: The simplest way to read samples from the audio input buffer is with robert@285: `audioReadFrame()` which we pass three arguments context, current audio robert@285: frame and current channel. In this example we have robert@285: `audioReadFrame(context, n, ch)` where both `n` and `ch` are provided by robert@285: the nested for loop structure. robert@285: robert@285: We can write samples to the audio output buffer in a similar way using robert@285: `audioWriteFrame()`. This has a fourth argument which is the value of the output. robert@285: For example `audioWriteFrame(context, n, ch, value_to_output)`. robert@285: robert@285: Reading and writing from the analog buffers robert@285: ------------------------------------------- robert@285: robert@285: The same is true for `analogReadFrame()` and `analogWriteFrame()`. robert@285: robert@285: Note that for the analog channels we write to and read from the buffers in a separate set robert@285: of nested for loops. This is because the they are sampled at half audio rate by default. robert@285: The first of these for loops cycles through `analogFrames`, the second through robert@285: `analogChannels`. robert@285: robert@285: By setting `audioWriteFrame(context, n, ch, audioReadFrame(context, n, ch))` and robert@285: `analogWriteFrame(context, n, ch, analogReadFrame(context, n, ch))` we have a simple robert@285: passthrough of audio input to output and analog input to output. robert@285: robert@285: robert@285: It is also possible to address the buffers directly like this: robert@285: `context->audioOut[n * context->audioChannels + ch]`. robert@269: robert@269: robert@269: */ robert@269: robert@269: robert@269: robert@269: andrewm@13: andrewm@56: #include andrewm@56: #include andrewm@13: #include andrewm@13: andrewm@56: // setup() is called once before the audio rendering starts. andrewm@13: // Use it to perform any initialisation and allocation which is dependent andrewm@13: // on the period size or sample rate. andrewm@13: // andrewm@13: // userData holds an opaque pointer to a data structure that was passed andrewm@13: // in from the call to initAudio(). andrewm@13: // andrewm@13: // Return true on success; returning false halts the program. andrewm@13: andrewm@56: bool setup(BeagleRTContext *context, void *userData) andrewm@13: { andrewm@13: // Nothing to do here... andrewm@13: return true; andrewm@13: } andrewm@13: andrewm@13: // render() is called regularly at the highest priority by the audio engine. andrewm@13: // Input and output are given from the audio hardware and the other andrewm@13: // ADCs and DACs (if available). If only audio is available, numMatrixFrames andrewm@13: // will be 0. andrewm@13: andrewm@52: void render(BeagleRTContext *context, void *userData) andrewm@13: { andrewm@13: // Simplest possible case: pass inputs through to outputs andrewm@52: for(unsigned int n = 0; n < context->audioFrames; n++) { giuliomoro@180: for(unsigned int ch = 0; ch < context->audioChannels; ch++){ giuliomoro@180: // Two equivalent ways to write this code giuliomoro@180: giuliomoro@180: // The long way, using the buffers directly: giuliomoro@180: // context->audioOut[n * context->audioChannels + ch] = giuliomoro@180: // context->audioIn[n * context->audioChannels + ch]; giuliomoro@180: giuliomoro@180: // Or using the macros: giuliomoro@180: audioWriteFrame(context, n, ch, audioReadFrame(context, n, ch)); giuliomoro@180: } andrewm@13: } andrewm@13: robert@285: // Same with analog channels giuliomoro@180: for(unsigned int n = 0; n < context->analogFrames; n++) { giuliomoro@180: for(unsigned int ch = 0; ch < context->analogChannels; ch++) { giuliomoro@180: // Two equivalent ways to write this code giuliomoro@180: giuliomoro@180: // The long way, using the buffers directly: giuliomoro@180: // context->analogOut[n * context->analogChannels + ch] = context->analogIn[n * context->analogChannels + ch]; giuliomoro@180: giuliomoro@180: // Or using the macros: giuliomoro@180: analogWriteFrame(context, n, ch, analogReadFrame(context, n, ch)); giuliomoro@180: } giuliomoro@180: } andrewm@13: } andrewm@13: andrewm@56: // cleanup() is called once at the end, after the audio has stopped. andrewm@56: // Release any resources that were allocated in setup(). andrewm@13: andrewm@56: void cleanup(BeagleRTContext *context, void *userData) andrewm@13: { andrewm@13: andrewm@13: }