changeset 0:307e5fb699fb

First commit.
author Robert Tubb <rt300@eecs.qmul.ac.uk>
date Mon, 19 Nov 2012 12:56:47 +0000
parents
children 23efe1f0cd8a
files 2dvector.h 2dvector.mm eventLogger.h eventLogger.mm grid.cpp grid.h main.mm presetManager.h presetManager.mm testApp.h testApp.mm
diffstat 11 files changed, 1675 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2dvector.h	Mon Nov 19 12:56:47 2012 +0000
@@ -0,0 +1,35 @@
+/*
+ *  2dvector.h
+ *  simplespring
+ *
+ *  Created by Robert Tubb on 01/06/2011.
+ *  Copyright 2011 __MyCompanyName__. All rights reserved.
+ *
+ */
+#ifndef _2DVECTORH
+#define _2DVECTORH
+
+class TwoVector{
+public:
+	double x, y;
+	TwoVector();
+	TwoVector(double ax, double ay);
+
+// public methods	
+	double norm();
+	void setCoord(double ax, double ay);
+	TwoVector minus(TwoVector otherPoint);
+    TwoVector operator-(TwoVector otherPoint);
+    TwoVector operator+(TwoVector otherPoint);
+    
+    TwoVector operator*(TwoVector otherPoint);
+    TwoVector operator*(double scalar); // scalar is right operand
+    
+    //TwoVector operator=(TwoVector otherPoint);
+    
+    double distanceTo(TwoVector otherPoint);
+	
+
+};
+
+#endif // #ifndef _2DVECTORH
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2dvector.mm	Mon Nov 19 12:56:47 2012 +0000
@@ -0,0 +1,79 @@
+/*
+ *  2dvector.cpp
+ *  simplespring
+ *
+ *  Created by Robert Tubb on 01/06/2011.
+ *  Copyright 2011 __MyCompanyName__. All rights reserved.
+ *
+ */
+
+#include "2dvector.h"
+#include <iostream>
+
+TwoVector::TwoVector(){
+	x = 0.0;
+	y = 0.0;
+	//cout << "def constr set vector to zeros" << endl;
+}
+
+TwoVector::TwoVector(double ax, double ay){
+	x = ax;
+	y = ay;
+	//cout << "spec constr set vector to " << ax << "," << ay << endl;
+}
+
+double TwoVector::norm(){
+	double norm;
+	norm = sqrt(x * x + y * y);
+	return norm;
+	
+}
+
+void TwoVector::setCoord(double ax, double ay){
+	x = ax;
+	y = ay;
+
+}
+
+TwoVector TwoVector::minus(TwoVector otherPoint){
+    TwoVector diff;
+    diff.setCoord(x - otherPoint.x, y - otherPoint.y);
+    return diff;
+}
+
+TwoVector TwoVector::operator-(TwoVector otherPoint){
+    TwoVector diff;
+    diff.setCoord(x - otherPoint.x, y - otherPoint.y);
+    return diff;
+}
+
+TwoVector TwoVector::operator*(TwoVector otherPoint){ // if multiplying two vectors - elementwise
+    TwoVector diff;
+    diff.setCoord(x * otherPoint.x, y * otherPoint.y);
+    return diff;
+}
+
+TwoVector TwoVector::operator*(double scalar){ // if multiplying two vectors - elementwise
+    TwoVector diff;
+    diff.setCoord(x * scalar, y * scalar);
+    return diff;
+}
+
+TwoVector TwoVector::operator+(TwoVector otherPoint){
+    TwoVector diff;
+    diff.setCoord(otherPoint.x + x, otherPoint.y + y);
+    return diff;
+}
+/*
+TwoVector TwoVector::operator=(TwoVector otherPoint){
+    TwoVector result;
+    result.setCoord(otherPoint.x, otherPoint.y);
+    return result;
+}
+*/
+double TwoVector::distanceTo(TwoVector otherPoint){
+    TwoVector diff;
+    diff.setCoord(otherPoint.x - x, otherPoint.y - y);
+    return diff.norm();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eventLogger.h	Mon Nov 19 12:56:47 2012 +0000
@@ -0,0 +1,27 @@
+//
+//  eventLogger.h
+//  oscSenderExample
+//
+//  Created by Robert Tubb on 05/11/2012.
+//
+//
+// This class handle everything to do with loggin user actions,
+// uploading logs to server, and storing locally if not uploaded
+
+#ifndef __oscSenderExample__eventLogger__
+#define __oscSenderExample__eventLogger__
+
+#include <iostream>
+
+
+class EventLogger{
+public:
+    // what we need...
+    /*
+     time, type, value
+     */
+    
+};
+
+
+#endif /* defined(__oscSenderExample__eventLogger__) */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eventLogger.mm	Mon Nov 19 12:56:47 2012 +0000
@@ -0,0 +1,9 @@
+//
+//  eventLogger.mm
+//  oscSenderExample
+//
+//  Created by Robert Tubb on 05/11/2012.
+//
+//
+
+#include "eventLogger.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/grid.cpp	Mon Nov 19 12:56:47 2012 +0000
@@ -0,0 +1,793 @@
+//
+//  grid.cpp
+//  oscSenderExample
+//
+//  Created by Robert Tubb on 03/10/2012.
+//
+//
+#include "ofMain.h"
+#include "grid.h"
+//#include "presetManager.h"
+
+#include <sstream>
+
+//extern PresetManager presetManager;
+
+//--------------------------------------------------------------
+Grid::Grid(){
+
+}
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+Grid::~Grid(){
+
+}
+void Grid::init(){
+    maxValue = pow(32.0,7.0)-1;
+    minValue = 60; // number of 1-size divisions at smallest scale
+    maxZoom = false;
+    minZoom = false;
+    paramsPerDim = 5;
+    paramBitDepth = 7;
+    codeLength = pow(2.0,paramsPerDim);
+    
+    pixSize.setCoord(ofGetWidth(), ofGetHeight());
+ 
+    //set scale and position to mid way
+    scale = pow(32.0,6.0);
+    
+
+    size.setCoord(pixSize.x*scale, pixSize.y*scale);
+    centre.setCoord(maxValue/2 , maxValue/2);
+    topLeft.setCoord(centre.x - size.x/2, centre.y - size.y/2);
+    
+    
+    makeCode();
+
+    // set a starting param value, find coord that does it.
+    vector<int> params(paramsPerDim*2);
+    for(int i = 0;i<2*paramsPerDim;i++){
+        midiCC[i] = 64;
+        params[i] = 64;
+    }
+    TwoVector coord = calculateCoordFromParams(params);
+    setCoord(coord);
+    
+    viewWasChanged();
+    
+    
+    
+}
+
+template <typename T> int sgn(T val) {
+    return (T(0) < val) - (val < T(0));
+}
+
+void Grid::makeCode(){
+ 
+    ////////////////////////////////~~~,,,,,,,,.........
+    ////////// gray code generation
+    //////
+    ///
+    // TODO 5bit specific
+    // transition sequence.... what a palaver! only need to do once though.
+    int trans[] = {0,1,2,3,0,4,2,1,0,3,2,1,0,4,2,3,0,1,2,3,0,4,2,1,0,3,2,1,0,4,2,3};
+
+    
+    int code[codeLength][paramsPerDim]; // start with normal array
+    
+   
+    
+    for(int j=0; j<paramsPerDim; j++){
+        code[0][j] = 0;
+    }
+    
+    for(int i=0; i < codeLength-1; i++){  // TODO went off end??
+        transSeq.push_back(trans[i]); // member vector
+        for(int j=0; j<paramsPerDim; j++){
+            
+            if (j == abs(trans[i])){
+                code[i+1][j] = !code[i][j];
+            }else{
+                code[i+1][j] = code[i][j]; 
+            }
+        }
+
+    }
+    
+    for(int i=0; i < codeLength; i++){ // fill vector
+        
+        vcode.push_back(vector<bool>());
+        
+        for(int j=0; j<paramsPerDim; j++){
+            vcode[i].push_back(code[i][j]);
+        }
+    }
+    
+    // now try with iterators to print...
+    vector< vector<bool> >::iterator cit;
+    //vector<bool>::iterator bit;
+    vector<bool>::iterator bit;
+    int i = 0;
+    for(cit=vcode.begin(); cit!=vcode.end() ; cit++){ // fill vector
+        i++;
+        cout << i << " = ";
+        bit = (*cit).begin();
+        for(bit=(*cit).begin(); bit!=(*cit).end() ; bit++){
+            
+            cout  << *bit;
+        }
+        cout << "\n";
+
+    }
+    /*
+    // codeToInt unit test
+    vector<bool> aCode = vcode[12];
+    int result = grayToInt(aCode);
+    cout << "GRAY TO INT : " << result << "\n";
+
+    cout << "-------------------------------\n";
+    
+    // base32toFloat unit test
+
+    vector<int> test32 = coordTobase32(869437.0);
+    double cresult = base32toCoord(test32);
+    cout << "base32toCoord : " << cresult << "\n";
+     
+     cout << "-------------------------------\n";
+    
+    
+    
+    // midiToGray unit test
+
+    vector<vector<bool> > incodes(paramBitDepth, vector<bool>(paramsPerDim));
+    for(int i=0;i<7;i++){
+        incodes[i] = vcode[i+5];
+    }
+
+    vector<int> midiTest;
+    midiTest = grayToMidi(incodes);
+    vector<vector<bool> > outcodes = midiToGray(midiTest);
+    
+    vector< vector<bool> >::iterator cit1;
+    //vector<bool>::iterator bit;
+    vector<bool>::iterator bit1;
+    cout << "midiToGray Unit test\n";
+    for(int i=0;i<paramBitDepth;i++){ // fill vector
+
+        for(int j=0;j<paramsPerDim;j++){
+            
+            cout  << (incodes[i][j] == outcodes[i][j]) << ",";
+        }
+        cout << "\n";
+        
+    }
+     cout << "-------------------------------\n";
+
+    
+    // whole process unit test(?)
+    
+    TwoVector inCoord(888999777,777666555);
+    vector<int> checkParam;
+    checkParam = calculateParamsFromCoord(inCoord);
+    for(int i=0; i<2*paramsPerDim;i++){
+        cout << checkParam[i] << "_";
+    }
+    TwoVector outCoord = calculateCoordFromParams(checkParam);
+    cout << "Unit TEst coord = " << outCoord.x << "," << outCoord.y << "\n";
+*/
+    
+}
+//--------------------------------------------------------------
+void Grid::draw(){  // draw lines
+    // TODO too friggin long
+    
+    //scale++;
+    // nice loopy thing
+    int power = 0;
+   
+    // these get big!
+    double  divsr;
+    double yl,xl;
+    double gridSize = 0;
+
+    double firstLineXPos, lastLineXPos,firstLineYPos, lastLineYPos, remleft, xoffset, yoffset = 0.0;
+    double xstart, xfinish, ystart,yfinish;
+    // these don't
+    int xpos, ypos = 0;
+    
+    float alpha;
+    bool done = false;
+    float markpow = 32.0;  // power that denotes next grid markings
+    int lineWidth = 0;
+    int colCycle = 0;
+    
+    // get all the preset points within this view
+    //presetManager.getPresetsInRange(topLeft, topLeft+size);
+ 
+    // loop thru powers of (base?) to determine which should be shown as grids
+    while (!done){
+        gridSize = pow(markpow,power);
+ 
+        colCycle = power % 7;
+
+        divsr = size.x / gridSize;
+
+        // if (divisor i.e. number of lines is less than 1000
+        if( divsr >= 1 && divsr < 1000){
+
+            // calculate transparency
+            float visCont = log10(divsr); // 0 if only 1 line, 3 if 1000 lines
+            alpha = 90*(3 - visCont);
+            ofSetLineWidth(lineWidth);
+            
+            // cycle colors for different scales
+            if(colCycle == 0){
+                ofSetColor(255,255,255,alpha);
+            }else if(colCycle == 1){
+                ofSetColor(255,0,0,alpha);
+            }else if(colCycle == 2){
+                ofSetColor(0,0,255,alpha);
+            }else if(colCycle == 3){
+                ofSetColor(0,255,0,alpha);
+            }else if(colCycle == 4){
+                ofSetColor(255,0,255,alpha);
+            }else if(colCycle == 5){
+                ofSetColor(0,255,255,alpha);
+            }else if(colCycle == 6){
+                ofSetColor(255,255,0,alpha);
+            }else if(colCycle == 7){
+                ofSetColor(255,255,255,alpha);
+            }else{
+                cout << "err colour messed up\n";
+            }
+            
+            
+            // draw level numbers associated with each color. This would not be true if markpow wasnt 2^d
+            ////////-------/////////
+            /*
+            temp << "THIS LEVEL = " << (int)pow(2.0,power) << "   ";
+            string s = temp.str();
+            ofDrawBitmapString( s, 10, line );
+            line+=30;
+            temp.str("");
+            *////////-------/////////
+            
+            // draw presets at this level
+            // fill in smallest squares if they contain a preset
+            // how to do this efficiently?
+            
+            
+            if(topLeft.x < 0.0){
+                firstLineXPos = 0.0;
+                xoffset = firstLineXPos - topLeft.x;
+                xstart = xoffset/scale;
+            }else{
+                firstLineXPos = topLeft.x;
+                // kinda float version of % operator
+                remleft = ceil(firstLineXPos/gridSize);
+                xoffset = (remleft * gridSize) - topLeft.x;
+                xstart = 0;
+            }
+            if(topLeft.x + size.x > maxValue){
+                lastLineXPos = maxValue+1 - topLeft.x;
+                
+                
+            }else{
+                lastLineXPos = size.x;
+                
+            }
+            xfinish = lastLineXPos/scale;
+            
+            //////////------------------------
+            // same for y
+            
+            if(topLeft.y < 0.0){
+                firstLineYPos = 0.0;
+                yoffset = firstLineYPos - topLeft.y;
+                ystart = yoffset/scale;
+            }else{
+                firstLineYPos = topLeft.y;
+                // kinda float version of % operator
+                remleft = ceil(firstLineYPos/gridSize);
+                yoffset = (remleft * gridSize) - topLeft.y;
+                ystart = 0;
+            }
+            if(topLeft.y + size.y > maxValue){
+                lastLineYPos = maxValue+1 - topLeft.y;
+               
+            }else{
+                lastLineYPos = size.y;
+                
+            }
+            yfinish = lastLineYPos/scale;
+            // -------------------------------------------
+                // now draw
+            for(xl = xoffset; xl <= (lastLineXPos); xl+= gridSize){
+
+                xpos = xl/scale;
+                ofLine(xpos, ystart, xpos, yfinish);
+            
+            }
+
+            for(yl = yoffset; yl <= (lastLineYPos); yl+= gridSize){
+                
+                ypos = yl/scale;
+                ofLine(xstart, ypos, xfinish, ypos);
+            }
+            
+            
+        }else if (divsr < 1){
+            // ignore...
+            done = true;
+        }
+        
+        power++;
+    }
+    //cout << "draw done" << "\n";
+    //displayInfo();
+
+    ////////-------/////////
+    
+    ////////-------/////////
+    
+    // draw centre cross hairs
+    ofSetColor(255, 0, 0);
+    ofNoFill();
+    ofLine(pixSize.x/2-20, pixSize.y/2, pixSize.x/2+20, pixSize.y/2);
+	ofLine(pixSize.x/2, pixSize.y/2-20, pixSize.x/2, pixSize.y/2+20);
+    ofEllipse(pixSize.x/2, pixSize.y/2, 20, 20);
+    ofFill();
+    ////////-------////////
+    /*
+    ostringstream temp;
+    temp << "Centre x = " << centre.x << "\n      y = " << centre.y << "   ";
+    string s = temp.str();
+    ofDrawBitmapString( s, pixSize.x/2+10, pixSize.y/2+10 );
+    */
+}
+//-----------------------------------------------------------------------
+void Grid::displayInfo(){
+    
+    // display some "useful information"
+    
+    ofSetColor(255,255,255,255);
+    
+    ostringstream temp;
+    int line = 10; // text output pos
+    
+    
+    ////////-------/////////
+    temp << "scale = " << scale << "   ";
+    string s = temp.str();
+	ofDrawBitmapString( s, 10, line );
+    line+=30;
+    temp.str("");
+    ////////-------/////////
+    temp << "Top Left = " << topLeft.x << "," << topLeft.y << "   ";
+    s = temp.str();
+    ofDrawBitmapString( s, 10, line );
+    line+=60;
+    temp.str("");
+    
+    ////////-------/////////
+    temp << "View Size = " << size.x << "," << size.y << "   ";
+    s = temp.str();
+    ofDrawBitmapString( s, 10, line );
+    line+=60;
+    temp.str("");
+    
+    ////////-------/////////
+    
+    for(int i=0;i<10;i++){ // TODO 5bit specific
+        temp << midiCC[i] << " ";
+        s = temp.str();
+        ofDrawBitmapString( s, 10, line );
+        line+=20;
+        temp.str("");
+    }
+}
+ //--------------------------------------------------------------
+void Grid::update(){  // ?
+    // "update" bit of a crap name - all we do here is calculate the dimension params from the x,y position
+
+    vector<int> params = calculateParamsFromCoord(centre);
+    for(int i = 0;i<2*paramsPerDim;i++){
+        midiCC[i] = params[i];
+    }
+
+}
+//--------------------------------------------------------------
+void Grid::move(int moveX, int moveY){
+    // numspacing, pixelspacing stay the same
+    
+    // convert pixels to surf units
+    TwoVector moveS;
+    moveS.setCoord(moveX * scale, moveY * scale);
+    
+    topLeft = topLeft - moveS;  // - because moving to the right means taking away from offset
+    centre = centre - moveS;
+
+    viewWasChanged();
+}
+//--------------------------------------------------------------
+void Grid::zoom(float factor){
+    if(maxZoom && factor > 1.0){
+        return;
+        
+    }
+    if(factor < 1.0){
+        maxZoom = false;
+    }
+    if(minZoom && factor < 1.0){
+        return;
+        
+    }
+    if(factor > 1.0){
+        minZoom = false;
+    }
+    scale = scale*factor; // simple eh?
+
+    // update view size using centre
+    // and scale...
+    size.x = size.x*factor; // zooming in, size gets SMALLER (view less)
+    size.y = size.y*factor;
+
+    viewWasChanged();
+
+}
+//--------------------------------------------------------------
+void Grid::viewWasChanged(){
+    checkLimits();
+    // and calculate new params?
+    
+
+}
+
+//--------------------------------------------------------------
+void Grid::checkLimits(){
+    // check for maximum zoom level
+    // TODO: DODGY
+
+    if(size.x > maxValue*2.0){
+        cout << "maxZoom\n";
+        maxZoom = true;
+        size.x = maxValue*2.0;
+        // need to also set y size back to
+    }
+    if(size.y > maxValue*2.0){
+        cout << "maxZoom\n";
+        maxZoom = true;
+        size.y = maxValue*2.0;
+    }
+    
+    if(size.x < minValue){
+        cout << "min Zoom\n";
+        minZoom = true;
+        size.x = minValue;
+        // need to also set y size back to
+    }
+    if(size.y < minValue){
+        minZoom = true;
+        cout << "min Zoom\n";
+        size.y = minValue;
+    }
+    
+    scale = size.x/pixSize.x;
+    size.y = scale * pixSize.y;
+    
+    topLeft.x = centre.x - size.x/2;
+    topLeft.y = centre.y - size.y/2;
+    // check for negatives
+    
+    // allow centre to be at limits
+    if((topLeft.x + size.x*0.5) < 0.0){
+        cout << "left Wall\n";
+        topLeft.x = 0.0 - size.x*0.5;
+        centre.x = 0.0;
+    }
+
+    if(topLeft.y + size.y*0.5 < 0.0) {
+        cout << "top Wall\n";
+        topLeft.y = 0.0 - size.y*0.5;
+        centre.y = 0.0;
+    }
+    
+   // does topleft refer to lines or view?
+    
+        // check max 
+    if(topLeft.x + size.x/2 > maxValue){
+        cout << "right Wall\n";
+        topLeft.x = maxValue - size.x/2;
+        centre.x = maxValue;
+    }
+    if(topLeft.y + size.y/2 > maxValue) {
+        cout << "bottom Wall\n";
+        topLeft.y = maxValue - size.y/2;
+        centre.y = maxValue;
+    }
+
+}
+//--------------------------------------------------------------
+void Grid::checkConsistencies(){
+    // debug function to check all the parameters are consistent maybe
+
+}
+//--------------------------------------------------------------
+void Grid::setCoord(TwoVector coord){
+    
+    centre = coord;
+    viewWasChanged();
+}
+//--------------------------------------------------------------
+TwoVector Grid::getCoord(){
+    
+    return centre;
+}
+//--------------------------------------------------------------
+vector<int> Grid::getParams(){
+    // return a vector with midiCCs in
+    // should we store params somewhere and use this as a low computation get ?
+    vector<int> params(2*paramsPerDim,0);
+    //
+    for(int i = 0;i<2*paramsPerDim;i++){
+        params[i] = midiCC[i];
+    }
+    return params;
+}
+//--------------------------------------------------------------
+void Grid::setParams(vector<int> params){
+    // input midiCCs, and go to the appropriate coordinate
+
+    for(int i = 0;i<2*paramsPerDim;i++){
+        midiCC[i] = 64;
+    }
+    TwoVector coord = calculateCoordFromParams(params);
+    setCoord(coord);
+    
+    viewWasChanged();
+
+}
+//--------------------------------------------------------------
+TwoVector Grid::calculateCoordFromParams(vector<int> params){
+
+    vector<int> ccValueX(paramsPerDim);
+    vector<int> ccValueY(paramsPerDim);
+    for(int i=0;i<paramsPerDim;i++){
+        ccValueX[i] = params[i];
+        ccValueY[i] = params[i+paramsPerDim];
+    }
+    vector<vector <bool> > codesX = midiToGray(ccValueX);
+    vector<vector <bool> > codesY = midiToGray(ccValueY);
+
+    vector<int> base32X = codesToBase32(codesX);
+    vector<int> base32Y = codesToBase32(codesY);
+    
+    TwoVector result;
+    result.x = base32toCoord(base32X);
+    result.y = base32toCoord(base32Y);
+    return result;
+}
+
+//--------------------------------------------------------------
+vector<int> Grid::calculateParamsFromCoord(TwoVector coord){
+    // some arrays in reverse order of power from normal numbers!   1,2,4,
+    
+    // centre to base 32
+    if (coord.x > maxValue || coord.y > maxValue){
+        cout << "calculateParams Error: centre double value is too large" << "\n";
+        vector<int> empty;
+        return empty;
+    }
+
+    //--------------------------
+    // X
+    vector<int> base32x = coordTobase32(coord.x); // 7 numbers from 0 to 31
+    vector<vector <bool> > grayCodesX;
+    
+    int size = base32x.size();
+    for(int i=0;i<size;i++){
+        grayCodesX.push_back(intToGray(base32x[i]));
+    }
+    
+    vector<int> result;
+    result = grayToMidi(grayCodesX);
+    //--------------------------
+    // AND FOR Y
+    vector<int> base32y = coordTobase32(coord.y);
+    vector<vector <bool> > grayCodesY;
+    
+    size = base32y.size();
+    for(int i=0;i<size;i++){
+        grayCodesY.push_back(intToGray(base32y[i]));
+    }
+
+    vector<int> resultY;
+    resultY = grayToMidi(grayCodesY);
+    
+    // concatenate
+    result.insert( result.end(), resultY.begin(), resultY.end() );
+    return result;
+}
+//-------------------------------------------------------------------
+
+// for 1 dimension!!! i.e. call this twice
+vector<int> Grid::grayToMidi(vector<vector <bool> > grayCodes){
+
+    // gray to midi CC values
+    // loop thru the scales to build up a CC number per dimension
+    int midiCCresult[paramsPerDim]; // TODO dims specific
+    for(int i=0;i<paramsPerDim;i++){
+        midiCCresult[i] = 0;
+    }
+    
+    int bin = 1;
+    bin = bin << grayCodes.size()-1;
+    
+    int midP = 0;
+    
+    vector<vector <bool> >::iterator piter = grayCodes.begin();
+    for(;piter < grayCodes.end();piter++){ // each lesser power of 2
+        midP = 0; // reset
+        vector<bool>::iterator diter = (*piter).begin();
+        for(; diter <= (*piter).end();diter++){ // each one is different dimension
+            int ig = int(*diter); // convert binary to int
+            //cout << "ig: " << ig;
+            midiCCresult[midP] += ig*bin; // mult by power of two
+            midP++;
+        }
+        bin = bin >> 1; // next power of 2 down
+        
+    }
+    
+    // put in vector
+    vector<int> result;
+    for(int i=0;i<paramsPerDim;i++){
+        result.push_back(midiCCresult[i]);
+    }
+    
+    return result;
+    
+    
+}
+
+
+//--------------------------------------------------------------
+
+vector<bool> Grid::intToGray(int num, int dimToTravel){
+
+    // dimToTravel - this is the dimension that we want the walk to traverse, i.e. the last non zero digit of the code
+    // so swap it for 3 to produce correct orientation
+
+    // just use look up table... until it gets huuuge.
+    vector<bool> grayCode = vcode[num];
+    grayCode[3] = vcode[num][dimToTravel];
+    grayCode[dimToTravel] = vcode[num][3];
+    return grayCode;
+}
+//--------------------------------------------------------------
+vector<int> Grid::walkDiff(vector<bool> left, vector<bool> right){
+    // horrible
+    vector<int> result(2,0);
+
+    int size = left.size();
+    for(int i = 0; i < size; i++){
+        if(left[i] && !right[i]){  // 1 - 0
+            // dim
+            result[0] = i;
+            result[1] = 1;
+        }else if(!left[i] && right[i]){ // 0 - 1
+            result[0] = i;
+            result[1] = -1;
+        }else{ // equal do nothing
+            
+            
+        }
+    }
+    
+    return result;
+}
+
+//--------------------------------------------------------------
+/*
+breaks down float into a base 32 number (2^D)
+each of these is converted to gray code
+this is then converted to 10 parameters, where each 32-digit becomes separate power of 2
+ so "zoom" grid 32-patches are converted to 2-scales. 1,2,4,8,16,32,64,(128?) biggest number is 32^7
+*/
+vector<int> Grid::coordTobase32(double value){
+    //double base = 32.0;
+    if(value < 0.0){
+        cout << "coordTobase32 error: input value is negative\n";
+        value = 0.0;
+    }else if(value > maxValue){
+        cout << "coordTobase32 error: input value too big!\n";
+    }
+    double rem, divdr = 0.0;
+    int digit32;
+
+    // what power of 32 to start at?
+    int maxpow = 7; // midi cc specific
+    vector<int> result; 
+
+    rem = value;
+    for(;maxpow >=0;maxpow--){
+        // repeatedly get digit and remainder. This is exactly what we're doing in draw !?... could put all this in one place?
+        divdr = pow((double)codeLength,(double)maxpow);
+        digit32 = floor(rem/divdr);
+        rem = rem - digit32*divdr; 
+        result.push_back(digit32);  // array, biggest index is smallest power
+    }
+    // at this point rem should be fractional... use for interp?
+
+    return result;
+}
+//--------------------------------------------------------------
+
+// WHY HERE XCODE?
+vector<int> Grid::codesToBase32(vector<vector<bool> > inCodes){
+    vector<int> result;
+    for(int i=0;i<paramBitDepth;i++){
+        result.push_back(grayToInt(inCodes[i]));
+    }
+    return result;
+}
+//--------------------------------------------------------------
+
+int Grid::grayToInt(vector<bool> incode){
+    // look for match in table
+    
+    int s = vcode.size();
+    
+    for(int i=0; i<s;i++){ // fill vector
+        if(vcode[i] == incode){
+            return i;
+        }
+        
+    }
+    cout << "grayToInt error: no matching code found!";
+    return -1;
+}
+//--------------------------------------------------------------
+double Grid::base32toCoord(vector<int> base32Digs){
+    // build up the big float from a base 32 number
+    double result = 0.0;
+   
+    // what power of 32 to start at?
+    int mpow = base32Digs.size() - 1; // should be 7...
+    
+    for(int p=0;p<=mpow;p++){ // biggest index is smallest power
+        result += ((double)base32Digs[p]) * pow(32.0, (double)mpow-p);
+  
+    }
+    return result;
+    
+}
+//--------------------------------------------------------------
+// for 1 dimension - takes in 5 cc params and outputs  7 codes 
+vector<vector <bool> > Grid::midiToGray(vector<int> ccValue){
+    int pow2 = 1 << (paramBitDepth-1);
+
+    vector<int> aCode(paramsPerDim);
+    vector<vector<int> > theXCodes(paramBitDepth,aCode);
+    
+    // build up binary gray code representations from the bits of the midi ccs
+
+    vector<vector<bool> > theCodes(paramBitDepth, vector<bool>(paramsPerDim));
+
+    // x
+    for(int p=0;p<paramBitDepth;p++){
+
+        for(int i=0;i<paramsPerDim;i++){
+            
+            bool bit = (pow2 == (ccValue[i] & pow2));
+            theCodes[p][i] = bit;
+        }
+        pow2 = pow2 >> 1;
+        
+    }
+    return theCodes;
+}
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+//--------------------------------------------------------------
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/grid.h	Mon Nov 19 12:56:47 2012 +0000
@@ -0,0 +1,80 @@
+//
+//  grid.h
+//  oscSenderExample
+//
+//  Created by Robert Tubb on 03/10/2012.
+//
+//  This is the view onto the zoomable movable grid
+
+#ifndef __oscSenderExample__grid__
+#define __oscSenderExample__grid__
+
+#include <iostream>
+#include "2dvector.h"
+using namespace std;
+
+class Grid {
+private:
+    double scale;        // surface units per pixel
+
+    double maxValue;    // width of entire space
+    double minValue;    // smallest zoom
+    TwoVector topLeft; // top left corner of view, surface coords
+    TwoVector bottomRight;
+    TwoVector size;     // size of view, surface coords
+    TwoVector pixSize; // size of view pixels (ie screen size!)
+    TwoVector centre;
+    bool maxZoom, minZoom;
+    int cubeWidth;    // side of hypercube. 2 for binary coding.
+    int paramsPerDim; // no of parameters per dimension (
+    int codeLength; // the 1d size of the code, determines max extent of single tile, related to params per dim
+    int paramBitDepth; // number of bits for the parameter control data - i.e. always 7 for midi CC
+    vector< vector<bool> > vcode; //
+    vector<int> icode;
+    vector<int> transSeq;
+    int midiCC[10]; // the actual params SHOULD BE INITED FROM 2*paramsPerDim
+    
+// private functions
+    
+    void makeCode();
+    void checkLimits();
+    void viewWasChanged();
+    void checkConsistencies();
+    
+    vector<int> calculateParamsFromCoord(TwoVector coord);
+    TwoVector calculateCoordFromParams(vector<int> params);
+    
+    vector<bool> intToGray(int num, int dimToTravel=3);
+    vector<int> coordTobase32(double coord);
+    vector<int> grayToMidi(vector<vector <bool> > grayCodes);
+    
+    // the inverse stuff
+    int grayToInt(vector<bool>);
+    double base32toCoord(vector<int>);
+    vector<vector <bool> > midiToGray(vector<int>);
+    vector<int> codesToBase32(vector<vector<bool> >);
+    
+    vector<int> walkDiff(vector<bool> left, vector<bool> right); // not used... not worth it!
+    
+    void displayInfo();
+    
+    void setCoord(TwoVector coord);
+public:
+    Grid();
+    ~Grid();
+    void init();
+    void move(int moveX, int moveY); // shift view by pixels
+    void zoom(float factor);
+    
+    void draw();    // draw lines
+    void update(); // change according to zoom
+    
+    vector<int> getParams();
+    TwoVector getCoord();
+    // the inverse stuff
+    void setParams(vector<int>);
+
+    
+};
+
+#endif /* defined(__oscSenderExample__grid__) */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.mm	Mon Nov 19 12:56:47 2012 +0000
@@ -0,0 +1,9 @@
+#include "ofMain.h"
+#include "testApp.h"
+
+Grid theGridView; // global because it saves PAIN
+
+int main(){
+	ofSetupOpenGL(1024,768, OF_FULLSCREEN);			// <-------- setup the GL context
+	ofRunApp(new testApp);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/presetManager.h	Mon Nov 19 12:56:47 2012 +0000
@@ -0,0 +1,53 @@
+//
+//  presetManager.h
+//  oscSenderExample
+//
+//  Created by Robert Tubb on 07/11/2012.
+//
+//
+
+#ifndef __oscSenderExample__presetManager__
+#define __oscSenderExample__presetManager__
+
+#include <iostream>
+#include "ofMain.h"
+#include "ofxiPhone.h"
+#include "ofxiPhoneExtras.h"
+#include "2dvector.h"
+
+//---------------------------------------------------------------------------
+class Preset{
+
+public:
+    int presetID;
+    string name;
+    TwoVector coordinates;
+    Preset(TwoVector acoord, string aname,int aID){
+        coordinates = acoord;
+        name = aname;
+        presetID = aID;
+        
+    };
+};
+//---------------------------------------------------------------------------
+class PresetManager{
+public:
+    int nextID;
+    
+    // names values
+    // check if already there
+    // find and return all(?) presets within a certain coordinate range
+    vector<Preset *> thePresets; // we want vector ? or list? pointers using new?
+    
+    int addPreset(TwoVector coord, string name); // returns id or negative error number
+    TwoVector recallPreset(int presetID); // by name ? id?
+    TwoVector recallPreset(string name); // by name ? id?
+    vector<TwoVector > getPresetsInRange(TwoVector min, TwoVector max);
+    
+    void startupLoadAll();  // get stuff from XML
+    void exitAndSaveAll();  // save to XML, delete presets array (?)
+    
+    PresetManager();
+};
+
+#endif /* defined(__oscSenderExample__presetManager__) */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/presetManager.mm	Mon Nov 19 12:56:47 2012 +0000
@@ -0,0 +1,61 @@
+//
+//  presetManager.mm
+//  oscSenderExample
+//
+//  Created by Robert Tubb on 07/11/2012.
+//
+//
+
+#include "presetManager.h"
+
+//---------------------------------------------------------------------------
+
+PresetManager presetManager;
+//---------------------------------------------------------------------------
+
+
+PresetManager::PresetManager(){
+    nextID = 0;
+    
+}
+//---------------------------------------------------------------------------
+
+int PresetManager::addPreset(TwoVector coord, string name){
+    // check for same name
+    vector<Preset *>::iterator iter;
+    for(iter = thePresets.begin(); iter < thePresets.end(); iter++){
+        if ((*iter)->name == name){
+            cout << " Preset by that name exists\n";
+            
+            // use exceptions!
+            return -1;
+        }
+    }
+    if(name == ""){
+        cout << "Please name preset\n";
+        return -2;
+        
+    }
+    // check for same coords (!?!)
+    thePresets.push_back(new Preset(coord, name,nextID));
+    
+    // if ok
+    return nextID++;
+}
+//---------------------------------------------------------------------------
+vector<TwoVector > getPresetsInRange(TwoVector min, TwoVector max){
+    //return all the coordinates. oh and names (displayed at certain scales?).
+}
+//---------------------------------------------------------------------------
+void startupLoadAll(){
+  // get stuff from XML  
+}
+//---------------------------------------------------------------------------
+void exitAndSaveAll(){
+    
+}
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testApp.h	Mon Nov 19 12:56:47 2012 +0000
@@ -0,0 +1,84 @@
+#pragma once
+
+#include "ofMain.h"
+#include "ofxiPhone.h"
+#include "ofxiPhoneExtras.h"
+#include "ofxOsc.h"
+#include "grid.h"
+#include "2dvector.h"
+#include "ofxUI.h"
+#include "eventLogger.h"
+#define HOST "169.254.1.1"
+#define PORT 12345
+
+class testApp : public ofxiPhoneApp {
+
+	public:
+    
+    
+    int prevTouchX;
+    int prevTouchY;
+    double prevDist;
+    // not many so dont bother with vectors/arrays?
+    TwoVector touch0;
+    TwoVector touch1;
+    TwoVector prevTouch0;
+    TwoVector prevTouch1;
+    
+    bool xLocked, yLocked;
+    
+    
+    TwoVector moveVel; // velocity at which we were moving the grid
+    
+    vector <ofxUISlider *> sliders;
+    
+    double slowFactor;
+    double zoomVel; // do the same
+     double prevZoom, prevZoom2;
+     TwoVector prevMove, prevMove2;
+    
+    vector<int> sliderVals;
+    
+    int numActiveTouches;
+    
+    ofxiPhoneKeyboard * keyboard;
+    //
+    
+		void setup();
+		void update();
+		void draw();
+		void exit();
+		
+		void touchDown(ofTouchEventArgs &touch);
+		void touchMoved(ofTouchEventArgs &touch);
+		void touchUp(ofTouchEventArgs &touch);
+		void touchDoubleTap(ofTouchEventArgs &touch);
+		void touchCancelled(ofTouchEventArgs &touch);
+    
+    vector<float> vectorFilter(vector<float> newVec);
+
+		void lostFocus();
+		void gotFocus();
+		void gotMemoryWarning();
+		void deviceOrientationChanged(int newOrientation);
+        
+		ofxOscSender sender;
+    void sendOSCParams();
+    
+    // stardard GUI - knbs and sliders - hides zoomer
+    bool standardGUIShowing;
+    void standardGUIEvent(ofxUIEventArgs &e);
+    void setupStandardGui();
+    ofxUICanvas *standardGUI;
+    
+    // zoom gui - the swap view button and save preset button
+    void zoomGUIEvent(ofxUIEventArgs &e);
+    void setupZoomGui();
+    
+    void updateSliderValue(int which, float value);
+    void setGUISliders(vector<int> vals);
+    
+    ofxUICanvas *zoomGUI;
+    
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testApp.mm	Mon Nov 19 12:56:47 2012 +0000
@@ -0,0 +1,445 @@
+#include "testApp.h"
+#include "grid.h"
+#include "presetManager.h"
+
+extern Grid theGridView;
+extern PresetManager presetManager;
+//--------------------------------------------------------------
+void testApp::setup(){
+	ofSetOrientation(OF_ORIENTATION_90_LEFT);
+
+	ofBackground( 0, 0, 0 );
+    ofEnableAlphaBlending();
+
+	// open an outgoing connection to HOST:PORT
+	sender.setup( HOST, PORT );
+    ofSetFrameRate(40);
+    // reciever
+    
+    
+    prevTouchX = 0;
+    prevTouchY = 0;
+    
+    xLocked = false;
+    yLocked = false;
+    
+    numActiveTouches = 0;
+    touch0.setCoord(1,2);
+    touch1.setCoord(10,20);
+    prevTouch0.setCoord(1,2);
+    prevTouch1.setCoord(10,20);
+    prevDist = 10;
+    
+    theGridView.init();
+
+    slowFactor = 0.97;
+    
+    setupStandardGui();
+    standardGUIShowing = false;
+    standardGUI->setVisible(standardGUIShowing);
+    
+    setupZoomGui();
+    zoomGUI->setVisible(!standardGUIShowing);
+    
+    // initial slider vals
+    for(int i=0; i<10;i++){
+        sliderVals.push_back(64);
+    }
+    
+    keyboard = new ofxiPhoneKeyboard(500,380,320,32);
+	keyboard->setVisible(false);
+	keyboard->setBgColor(255, 255, 255, 255);
+	keyboard->setFontColor(0,0,0, 255);
+	keyboard->setFontSize(26);
+    
+    ofxiPhoneSetOrientation( OF_ORIENTATION_90_RIGHT );
+    
+}
+//--------------------------------------------------------------
+void testApp::setupZoomGui(){
+    zoomGUI = new ofxUICanvas(ofGetWidth()-200,0,190,125);
+    zoomGUI->setTheme(OFX_UI_THEME_HIPSTER);
+    
+    ofxUIWidget *bwidge = zoomGUI->addLabelToggle("SWITCH VIEW", false);
+    
+    zoomGUI->addLabelButton("SAVE PRESET", false);
+    
+    zoomGUI->addLabelToggle("LOCK SEQUENCE (X)", false);
+    zoomGUI->addLabelToggle("LOCK SYNTH (Y)", false);
+    
+    ofAddListener(zoomGUI->newGUIEvent, this, &testApp::zoomGUIEvent);
+}
+//--------------------------------------------------------------
+void testApp::zoomGUIEvent(ofxUIEventArgs &e){
+
+    if(e.widget->getName() == "SWITCH VIEW")
+    {
+        cout << "change VIEW\n";
+
+        standardGUI->setVisible(!standardGUIShowing);
+        standardGUIShowing = !standardGUIShowing;
+        if(standardGUIShowing){
+            // set the slider values to stuff got from zoomer
+            sliderVals = theGridView.getParams();
+            setGUISliders(sliderVals);
+        }
+
+    }else if(e.widget->getName() == "SAVE PRESET")
+    {
+        cout << "SAVE PRESET\n";
+        // uh...
+        // TwoVector preset = theGridView.getCoord();
+        // presetManager.savePreset(preset);
+        // just coordinate or all the dims?
+        TwoVector preset = theGridView.getCoord();
+        
+        if(!keyboard->isKeyboardShowing()){
+			keyboard->openKeyboard();
+			keyboard->setVisible(true);
+		} else{
+			keyboard->setVisible(false);
+		}
+        // set some kind of modal dialog thing to stop other stuff going on...
+        // this wont work
+        presetManager.addPreset(preset,keyboard->getText());
+    }else if(e.widget->getName() == "LOCK SEQUENCE (X)")
+    {
+        cout << "LOCK SEQUENCE (X)\n";
+        // lock
+        xLocked = !xLocked;
+    }else if(e.widget->getName() == "LOCK SYNTH (Y)")
+    {
+        cout << "LOCK SYNTH (Y)\n";
+        // lock
+        
+        yLocked = !yLocked;
+    }else{
+        cout << "GUI error :  unknown event recieved\n";
+    }
+    
+}
+//--------------------------------------------------------------
+void testApp::setupStandardGui(){
+    float xInit = OFX_UI_GLOBAL_WIDGET_SPACING;
+    float length = 256-xInit*2;
+    
+    
+    float dim = 42;
+    
+    // LEFT GUI
+    standardGUI = new ofxUICanvas(0,0,length+90,ofGetHeight()-90);
+    
+    
+    
+    // Uh.. loop this
+    for(int i = 1; i<=10;i++){
+        stringstream ss;
+        ss << "P" << i;
+        ofxUISlider *slider;
+        slider = (ofxUISlider *)standardGUI->addWidgetDown(new ofxUISlider(length,dim,0.0,127,64,ss.str()));
+        slider->setDrawPadding(true);
+        slider->setColorFill(ofColor(0,0,255));
+        slider->setColorFillHighlight(ofColor(0,0,255));
+        sliders.push_back(slider);
+    }
+    
+    ofAddListener(standardGUI->newGUIEvent, this, &testApp::standardGUIEvent);
+    standardGUI->loadSettings(ofxiPhoneGetDocumentsDirectory() + "guiSettings.xml");
+    
+}
+//--------------------------------------------------------------
+void testApp::standardGUIEvent(ofxUIEventArgs &e){
+    if(!standardGUIShowing){
+        cout << "GUI ERROR";
+        return;
+    }
+    // "normal" parameter changes
+    for(int i = 1; i<=10;i++){
+        stringstream ss;
+        ss << "P" << i;
+        string p = ss.str();
+        
+        if(e.widget->getName() == p)
+        {
+            //cout << "param change: " << p;
+            ofxUISlider *slider = (ofxUISlider *) e.widget;
+            updateSliderValue(i-1,slider->getScaledValue()); // internal array 0 indexed
+            
+        }
+    }
+    
+    // TODO reflect these changes in zoomer view? Or only when switching?
+    
+}
+//--------------------------------------------------------------
+void testApp::updateSliderValue(int which, float value){
+    sliderVals[which] = (int)value;
+    theGridView.setParams(sliderVals);
+}
+//--------------------------------------------------------------
+void testApp::setGUISliders(vector<int> vals){
+    for(int i = 0; i<10;i++){
+        // uh shit need to have reference to this lot
+        sliders[i]->setValue(vals[i]);
+    }
+}
+//--------------------------------------------------------------
+void testApp::update(){
+	//we do a heartbeat on iOS as the phone will shut down the network connection to save power
+	//this keeps the network alive as it thinks it is being used.
+
+    
+	if( ofGetFrameNum() % 120 == 0 ){
+		ofxOscMessage m;
+		m.setAddress( "/misc/heartbeat" );
+		m.addIntArg( ofGetFrameNum() );
+		sender.sendMessage( m );
+	}
+    
+    // continiue to move at velocity
+    if (numActiveTouches == 0 && moveVel.norm() > 0.01){
+        theGridView.move(moveVel.x,moveVel.y);
+        moveVel = moveVel*slowFactor;
+    }
+    // continiue to zoom at velocity
+    if (numActiveTouches < 2 && abs(zoomVel)>0.001){
+        theGridView.zoom(zoomVel + 1.0); // +1 because zoomVel factor is + or - , wheras zoom is a multiplier near 1 
+        zoomVel = zoomVel*slowFactor;
+    }
+    
+    // we need this?
+    theGridView.update();
+    vector<int> params = theGridView.getParams(); // FILTER HERE? NEED FLOATS...
+    setGUISliders(params);
+    // sendOSCParams();
+    
+}
+//--------------------------------------------------------------
+void testApp::sendOSCParams(){
+    
+    vector<int> params = theGridView.getParams(); // FILTER HERE? NEED FLOATS...
+    vector<int>::iterator iter = params.begin();
+    
+    ofxOscMessage m;
+    m.setAddress( "p" );
+    
+    for(;iter < params.end();iter++){
+        
+        m.addFloatArg( *iter );
+        
+    }
+    sender.sendMessage( m );
+}
+//--------------------------------------------------------------
+void testApp::draw(){
+
+    if (standardGUIShowing){
+        ofSetColor(57, 57, 57,200);
+        ofRect(0,0,ofGetWidth(),ofGetHeight());
+    }
+    theGridView.draw();
+    
+    ofSetColor(20, 160, 240, 255);
+	ofDrawBitmapString("text entered = "+  keyboard->getText() , 2, 70);
+}
+
+//--------------------------------------------------------------
+void testApp::exit(){
+    delete standardGUI;
+    delete zoomGUI;
+}
+
+//--------------------------------------------------------------
+void testApp::touchDown(ofTouchEventArgs &touch){
+    if(standardGUIShowing){
+        // check if in GUI area
+        if(touch.x < 256) return;
+    }
+    
+    numActiveTouches++;
+    // absolute position doesn't matter
+    // which one?
+    if(touch.id == 0){
+        touch0.setCoord(touch.x,touch.y);
+        prevTouch0 = touch0;
+    }else if(touch.id == 1){
+        
+        touch1.setCoord(touch.x,touch.y);
+        prevTouch1 = touch1;
+        
+    }
+    if(numActiveTouches == 1){
+        moveVel.setCoord(0.0, 0.0);
+        prevMove.setCoord(0.0, 0.0);
+        prevMove2.setCoord(0.0, 0.0);
+    }else if(numActiveTouches == 2){
+        zoomVel = 0.0;
+        prevZoom = 0.0;
+        prevZoom2 = 0.0;
+        double dist = touch1.distanceTo(touch0);
+        prevDist = dist;
+    }
+
+}
+
+//--------------------------------------------------------------
+void testApp::touchMoved(ofTouchEventArgs &touch){
+    if(standardGUIShowing){
+        // check if in GUI area
+        if(touch.x < 256) return;
+    }
+
+    //
+    // which one?
+    if(touch.id == 0){
+        touch0.setCoord(touch.x,touch.y);
+        
+    }else if(touch.id == 1){
+        
+        touch1.setCoord(touch.x,touch.y);
+    }
+
+
+    //cout << "touch id  " << touch.id << "\n";
+    //cout << "active touches  " << numActiveTouches << "\n";
+    
+   
+    if(numActiveTouches == 1){
+        // TODO: when num touches goes down to 1 after zoom prevTouch can be hugely different!
+        
+        TwoVector move = touch0 - prevTouch0;
+        moveVel = move*0.3 + prevMove*0.34 + prevMove2*0.38; // broke?
+        prevMove2 = prevMove;
+        prevMove = move;
+        
+        theGridView.move(move.x,move.y);
+
+
+        
+    }else if(numActiveTouches == 2){
+        // work out change in difference
+        double dist = touch1.distanceTo(touch0);
+        double zoomFactor = prevDist/dist;
+        
+        cout << "Zoom: " << zoomFactor << "\n";
+        //TODO check for sensible maximums, e.g. spurious touch data
+        if(zoomFactor > 2.0 || zoomFactor < 0.5){
+            cout << "Zoom too much!!!!" << zoomFactor;
+            zoomFactor = 1.0;
+        }
+        
+        zoomVel = (zoomFactor-1)*0.3 + prevZoom*0.34 + prevZoom2*0.38;
+        prevZoom2 = prevZoom;
+        prevZoom = (zoomFactor-1);
+        
+        theGridView.zoom(zoomFactor);
+        
+        prevDist = dist;
+        // TODO: when num touches goes down to 1 after zoom prevTouch can be hugely different!
+        // also if try to move with other finger after zoom , this is touch1 :(
+        // prevTouch0 = ???
+        
+    }
+    prevTouch0 = touch0;
+   
+    
+}
+
+//--------------------------------------------------------------
+void testApp::touchUp(ofTouchEventArgs &touch){
+    if(standardGUIShowing){
+        // check if in GUI area
+        if(touch.x < 256)
+        if(numActiveTouches > 0) numActiveTouches--; // dirty
+        return;
+    }
+    
+    numActiveTouches--;
+    // which one?
+    if(touch.id == 0){
+        // tricky situation - we tried to zoom but may have left non-move finger on
+        prevTouch0.setCoord(touch.x,touch.y);
+        
+    }else if(touch.id == 1){
+        
+
+        prevTouch1.setCoord(0,0);
+    }
+
+}
+
+//--------------------------------------------------------------
+void testApp::touchDoubleTap(ofTouchEventArgs &touch){
+    // preset?
+
+}
+
+//--------------------------------------------------------------
+void testApp::lostFocus(){
+
+}
+
+//--------------------------------------------------------------
+void testApp::gotFocus(){
+
+}
+
+//--------------------------------------------------------------
+void testApp::gotMemoryWarning(){
+
+}
+
+//--------------------------------------------------------------
+void testApp::deviceOrientationChanged(int newOrientation){
+    cout << "orientation: " << newOrientation;
+    keyboard->updateOrientation(); // takes ages , only applies to text box
+    if(newOrientation == 4){
+        ofxiPhoneSetOrientation( OF_ORIENTATION_90_RIGHT );
+    }else if(newOrientation == 3){
+        ofxiPhoneSetOrientation( OF_ORIENTATION_90_LEFT );
+    }
+    
+}
+
+
+//--------------------------------------------------------------
+void testApp::touchCancelled(ofTouchEventArgs& args){
+
+}
+
+// 5hz cut off
+const double fB[3] = {0.049489956268677,   0.098979912537354,   0.049489956268677};
+
+const double fA[3] = {1.000000000000000,  -1.279632424997809,   0.477592250072517};
+
+// 1hz cut off
+//const double fB[3] = {0.002550535158536,   0.005101070317073,   0.002550535158536};
+
+//const double fA[3] = {1.000000000000000,  -1.852146485395936,   0.862348626030081};
+
+
+//a(1)*y(n) = b(1)*x(n) + b(2)*x(n-1) + ... + b(nb+1)*x(n-nb)- a(2)*y(n-1) - ... - a(na+1)*y(n-na)
+//---------------------------------------------------------------
+vector<float> testApp::vectorFilter(vector<float> newVec){
+    static vector<float> x0(10,0);
+    static vector<float> x1(10,0);
+    static vector<float> x2(10,0);
+    static vector<float> y0(10,0);
+    static vector<float> y1(10,0);
+    static vector<float> y2(10,0);
+    
+    x0 = newVec;
+    
+    // this low passes a bunch of params values all at once
+    int sz =  newVec.size();
+    for(int i=0; i<sz; i++){
+        y0[i] = fB[0]*x0[i] + fB[1]*x1[i] + fB[2]*x2[i] - fA[1]*y1[i] - fA[2]*y2[i];
+    }
+    // shift
+    x2 = x1;
+    x1 = x0;
+    y2 = y1;
+    y1 = y0;
+    
+    return y0;
+}
\ No newline at end of file