robert@501: /* robert@501: ____ _____ _ _ robert@501: | __ )| ____| | / \ robert@501: | _ \| _| | | / _ \ robert@501: | |_) | |___| |___ / ___ \ robert@501: |____/|_____|_____/_/ \_\ robert@501: robert@501: The platform for ultra-low latency audio and sensor processing robert@501: robert@501: http://bela.io robert@501: robert@501: A project of the Augmented Instruments Laboratory within the robert@501: Centre for Digital Music at Queen Mary University of London. robert@501: http://www.eecs.qmul.ac.uk/~andrewm robert@501: robert@501: (c) 2016 Augmented Instruments Laboratory: Andrew McPherson, robert@501: Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, robert@501: Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. robert@501: robert@501: The Bela software is distributed under the GNU Lesser General Public License robert@501: (LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt robert@501: */ robert@501: robert@501: robert@501: #include robert@501: #include robert@501: #include robert@501: #include "I2C_MPR121.h" robert@501: robert@501: // How many pins there are robert@501: #define NUM_TOUCH_PINS 12 robert@501: robert@501: // Define this to print data to terminal robert@501: #undef DEBUG_MPR121 robert@501: robert@501: // Change this to change how often the MPR121 is read (in Hz) robert@501: int readInterval = 50; robert@501: robert@501: // Change this threshold to set the minimum amount of touch robert@501: int threshold = 40; robert@501: robert@501: // This array holds the continuous sensor values robert@501: int sensorValue[NUM_TOUCH_PINS]; robert@501: robert@501: // ---- test code stuff -- can be deleted for your example ---- robert@501: robert@501: // 12 notes of a C major scale... robert@501: 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: robert@501: // This is internal stuff for the demo robert@501: float gNormFrequencies[NUM_TOUCH_PINS]; robert@501: float gPhases[NUM_TOUCH_PINS] = {0}; robert@501: robert@501: // ---- internal stuff -- do not change ----- robert@501: robert@501: I2C_MPR121 mpr121; // Object to handle MPR121 sensing robert@501: AuxiliaryTask i2cTask; // Auxiliary task to read I2C robert@501: robert@501: int readCount = 0; // How long until we read again... robert@501: int readIntervalSamples = 0; // How many samples between reads robert@501: robert@501: void readMPR121(); robert@501: robert@501: // setup() is called once before the audio rendering starts. robert@501: // Use it to perform any initialisation and allocation which is dependent robert@501: // on the period size or sample rate. robert@501: // robert@501: // userData holds an opaque pointer to a data structure that was passed robert@501: // in from the call to initAudio(). robert@501: // robert@501: // Return true on success; returning false halts the program. robert@501: robert@501: bool setup(BelaContext *context, void *userData) robert@501: { robert@501: if(!mpr121.begin(1, 0x5A)) { robert@501: rt_printf("Error initialising MPR121\n"); robert@501: return false; robert@501: } robert@501: robert@501: i2cTask = Bela_createAuxiliaryTask(readMPR121, 50, "bela-mpr121"); robert@501: readIntervalSamples = context->audioSampleRate / readInterval; robert@501: robert@501: for(int i = 0; i < NUM_TOUCH_PINS; i++) { robert@501: gNormFrequencies[i] = 2.0 * M_PI * gFrequencies[i] / context->audioSampleRate; robert@501: } robert@501: robert@501: return true; robert@501: } robert@501: robert@501: // render() is called regularly at the highest priority by the audio engine. robert@501: // Input and output are given from the audio hardware and the other robert@501: // ADCs and DACs (if available). If only audio is available, numAnalogFrames robert@501: // will be 0. robert@501: robert@501: void render(BelaContext *context, void *userData) robert@501: { robert@501: for(int n = 0; n < context->audioFrames; n++) { robert@501: // Keep this code: it schedules the touch sensor readings robert@501: if(++readCount >= readIntervalSamples) { robert@501: readCount = 0; robert@501: Bela_scheduleAuxiliaryTask(i2cTask); robert@501: } robert@501: robert@501: float sample = 0.0; robert@501: robert@501: // This code can be replaced with your favourite audio code robert@501: for(int i = 0; i < NUM_TOUCH_PINS; i++) { robert@501: float amplitude = sensorValue[i] / 400.0; robert@501: robert@501: // Prevent clipping robert@501: if(amplitude > 0.5) robert@501: amplitude = 0.5; robert@501: robert@501: sample += amplitude * sinf(gPhases[i]); robert@501: gPhases[i] += gNormFrequencies[i]; robert@501: if(gPhases[i] > 2.0 * M_PI) robert@501: gPhases[i] -= 2.0 * M_PI; robert@501: } robert@501: robert@501: for(int ch = 0; ch < context->audioChannels; ch++) robert@501: context->audioOut[context->audioChannels * n + ch] = sample; robert@501: } robert@501: } robert@501: robert@501: // cleanup() is called once at the end, after the audio has stopped. robert@501: // Release any resources that were allocated in setup(). robert@501: robert@501: void cleanup(BelaContext *context, void *userData) robert@501: { robert@501: // Nothing to do here robert@501: } robert@501: robert@501: robert@501: // Auxiliary task to read the I2C board robert@501: void readMPR121() robert@501: { robert@501: for(int i = 0; i < NUM_TOUCH_PINS; i++) { robert@501: sensorValue[i] = -(mpr121.filteredData(i) - mpr121.baselineData(i)); robert@501: sensorValue[i] -= threshold; robert@501: if(sensorValue[i] < 0) robert@501: sensorValue[i] = 0; robert@501: #ifdef DEBUG_MPR121 robert@501: rt_printf("%d ", sensorValue[i]); robert@501: #endif robert@501: } robert@501: #ifdef DEBUG_MPR121 robert@501: rt_printf("\n"); robert@501: #endif robert@501: robert@501: // You can use this to read binary on/off touch state more easily robert@501: //rt_printf("Touched: %x\n", mpr121.touched()); robert@501: } robert@501: robert@501: robert@501: /** robert@502: \example capacitive-touch/render.cpp robert@501: robert@501: Capacitive touch sensing with MPR121 robert@501: --------------------------- robert@501: robert@501: This sketch allows you to hook up an MPR121 capactive touch sensing device robert@501: to Bela, for example the SparkFun Capacitive Touch Sensor Breakout - MPR121. robert@501: The breakout board gives you 12 electrode connections. robert@501: robert@501: To get this working with Bela you need to connect the breakout board to the I2C robert@501: terminal on the Bela board. See the Pin guide for details of which pin is which. robert@501: robert@501: The sensor data will then be available for you to use in the array robert@501: `sensorValue[NUM_TOUCH_PINS]`. robert@501: */