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