giuliomoro@301: #include <Bela.h>
andrewm@268: #include <Utilities.h>
andrewm@268: #include <cmath>
andrewm@268: #include <rtdk.h>
andrewm@268: #include "I2C_MPR121.h"
andrewm@268: 
andrewm@268: // How many pins there are
andrewm@268: #define NUM_TOUCH_PINS 12
andrewm@268: 
andrewm@268: // Define this to print data to terminal
andrewm@268: #undef DEBUG_MPR121
andrewm@268: 
andrewm@268: // Change this to change how often the MPR121 is read (in Hz)
andrewm@268: int readInterval = 50;
andrewm@268: 
andrewm@268: // Change this threshold to set the minimum amount of touch
andrewm@268: int threshold = 40;
andrewm@268: 
andrewm@268: // This array holds the continuous sensor values
andrewm@268: int sensorValue[NUM_TOUCH_PINS];
andrewm@268: 
andrewm@268: // ---- test code stuff -- can be deleted for your example ----
andrewm@268: 
andrewm@268: // 12 notes of a C major scale...
andrewm@268: 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: 
andrewm@268: // This is internal stuff for the demo
andrewm@268: float gNormFrequencies[NUM_TOUCH_PINS];
andrewm@268: float gPhases[NUM_TOUCH_PINS] = {0};
andrewm@268: 
andrewm@268: // ---- internal stuff -- do not change -----
andrewm@268: 
andrewm@268: I2C_MPR121 mpr121;			// Object to handle MPR121 sensing
andrewm@268: AuxiliaryTask i2cTask;		// Auxiliary task to read I2C
andrewm@268: 
andrewm@268: int readCount = 0;			// How long until we read again...
andrewm@268: int readIntervalSamples = 0; // How many samples between reads
andrewm@268: 
andrewm@268: void readMPR121();
andrewm@268: 
andrewm@268: // setup() is called once before the audio rendering starts.
andrewm@268: // Use it to perform any initialisation and allocation which is dependent
andrewm@268: // on the period size or sample rate.
andrewm@268: //
andrewm@268: // userData holds an opaque pointer to a data structure that was passed
andrewm@268: // in from the call to initAudio().
andrewm@268: //
andrewm@268: // Return true on success; returning false halts the program.
andrewm@268: 
giuliomoro@301: bool setup(BelaContext *context, void *userData)
andrewm@268: {
andrewm@268: 	if(!mpr121.begin(1, 0x5A)) {
andrewm@268: 		rt_printf("Error initialising MPR121\n");
andrewm@268: 		return false;
andrewm@268: 	}
andrewm@268: 	
andrewm@303: 	i2cTask = Bela_createAuxiliaryTask(readMPR121, 50, "bela-mpr121");
andrewm@268: 	readIntervalSamples = context->audioSampleRate / readInterval;
andrewm@268: 	
andrewm@268: 	for(int i = 0; i < NUM_TOUCH_PINS; i++) {
andrewm@268: 		gNormFrequencies[i] = 2.0 * M_PI * gFrequencies[i] / context->audioSampleRate;
andrewm@268: 	}
andrewm@268: 	
andrewm@268: 	return true;
andrewm@268: }
andrewm@268: 
andrewm@268: // render() is called regularly at the highest priority by the audio engine.
andrewm@268: // Input and output are given from the audio hardware and the other
andrewm@268: // ADCs and DACs (if available). If only audio is available, numAnalogFrames
andrewm@268: // will be 0.
andrewm@268: 
giuliomoro@301: void render(BelaContext *context, void *userData)
andrewm@268: {
andrewm@268: 	for(int n = 0; n < context->audioFrames; n++) {
andrewm@268: 		// Keep this code: it schedules the touch sensor readings
andrewm@268: 		if(++readCount >= readIntervalSamples) {
andrewm@268: 			readCount = 0;
giuliomoro@301: 			Bela_scheduleAuxiliaryTask(i2cTask);
andrewm@268: 		}
andrewm@268: 		
andrewm@268: 		float sample = 0.0;
andrewm@268: 		
andrewm@268: 		// This code can be replaced with your favourite audio code
andrewm@268: 		for(int i = 0; i < NUM_TOUCH_PINS; i++) {
andrewm@268: 			float amplitude = sensorValue[i] / 400.0;
andrewm@268: 			
andrewm@268: 			// Prevent clipping
andrewm@268: 			if(amplitude > 0.5)
andrewm@268: 				amplitude = 0.5;
andrewm@268: 			
andrewm@268: 			sample += amplitude * sinf(gPhases[i]);
andrewm@268: 			gPhases[i] += gNormFrequencies[i];
andrewm@268: 			if(gPhases[i] > 2.0 * M_PI)
andrewm@268: 				gPhases[i] -= 2.0 * M_PI;
andrewm@268: 		}
andrewm@268: 		
andrewm@268: 		for(int ch = 0; ch < context->audioChannels; ch++)
andrewm@268: 			context->audioOut[context->audioChannels * n + ch] = sample;
andrewm@268: 	}
andrewm@268: }
andrewm@268: 
andrewm@268: // cleanup() is called once at the end, after the audio has stopped.
andrewm@268: // Release any resources that were allocated in setup().
andrewm@268: 
giuliomoro@301: void cleanup(BelaContext *context, void *userData)
andrewm@268: {
andrewm@268: 	// Nothing to do here
andrewm@268: }
andrewm@268: 
andrewm@268: 
andrewm@268: // Auxiliary task to read the I2C board
andrewm@268: void readMPR121()
andrewm@268: {
andrewm@268: 	for(int i = 0; i < NUM_TOUCH_PINS; i++) {
andrewm@268: 		sensorValue[i] = -(mpr121.filteredData(i) - mpr121.baselineData(i));
andrewm@268: 		sensorValue[i] -= threshold;
andrewm@268: 		if(sensorValue[i] < 0)
andrewm@268: 			sensorValue[i] = 0;
andrewm@268: #ifdef DEBUG_MPR121
andrewm@268: 		rt_printf("%d ", sensorValue[i]);
andrewm@268: #endif
andrewm@268: 	}
andrewm@268: #ifdef DEBUG_MPR121
andrewm@268: 	rt_printf("\n");
andrewm@268: #endif
andrewm@268: 	
andrewm@268: 	// You can use this to read binary on/off touch state more easily
andrewm@268: 	//rt_printf("Touched: %x\n", mpr121.touched());
giuliomoro@301: }