giuliomoro@301
|
1 #include <Bela.h>
|
andrewm@268
|
2 #include <cmath>
|
andrewm@268
|
3 #include <rtdk.h>
|
andrewm@268
|
4 #include "I2C_MPR121.h"
|
andrewm@268
|
5
|
andrewm@268
|
6 // How many pins there are
|
andrewm@268
|
7 #define NUM_TOUCH_PINS 12
|
andrewm@268
|
8
|
andrewm@268
|
9 // Define this to print data to terminal
|
andrewm@268
|
10 #undef DEBUG_MPR121
|
andrewm@268
|
11
|
andrewm@268
|
12 // Change this to change how often the MPR121 is read (in Hz)
|
andrewm@268
|
13 int readInterval = 50;
|
andrewm@268
|
14
|
andrewm@268
|
15 // Change this threshold to set the minimum amount of touch
|
andrewm@268
|
16 int threshold = 40;
|
andrewm@268
|
17
|
andrewm@268
|
18 // This array holds the continuous sensor values
|
andrewm@268
|
19 int sensorValue[NUM_TOUCH_PINS];
|
andrewm@268
|
20
|
andrewm@268
|
21 // ---- test code stuff -- can be deleted for your example ----
|
andrewm@268
|
22
|
andrewm@268
|
23 // 12 notes of a C major scale...
|
andrewm@268
|
24 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};
|
andrewm@268
|
25
|
andrewm@268
|
26 // This is internal stuff for the demo
|
andrewm@268
|
27 float gNormFrequencies[NUM_TOUCH_PINS];
|
andrewm@268
|
28 float gPhases[NUM_TOUCH_PINS] = {0};
|
andrewm@268
|
29
|
andrewm@268
|
30 // ---- internal stuff -- do not change -----
|
andrewm@268
|
31
|
andrewm@268
|
32 I2C_MPR121 mpr121; // Object to handle MPR121 sensing
|
andrewm@268
|
33 AuxiliaryTask i2cTask; // Auxiliary task to read I2C
|
andrewm@268
|
34
|
andrewm@268
|
35 int readCount = 0; // How long until we read again...
|
andrewm@268
|
36 int readIntervalSamples = 0; // How many samples between reads
|
andrewm@268
|
37
|
andrewm@268
|
38 void readMPR121();
|
andrewm@268
|
39
|
andrewm@268
|
40 // setup() is called once before the audio rendering starts.
|
andrewm@268
|
41 // Use it to perform any initialisation and allocation which is dependent
|
andrewm@268
|
42 // on the period size or sample rate.
|
andrewm@268
|
43 //
|
andrewm@268
|
44 // userData holds an opaque pointer to a data structure that was passed
|
andrewm@268
|
45 // in from the call to initAudio().
|
andrewm@268
|
46 //
|
andrewm@268
|
47 // Return true on success; returning false halts the program.
|
andrewm@268
|
48
|
giuliomoro@301
|
49 bool setup(BelaContext *context, void *userData)
|
andrewm@268
|
50 {
|
andrewm@268
|
51 if(!mpr121.begin(1, 0x5A)) {
|
andrewm@268
|
52 rt_printf("Error initialising MPR121\n");
|
andrewm@268
|
53 return false;
|
andrewm@268
|
54 }
|
andrewm@268
|
55
|
andrewm@303
|
56 i2cTask = Bela_createAuxiliaryTask(readMPR121, 50, "bela-mpr121");
|
andrewm@268
|
57 readIntervalSamples = context->audioSampleRate / readInterval;
|
andrewm@268
|
58
|
andrewm@268
|
59 for(int i = 0; i < NUM_TOUCH_PINS; i++) {
|
andrewm@268
|
60 gNormFrequencies[i] = 2.0 * M_PI * gFrequencies[i] / context->audioSampleRate;
|
andrewm@268
|
61 }
|
andrewm@268
|
62
|
andrewm@268
|
63 return true;
|
andrewm@268
|
64 }
|
andrewm@268
|
65
|
andrewm@268
|
66 // render() is called regularly at the highest priority by the audio engine.
|
andrewm@268
|
67 // Input and output are given from the audio hardware and the other
|
andrewm@268
|
68 // ADCs and DACs (if available). If only audio is available, numAnalogFrames
|
andrewm@268
|
69 // will be 0.
|
andrewm@268
|
70
|
giuliomoro@301
|
71 void render(BelaContext *context, void *userData)
|
andrewm@268
|
72 {
|
andrewm@268
|
73 for(int n = 0; n < context->audioFrames; n++) {
|
andrewm@268
|
74 // Keep this code: it schedules the touch sensor readings
|
andrewm@268
|
75 if(++readCount >= readIntervalSamples) {
|
andrewm@268
|
76 readCount = 0;
|
giuliomoro@301
|
77 Bela_scheduleAuxiliaryTask(i2cTask);
|
andrewm@268
|
78 }
|
andrewm@268
|
79
|
andrewm@268
|
80 float sample = 0.0;
|
andrewm@268
|
81
|
andrewm@268
|
82 // This code can be replaced with your favourite audio code
|
andrewm@268
|
83 for(int i = 0; i < NUM_TOUCH_PINS; i++) {
|
andrewm@268
|
84 float amplitude = sensorValue[i] / 400.0;
|
andrewm@268
|
85
|
andrewm@268
|
86 // Prevent clipping
|
andrewm@268
|
87 if(amplitude > 0.5)
|
andrewm@268
|
88 amplitude = 0.5;
|
andrewm@268
|
89
|
andrewm@268
|
90 sample += amplitude * sinf(gPhases[i]);
|
andrewm@268
|
91 gPhases[i] += gNormFrequencies[i];
|
andrewm@268
|
92 if(gPhases[i] > 2.0 * M_PI)
|
andrewm@268
|
93 gPhases[i] -= 2.0 * M_PI;
|
andrewm@268
|
94 }
|
andrewm@268
|
95
|
andrewm@268
|
96 for(int ch = 0; ch < context->audioChannels; ch++)
|
andrewm@268
|
97 context->audioOut[context->audioChannels * n + ch] = sample;
|
andrewm@268
|
98 }
|
andrewm@268
|
99 }
|
andrewm@268
|
100
|
andrewm@268
|
101 // cleanup() is called once at the end, after the audio has stopped.
|
andrewm@268
|
102 // Release any resources that were allocated in setup().
|
andrewm@268
|
103
|
giuliomoro@301
|
104 void cleanup(BelaContext *context, void *userData)
|
andrewm@268
|
105 {
|
andrewm@268
|
106 // Nothing to do here
|
andrewm@268
|
107 }
|
andrewm@268
|
108
|
andrewm@268
|
109
|
andrewm@268
|
110 // Auxiliary task to read the I2C board
|
andrewm@268
|
111 void readMPR121()
|
andrewm@268
|
112 {
|
andrewm@268
|
113 for(int i = 0; i < NUM_TOUCH_PINS; i++) {
|
andrewm@268
|
114 sensorValue[i] = -(mpr121.filteredData(i) - mpr121.baselineData(i));
|
andrewm@268
|
115 sensorValue[i] -= threshold;
|
andrewm@268
|
116 if(sensorValue[i] < 0)
|
andrewm@268
|
117 sensorValue[i] = 0;
|
andrewm@268
|
118 #ifdef DEBUG_MPR121
|
andrewm@268
|
119 rt_printf("%d ", sensorValue[i]);
|
andrewm@268
|
120 #endif
|
andrewm@268
|
121 }
|
andrewm@268
|
122 #ifdef DEBUG_MPR121
|
andrewm@268
|
123 rt_printf("\n");
|
andrewm@268
|
124 #endif
|
andrewm@268
|
125
|
andrewm@268
|
126 // You can use this to read binary on/off touch state more easily
|
andrewm@268
|
127 //rt_printf("Touched: %x\n", mpr121.touched());
|
giuliomoro@301
|
128 }
|