robert@501
|
1 /*
|
robert@501
|
2 ____ _____ _ _
|
robert@501
|
3 | __ )| ____| | / \
|
robert@501
|
4 | _ \| _| | | / _ \
|
robert@501
|
5 | |_) | |___| |___ / ___ \
|
robert@501
|
6 |____/|_____|_____/_/ \_\
|
robert@501
|
7
|
robert@501
|
8 The platform for ultra-low latency audio and sensor processing
|
robert@501
|
9
|
robert@501
|
10 http://bela.io
|
robert@501
|
11
|
robert@501
|
12 A project of the Augmented Instruments Laboratory within the
|
robert@501
|
13 Centre for Digital Music at Queen Mary University of London.
|
robert@501
|
14 http://www.eecs.qmul.ac.uk/~andrewm
|
robert@501
|
15
|
robert@501
|
16 (c) 2016 Augmented Instruments Laboratory: Andrew McPherson,
|
robert@501
|
17 Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack,
|
robert@501
|
18 Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved.
|
robert@501
|
19
|
robert@501
|
20 The Bela software is distributed under the GNU Lesser General Public License
|
robert@501
|
21 (LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt
|
robert@501
|
22 */
|
robert@501
|
23
|
robert@501
|
24
|
robert@501
|
25 #include <Bela.h>
|
robert@501
|
26 #include <cmath>
|
robert@501
|
27 #include <rtdk.h>
|
robert@501
|
28 #include "I2C_MPR121.h"
|
robert@501
|
29
|
robert@501
|
30 // How many pins there are
|
robert@501
|
31 #define NUM_TOUCH_PINS 12
|
robert@501
|
32
|
robert@501
|
33 // Define this to print data to terminal
|
robert@501
|
34 #undef DEBUG_MPR121
|
robert@501
|
35
|
robert@501
|
36 // Change this to change how often the MPR121 is read (in Hz)
|
robert@501
|
37 int readInterval = 50;
|
robert@501
|
38
|
robert@501
|
39 // Change this threshold to set the minimum amount of touch
|
robert@501
|
40 int threshold = 40;
|
robert@501
|
41
|
robert@501
|
42 // This array holds the continuous sensor values
|
robert@501
|
43 int sensorValue[NUM_TOUCH_PINS];
|
robert@501
|
44
|
robert@501
|
45 // ---- test code stuff -- can be deleted for your example ----
|
robert@501
|
46
|
robert@501
|
47 // 12 notes of a C major scale...
|
robert@501
|
48 float gFrequencies[NUM_TOUCH_PINS] = {261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25, 587.33, 659.25, 698.25, 783.99};
|
robert@501
|
49
|
robert@501
|
50 // This is internal stuff for the demo
|
robert@501
|
51 float gNormFrequencies[NUM_TOUCH_PINS];
|
robert@501
|
52 float gPhases[NUM_TOUCH_PINS] = {0};
|
robert@501
|
53
|
robert@501
|
54 // ---- internal stuff -- do not change -----
|
robert@501
|
55
|
robert@501
|
56 I2C_MPR121 mpr121; // Object to handle MPR121 sensing
|
robert@501
|
57 AuxiliaryTask i2cTask; // Auxiliary task to read I2C
|
robert@501
|
58
|
robert@501
|
59 int readCount = 0; // How long until we read again...
|
robert@501
|
60 int readIntervalSamples = 0; // How many samples between reads
|
robert@501
|
61
|
robert@501
|
62 void readMPR121();
|
robert@501
|
63
|
robert@501
|
64 // setup() is called once before the audio rendering starts.
|
robert@501
|
65 // Use it to perform any initialisation and allocation which is dependent
|
robert@501
|
66 // on the period size or sample rate.
|
robert@501
|
67 //
|
robert@501
|
68 // userData holds an opaque pointer to a data structure that was passed
|
robert@501
|
69 // in from the call to initAudio().
|
robert@501
|
70 //
|
robert@501
|
71 // Return true on success; returning false halts the program.
|
robert@501
|
72
|
robert@501
|
73 bool setup(BelaContext *context, void *userData)
|
robert@501
|
74 {
|
robert@501
|
75 if(!mpr121.begin(1, 0x5A)) {
|
robert@501
|
76 rt_printf("Error initialising MPR121\n");
|
robert@501
|
77 return false;
|
robert@501
|
78 }
|
robert@501
|
79
|
robert@501
|
80 i2cTask = Bela_createAuxiliaryTask(readMPR121, 50, "bela-mpr121");
|
robert@501
|
81 readIntervalSamples = context->audioSampleRate / readInterval;
|
robert@501
|
82
|
robert@501
|
83 for(int i = 0; i < NUM_TOUCH_PINS; i++) {
|
robert@501
|
84 gNormFrequencies[i] = 2.0 * M_PI * gFrequencies[i] / context->audioSampleRate;
|
robert@501
|
85 }
|
robert@501
|
86
|
robert@501
|
87 return true;
|
robert@501
|
88 }
|
robert@501
|
89
|
robert@501
|
90 // render() is called regularly at the highest priority by the audio engine.
|
robert@501
|
91 // Input and output are given from the audio hardware and the other
|
robert@501
|
92 // ADCs and DACs (if available). If only audio is available, numAnalogFrames
|
robert@501
|
93 // will be 0.
|
robert@501
|
94
|
robert@501
|
95 void render(BelaContext *context, void *userData)
|
robert@501
|
96 {
|
robert@501
|
97 for(int n = 0; n < context->audioFrames; n++) {
|
robert@501
|
98 // Keep this code: it schedules the touch sensor readings
|
robert@501
|
99 if(++readCount >= readIntervalSamples) {
|
robert@501
|
100 readCount = 0;
|
robert@501
|
101 Bela_scheduleAuxiliaryTask(i2cTask);
|
robert@501
|
102 }
|
robert@501
|
103
|
robert@501
|
104 float sample = 0.0;
|
robert@501
|
105
|
robert@501
|
106 // This code can be replaced with your favourite audio code
|
robert@501
|
107 for(int i = 0; i < NUM_TOUCH_PINS; i++) {
|
robert@501
|
108 float amplitude = sensorValue[i] / 400.0;
|
robert@501
|
109
|
robert@501
|
110 // Prevent clipping
|
robert@501
|
111 if(amplitude > 0.5)
|
robert@501
|
112 amplitude = 0.5;
|
robert@501
|
113
|
robert@501
|
114 sample += amplitude * sinf(gPhases[i]);
|
robert@501
|
115 gPhases[i] += gNormFrequencies[i];
|
robert@501
|
116 if(gPhases[i] > 2.0 * M_PI)
|
robert@501
|
117 gPhases[i] -= 2.0 * M_PI;
|
robert@501
|
118 }
|
robert@501
|
119
|
robert@501
|
120 for(int ch = 0; ch < context->audioChannels; ch++)
|
robert@501
|
121 context->audioOut[context->audioChannels * n + ch] = sample;
|
robert@501
|
122 }
|
robert@501
|
123 }
|
robert@501
|
124
|
robert@501
|
125 // cleanup() is called once at the end, after the audio has stopped.
|
robert@501
|
126 // Release any resources that were allocated in setup().
|
robert@501
|
127
|
robert@501
|
128 void cleanup(BelaContext *context, void *userData)
|
robert@501
|
129 {
|
robert@501
|
130 // Nothing to do here
|
robert@501
|
131 }
|
robert@501
|
132
|
robert@501
|
133
|
robert@501
|
134 // Auxiliary task to read the I2C board
|
robert@501
|
135 void readMPR121()
|
robert@501
|
136 {
|
robert@501
|
137 for(int i = 0; i < NUM_TOUCH_PINS; i++) {
|
robert@501
|
138 sensorValue[i] = -(mpr121.filteredData(i) - mpr121.baselineData(i));
|
robert@501
|
139 sensorValue[i] -= threshold;
|
robert@501
|
140 if(sensorValue[i] < 0)
|
robert@501
|
141 sensorValue[i] = 0;
|
robert@501
|
142 #ifdef DEBUG_MPR121
|
robert@501
|
143 rt_printf("%d ", sensorValue[i]);
|
robert@501
|
144 #endif
|
robert@501
|
145 }
|
robert@501
|
146 #ifdef DEBUG_MPR121
|
robert@501
|
147 rt_printf("\n");
|
robert@501
|
148 #endif
|
robert@501
|
149
|
robert@501
|
150 // You can use this to read binary on/off touch state more easily
|
robert@501
|
151 //rt_printf("Touched: %x\n", mpr121.touched());
|
robert@501
|
152 }
|
robert@501
|
153
|
robert@501
|
154 /* ------------ Project Explantation ------------ */
|
robert@501
|
155
|
robert@501
|
156 /**
|
robert@501
|
157 \example 06-capacitive-touch
|
robert@501
|
158
|
robert@501
|
159 Capacitive touch sensing with MPR121
|
robert@501
|
160 ---------------------------
|
robert@501
|
161
|
robert@501
|
162 This sketch allows you to hook up an MPR121 capactive touch sensing device
|
robert@501
|
163 to Bela, for example the SparkFun Capacitive Touch Sensor Breakout - MPR121.
|
robert@501
|
164 The breakout board gives you 12 electrode connections.
|
robert@501
|
165
|
robert@501
|
166 To get this working with Bela you need to connect the breakout board to the I2C
|
robert@501
|
167 terminal on the Bela board. See the Pin guide for details of which pin is which.
|
robert@501
|
168
|
robert@501
|
169 The sensor data will then be available for you to use in the array
|
robert@501
|
170 `sensorValue[NUM_TOUCH_PINS]`.
|
robert@501
|
171 */
|