andrewm@0: /* robert@372: ____ _____ _ _ robert@372: | __ )| ____| | / \ robert@372: | _ \| _| | | / _ \ robert@372: | |_) | |___| |___ / ___ \ robert@372: |____/|_____|_____/_/ \_\.io robert@372: andrewm@0: */ andrewm@0: robert@372: /* robert@372: * robert@372: * Andrew McPherson and Victor Zappi robert@372: * Queen Mary, University of London robert@372: */ robert@372: robert@372: /** robert@372: \example 3_analog_output robert@372: robert@372: Fading LEDs robert@372: ----------- robert@372: robert@372: This sketch uses a sine wave to drive the brightness of a series of LEDs robert@372: connected to the eight analog out pins. Again you can see the nested `for` loop robert@372: structure but this time for the analog output channels rather than the audio. robert@372: robert@372: - connect an LED in series with a 470ohm resistor between each of the analogOut pins and ground. robert@372: robert@372: Within the first for loop in render we cycle through each frame in the analog robert@372: output matrix. At each frame we then cycle through the analog output channels robert@372: with another for loop and set the output voltage according to the phase of a robert@372: sine tone that acts as an LFO. The analog output pins can provide a voltage of robert@372: ~4.092V. robert@372: robert@372: The output on each pin is set with `analogWrite()` within the for loop that robert@372: cycles through the analog output channels. This needs to be provided with robert@372: arguments as follows `analogWrite(context, n, channel, out)`. Channel is robert@372: where the you give the address of the analog output pin (in this case we cycle robert@372: through each pin address in the for loop), out is the variable that holds the robert@372: desired output (in this case set by the sine wave). robert@372: robert@372: Notice that the phase of the brightness cycle for each led is different. This robert@372: is achieved by updating a variable that stores a relative phase value. This robert@372: variable is advanced by pi/4 (1/8 of a full rotation) for each channel giving robert@372: each of the eight LEDs a different phase. robert@372: */ andrewm@0: giuliomoro@301: #include andrewm@0: #include andrewm@0: #include andrewm@0: andrewm@0: // Set range for analog outputs designed for driving LEDs andrewm@52: const float kMinimumAmplitude = (1.5 / 5.0); andrewm@52: const float kAmplitudeRange = 1.0 - kMinimumAmplitude; andrewm@0: andrewm@0: float gFrequency; andrewm@0: float gPhase; andrewm@0: float gInverseSampleRate; andrewm@0: andrewm@56: // setup() is called once before the audio rendering starts. andrewm@0: // Use it to perform any initialisation and allocation which is dependent andrewm@0: // on the period size or sample rate. andrewm@0: // andrewm@0: // userData holds an opaque pointer to a data structure that was passed andrewm@0: // in from the call to initAudio(). andrewm@0: // andrewm@0: // Return true on success; returning false halts the program. andrewm@0: giuliomoro@301: bool setup(BelaContext *context, void *userData) andrewm@0: { andrewm@0: // Retrieve a parameter passed in from the initAudio() call andrewm@0: gFrequency = *(float *)userData; andrewm@0: andrewm@52: if(context->analogFrames == 0) { andrewm@12: rt_printf("Error: this example needs the matrix enabled\n"); andrewm@0: return false; andrewm@0: } andrewm@0: andrewm@52: gInverseSampleRate = 1.0 / context->analogSampleRate; andrewm@0: gPhase = 0.0; andrewm@0: andrewm@0: return true; andrewm@0: } andrewm@0: andrewm@0: // render() is called regularly at the highest priority by the audio engine. andrewm@0: // Input and output are given from the audio hardware and the other andrewm@0: // ADCs and DACs (if available). If only audio is available, numMatrixFrames andrewm@0: // will be 0. andrewm@0: giuliomoro@301: void render(BelaContext *context, void *userData) andrewm@0: { andrewm@56: for(unsigned int n = 0; n < context->analogFrames; n++) { andrewm@0: // Set LED to different phase for each matrix channel andrewm@0: float relativePhase = 0.0; andrewm@56: for(unsigned int channel = 0; channel < context->analogChannels; channel++) { andrewm@0: float out = kMinimumAmplitude + kAmplitudeRange * 0.5f * (1.0f + sinf(gPhase + relativePhase)); andrewm@0: andrewm@308: analogWrite(context, n, channel, out); andrewm@0: andrewm@0: // Advance by pi/4 (1/8 of a full rotation) for each channel andrewm@0: relativePhase += M_PI * 0.25; andrewm@0: } andrewm@0: andrewm@0: gPhase += 2.0 * M_PI * gFrequency * gInverseSampleRate; andrewm@0: if(gPhase > 2.0 * M_PI) andrewm@0: gPhase -= 2.0 * M_PI; andrewm@0: } andrewm@0: } andrewm@0: 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@0: giuliomoro@301: void cleanup(BelaContext *context, void *userData) andrewm@0: { andrewm@0: andrewm@0: }