changeset 14:f83635861187

rewrote sequence controller. ticks show relevant UI modes. images show for preset textures (but greenish?)
author Robert Tubb <rt300@eecs.qmul.ac.uk>
date Tue, 21 Oct 2014 16:39:39 +0100
parents ab3e0e980c82
children e439bf85b665
files ExplorePresetManager.h MessageOrganiser.h PDSynthWrapper.h SequenceController.h SequenceController.mm TrainingMessageOrganiser.h UI code/IconPanel.h UI code/IconPanel.mm UI code/UIElement.h UI code/sliderPanel.h presetManager.mm testApp.h testApp.mm
diffstat 13 files changed, 623 insertions(+), 282 deletions(-) [+]
line wrap: on
line diff
--- a/ExplorePresetManager.h	Mon Oct 20 19:36:39 2014 +0100
+++ b/ExplorePresetManager.h	Tue Oct 21 16:39:39 2014 +0100
@@ -16,7 +16,7 @@
 #include <iostream>
 #include "presetManager.h"
 
-
+#define MAX_PRESETS 8
 
 class ExplorePresetManager : public PresetManager {
 
@@ -25,8 +25,8 @@
         // check for already saved stuff
         startLoadAll();
         
-        if (thePresets.size() != 16){
-        // if numpresets != 16
+        if (thePresets.size() != MAX_PRESETS){
+
             initPresets();
         }
         
@@ -35,7 +35,7 @@
 
         presetSlotFilename = ofFilePath::getAbsolutePath(ofToDataPath("presetSlots.json"));
         
-        // set up 16 preset slots with names and images
+        // set up preset slots with names and images
         Json::Value root;
         Json::Reader reader;
         
--- a/MessageOrganiser.h	Mon Oct 20 19:36:39 2014 +0100
+++ b/MessageOrganiser.h	Tue Oct 21 16:39:39 2014 +0100
@@ -195,6 +195,11 @@
             setUIToParam(i, vals[i]);
         }
     }
+    void setSlidersToDefault(){
+        for(int i=1; i < targetSynth.getNumParams(); i++){
+            setUIToParam(i, 0);
+        }
+    }
     
     bool onlyChangeCandidateOnTrigger;
 
--- a/PDSynthWrapper.h	Mon Oct 20 19:36:39 2014 +0100
+++ b/PDSynthWrapper.h	Tue Oct 21 16:39:39 2014 +0100
@@ -60,6 +60,7 @@
         
         core->pd.sendList("fromOF", toPD);
     }
+
     void setNoteLength(int lms){
         List toPD;
         toPD.addSymbol(synthPrefix);
@@ -251,6 +252,13 @@
         core->pd.sendMessage("fromOF", "stopMetro", toPD);
         
     }
+    void setMetroTime(float t){
+        List toPD;
+        toPD.addSymbol("setMetroTime");
+        toPD.addFloat(t); // rounding here??
+        
+        core->pd.sendList("fromOF", toPD);
+    }
     void onTick(int tickNo){
         //
         
--- a/SequenceController.h	Mon Oct 20 19:36:39 2014 +0100
+++ b/SequenceController.h	Tue Oct 21 16:39:39 2014 +0100
@@ -1,229 +1,272 @@
 //
-//  SequenceController.h
+//  SequenceGenerator.h
 //  riftathon
 //
-//  Created by Robert Tubb on 17/10/2014.
+//  Created by Robert Tubb on 21/10/2014.
 //
 //
 
-#ifndef __riftathon__SequenceController__
-#define __riftathon__SequenceController__
+#ifndef __riftathon__SequenceGenerator__
+#define __riftathon__SequenceGenerator__
 
 #include <iostream>
-#include "presetManager.h"
+#include "ofMain.h"
 
-#define MAX_TARGETS_IN_SEQUENCE 2
+#define MIN_TARGETS_IN_SEQUENCE 3
+#define MAX_TARGETS_IN_SEQUENCE 5
 #define MIN_TEMPO   80
-#define MAX_TEMPO   200
-#define NUM_TEMPO_STEPS 3
-#define NUM_PRESETS 16
+#define MAX_TEMPO   150
+#define NUM_TEMPO_STEPS 16
+#define NUM_PRESETS 8
 
-//===============================================================================
-
-
-class Sequence{
+class Step{
 public:
-    Sequence(vector<int> si, int t, bool pv){
-        tempo = t;
-        presetSequence =  si;
-        isSequencePreview = pv;
-        curStep = 0;
-    };
-    bool moveToNextStep(){
-        curStep++;
+    typedef enum {COUNT_IN, PREVIEW_DISPLAY, PREVIEW_PLAY, MATCHING_INTERACTION, MATCHING_RESULT} stepTypes;
+// gui display
+    bool showsTargetIcon;
+    bool showsControlSettings;
+    bool showsControlGuides;
+    bool showsMatchResults;
+// gui input
+    bool allowsCandidateControl;
+// sound
+    bool playsTarget;
+    bool playsCandidate;
+// control flow
+    stepTypes type;
+    bool isPreview;
+    
+    int seqNumber;
+    int runNumber;
+    bool isLastOfSeq;
+    bool isLastOfRun;
+    bool playsMetroClick;
+    int tempo;
+// preset info
+    int presetIndex;
+    int numInSequence;
+    bool isLastOfAll;
+    
+    Step(){
+        type = COUNT_IN;
         
-        if (curStep >= presetSequence.size()){
-            return false;
-        }else{
-            return true;
-        }
-    };
-    int getCurrentPresetIndex(){
-        cout << "step : " << curStep << endl;
-        if (curStep >= presetSequence.size()){
-            cout << "ERROR: off end of seq" << endl;
-            return 0;
-        }
-        int i = presetSequence[curStep];
-        if(i < 0){
-            cout << "ERROR: negative index" << endl;
-        }
-        return i;
-
-    };
-    int getStepNo(){
-        return curStep;
+        showsTargetIcon = false;
+        showsControlSettings = false;
+        showsControlGuides = false;
+        showsMatchResults = false;
+        isPreview = false;
+        
+        allowsCandidateControl = false;
+        playsTarget = false;
+        playsCandidate = false;
+        
+        playsMetroClick = true;
+        
+        isLastOfSeq = false;
+        isLastOfRun = false;
+        isLastOfAll = false;
+        presetIndex = -1;
+        seqNumber = -1;
+        runNumber = -1;
+        
+        tempo = MIN_TEMPO;
     }
-    float tempo;
-    
-    bool isSequencePreview; // true if demoing the seq to the user, false if user is matching a seq
-    vector<int> presetSequence;
-    int curStep;
-    
-};
-
-//===============================================================================
-
-class Run{
-public:
-    Run(vector<Sequence> vs, int sl){
-        theSequences = vs;
-        sequenceLength = sl;
-        curSeq = 0;
-    };
-    bool moveToNextStep(){
-        if (curSeq >= theSequences.size()){
-            return false;
-        }
+    void setAsPreviewShower(){
+        type = PREVIEW_DISPLAY;
+        showsTargetIcon = true;
+        showsControlSettings = true;
+        showsMatchResults = false;
+        isPreview = true;
         
-        bool stepFound = theSequences[curSeq].moveToNextStep();
-        if (stepFound){
-            return true;
-        }else{
-            curSeq++;
-            if (curSeq >= theSequences.size()){
-                return false;
-                
-            }else{
-                return true;
-            }
-        }
+        allowsCandidateControl = false;
+        playsTarget = true;
+        playsCandidate = false;
+        playsMetroClick = false;
+    }
+    void setAsPreviewPlayer(){
+        type = PREVIEW_PLAY;
+        showsTargetIcon = true;
+        showsControlSettings = false;
+        showsMatchResults = false;
+        isPreview = true;
         
-        return false;
-    };
-    int getCurrentPresetIndex(){
-        cout << "seq : " << curSeq << endl;
-        if (curSeq >= theSequences.size()){
-            cout << "ERROR: get preset" << endl;
-            return 0;
-        }
-        return theSequences[curSeq].getCurrentPresetIndex();
+        allowsCandidateControl = false;
+        playsTarget = true;
+        playsCandidate = false;
         
-    };
-    int getSequenceNo(){
-        return curSeq;
+        playsMetroClick = false;
+    }
+    void setAsMatchingPreparer(){
+        type = MATCHING_INTERACTION;
+        showsTargetIcon = true;
+        showsControlSettings = false;
+        showsControlGuides = true;
+        showsMatchResults = false;
+        isPreview = false;
+        
+        allowsCandidateControl = true;
+        playsTarget = false;
+        playsCandidate = false;
+        
+        playsMetroClick = false;
+    }
+    void setAsMatchingReckoner(){
+        type = MATCHING_RESULT;
+        showsTargetIcon = true;
+        showsControlSettings = false;
+        showsControlGuides = true;
+        showsMatchResults = true; // shows how far off you were?
+        isPreview = false;
+        
+        allowsCandidateControl = false;
+        playsTarget = false;
+        playsCandidate = true;
+        
+        playsMetroClick = false;
     }
     
-    vector<Sequence> theSequences;
-    int curSeq;
-    int sequenceLength;
-    
+    float getTimeBetweenTicks(){
+        return 1000. * (60.0/tempo);
+    }
 };
-//===============================================================================
 
 class SequenceController{
 public:
-  
     SequenceController(){
-        makeSequences();
         tempoInc = float(MAX_TEMPO - MIN_TEMPO) / float(NUM_TEMPO_STEPS);
-        curRun = 0;
+        generateSteps();
+        setToStart();
     };
+    Step getNextStep(){
 
-    int stepForward(){
-        cout << "run : " << curRun << endl;
-        if (curRun >= theRuns.size()){
-            return -1;
+        currentStep++;
+        if ((*currentStep).isLastOfRun){
+            // uh
         }
+        if ((*currentStep).isLastOfSeq){
             
-        bool stepFound = theRuns[curRun].moveToNextStep();
-        if (stepFound){
-            return curRun;
-        }else{
-            curRun++;
-            if (curRun >= theRuns.size()){
-                cout << " END OF RUNS " << endl;
-                return -1;
+        }
+        return (*currentStep);
+        
+    };
+    void setToStart(){
+        currentStep = steps.begin();
+    }
+    void stepForward(){
+        currentStep++;
+    };
+    float getStartTickTime(){
+        return 1000. * (60.0/MIN_TEMPO);
+    }
+private:
+    void generateSteps(){
+        srand (time(NULL));
+        
+        int run = 0;
+        
+        
+        
+        for(int numInSequence = MIN_TARGETS_IN_SEQUENCE; numInSequence <= MAX_TARGETS_IN_SEQUENCE; numInSequence++){
+            generateCountIn(2);
+            generateARun(run, numInSequence);
+
+            steps.back().isLastOfRun = true;
+            run++;
+            cout << "-generate run finished-" << endl;
+        }
+        steps.back().isLastOfAll = true;
+    };
+    void generateCountIn(int countInLength){
+        Step countStep;
+        for (int i = 0; i < countInLength; i++){
+            countStep.numInSequence = countInLength - i + 1;
+            steps.push_back(countStep);
+            
+        }
+    };
+    void generateARun(int run, int numInSequence){
+        float curTempo = MIN_TEMPO;
+        int seqNo = 0;
+        
+        for(int tempoLevel = 0; tempoLevel < NUM_TEMPO_STEPS; tempoLevel++){
+            
+            vector<int> stepPreset;
+            
+            // get some random ints
+            for(int n=0; n < numInSequence; n++){
+                int nextPreset = getRandomButNot(NUM_PRESETS,stepPreset);
+                stepPreset.push_back(nextPreset);
+                cout << nextPreset << ",";
+            }
+            // put preview
+            Step nextStep;
+            
+            int n = 0;
+            for(auto si = stepPreset.begin(); si < stepPreset.end(); si++){
+                // put loader
                 
-            }else{
-                return -2; // in order to stop the metro, next tick will just start thjings agaaain
+                nextStep.presetIndex = *si;
+                nextStep.runNumber = run;
+                nextStep.seqNumber = seqNo;
+                nextStep.numInSequence = n;
+                nextStep.tempo = curTempo;
+                nextStep.setAsPreviewShower();
+                steps.push_back(nextStep);
+                
+                // put player
+//
+//                nextStep.setAsPreviewPlayer();
+//                steps.push_back(nextStep);
+                n++;
             }
+            // last one in sequence allows control ?
+            steps.back().allowsCandidateControl = true;
+            // put in matching sequence
+            n = 0;
+            for(auto si = stepPreset.begin(); si < stepPreset.end(); si++){
+                // put loader
+                
+                nextStep.presetIndex = *si;
+                nextStep.numInSequence = n;
+                nextStep.setAsMatchingPreparer();
+                steps.push_back(nextStep);
+                
+                // put player
+                
+                nextStep.setAsMatchingReckoner();
+                steps.push_back(nextStep);
+                n++;
+            }
+            
+            steps.back().isLastOfSeq = true;
+            curTempo += tempoInc;
+            seqNo++;
+            cout << endl;
+            
         }
         
-        return false;
-        
     }
-
-    int getCurrentPresetIndex(){
-        
-        // if end of sequence return something else so we can do something
-        // if end of tempo ramp return something else
-        if (curRun >= theRuns.size()){
-            cout << "DAAAAHHH" << endl;
-            return -1;
-        }
-        int nextIndex = theRuns[curRun].getCurrentPresetIndex();
-
-        return nextIndex;
-    };
-    vector<int> getCurrentRunSeqAndStep(){
-        vector<int> rss;
-//        int r = curRun - theRuns.begin();
-//        int sq = (*curRun).getSequenceNo();
-//        int s = 4534534;
-//        rss.push_back(r);
-//        rss.push_back(sq);
-//        rss.push_back(s);
-        return rss;
-        
-    }
-protected:
-    void makeSequences(){
-        srand (time(NULL));
-        
-
-        for(int numInSequence = 1; numInSequence <= MAX_TARGETS_IN_SEQUENCE; numInSequence++){
-            float curTempo = MIN_TEMPO;
-            vector<Sequence> seqsForRun;
-            
-            for(int tempoLevel = 0; tempoLevel < NUM_TEMPO_STEPS; tempoLevel++){
-                
-                vector<int> stepsForSequence;
-                
-                // repeat the same tests for xtra practice?
-                for(int n=0; n < numInSequence; n++){
-                    int next = getRandomButNot(NUM_PRESETS,stepsForSequence);
-                    stepsForSequence.push_back(next);
-                    
-                    cout << next << ",";
-                }
-                seqsForRun.push_back(Sequence(stepsForSequence, curTempo, true));
-                seqsForRun.push_back(Sequence(stepsForSequence, curTempo, false));
-                curTempo += tempoInc;
-                cout << endl;
-                
-            }
-            
-            theRuns.push_back( Run(seqsForRun,numInSequence) );
-            
-            cout << "---" << endl;
-        }
-    };
-
+    
+    
     int getRandomButNot(int max, vector<int> notThese){
         
         bool there = true;
         int randomInt = rand() % max;
         
         if (notThese.size()){
-        while(there){
-            randomInt = rand() % max;
-            vector<int>::iterator result = std::find(notThese.begin(), notThese.end(), randomInt);
-            there =  (result != notThese.end());
-        }
+            while(there){
+                randomInt = rand() % max;
+                vector<int>::iterator result = std::find(notThese.begin(), notThese.end(), randomInt);
+                there =  (result != notThese.end());
+            }
         }
         return randomInt;
         
     };
-
     
-private:
-   
-    vector<Run> theRuns;
-    int curRun;
-    
+    vector<Step> steps;
+    vector<Step>::iterator currentStep;
     float tempoInc;
 };
-//===============================================================================
 
-#endif /* defined(__riftathon__SequenceController__) */
+#endif /* defined(__riftathon__SequenceGenerator__) */
--- a/SequenceController.mm	Mon Oct 20 19:36:39 2014 +0100
+++ b/SequenceController.mm	Tue Oct 21 16:39:39 2014 +0100
@@ -1,8 +1,8 @@
 //
-//  SequenceController.mm
+//  SequenceGenerator.mm
 //  riftathon
 //
-//  Created by Robert Tubb on 17/10/2014.
+//  Created by Robert Tubb on 21/10/2014.
 //
 //
 
--- a/TrainingMessageOrganiser.h	Mon Oct 20 19:36:39 2014 +0100
+++ b/TrainingMessageOrganiser.h	Tue Oct 21 16:39:39 2014 +0100
@@ -19,6 +19,7 @@
 
 class TrainingMessageOrganiser : public MessageOrganiser {
 public:
+    int numParamsToUse;
     void init( PDSynthWrapper& cs, PDSynthWrapper& ts){
         
         MessageOrganiser::init(cs,ts);
@@ -27,15 +28,16 @@
         callback = boost::bind(&TrainingMessageOrganiser::onNextTick, this, _1);
         candidateSynth.registerForTicks(callback);
         
-        sequencePreview = true;
+        numParamsToUse = 3;
+        
     }
-
+    
     void setupDefaultMapping(){
         vector<int> mappingIDsForChangeableParams = getMappingIDsFromSynths();
         
         controlPanelType cpt = REVISITABLE;
         vector<controllerType> elemList;
-        for(int i = 0; i < TOTAL_NUM_PARAMS; i++){
+        for(int i = 0; i < numParamsToUse; i++){
             elemList.push_back(SLIDER);
         }
         
@@ -48,7 +50,7 @@
     
     vector<int> getMappingIDsFromSynths(){
         vector<int> index;
-        for(int i = 0; i < TOTAL_NUM_PARAMS; i++){
+        for(int i = 0; i < numParamsToUse; i++){
             index.push_back(i);
         }
         vector<int> mids = candidateSynth.getMappingIDForIndices(index);
@@ -57,73 +59,123 @@
     }
     
     void setupNewTest(){
-
+        
         
     };
     
     void setIconPanel(IconPanel * ip){
         presetIconPanel = ip;
     }
+    void setInstructionPanel(TextPanel * ip){
+        instructionPanel = ip;
+        instructionPanel->show();
+    }
+//-----------------------------------------------------------------------
+    void displayInstructions(Step s){
+        
+
+        if (s.type == Step::COUNT_IN){
+            instructionPanel->setText("GET READY");
+        }
+        if (s.type == Step::PREVIEW_DISPLAY){
+            instructionPanel->setText("MEMORISE");
+            panel->setColor(ofColor(0,0,0));
+        }
+        if (s.type == Step::PREVIEW_PLAY){
+            instructionPanel->setText("MEMORISE");
+            panel->setColor(ofColor(0,0,0));
+        }
+        if (s.type == Step::MATCHING_INTERACTION){
+            instructionPanel->setText("MATCH:");
+            panel->setColor(ofColor(100,0,0));
+        }
+        if (s.type == Step::MATCHING_RESULT){
+            instructionPanel->setText("RESULT");
+            panel->setColor(ofColor(0,100,0));
+        }
+    }
+//-----------------------------------------------------------------------
     void onNextTick(int tickNumber){
         cout << "TICK " << tickNumber << endl;
+
+        // only first beat in bar is active one
+        if ( tickNumber % 4  != 0){
+            return;
+        }
+        // load next target preset
         
-        if ( !(tickNumber % 2)){
-            // load next target preset
-            
-            int i = sequenceController.getCurrentPresetIndex();
-            
-            currentTargetPreset =  expPresetManager.getPreset(i);
-            
-            if (sequencePreview){
-                // show next target preset
-                // presetIconPanel->setTextAndImage(currentTargetPreset->name, currentTargetPreset->getImage());
-             
-                // show image
-                // show name
-                // show controllersettings
-                
-                
-            }else{ // the user is matching it
-                // show image
-                // show name
-                
-                // if guided
-                    // show controller guide
-            }
-            
-            
-        }else{ // we're plying the sound
-         
-            //
-            if (sequencePreview){
-                // send target values again
-                targetSynth.setAllParams(currentTargetPreset->getValues());
-                setSlidersToTarget();
-                targetSynth.trigger();
-                
-                // flash the interface?
-            }else{
-                // has this been done? yes. candidateSynth.setAllParams(ui stuff);
-                candidateSynth.trigger();
-                showUserHowTheyDid();
-                
-            }
+        Step newStep = sequenceController.getNextStep();
+        displayInstructions(newStep);
+        
+        if(newStep.isLastOfAll){
+            // do finished run stuff, show summary
+            candidateSynth.stopMetronome();
+            cout << "FINISHED BLOCK" << endl;
         }
-        
-        int run = sequenceController.stepForward();
-        if (run == -2){
+        if(newStep.isLastOfRun){
             // do finished run stuff, show summary
             candidateSynth.stopMetronome();
             cout << "FINISHED RUN" << endl;
         }
-        if (run == -1){
-            // finished whole block
-            candidateSynth.stopMetronome();
-            cout << "FINISHED BLOCK" << endl;
+        
+        float t = newStep.getTimeBetweenTicks();
+        candidateSynth.setMetroTime(t);
+        
+        if(newStep.type == Step::COUNT_IN){
+            // count in
+            return;
         }
+        
+        if(newStep.presetIndex >= 0 && newStep.presetIndex <= 8){
+            currentTargetPreset =  expPresetManager.getPreset(newStep.presetIndex);
+        }
+        
+        if(newStep.showsTargetIcon){
+            presetIconPanel->setTextAndImage(currentTargetPreset->name, currentTargetPreset->getImage());
+            presetIconPanel->show();
+        }else{
+            presetIconPanel->hide();
+        }
+        
+        if(newStep.showsControlSettings){
+            targetSynth.setAllParams(currentTargetPreset->getValues());
+            setSlidersToTarget();
+            
+        }else{
+            //setSlidersToDefault();
+            
+        }
+        
+        if(newStep.playsTarget){
+            targetSynth.setAllParams(currentTargetPreset->getValues());
+            targetSynth.trigger();
+        }
+        
+        if(newStep.playsCandidate){
+            triggerCandidateSound();
+        }
+        
+        if(newStep.allowsCandidateControl){
+            panel->setActive(true);
+        }else{
+            panel->setActive(false);
+        }
+        
+        if(newStep.showsMatchResults){
+            // do something
+        }
+        
+        if(newStep.showsControlGuides){
+            
+            panel->setHintValues(currentTargetPreset->getValues());
+            panel->showHint(true);
+        }else{
+            panel->showHint(false);
+        }
+        
     }
-
-   
+    
+    //-----------------------------------------------------------------------
 protected:
     void showUserHowTheyDid(){
         // colour flash
@@ -143,6 +195,7 @@
     }
     
     
+    //-----------------------------------------------------------------------
     void showATargetPresetWithGuide(Preset * p){ // this is when demoing the sequence to the user
         // p.show icon
         vector<int> values = p->getValues();
@@ -153,6 +206,7 @@
             cout << "WARNING, preset to show had no values" << endl;
         }
     }
+    //-----------------------------------------------------------------------------
     
     void mapSlidersToParams(vector<UIElement*> elems, vector<int> mids){
         
@@ -181,6 +235,7 @@
         
         eventLogger.logEvent(CONTROL_LIST,typeListLog);
     };
+//-----------------------------------------------------------------------------
     
     void buttonPressCallback(int mappingID, int value){
         if(mappingID == VOLUME_CHANGE_ID){
@@ -188,10 +243,11 @@
             candidateSynth.sendVolume(value);
             return;
         }
-
+        
         if (mappingID == TRIGGER_CANDIDATE_ID){
-            triggerCandidateSound();
+            //triggerCandidateSound();
             // compare to target
+            candidateSynth.setMetroTime(sequenceController.getStartTickTime());
             candidateSynth.startMetronome();
             return;
         }
@@ -205,9 +261,12 @@
             return;
         }
     }
+    //-----------------------------------------------------------------------------
+    
     SequenceController sequenceController;
     bool sequencePreview;
     Preset * currentTargetPreset;
     IconPanel* presetIconPanel;
+    TextPanel* instructionPanel;
 };
 #endif /* defined(__riftathon__TrainingMessageOrganiser__) */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UI code/IconPanel.h	Tue Oct 21 16:39:39 2014 +0100
@@ -0,0 +1,64 @@
+//
+//  IconPanel.h
+//  riftathon
+//
+//  Created by Robert Tubb on 20/10/2014.
+//
+//
+
+#ifndef __riftathon__IconPanel__
+#define __riftathon__IconPanel__
+
+#include <iostream>
+
+#include <iostream>
+#include "ofMain.h"
+#include "UIElement.h"
+#include "UIProperties.h"
+
+class IconPanel : public UIElement{
+    
+public:
+
+    float thickness; // width of border
+    float radius;   // inner radius of corners, reccomended to be same as thickness
+    ofColor foregroundHi;
+    ofColor backgroundHi;
+    ofColor foregroundLo;
+    ofColor backgroundLo;
+    ofColor fgInactive;
+    
+    bool pressed; // on and pressed can be different
+    
+    IconPanel();
+    ~IconPanel(){};
+    
+    // this constructor sets up with defaults obtained from UIProperties (recoomemnded)
+
+    IconPanel(float x,
+            float y,
+            float width,
+            float height,
+            const UIProps& props
+            );
+       void draw();
+    void drawOutline();
+    void drawTextLabel();
+    void drawTexture();
+    
+    void setTextAndImage(string text, ofImage* image){
+        setLabel(text);
+        textureImage = image;
+        hasBeenSet = true;
+    }
+    
+    virtual bool handleMyTouch(int x, int y, touchType ttype, int touchID);
+    
+protected:
+
+    ofImage* textureImage;
+    bool hasBeenSet;
+};
+
+
+#endif /* defined(__riftathon__IconPanel__) */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UI code/IconPanel.mm	Tue Oct 21 16:39:39 2014 +0100
@@ -0,0 +1,146 @@
+//
+//  IconPanel.mm
+//  riftathon
+//
+//  Created by Robert Tubb on 20/10/2014.
+//
+//
+
+#include "IconPanel.h"
+
+//------------------------------------------------------------------
+IconPanel::IconPanel(float ax,
+                 float ay,
+                 float awidth,
+                 float aheight,
+                 const UIProps& props):
+UIElement(ax,ay,awidth,aheight, props)
+
+{
+    cout << "ICON PANEL  constructor\n";
+    
+    thickness = 2.;
+    radius = props.cornerRadius;
+    foregroundHi = props.buttonHi;
+    backgroundHi = props.generalBackground;
+    foregroundLo = props.buttonLo;
+    backgroundLo = props.generalBackground;
+    fgInactive = props.inactiveGreyedOut;
+    labelName = "YO";
+    on = false;
+    hasBeenSet = false;
+    textureImage = NULL;
+}
+//------------------------------------------------------------------
+void IconPanel::draw(){
+    if(hidden) return;
+    //cout << "drawing button" << endl;
+    //ofFill();
+    //UIElement::draw(); // should do background
+    //drawOutline();
+    if(hasBeenSet){
+        drawTexture();
+        drawTextLabel();
+        
+    }
+    
+    
+}
+void IconPanel::drawTexture(){
+    
+    textureImage->draw(x+10,y+10,width-20,height-20);
+}
+//------------------------------------------------------------------
+void IconPanel::drawTextLabel(){
+    ofColor fg,bg;
+    
+    if(on){
+        fg = foregroundHi;
+        bg = backgroundHi;
+    }else{
+        fg = foregroundLo;
+        bg = backgroundLo;
+    }
+    if(inactive){
+        fg = fgInactive;
+    }
+    ofSetColor(fg);
+    verdana16.drawString(labelName, x + thickness*2, y + 35);
+    
+}
+//------------------------------------------------------------------
+void IconPanel::drawOutline(){
+    
+    // draw bars
+    ofColor fg,bg;
+    
+    if(on){
+        fg = foregroundHi;
+        bg = backgroundHi;
+    }else{
+        fg = foregroundLo;
+        bg = backgroundLo;
+    }
+    ofSetColor(fg);
+    
+    float cornerSize = thickness + radius;
+    // left
+    ofRect(x, y+cornerSize, thickness, height - 2*(cornerSize));
+    //right
+    ofRect(x + width - thickness, y+cornerSize, thickness, height - 2*(cornerSize));
+    // top
+    ofRect(x+cornerSize, y, width-2*(cornerSize), thickness);
+    // bottom
+    ofRect(x+cornerSize, y+height-thickness, width-2*(cornerSize), thickness);
+    
+    // draw corner  foreground circles
+    
+    //tl
+    ofCircle(x+cornerSize, y+cornerSize, cornerSize);
+    
+    
+    //tr
+    
+    ofCircle(x+width-cornerSize, y+cornerSize, cornerSize);
+    
+    //bl
+    
+    ofCircle(x+cornerSize, y+height-cornerSize, cornerSize);
+    
+    //br
+    
+    ofCircle(x+width-cornerSize, y+height-cornerSize, cornerSize);
+    
+    // draw corner inner bg circles
+    ofSetColor(bg);
+    ofCircle(x+cornerSize, y+cornerSize, radius);
+    
+    ofCircle(x+width-cornerSize, y+cornerSize, radius);
+    
+    ofCircle(x+cornerSize, y+height-cornerSize, radius);
+    
+    ofCircle(x+width-cornerSize, y+height-cornerSize, radius);
+    
+    // fill in background
+    ofRect(x+cornerSize,y+thickness,width-2*cornerSize,height-2*thickness);
+    ofRect(x+thickness, y+cornerSize, radius, height-2*cornerSize);
+    ofRect(x+width-cornerSize, y+cornerSize, radius, height-2*cornerSize);
+}
+//------------------------------------------------------------------------------
+bool IconPanel::handleMyTouch(int tx, int ty, touchType ttype, int touchID){
+    
+    //cout << "buttron handling touch\n";
+    if(ttype == TOUCH_DOWN){
+        on = true;
+        if(callback) callback(myParamID,1);
+        
+    }else if(ttype == TOUCH_MOVED){
+        
+    }else if(ttype == TOUCH_UP){
+        on = false;
+    }
+    return true; // necessary?
+    
+}
+
+//------------------------------------------------------------------------------
--- a/UI code/UIElement.h	Mon Oct 20 19:36:39 2014 +0100
+++ b/UI code/UIElement.h	Tue Oct 21 16:39:39 2014 +0100
@@ -98,6 +98,9 @@
     void setY(float ay){
         y = ay;
     };
+    void setColor(ofColor c){
+        background = c;
+    }
 protected:
     
     float x;
--- a/UI code/sliderPanel.h	Mon Oct 20 19:36:39 2014 +0100
+++ b/UI code/sliderPanel.h	Tue Oct 21 16:39:39 2014 +0100
@@ -40,6 +40,14 @@
         }
     }
     //
+    void setHintValues(vector<int> vals){
+        auto valItr = vals.begin();
+        for(auto UIitr = subElements.begin(); UIitr < subElements.end(); UIitr++){
+            if (++valItr != vals.end()){
+                (*UIitr)->setHintValue(*valItr);
+            }
+        }
+    }
     void setHintColor(ofColor c){
         vector<UIElement *>::iterator UIitr;
         for(UIitr = subElements.begin(); UIitr < subElements.end(); UIitr++){
@@ -69,6 +77,13 @@
         
     }
     //------------------------
+    void setBgColor(ofColor c){
+        vector<UIElement *>::iterator UIitr;
+        for(UIitr = subElements.begin(); UIitr < subElements.end(); UIitr++){
+            (*UIitr)->setColor(c);
+        }
+    }
+    //------------------------
     vector<UIElement*> generateControls(vector<controllerType> elemList, controlPanelType panelType);
     //------------------------
     UIElement* getSlider(int index){
--- a/presetManager.mm	Mon Oct 20 19:36:39 2014 +0100
+++ b/presetManager.mm	Tue Oct 21 16:39:39 2014 +0100
@@ -159,7 +159,7 @@
 }
 //-----------------------------------------------------------------------------
 void PresetManager::generatePresetSlot(const string name, const string imagefn){
-    vector<int> values = makeVector8(0,0,0,0,45,0,0,0); // empty
+    vector<int> values = makeVector8(int(rand() % 128),int(rand() % 128),int(rand() % 128),int(rand() % 128),int(rand() % 128),0,0,0); // empty
     thePresets.push_back(new Preset(values, name, nextID, eventLogger.userName, eventLogger.deviceID, imagefn));
     
 }
--- a/testApp.h	Mon Oct 20 19:36:39 2014 +0100
+++ b/testApp.h	Tue Oct 21 16:39:39 2014 +0100
@@ -102,7 +102,7 @@
     double ofFixGetHeight();
     ofTouchEventArgs transformTouchCoords(ofTouchEventArgs &point);
     ofLight light;
-        
+    UIProps* props;
     void lostFocus();
     void gotFocus();
     void gotMemoryWarning();
@@ -172,6 +172,7 @@
     void rotateToLandscapeRight(){};
     void toggleAutoRotation(){};
     
+    ofImage image;
 };
 
 // should be off split into
--- a/testApp.mm	Mon Oct 20 19:36:39 2014 +0100
+++ b/testApp.mm	Tue Oct 21 16:39:39 2014 +0100
@@ -13,9 +13,7 @@
     ofxiPhoneSetOrientation( OF_ORIENTATION_90_LEFT );
     //ofxiPhoneExternalDisplay::mirrorOn();
     [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
-    // initilaise
-    
-    
+
     initialiseVariables();
 
     
@@ -33,20 +31,15 @@
     initialiseMIDI();
     setupUIElements();
 
+    
 
-
-    
-    light.setSpotlight(45. , 1.);
-    light.enable();
-    ofEnableSeparateSpecularLight();
+//    
+//    light.setSpotlight(45. , 1.);
+//    light.enable();
+//    ofEnableSeparateSpecularLight();
     ofEnableDepthTest();
     ofEnableAlphaBlending();
     // in setup:
-    myfont.loadFont("NewMedia Fett.ttf", 32);
-    
-    verdBig.loadFont("verdana.ttf", 18, true, true);
-	verdBig.setLineHeight(18.0f);
-	verdBig.setLetterSpacing(1.037);
 
     //--------------------------------------
     
@@ -98,7 +91,7 @@
 	// open an outgoing connection to HOST:PORT for OSC
 	// sender.setup( OSC_HOST, OSC_PORT );
     ofSetFrameRate(60);
-    
+    props = new UIProps();
 
 }
 //---------------------------------------------------------
@@ -125,11 +118,11 @@
 //--------------------------------------------------------------
 // gui for the main training stage
 void testApp::setupTrainingViewPanels(){
-    UIProps p;
-    ButtonPanel* bottomButtonPanel = new ButtonPanel(1,160+p.sliderPanelHeight,ofGetWidth(),250,p);
+
+    ButtonPanel* bottomButtonPanel = new ButtonPanel(1,160+props->sliderPanelHeight,ofGetWidth(),250,*props);
     
     // play and submit are now same thing
-    Buttron * playCandidateButton = new Buttron(p.buttonWidth*1.4,680, p);
+    Buttron * playCandidateButton = new Buttron(props->buttonWidth*1.4,680, *props);
     playCandidateButton->setLabel("PLAY");
     trainingMessageOrganiser.mapButtonToAction(playCandidateButton, TRIGGER_CANDIDATE_ID);
     bottomButtonPanel->addButton(playCandidateButton);
@@ -138,45 +131,50 @@
     UIElements.push_back(bottomButtonPanel);
     bottomButtonPanel->hide();
     
-    IconPanel* iconPanel = new IconPanel(200, 10, 200, 150, p);
+    IconPanel* iconPanel = new IconPanel(420, 10, 150, 150, *props);
     trainingMessageOrganiser.setIconPanel(iconPanel);
     UIElements.push_back(iconPanel);
     iconPanel->show();
     
+    TextPanel * instructionPanel = new TextPanel("Instrcution panel", 10, 50, 300,150,(*props));
+    instructionPanel->setFontSize(LARGEFONT);
+    UIElements.push_back(instructionPanel);
+    trainingMessageOrganiser.setInstructionPanel(instructionPanel);
+    instructionPanel->show();
+    
 }
 //--------------------------------------------------------------
 // gui for the old style tweakathlon  stage
 void testApp::setupSearchViewPanels(){
+
+    ButtonPanel* bottomButtonPanel = new ButtonPanel(1,160+(*props).sliderPanelHeight,ofGetWidth(),250,(*props));
     
-    UIProps p;
-    ButtonPanel* bottomButtonPanel = new ButtonPanel(1,160+p.sliderPanelHeight,ofGetWidth(),250,p);
-    
-    Buttron* playTargetButton = new Buttron(p.buttonWidth*0.2,680, p);
+    Buttron* playTargetButton = new Buttron((*props).buttonWidth*0.2,680, (*props));
     playTargetButton->setLabel("Target");
     searchMessageOrganiser.mapButtonToAction(playTargetButton, TRIGGER_TARGET_ID);
     bottomButtonPanel->addButton(playTargetButton);
     searchMessageOrganiser.setTargetButton(playTargetButton);
     
-    Buttron * playCandidateButton = new Buttron(p.buttonWidth*1.4,680, p);
+    Buttron * playCandidateButton = new Buttron((*props).buttonWidth*1.4,680, (*props));
     playCandidateButton->setLabel("Current");
     searchMessageOrganiser.mapButtonToAction(playCandidateButton, TRIGGER_CANDIDATE_ID);
     bottomButtonPanel->addButton(playCandidateButton);
     
     
     // submit button - only one for now
-    Buttron * submitButton = new Buttron(ofGetWidth()*0.5 - p.buttonWidth*0.5,680, p);
+    Buttron * submitButton = new Buttron(ofGetWidth()*0.5 - (*props).buttonWidth*0.5,680, (*props));
     submitButton->setLabel("Submit");
     searchMessageOrganiser.mapButtonToAction(submitButton, SUBMIT_CANDIDATE);
     bottomButtonPanel->addButton(submitButton);
     
     //  button - just for spacing pruposes
-    Buttron * saveButton = new Buttron(ofGetWidth()*0.5 - p.buttonWidth*0.5,680, p);
+    Buttron * saveButton = new Buttron(ofGetWidth()*0.5 - (*props).buttonWidth*0.5,680, (*props));
     saveButton->setLabel("SAVE");
     searchMessageOrganiser.mapButtonToAction(saveButton, SAVE_PRESET_HIT);
     bottomButtonPanel->addButton(saveButton);
     saveButton->hide();
     
-    Buttron * recallButton = new Buttron(ofGetWidth()*0.5 - p.buttonWidth*0.5,680, p);
+    Buttron * recallButton = new Buttron(ofGetWidth()*0.5 - (*props).buttonWidth*0.5,680, (*props));
     recallButton->setLabel("RECALL");
     searchMessageOrganiser.mapButtonToAction(recallButton, RECALL_PRESET_HIT);
     bottomButtonPanel->addButton(recallButton);
@@ -188,18 +186,18 @@
     bottomButtonPanel->hide();
 // -   -   - - - -- -  - OTHER BITS
     
-    CountdownText * countDownBox = new CountdownText("5" , 500, 380, 455, 455, p);
+    CountdownText * countDownBox = new CountdownText("5" , 500, 380, 455, 455, (*props));
     UIElements.push_back(countDownBox);
     searchMessageOrganiser.setCountdownPanel(countDownBox);
     countDownBox->hide();
     
-    TextPanel * scoreFeedback = new TextPanel("Feedback panel", ofGetWidth()*0.5 - p.buttonWidth*0.5, 666, 400,100,p);
+    TextPanel * scoreFeedback = new TextPanel("Feedback panel", ofGetWidth()*0.5 - (*props).buttonWidth*0.5, 666, 400,100,(*props));
     scoreFeedback->setFontSize(SMALLFONT);
     UIElements.push_back(scoreFeedback);
     searchMessageOrganiser.setScorePanel(scoreFeedback);
     scoreFeedback->hide();
     
-    TextPanel * finishPanel = new TextPanel("Finish txt panel", 250, 250, 1000,400,p);
+    TextPanel * finishPanel = new TextPanel("Finish txt panel", 250, 250, 1000,400,(*props));
     finishPanel->setFontSize(LARGEFONT);
     finishPanel->setText("Experiment completed");
     searchMessageOrganiser.setFinishPanel(finishPanel);
@@ -208,14 +206,14 @@
     finishPanel->hide();
     
     
-    Buttron * newTestButton = new Buttron(ofGetWidth()-300,690, p);
+    Buttron * newTestButton = new Buttron(ofGetWidth()-300,690, (*props));
     newTestButton->setLabel("Next Test");
     UIElements.push_back(newTestButton);
     searchMessageOrganiser.mapButtonToAction(newTestButton, NEW_TEST_ID);
     newTestButton->hide();
     searchMessageOrganiser.setNewTestButton(newTestButton);
     
-    TargetSymbol* targetSymbol = new TargetSymbol(ofGetWidth()*0.5,160,30,p);
+    TargetSymbol* targetSymbol = new TargetSymbol(ofGetWidth()*0.5,160,30,(*props));
     searchMessageOrganiser.setTargetSymbol(targetSymbol);
     UIElements.push_back(targetSymbol);
     
@@ -229,8 +227,8 @@
     SliderPanel * controlPanel = new SliderPanel(1,
                                                  160,
                                                  ofGetWidth(),
-                                                 p.sliderPanelHeight,
-                                                 p,
+                                                 (*props).sliderPanelHeight,
+                                                 (*props),
                                                  sl2);
     
     UIElements.push_back(controlPanel);
@@ -241,8 +239,7 @@
 //--------------------------------------------------------------
 void testApp::setupUIElements(){
 
-    UIProps p;
-    ofBackground(p.generalBackground);
+    ofBackground((*props).generalBackground);
 
     setupSearchViewPanels();
 
@@ -516,7 +513,7 @@
     if (currentStage == SEARCH)
         searchMessageOrganiser.drawScore();
     
-    
+    //image.draw(10,10,200,200);
 
 }
 //------------------------------------------------------------------------