robert@464
|
1 /*
|
robert@464
|
2 ____ _____ _ _
|
robert@464
|
3 | __ )| ____| | / \
|
robert@464
|
4 | _ \| _| | | / _ \
|
robert@464
|
5 | |_) | |___| |___ / ___ \
|
robert@464
|
6 |____/|_____|_____/_/ \_\
|
robert@464
|
7
|
robert@464
|
8 The platform for ultra-low latency audio and sensor processing
|
robert@464
|
9
|
robert@464
|
10 http://bela.io
|
robert@464
|
11
|
robert@464
|
12 A project of the Augmented Instruments Laboratory within the
|
robert@464
|
13 Centre for Digital Music at Queen Mary University of London.
|
robert@464
|
14 http://www.eecs.qmul.ac.uk/~andrewm
|
robert@464
|
15
|
robert@464
|
16 (c) 2016 Augmented Instruments Laboratory: Andrew McPherson,
|
robert@464
|
17 Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack,
|
robert@464
|
18 Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved.
|
robert@464
|
19
|
robert@464
|
20 The Bela software is distributed under the GNU Lesser General Public License
|
robert@464
|
21 (LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt
|
robert@464
|
22 */
|
robert@464
|
23
|
robert@464
|
24
|
robert@464
|
25 #include <Bela.h>
|
robert@464
|
26 #include <cmath>
|
robert@464
|
27 #include <Scope.h>
|
robert@464
|
28
|
robert@464
|
29 Scope scope;
|
robert@464
|
30
|
robert@464
|
31 float gInverseSampleRate;
|
robert@464
|
32 float gPhase;
|
robert@464
|
33
|
robert@464
|
34 bool setup(BelaContext *context, void *userData)
|
robert@464
|
35 {
|
robert@464
|
36
|
robert@464
|
37 // setup the scope with 3 channels at the audio sample rate
|
robert@464
|
38 scope.setup(3, context->audioSampleRate);
|
robert@464
|
39
|
robert@542
|
40 // Check if analog channels are enabled
|
robert@542
|
41 if(context->analogFrames == 0 || context->analogFrames > context->audioFrames) {
|
robert@542
|
42 rt_printf("Error: this example needs analog enabled, with 4 or 8 channels\n");
|
robert@542
|
43 return false;
|
robert@542
|
44 }
|
robert@542
|
45
|
robert@542
|
46 // Check that we have the same number of inputs and outputs.
|
robert@542
|
47 if(context->audioInChannels != context->audioOutChannels ||
|
robert@542
|
48 context->analogInChannels != context-> analogOutChannels){
|
robert@542
|
49 printf("Error: for this project, you need the same number of input and output channels.\n");
|
robert@542
|
50 return false;
|
robert@542
|
51 }
|
robert@542
|
52
|
robert@464
|
53 gInverseSampleRate = 1.0 / context->audioSampleRate;
|
robert@464
|
54 gPhase = 0.0;
|
robert@464
|
55
|
robert@464
|
56 return true;
|
robert@464
|
57 }
|
robert@464
|
58
|
robert@464
|
59 void render(BelaContext *context, void *userData)
|
robert@464
|
60 {
|
robert@464
|
61
|
robert@464
|
62 for(unsigned int n = 0; n < context->audioFrames; n++) {
|
robert@464
|
63
|
robert@464
|
64 // read analogIn channels 0 and 1
|
robert@464
|
65 float in1 = analogRead(context, n, 0);
|
robert@464
|
66 float in2 = analogRead(context, n, 1);
|
robert@464
|
67
|
robert@464
|
68 // map in1 to amplitude and in2 to frequency
|
robert@464
|
69 float amplitude = in1 * 0.8f;
|
robert@464
|
70 float frequency = map(in2, 0, 1, 100, 1000);
|
robert@464
|
71
|
robert@464
|
72 // generate a sine wave with the amplitude and frequency
|
robert@464
|
73 float out = amplitude * sinf(gPhase);
|
robert@464
|
74 gPhase += 2.0 * M_PI * frequency * gInverseSampleRate;
|
robert@464
|
75 if(gPhase > 2.0 * M_PI)
|
robert@464
|
76 gPhase -= 2.0 * M_PI;
|
robert@464
|
77
|
robert@464
|
78 // log the sine wave and sensor values on the scope
|
robert@464
|
79 scope.log(out, in1, in2);
|
robert@464
|
80
|
robert@464
|
81 // pass the sine wave to the audio outputs
|
robert@542
|
82 for(unsigned int channel = 0; channel < context->audioOutChannels; channel++) {
|
robert@542
|
83 audioWrite(context, n, channel, out);
|
robert@542
|
84 }
|
robert@542
|
85
|
robert@464
|
86
|
robert@464
|
87 }
|
robert@464
|
88 }
|
robert@464
|
89
|
robert@464
|
90 void cleanup(BelaContext *context, void *userData)
|
robert@464
|
91 {
|
robert@464
|
92
|
robert@464
|
93 }
|
robert@464
|
94
|
robert@464
|
95
|
robert@464
|
96 /**
|
robert@500
|
97 \example scope-analog/render.cpp
|
robert@464
|
98
|
robert@542
|
99 Scoping sensor input
|
robert@464
|
100 -------------------------
|
robert@464
|
101
|
robert@542
|
102 This example reads from analogue inputs 0 and 1 via `analogRead()` and
|
robert@464
|
103 generates a sine wave with amplitude and frequency determined by their values.
|
robert@464
|
104 It's best to connect a 10K potentiometer to each of these analog inputs. Far
|
robert@464
|
105 left and far right pins of the pot go to 3.3V and GND, the middle should be
|
robert@464
|
106 connected to the analog in pins.
|
robert@464
|
107
|
robert@464
|
108 The sine wave is then plotted on the oscilloscope. Click the Open Scope button to
|
robert@464
|
109 view the results. As you turn the potentiometers you will see the amplitude and
|
robert@542
|
110 frequency of the sine wave change. You can also see the two sensor readings plotted
|
robert@542
|
111 on the oscilloscope.
|
robert@542
|
112
|
robert@542
|
113 The scope is initialised in `setup()` where the number of channels and sampling rate
|
robert@542
|
114 are set.
|
robert@542
|
115
|
robert@542
|
116 `````
|
robert@542
|
117 scope.setup(3, context->audioSampleRate);
|
robert@542
|
118 `````
|
robert@542
|
119
|
robert@542
|
120 We can then pass signals to the scope in `render()` using:
|
robert@542
|
121
|
robert@542
|
122 ``````
|
robert@542
|
123 scope.log(out, in1, in2);
|
robert@542
|
124 ``````
|
robert@464
|
125
|
robert@464
|
126 This project also shows as example of `map()` which allows you to re-scale a number
|
robert@464
|
127 from one range to another. Note that `map()` does not constrain your variable
|
robert@464
|
128 within the upper and lower limits. If you want to do this use the `constrain()`
|
robert@464
|
129 function.
|
robert@464
|
130 */
|