andrewm@0: /*
andrewm@0:  * sensors.cpp
andrewm@0:  *
andrewm@0:  *  Created on: May 28, 2014
andrewm@0:  *      Author: Victor Zappi
andrewm@0:  */
andrewm@0: 
andrewm@0: #include <stdio.h>
andrewm@0: #include <pthread.h>
andrewm@0: #include <unistd.h>
andrewm@0: #include <math.h>
andrewm@0: #include <vector>
andrewm@0: #include "prio.h"
andrewm@0: #include "sensors.h"
andrewm@0: #include "OscillatorBank.h"
andrewm@0: #include "DboxSensors.h"
andrewm@0: 
andrewm@0: 
andrewm@0: //----------------------------------------
andrewm@0: // main extern variables
andrewm@0: //----------------------------------------
andrewm@0: extern vector<OscillatorBank*> gOscBanks;
andrewm@0: extern int gCurrentOscBank;
andrewm@0: extern int gNextOscBank;
giuliomoro@233: extern int gShouldStop;
andrewm@0: extern int gVerbose;
andrewm@0: 
andrewm@0: float gSensor0LatestTouchPos = 0;	// most recent pitch touch location [0-1] on sensor 0, used by render.cpp
andrewm@0: int gSensor0LatestTouchNum	 = 0;	// most recent num of touches on sensor 0, used by render.cpp
andrewm@0: float gSensor1LatestTouchPos[5];	// most recent touche locations on sensor 1, used by render.cpp
andrewm@0: //float gSensor1LatestTouchSizes[5];
andrewm@0: int gSensor1LatestTouchCount;		// most recent number touches on sensor 1, used by render.cpp
andrewm@0: int gSensor1LatestTouchIndex = 0;	// index of last touch in gSensor1LatestTouchPos[5], used by render.cpp
andrewm@0: int gLastFSRValue = 1799;			// most recent fsr value, used by render.cpp
andrewm@0: 
andrewm@0: 
andrewm@0: DboxSensors Sensors;
andrewm@0: 
andrewm@0: 
andrewm@0: //----------------------------------------
andrewm@0: // var shared with logger
andrewm@0: //----------------------------------------
andrewm@0: int s0TouchNum	 	= 0;
andrewm@0: float s0Touches_[MAX_TOUCHES];
andrewm@0: float s0Size_[MAX_TOUCHES];
andrewm@0: int s0LastIndex;
andrewm@0: 
andrewm@0: int s1TouchNum	 	= 0;
andrewm@0: float s1Touches_[MAX_TOUCHES];
andrewm@0: float s1Size_[MAX_TOUCHES];
andrewm@0: int s1LastIndex;
andrewm@0: 
andrewm@0: int fsr				= 1799;
andrewm@0: 
andrewm@0: 
andrewm@0: 
andrewm@0: using namespace std;
andrewm@0: 
andrewm@15: int initSensorLoop(int sensorAddress0, int sensorAddress1, int sensorType)
andrewm@0: {
andrewm@0: 	int tk0_bus			= 1;
andrewm@0: 	int tk0_address		= sensorAddress0;
andrewm@0: 	int tk1_bus			= 1;
andrewm@0: 	int tk1_address		= sensorAddress1;
andrewm@0: 	int tk_file			= 0;
andrewm@0: 	int fsr_max			= 1799;
andrewm@0: 	int fsr_pinNum		= 4;
andrewm@0: 
andrewm@0: 	if(gVerbose==1)
andrewm@0: 		cout << "---------------->Init Control Thread" << endl;
andrewm@0: 
andrewm@15: 	if(Sensors.initSensors(tk0_bus, tk0_address, tk1_bus, tk1_address, tk_file, fsr_pinNum, fsr_max, sensorType)>0)
andrewm@0: 	{
andrewm@0: 		gShouldStop = 1;
andrewm@0: 		cout << "control cannot start" << endl;
andrewm@0: 		return -1;
andrewm@0: 	}
andrewm@0: 
andrewm@0: 	for(int i=0; i<MAX_TOUCHES; i++)
andrewm@0: 	{
andrewm@0: 		s0Touches_[i]	= 0.0;
andrewm@0: 		s0Size_[i]		= 0.0;
andrewm@0: 
andrewm@0: 		s1Touches_[i]	= 0.0;
andrewm@0: 		s1Size_[i]	= 0.0;
andrewm@0: 	}
andrewm@0: 
andrewm@0: 	return 0;
andrewm@0: }
andrewm@0: 
andrewm@0: void sensorLoop(void *)
andrewm@0: {
andrewm@0: 	timeval start, end;
andrewm@0: 	unsigned long elapsedTime;
andrewm@0: 	//float touchSize		= 0;	// once used for timbre
andrewm@0: 
andrewm@0: 
andrewm@0: 
andrewm@0: 	float *s0Touches;
andrewm@0: 	float *s0Size;
andrewm@0: 	int s0PrevTouchNum 	= 0;
andrewm@0: 	int s0SortedTouchIndices[MAX_TOUCHES];
andrewm@0: 	float s0SortedTouches[MAX_TOUCHES];
andrewm@0: 	float s0PrevSortedTouches[MAX_TOUCHES];
andrewm@0: 
andrewm@0: 	float *s1Touches;
andrewm@0: 	float *s1Size;
andrewm@0: 	int s1PrevTouchNum 	= 0;
andrewm@0: 	int s1SortedTouchIndices[MAX_TOUCHES];
andrewm@0: 	float s1SortedTouches[MAX_TOUCHES];
andrewm@0: 	float s1PrevSortedTouches[MAX_TOUCHES];
andrewm@0: 
andrewm@0: 	float freqScaler	= 0;
andrewm@0: 	int fsrMin			= 0;//50; // was 200
andrewm@0: 	int fsrMax			= 1799;//1300; // was 800
andrewm@0: 	float vel			= 0;
andrewm@0: 	float prevVel		= 0;
andrewm@0: 	float filterMaxF	= 0;
andrewm@0: 	if(gVerbose==1)
andrewm@0: 		dbox_printf("__________set Control Thread priority\n");
andrewm@0: 
andrewm@0: 	if(gVerbose==1)
andrewm@0: 		dbox_printf("_________________Control Thread!\n");
andrewm@0: 
andrewm@0: 	// get freq scaler, cos freqs must be scaled according to the wavetable used in the oscillator bank
andrewm@0: 	freqScaler 		= gOscBanks[gCurrentOscBank]->getFrequencyScaler();
andrewm@0: 	filterMaxF		= gOscBanks[gCurrentOscBank]->filterMaxF;
andrewm@0: 
andrewm@0: 	// init time vals
andrewm@0: 	gettimeofday(&start, NULL);
andrewm@0: 
andrewm@0: 	// here we go, sensor loop until the end of the application
andrewm@0: 	while(!gShouldStop)
andrewm@0: 	{
andrewm@0: 		gettimeofday(&end, NULL);
andrewm@0: 		elapsedTime = ( (end.tv_sec*1000000+end.tv_usec) - (start.tv_sec*1000000+start.tv_usec) );
andrewm@0: 		if( elapsedTime<4000 )
andrewm@0: 			usleep(4000-elapsedTime);
andrewm@0: 		else
andrewm@0: 			dbox_printf("%d\n", (int)elapsedTime); // this print happens when something's gone bad...
andrewm@0: 
andrewm@0: 		if(Sensors.readSensors()==0)
andrewm@0: 		{
andrewm@0: 			s0TouchNum	= Sensors.getTKTouchCount(0);
andrewm@0: 			s0Touches	= Sensors.getTKXPositions(0);
andrewm@0: 			s0Size 		= Sensors.getTKTouchSize(0);
andrewm@0: 
andrewm@0: 			s1TouchNum	= Sensors.getTKTouchCount(1);
andrewm@0: 			s1Touches	= Sensors.getTKXPositions(1);
andrewm@0: 			s1Size 		= Sensors.getTKTouchSize(1);
andrewm@0: 
andrewm@0: 			for(int i=0; i<MAX_TOUCHES; i++)
andrewm@0: 			{
andrewm@0: 				s0Touches_[i]	= s0Touches[i];
andrewm@0: 				s0Size_[i]		= s0Size[i];
andrewm@0: 
andrewm@0: 				s1Touches_[i]	= s1Touches[i];
andrewm@0: 				s1Size_[i]		= s1Size[i];
andrewm@0: 			}
andrewm@0: 
andrewm@0: 			gSensor0LatestTouchNum	= s0TouchNum;
andrewm@0: 			if(s0TouchNum > 0)
andrewm@0: 			{
andrewm@0: 				//-----------------------------------------------------------------------------------
andrewm@0: 				// timbre, speed and  pitch
andrewm@0: 				//touchSize	 = 0;	\\ once used for timbre
andrewm@0: 
andrewm@0: 				// if we have a number of touches different from previous round, track their order of arrival [calculated using distance comparison]
andrewm@0: 				if(s0PrevTouchNum!=s0TouchNum)
andrewm@0: 				{
andrewm@0: 					float distances[MAX_TOUCHES*(MAX_TOUCHES-1)]; // maximum number of current+previous touches between rounds with different num of touches
andrewm@0: 					int ids[MAX_TOUCHES*(MAX_TOUCHES-1)];
andrewm@0: 					// calculate all distance permutations between previous and current touches
andrewm@0: 					for(int i=0; i<s0TouchNum; i++)
andrewm@0: 					{
andrewm@0: 						for(int p=0; p<s0PrevTouchNum; p++)
andrewm@0: 						{
andrewm@0: 							int index			= i*s0PrevTouchNum+p;	// permutation id [says between which touches we are calculating distance]
andrewm@0: 							distances[index]	= fabs(s0Touches[i]-s0PrevSortedTouches[p]);
andrewm@0: 							ids[index]			= index;
andrewm@0: 							if(index>0)
andrewm@0: 							{
andrewm@0: 								// sort, from min to max distance
andrewm@0: 								float tmp;
andrewm@0: 								while(distances[index]<distances[index-1])
andrewm@0: 								{
andrewm@0: 									tmp				= ids[index-1];
andrewm@0: 									ids[index-1]	= ids[index];
andrewm@0: 									ids[index]		= tmp;
andrewm@0: 
andrewm@0: 									tmp				= distances[index-1];
andrewm@0: 									distances[index-1] = distances[index];
andrewm@0: 									distances[index] = tmp;
andrewm@0: 
andrewm@0: 									index--;
andrewm@0: 
andrewm@0: 									if(index == 0)
andrewm@0: 										break;
andrewm@0: 								}
andrewm@0: 							}
andrewm@0: 						}
andrewm@0: 					}
andrewm@0: 
andrewm@0: 					int sorted = 0;
andrewm@0: 					bool currAssigned[MAX_TOUCHES] = {false};
andrewm@0: 					bool prevAssigned[MAX_TOUCHES] = {false};
andrewm@0: 
andrewm@0: 					// track touches assigning index according to shortest distance
andrewm@0: 					for(int i=0; i<s0TouchNum*s0PrevTouchNum; i++)
andrewm@0: 					{
andrewm@0: 						int currentIndex	= ids[i]/s0PrevTouchNum;
andrewm@0: 						int prevIndex		= ids[i]%s0PrevTouchNum;
andrewm@0: 						// avoid double assignment
andrewm@0: 						if(!currAssigned[currentIndex] && !prevAssigned[prevIndex])
andrewm@0: 						{
andrewm@0: 							currAssigned[currentIndex]	= true;
andrewm@0: 							prevAssigned[prevIndex]		= true;
andrewm@0: 							s0SortedTouchIndices[currentIndex] = prevIndex;
andrewm@0: 							sorted++;
andrewm@0: 						}
andrewm@0: 					}
andrewm@0: 					// we still have to assign a free index to new touches
andrewm@0: 					if(s0PrevTouchNum<s0TouchNum)
andrewm@0: 					{
andrewm@0: 						for(int i=0; i<s0TouchNum; i++)
andrewm@0: 						{
andrewm@0: 							if(!currAssigned[i])
andrewm@0: 								s0SortedTouchIndices[i] = sorted++; // assign next free index
andrewm@0: 
andrewm@0: 							// update tracked value
andrewm@0: 							s0SortedTouches[s0SortedTouchIndices[i]] = s0Touches[i];
andrewm@0: 							s0PrevSortedTouches[i]			         = s0SortedTouches[i];
andrewm@0: 							if(s0SortedTouchIndices[i]==s0TouchNum-1)
andrewm@0: 								s0LastIndex = i;
andrewm@0: 
andrewm@0: 							// accumulate sizes for timbre
andrewm@0: 							//touchSize += s0Size[i];
andrewm@0: 						}
andrewm@0: 					}
andrewm@0: 					else // some touches have disappeared...
andrewm@0: 					{
andrewm@0: 						// ...we have to shift all indices...
andrewm@0: 						for(int i=s0PrevTouchNum-1; i>=0; i--)
andrewm@0: 						{
andrewm@0: 							if(!prevAssigned[i])
andrewm@0: 							{
andrewm@0: 								for(int j=0; j<s0TouchNum; j++)
andrewm@0: 								{
andrewm@0: 									// ...only if touches that disappeared were before the current one
andrewm@0: 									if(s0SortedTouchIndices[j]>i)
andrewm@0: 										s0SortedTouchIndices[j]--;
andrewm@0: 								}
andrewm@0: 							}
andrewm@0: 						}
andrewm@0: 						// done! now update
andrewm@0: 						for(int i=0; i<s0TouchNum; i++)
andrewm@0: 						{
andrewm@0: 							// update tracked value
andrewm@0: 							s0SortedTouches[s0SortedTouchIndices[i]] = s0Touches[i];
andrewm@0: 							s0PrevSortedTouches[i]			         = s0SortedTouches[i];
andrewm@0: 							if(s0SortedTouchIndices[i]==s0TouchNum-1)
andrewm@0: 								s0LastIndex = i;
andrewm@0: 
andrewm@0: 							// accumulate sizes for timbre
andrewm@0: 							//touchSize += s0Size[i];
andrewm@0: 						}
andrewm@0: 					}
andrewm@0: 				}
andrewm@0: 				else // nothing's changed since last round
andrewm@0: 				{
andrewm@0: 					for(int i=0; i<s0TouchNum; i++)
andrewm@0: 					{
andrewm@0: 						// update tracked value
andrewm@0: 						s0SortedTouches[s0SortedTouchIndices[i]] = s0Touches[i];
andrewm@0: 						s0PrevSortedTouches[i]			         = s0SortedTouches[i];
andrewm@0: 
andrewm@0: 						// accumulate sizes for timbre
andrewm@0: 						//touchSize += s0Size[i];
andrewm@0: 					}
andrewm@0: 				}
andrewm@0: 
andrewm@0: 				if(s0TouchNum == 0)
andrewm@0: 					s0LastIndex = -1;
andrewm@0: 
andrewm@0: 				// timbre
andrewm@0: 				//touchSize = (touchSize > 0.7) ? 1 : touchSize/0.7;
andrewm@0: 				//gOscBanks[gCurrentOscBank]->hopNumTh = log((1-touchSize)+1)/log(2)*20000;
andrewm@0: 				//gOscBanks[gCurrentOscBank]->hopNumTh = 0;
andrewm@0: 
andrewm@0: 
andrewm@0: 				// pitch, controlled by last touch
andrewm@0: 				//prevTouchPos 				= touch[touchIndex];
andrewm@0: 				//touchPos	 			 	= (s0SortedTouches[s0TouchNum-1]-0.5)/0.5;	// from [0,1] to [-1,1]
andrewm@0: 				gSensor0LatestTouchPos      = s0SortedTouches[s0TouchNum-1];
andrewm@0: 				//touchPos					= s0Touches[0];
andrewm@0: 				//gOscBanks[gCurrentOscBank]->pitchMultiplier 	= pow(2, touchPos);
andrewm@0: 				//-----------------------------------------------------------------------------------
andrewm@0: 
andrewm@0: 
andrewm@0: 
andrewm@0: 				//-----------------------------------------------------------------------------------
andrewm@0: 				// note on
andrewm@0: 				//if(s0PrevTouchNum == 0)
andrewm@0: 				//	gOscBanks[gCurrentOscBank]->play();
andrewm@0: 				// fsr = Sensors.getFSRVAlue();
andrewm@0: 				fsr = gLastFSRValue;
andrewm@0: 				//dbox_printf("fsr: %d\n", fsr);
andrewm@0: 				if(!gOscBanks[gCurrentOscBank]->note)
andrewm@0: 				{
andrewm@0: 					vel = fsr;
andrewm@0: 					vel /= (float)(fsrMax-fsrMin);
andrewm@0: 
andrewm@0: 					vel = 1-vel;
andrewm@0: 					dbox_printf("Attack vel: %f\n", vel);
andrewm@0: 					gOscBanks[gCurrentOscBank]->play(vel);
andrewm@0: 					prevVel = vel;
andrewm@0: 				}
andrewm@0: 				else if(gOscBanks[gCurrentOscBank]->getEnvelopeState() != env_release)
andrewm@0: 				{
andrewm@0: 					fsr = (fsr > fsrMax) ? fsrMax : fsr;
andrewm@0: 					vel = (fsr < fsrMin) ? fsrMin : fsr;
andrewm@0: 					vel -= fsrMin;
andrewm@0: 					vel /= (float)(fsrMax-fsrMin);
andrewm@0: 					vel = 1-vel;
andrewm@0: 					if(vel > prevVel)
andrewm@0: 					{
andrewm@0: 						gOscBanks[gCurrentOscBank]->afterTouch(vel);
andrewm@0: 						prevVel = vel;
andrewm@0: 					}
andrewm@0: 				}
andrewm@0: 				//-----------------------------------------------------------------------------------
andrewm@0: 			}
andrewm@0: 			else
andrewm@0: 			{
andrewm@0: 				//prevFsr = 1799;
andrewm@0: 				//prevTouchPos = -1;
andrewm@0: 				//-----------------------------------------------------------------------------------
andrewm@0: 				// note off
andrewm@0: 				if(s0PrevTouchNum > 0)
andrewm@0: 				{
andrewm@0: 					if(gOscBanks[gCurrentOscBank]->state==bank_playing)
andrewm@0: 						gOscBanks[gCurrentOscBank]->stop();
andrewm@0: 				}
andrewm@0: 				//-----------------------------------------------------------------------------------
andrewm@0: 			}
andrewm@0: 
andrewm@0: 
andrewm@0: 
andrewm@0: 			// sensor 2
andrewm@0: 			//-----------------------------------------------------------------------------------
andrewm@0: 			//filter - calculated even when no touches on first sensor, to filter also release tail
andrewm@0: 			gOscBanks[gCurrentOscBank]->filterNum	= s1TouchNum;
andrewm@0: 
andrewm@0: 			gSensor1LatestTouchCount = gOscBanks[gCurrentOscBank]->filterNum;
andrewm@0: 			for(int i = 0; i < gSensor1LatestTouchCount; i++) {
andrewm@0: 				gSensor1LatestTouchPos[i] = s1Touches[i];
andrewm@0: 				//gSensor1LatestTouchSizes[i] = s1Size[i];
andrewm@0: 			}
andrewm@0: 
andrewm@0: /*			for(int i=0; i<gOscBanks[gCurrentOscBank]->filterNum; i++)
andrewm@0: 			{
andrewm@0: 				// touch pos is linear but freqs are log
andrewm@0: 				gOscBanks[gCurrentOscBank]->filterFreqs[i] = ((exp(s0Touches[i]*4)-1)/(exp(4)-1))*filterMaxF*freqScaler;
andrewm@0: 				//gOscBanks[gCurrentOscBank]->filterQ[i] = size[i]*5*(1+touch[i]*1000)*freqScaler;
andrewm@0: 				gOscBanks[gCurrentOscBank]->filterQ[i] = s0Size[i];
andrewm@0: 				if(gOscBanks[gCurrentOscBank]->filterFreqs[i]>500*freqScaler)
andrewm@0: 					gOscBanks[gCurrentOscBank]->filterPadding[i] = 1+100000*( (gOscBanks[gCurrentOscBank]->filterFreqs[i]-500*freqScaler)/(filterMaxF-500)*freqScaler );
andrewm@0: 				else
andrewm@0: 					gOscBanks[gCurrentOscBank]->filterPadding[i] = 1;
andrewm@0: 			}*/
andrewm@0: 
andrewm@0: 			// each touch on sensor 2 is a notch filter, whose Q is determined by touch size
andrewm@0: 			for(int i=0; i<gOscBanks[gCurrentOscBank]->filterNum; i++)
andrewm@0: 			{
andrewm@0: 				// map touch pos [which is linear] on freqs exponentially
andrewm@0: 				float freq = ((exp(s1Touches[i]*4)-1)/EXP_DENOM)*filterMaxF;
andrewm@0: 				gOscBanks[gCurrentOscBank]->filterFreqs[i] = freq*freqScaler;
andrewm@0: 				// also size is mapped exponentially on Q
andrewm@0: 				float siz = (exp(s1Size[i])-1)/1.71828;
andrewm@0: 				gOscBanks[gCurrentOscBank]->filterQ[i] = siz*( (filterMaxF-freq)/filterMaxF * 0.9 + 0.1 );	// size weight on Q decreases with frequency
andrewm@0: 			}
andrewm@0: 			//-----------------------------------------------------------------------------------
andrewm@0: 
andrewm@0: 
andrewm@0: 
andrewm@0: 			//-----------------------------------------------------------------------------------
andrewm@0: 			// sort touches on sensor 2
andrewm@0: 			if(s1TouchNum > 0)
andrewm@0: 			{
andrewm@0: 				// if we have a number of touches different from previous round, track their order of arrival [calculated using distance comparison]
andrewm@0: 				if(s1PrevTouchNum!=s1TouchNum)
andrewm@0: 				{
andrewm@0: 					float distances[MAX_TOUCHES*(MAX_TOUCHES-1)]; // maximum number of current+previous touches between rounds with different num of touches
andrewm@0: 					int ids[MAX_TOUCHES*(MAX_TOUCHES-1)];
andrewm@0: 					// calculate all distance permutations between previous and current touches
andrewm@0: 					for(int i=0; i<s1TouchNum; i++)
andrewm@0: 					{
andrewm@0: 						for(int p=0; p<s1PrevTouchNum; p++)
andrewm@0: 						{
andrewm@0: 							int index 			= i*s1PrevTouchNum+p;	// permutation id [says between which touches we are calculating distance]
andrewm@0: 							distances[index]	= fabs(s1Touches[i]-s1PrevSortedTouches[p]);
andrewm@0: 							ids[index]			= index;
andrewm@0: 							if(index>0)
andrewm@0: 							{
andrewm@0: 								// sort, from min to max distance
andrewm@0: 								float tmp;
andrewm@0: 								while(distances[index]<distances[index-1])
andrewm@0: 								{
andrewm@0: 									tmp 				= ids[index-1];
andrewm@0: 									ids[index-1] 		= ids[index];
andrewm@0: 									ids[index] 			= tmp;
andrewm@0: 
andrewm@0: 									tmp					= distances[index-1];
andrewm@0: 									distances[index-1]	= distances[index];
andrewm@0: 									distances[index] 	= tmp;
andrewm@0: 
andrewm@0: 									index--;
andrewm@0: 
andrewm@0: 									if(index == 0)
andrewm@0: 										break;
andrewm@0: 								}
andrewm@0: 							}
andrewm@0: 						}
andrewm@0: 					}
andrewm@0: 
andrewm@0: 					int sorted = 0;
andrewm@0: 					bool currAssigned[MAX_TOUCHES] = {false};
andrewm@0: 					bool prevAssigned[MAX_TOUCHES] = {false};
andrewm@0: 
andrewm@0: 					// track touches assigning index according to shortest distance
andrewm@0: 					for(int i=0; i<s1TouchNum*s1PrevTouchNum; i++)
andrewm@0: 					{
andrewm@0: 						int currentIndex	= ids[i]/s1PrevTouchNum;
andrewm@0: 						int prevIndex		= ids[i]%s1PrevTouchNum;
andrewm@0: 						// avoid double assignment
andrewm@0: 						if(!currAssigned[currentIndex] && !prevAssigned[prevIndex])
andrewm@0: 						{
andrewm@0: 							currAssigned[currentIndex]			= true;
andrewm@0: 							prevAssigned[prevIndex]				= true;
andrewm@0: 							s1SortedTouchIndices[currentIndex] = prevIndex;
andrewm@0: 							sorted++;
andrewm@0: 						}
andrewm@0: 					}
andrewm@0: 					// we still have to assign a free index to new touches
andrewm@0: 					if(s1PrevTouchNum<s1TouchNum)
andrewm@0: 					{
andrewm@0: 						for(int i=0; i<s1TouchNum; i++)
andrewm@0: 						{
andrewm@0: 							if(!currAssigned[i])
andrewm@0: 								s1SortedTouchIndices[i] = sorted++; // assign next free index
andrewm@0: 
andrewm@0: 							// update tracked value
andrewm@0: 							s1SortedTouches[s1SortedTouchIndices[i]] = s1Touches[i];
andrewm@0: 							s1PrevSortedTouches[i]			       	 = s1SortedTouches[i];
andrewm@0: 							if(s1SortedTouchIndices[i]==s1TouchNum-1)
andrewm@0: 								s1LastIndex = i;
andrewm@0: 						}
andrewm@0: 					}
andrewm@0: 					else // some touches have disappeared...
andrewm@0: 					{
andrewm@0: 						// ...we have to shift all indices...
andrewm@0: 						for(int i=s1PrevTouchNum-1; i>=0; i--)
andrewm@0: 						{
andrewm@0: 							if(!prevAssigned[i])
andrewm@0: 							{
andrewm@0: 								for(int j=0; j<s1TouchNum; j++)
andrewm@0: 								{
andrewm@0: 									// ...only if touches that disappeared were before the current one
andrewm@0: 									if(s1SortedTouchIndices[j]>i)
andrewm@0: 										s1SortedTouchIndices[j]--;
andrewm@0: 								}
andrewm@0: 							}
andrewm@0: 						}
andrewm@0: 						// done! now update
andrewm@0: 						for(int i=0; i<s1TouchNum; i++)
andrewm@0: 						{
andrewm@0: 							// update tracked value
andrewm@0: 							s1SortedTouches[s1SortedTouchIndices[i]] = s1Touches[i];
andrewm@0: 							s1PrevSortedTouches[i]			       	 = s1SortedTouches[i];
andrewm@0: 							if(s1SortedTouchIndices[i]==s1TouchNum-1)
andrewm@0: 								s1LastIndex = i;
andrewm@0: 						}
andrewm@0: 					}
andrewm@0: 				}
andrewm@0: 				else // nothing's changed since last round
andrewm@0: 				{
andrewm@0: 					for(int i=0; i<s1TouchNum; i++)
andrewm@0: 					{
andrewm@0: 						// update tracked value
andrewm@0: 						s1SortedTouches[s1SortedTouchIndices[i]] = s1Touches[i];
andrewm@0: 						s1PrevSortedTouches[i]			       	 = s1SortedTouches[i];
andrewm@0: 					}
andrewm@0: 				}
andrewm@0: 			}
andrewm@0: 
andrewm@0: 			if(s1TouchNum > 0)
andrewm@0: 			{
andrewm@0: 				gSensor1LatestTouchIndex = s1LastIndex;
andrewm@0: 			}
andrewm@0: 			else
andrewm@0: 				s1LastIndex = -1;
andrewm@0: 
andrewm@0: /*			dbox_printf("-----------------------------\nnum: %d, latest: %d\n", s1TouchNum, gSensor1LatestTouchIndex);
andrewm@0: 			for(int i=0; i<s1TouchNum; i++)
andrewm@0: 				dbox_printf("\t%f\n", gSensor1LatestTouchPos[i]);
andrewm@0: 			dbox_printf("------\n");
andrewm@0: 			for(int i=0; i<s1TouchNum; i++)
andrewm@0: 				dbox_printf("\t%f\n", s1SortedTouches[i]);*/
andrewm@0: 
andrewm@0: 
andrewm@0: 
andrewm@0: 			// update variables for both sensors
andrewm@0: 			s0PrevTouchNum	= s0TouchNum;
andrewm@0: 			s1PrevTouchNum	= s1TouchNum;
andrewm@0: 		}
andrewm@0: 		else
andrewm@0: 			dbox_printf("Come on instrument!\n");	//break
andrewm@0: 
andrewm@0: 		gettimeofday(&start, NULL);
andrewm@0: 	}
andrewm@0: 
andrewm@0: 	dbox_printf("sensor thread ended\n");
andrewm@0: }
andrewm@0: 
andrewm@0: void *keyboardLoop(void *)
andrewm@0: {
andrewm@0: 	if(gVerbose==1)
andrewm@0: 		cout << "_________________Keyboard Control Thread!" << endl;
andrewm@0: 
andrewm@0: 	char keyStroke = '.';
andrewm@0: 	cout << "Press q to quit." << endl;
andrewm@0: 
andrewm@0: 	float speed;
andrewm@0: 
andrewm@0: 	do
andrewm@0: 	{
andrewm@0: 		keyStroke =	getchar();
andrewm@0: 		while(getchar()!='\n'); // to read the first stroke
andrewm@0: 
andrewm@0: 		switch (keyStroke)
andrewm@0: 		{
andrewm@0: 			//----------------------------------------------------------------------------
andrewm@0: 			case 'a':
andrewm@0: 				gOscBanks[gCurrentOscBank]->hopNumTh = 0;
andrewm@0: 				gOscBanks[gCurrentOscBank]->play(1);
andrewm@0: 				//cout << "Note on" << endl;
andrewm@0: 				break;
andrewm@0: 			case 's':
andrewm@0: 				if(gOscBanks[gCurrentOscBank]->state==bank_playing)
andrewm@0: 				{
andrewm@0: 					gOscBanks[gCurrentOscBank]->stop();
andrewm@0: 					//cout << "Note off" << endl;
andrewm@0: 				}
andrewm@0: 				break;
andrewm@0: 			//----------------------------------------------------------------------------
andrewm@0: 			case '[':
andrewm@0: 				gOscBanks[gCurrentOscBank]->freqMovement-=0.05;
andrewm@0: 				if(gOscBanks[gCurrentOscBank]->freqMovement<0)
andrewm@0: 					gOscBanks[gCurrentOscBank]->freqMovement = 0;
andrewm@0: 				//cout << "gOscBanks[gCurrentOscBank]->FreqMov: " << gOscBanks[gCurrentOscBank]->freqMovement << endl;
andrewm@0: 				break;
andrewm@0: 			case ']':
andrewm@0: 				gOscBanks[gCurrentOscBank]->freqMovement+=0.05;
andrewm@0: 				if(gOscBanks[gCurrentOscBank]->freqMovement>1)
andrewm@0: 					gOscBanks[gCurrentOscBank]->freqMovement = 1;
andrewm@0: 				//cout << "gOscBanks[gCurrentOscBank]->FreqMov: " << gOscBanks[gCurrentOscBank]->freqMovement << endl;
andrewm@0: 				break;
andrewm@0: 			//----------------------------------------------------------------------------
andrewm@0: 			case '<':
andrewm@0: 				speed = gOscBanks[gCurrentOscBank]->getSpeed() - 0.1 ;
andrewm@0: 				gOscBanks[gCurrentOscBank]->setSpeed(speed);
andrewm@0: 				dbox_printf("Speed: %f\n", speed);
andrewm@0: 
andrewm@0: 				break;
andrewm@0: 			case '>':
andrewm@0: 				speed = gOscBanks[gCurrentOscBank]->getSpeed() + 0.1 ;
andrewm@0: 				gOscBanks[gCurrentOscBank]->setSpeed(speed);
andrewm@0: 				dbox_printf("Speed: %f\n", speed);
andrewm@0: 				break;
andrewm@0: 			case '0':
andrewm@0: 				speed = 0.1;
andrewm@0: 				gOscBanks[gCurrentOscBank]->setSpeed(speed);
andrewm@0: 				dbox_printf("Speed: %f\n", speed);
andrewm@0: 				break;
andrewm@0: 			case '1':
andrewm@0: 				speed = 0.5;
andrewm@0: 				gOscBanks[gCurrentOscBank]->setSpeed(speed);
andrewm@0: 				dbox_printf("Speed: %f\n", speed);
andrewm@0: 				break;
andrewm@0: 			case '2':
andrewm@0: 				speed = 1;
andrewm@0: 				gOscBanks[gCurrentOscBank]->setSpeed(speed);
andrewm@0: 				dbox_printf("Speed: %f\n", speed);
andrewm@0: 				break;
andrewm@0: 			case '3':
andrewm@0: 				speed = 2;
andrewm@0: 				gOscBanks[gCurrentOscBank]->setSpeed(speed);
andrewm@0: 				dbox_printf("Speed: %f\n", speed);
andrewm@0: 				break;
andrewm@0: 			case '4':
andrewm@0: 				speed = 3;
andrewm@0: 				gOscBanks[gCurrentOscBank]->setSpeed(speed);
andrewm@0: 				dbox_printf("Speed: %f\n", speed);
andrewm@0: 				break;
andrewm@0: 			//----------------------------------------------------------------------------
andrewm@0: 			case 'z':
andrewm@0: 				gOscBanks[gCurrentOscBank]->setJumpHop(0);
andrewm@0: 				break;
andrewm@0: 			case 'x':
andrewm@0: 				gOscBanks[gCurrentOscBank]->setJumpHop(100);
andrewm@0: 				break;
andrewm@0: 			case 'c':
andrewm@0: 				gOscBanks[gCurrentOscBank]->setJumpHop(600);
andrewm@0: 				break;
andrewm@0: 			case 'v':
andrewm@0: 				gOscBanks[gCurrentOscBank]->setJumpHop(1100);
andrewm@0: 				break;
andrewm@0: 			case 'b':
andrewm@0: 				gOscBanks[gCurrentOscBank]->setJumpHop(2000);
andrewm@0: 				break;
andrewm@0: 			case 'n':
andrewm@0: 				gOscBanks[gCurrentOscBank]->setJumpHop(gOscBanks[gCurrentOscBank]->getLastHop());
andrewm@0: 				break;
andrewm@0: 			//----------------------------------------------------------------------------
andrewm@0: 			case 'q':
andrewm@0: 				gShouldStop = true;
andrewm@0: 				break;
andrewm@0: 			case 'o':
andrewm@0: 				gNextOscBank = (gCurrentOscBank + 1) % gOscBanks.size();
andrewm@0: 				break;
andrewm@0: 			default:
andrewm@0: 				break;
andrewm@0: 			//----------------------------------------------------------------------------
andrewm@0: 		}
andrewm@0: 		usleep(1000); /* Wait 1ms to avoid checking too quickly */
andrewm@0: 	}
andrewm@0: 	while (keyStroke!='q');
andrewm@0: 
andrewm@0: 	cout << "keyboard thread ended" << endl;
andrewm@0: 
andrewm@0: 	return (void *)0;
andrewm@0: }