robert@269
|
1 /*
|
robert@269
|
2 ____ _____ _ _
|
robert@269
|
3 | __ )| ____| | / \
|
robert@269
|
4 | _ \| _| | | / _ \
|
robert@269
|
5 | |_) | |___| |___ / ___ \
|
robert@269
|
6 |____/|_____|_____/_/ \_\.io
|
robert@269
|
7
|
robert@269
|
8 */
|
robert@269
|
9
|
andrewm@57
|
10 /*
|
andrewm@57
|
11 * render.cpp
|
andrewm@57
|
12 *
|
andrewm@57
|
13 * Created on: Oct 24, 2014
|
andrewm@57
|
14 * Author: parallels
|
andrewm@57
|
15 */
|
andrewm@57
|
16
|
robert@269
|
17 /**
|
robert@269
|
18 \example 3_analog_input
|
robert@269
|
19
|
robert@269
|
20 Connecting potentiometers
|
robert@269
|
21 -------------------------
|
robert@269
|
22
|
robert@269
|
23 This sketch produces a sine tone, the frequency and amplitude of which are
|
robert@269
|
24 affected by data received on the analog pins. Before looping through each audio
|
robert@269
|
25 frame, we declare a value for the frequency and amplitude of our sine tone
|
robert@269
|
26 (line 55); we adjust these values by taking in data from analog sensors
|
robert@269
|
27 (for example, a potentiometer).
|
robert@269
|
28
|
robert@269
|
29 The important thing to notice is that audio is sampled twice as often as analog
|
robert@269
|
30 data. The audio sampling rate is 44.1kHz (44100 frames per second) and the
|
robert@269
|
31 analog sampling rate is 22.05kHz (22050 frames per second). On line 62 you might
|
robert@269
|
32 notice that we are processing the analog data and updating frequency and
|
robert@269
|
33 amplitude only on every second audio sample, since the analog sampling rate is
|
robert@269
|
34 half that of the audio.
|
robert@269
|
35
|
robert@269
|
36 Note that the pin numbers are stored in the variables `gAnalogInputFrequency` and
|
robert@269
|
37 `gAnalogInputAmplitude`. These are declared in the main.cpp file; if you look in
|
robert@269
|
38 that file you will see that they have the values of 0 and 1. Bear in mind that
|
robert@269
|
39 these are analog input pins which is a specific header!
|
robert@269
|
40 */
|
andrewm@57
|
41
|
andrewm@57
|
42 #include <BeagleRT.h>
|
andrewm@57
|
43 #include <Utilities.h>
|
andrewm@57
|
44 #include <rtdk.h>
|
andrewm@57
|
45 #include <cmath>
|
andrewm@57
|
46
|
andrewm@57
|
47 float gPhase;
|
andrewm@57
|
48 float gInverseSampleRate;
|
andrewm@57
|
49 int gAudioFramesPerAnalogFrame;
|
andrewm@57
|
50
|
andrewm@57
|
51 // These settings are carried over from main.cpp
|
andrewm@57
|
52 // Setting global variables is an alternative approach
|
andrewm@57
|
53 // to passing a structure to userData in setup()
|
andrewm@57
|
54
|
andrewm@57
|
55 extern int gSensorInputFrequency;
|
andrewm@57
|
56 extern int gSensorInputAmplitude;
|
andrewm@57
|
57
|
andrewm@57
|
58 // setup() is called once before the audio rendering starts.
|
andrewm@57
|
59 // Use it to perform any initialisation and allocation which is dependent
|
andrewm@57
|
60 // on the period size or sample rate.
|
andrewm@57
|
61 //
|
andrewm@57
|
62 // userData holds an opaque pointer to a data structure that was passed
|
andrewm@57
|
63 // in from the call to initAudio().
|
andrewm@57
|
64 //
|
andrewm@57
|
65 // Return true on success; returning false halts the program.
|
andrewm@57
|
66
|
robert@269
|
67
|
andrewm@57
|
68 bool setup(BeagleRTContext *context, void *userData)
|
andrewm@57
|
69 {
|
andrewm@57
|
70 if(context->analogFrames == 0 || context->analogFrames > context->audioFrames) {
|
andrewm@57
|
71 rt_printf("Error: this example needs analog enabled, with 4 or 8 channels\n");
|
andrewm@57
|
72 return false;
|
andrewm@57
|
73 }
|
andrewm@57
|
74
|
andrewm@57
|
75 gAudioFramesPerAnalogFrame = context->audioFrames / context->analogFrames;
|
andrewm@57
|
76 gInverseSampleRate = 1.0 / context->audioSampleRate;
|
andrewm@57
|
77 gPhase = 0.0;
|
andrewm@57
|
78
|
andrewm@57
|
79 return true;
|
andrewm@57
|
80 }
|
andrewm@57
|
81
|
andrewm@57
|
82 // render() is called regularly at the highest priority by the audio engine.
|
andrewm@57
|
83 // Input and output are given from the audio hardware and the other
|
andrewm@57
|
84 // ADCs and DACs (if available). If only audio is available, numMatrixFrames
|
andrewm@57
|
85 // will be 0.
|
andrewm@57
|
86
|
andrewm@57
|
87 void render(BeagleRTContext *context, void *userData)
|
andrewm@57
|
88 {
|
andrewm@57
|
89 float frequency = 440.0;
|
andrewm@57
|
90 float amplitude = 0.8;
|
andrewm@57
|
91
|
andrewm@57
|
92 // There are twice as many audio frames as matrix frames since audio sample rate
|
andrewm@57
|
93 // is twice as high
|
andrewm@57
|
94
|
andrewm@57
|
95 for(unsigned int n = 0; n < context->audioFrames; n++) {
|
andrewm@57
|
96 if(!(n % gAudioFramesPerAnalogFrame)) {
|
andrewm@57
|
97 // Even audio samples: update frequency and amplitude from the matrix
|
andrewm@57
|
98 frequency = map(analogReadFrame(context, n/gAudioFramesPerAnalogFrame, gSensorInputFrequency), 0, 1, 100, 1000);
|
andrewm@57
|
99 amplitude = analogReadFrame(context, n/gAudioFramesPerAnalogFrame, gSensorInputAmplitude);
|
andrewm@57
|
100 }
|
andrewm@57
|
101
|
andrewm@57
|
102 float out = amplitude * sinf(gPhase);
|
andrewm@57
|
103
|
andrewm@57
|
104 for(unsigned int channel = 0; channel < context->audioChannels; channel++)
|
andrewm@57
|
105 context->audioOut[n * context->audioChannels + channel] = out;
|
andrewm@57
|
106
|
andrewm@57
|
107 gPhase += 2.0 * M_PI * frequency * gInverseSampleRate;
|
andrewm@57
|
108 if(gPhase > 2.0 * M_PI)
|
andrewm@57
|
109 gPhase -= 2.0 * M_PI;
|
andrewm@57
|
110 }
|
andrewm@57
|
111 }
|
andrewm@57
|
112
|
andrewm@57
|
113 // cleanup() is called once at the end, after the audio has stopped.
|
andrewm@57
|
114 // Release any resources that were allocated in setup().
|
andrewm@57
|
115
|
andrewm@57
|
116 void cleanup(BeagleRTContext *context, void *userData)
|
andrewm@57
|
117 {
|
andrewm@57
|
118
|
andrewm@57
|
119 }
|