Mercurial > hg > tweakathon2ios
view SearchMessageOrganiser.h @ 44:d810aa9ca03a
times. cosmetic stuff
author | Robert Tubb <rt300@eecs.qmul.ac.uk> |
---|---|
date | Mon, 15 Dec 2014 17:33:41 +0000 |
parents | 953db6518738 |
children |
line wrap: on
line source
// // SearchMessageOrganiser.h // riftathon // // Created by Robert Tubb on 17/10/2014. // // #ifndef __riftathon__SearchMessageOrganiser__ #define __riftathon__SearchMessageOrganiser__ #include <iostream> #include "MessageOrganiser.h" class SearchMessageOrganiser : public MessageOrganiser { public: void init( PDSynthWrapper& cs, PDSynthWrapper& ts){ testController = new TestController; MessageOrganiser::init(cs,ts); currentSoundPlayTimer = -1; okToGetLeapMidi = false; alternationSpeed = 200; candidateSynth.setNoteLength(alternationSpeed); targetSynth.setNoteLength(alternationSpeed); playingAlternating = false; verdBig.loadFont("verdana.ttf", 18, true, true); verdBig.setLineHeight(18.0f); verdBig.setLetterSpacing(1.037); }; //------------------------------------------------------------------------ void drawScore(){ ofColor txtCol = ofColor(150,235,200,255); int score = getScore(); stringstream msg; msg << "Test: " << testController->getCurrentTestLetter(); ofSetColor(txtCol); verdBig.drawString(msg.str(), 40, 140); msg.str(std::string()); msg << "Score: " << score; verdBig.drawString(msg.str(), 240, 140); msg.str(std::string()); pair<int,int> time; time = getTime(); msg << "Time taken: " << time.first << ":" << time.second << endl; verdBig.drawString(msg.str(), 600, 140); } void setNewTestButton(Buttron * ntb){ newTestButton = ntb; }; void set3Dbox(Leap3DBoxGL* box){ box3D = box; }; void setCountdownPanel(CountdownText* cd){ countdownPanel = cd; }; void setTargetSymbol(TargetSymbol* ts){ targetSymbol = ts; }; void setScorePanel(TextPanel* tp){ scorePanel = tp; }; void setFinishPanel(TextPanel* fp){ finishPanel = fp; } void setTargetButton(Buttron* tb){ targetPlayButton = tb; } int getScore(){ return testController->getScoreRunningTotal(); }; pair<int,int> getTime(){ TimerMillisec tms = timeController.getStopwatchElapsedTime(); int s = int(tms/1000); int hs = int((tms%1000)/10); pair<int,int> p(s,hs); return p; }; void countdownToNewTest(){ controlPanel->hide(); controlPanel->setActive(false); scorePanel->hide(); bottomPanel->hide(); newTestButton->hide(); // set up stuff setupNewTest(); eventLogger.logEvent(COUNTDOWN_INITIATED); countdownPanel->showAndStart(3); timeController.scheduleEvent(boost::bind(&SearchMessageOrganiser::startNewTest, this), 3000); }; void playTargetButtonPressed(){ static int numPlays = 3; Test* t = testController->getCurrentTestPtr(); if (!t->checkTargetPlaysRemaining()){ cout << t->getTargetPlaysLeft() << endl; sendSynthValuesAgain(); targetSynth.trigger(); eventLogger.logEvent(TARGET_PLAYED); targetPlayButton->hide(); return; } cout << t->getTargetPlaysLeft() << endl; sendSynthValuesAgain(); targetSynth.trigger(); eventLogger.logEvent(TARGET_PLAYED); return; } void buttonPressCallback(int mappingID, int value){ if(mappingID == VOLUME_CHANGE_ID){ targetSynth.sendVolume(value); candidateSynth.sendVolume(value); } if(mappingID == SPEED_CHANGE_ID){ alternationSpeed = 2*(140 - value); vector<int> eData; eData.push_back(alternationSpeed); eventLogger.logEvent(SPEED_CHANGED, eData); } if(mappingID == NEW_TEST_ID){ countdownToNewTest(); return; } if (mappingID == START_ALTERNATE_ID){ if(!playingAlternating){ startAlternatingPlayback(); }else{ stopAlternatingPlayback(); } return; } if (mappingID == RANDOMISE_TARGET_ID){ // bleyeueurrrr targetSynth.randomiseParams(); return; } if (mappingID == TRIGGER_TARGET_ID){ playTargetButtonPressed(); } if (mappingID == TRIGGER_CANDIDATE_ID){ // log event sendSynthValuesAgain(); candidateSynth.trigger(); eventLogger.logEvent(CANDIDATE_PLAYED); // flash panel? controlPanel->flash(); return; } if (mappingID == SUBMIT_CANDIDATE){ // log event submitPressed(); return; } if (mappingID == CRAP_TEST_ID){ // this is rubbish! send a log of target values, and mapping ids vector<int> data; vector<int> tvals = targetSynth.getAllParamValues(); vector<int> pidx = testController->getCurrentChangeableParams(); data.insert(data.end(), tvals.begin(), tvals.end()); data.insert(data.end(), pidx.begin(), pidx.end()); eventLogger.logEvent(CRAP_TEST, data); } if(mappingID == SHOW_HIDE_PANEL){ static bool showing; if(showing){ cout << " showing"<<endl; controlPanel->show(); }else{ cout << " hiding"<<endl; controlPanel->hide(); } showing = !showing; } if(mappingID == SHOW_HIDE_HINT){ static bool showingHint; if(showingHint){ controlPanel->showHint(false); showingHint = false; }else{ controlPanel->showHint(true); showingHint = true; } } } // called from UI void midiFromLeap(int ctl_num, int ctl_val){ if (!okToGetLeapMidi){ return; } Test *theTest = testController->getCurrentTestPtr(); if (theTest == NULL) return; vector<int> ci = theTest->getChangeableIndices(); vector<int> mids = candidateSynth.getMappingIDForIndices(ci); if (ctl_num >= mids.size() || ctl_num < 0) return; candidateSynth.paramChangeCallback(mids[ctl_num], ctl_val); setUIToParam(ctl_num, ctl_val); vector<int> evtData; evtData.push_back(mids[ctl_num]); // or just index? evtData.push_back(ctl_val); eventLogger.logEvent(CANDIDATE_PARAM_ADJUSTED, evtData); } ofTrueTypeFont verdBig; protected: // protected methods void testsFinished(){ controlPanel->hide(); bottomPanel->hide(); newTestButton->hide(); vector<int> eData; eData.push_back(testController->getScoreRunningTotal()); eventLogger.logEvent(ALL_TESTS_COMPLETED, eData); // TODO set final score screen txt to testController->getScoreRunningTotal() finishPanel->show(); string user = eventLogger.getUsername(); stringstream s; s << "Experiment completed" << endl << endl << "You scored: " << testController->getScoreRunningTotal() << " well done " << user << endl << endl << "to retake test please close " << endl << endl << "the app and restart with username<num test>"; finishPanel->setText(s.str()); // get test app to do something... eventLogger.saveSessionToFile(); }; void setupNewTest(){ // get mapping for new test and make sure we have right controls and stuff Test newTest = testController->goToNextTest(); // V0.2 put details about what kind of test it is vector<int> eData; eData.push_back(newTest.isPractice()); eData.push_back(newTest.isWithHint()); eData.push_back(newTest.isMemoryTest()); eventLogger.logEvent(NEW_TEST, eData); vector<int> mappingIDsForChangeableParams = setSynthsUpForNewTest(newTest); vector<UIElement*> UIElemHandles = controlPanel->generateControls(testController->getCurrentListOfControls(), testController->getCurrentPanelType()); mapUIToNewTestParams(UIElemHandles, mappingIDsForChangeableParams); countdownPanel->setTestTypeString(newTest.getTestTypeAdvanceWarning()); }; void startNewTest(){ Test t = testController->getCurrentTest(); countdownPanel->hide(); controlPanel->show(); controlPanel->setActive(true); if(t.isWithHint()){ controlPanel->showHint(true); } bottomPanel->show(); targetPlayButton->show(); // incase it was memory test if (t.isMemoryTest()){ targetPlayButton->setLabel("Memorise!"); }else{ targetPlayButton->setLabel("Target"); } timeController.startStopwatch(); eventLogger.logEvent(TEST_TIMER_STARTED); if(t.getListOfControlTypes()[0] == LEAP3D){ okToGetLeapMidi = true; } }; vector<int> setSynthsUpForNewTest(Test newTest){ targetSynth.setAllParams(newTest.getTargetValues()); eventLogger.logEvent(TARGET_PARAM_SET, newTest.getTargetValues()); // unless something goes wrong in setAllParams candidateSynth.setAllParams(newTest.getStartingCandidateValues()); eventLogger.logEvent(CANDIDATE_PARAM_SET,newTest.getStartingCandidateValues()); vector<int> mids = candidateSynth.getMappingIDForIndices(newTest.getChangeableIndices()); eventLogger.logEvent(CANDIDATE_CHANGEABLE_IDX, newTest.getChangeableIndices()); eventLogger.logEvent(CANDIDATE_MAPPING_IDS, mids); return mids; }; // could have been cleverer. takes forever due to searching ??? void mapUIToNewTestParams(vector<UIElement*> elems, vector<int> mids){ vector<UIElement*>::iterator elit; vector<int> typeListLog; int i = 0; for(elit=elems.begin(); elit<elems.end();elit++){ if ( (*elit)->getType() == XYPAD){ if(i+1 >= mids.size()){ cout << "ERROR ERROR: too many controls for mapping IDs" << endl; } ButtronXY* theXY = (ButtronXY*)(*elit); mapXYToParams(theXY, mids[i], mids[i+1]); theXY->setValueAndScale(candidateSynth.getParamValueForID(mids[i]), candidateSynth.getParamValueForID(mids[i+1])); theXY->setHintValue(targetSynth.getParamValueFromName(candidateSynth.getNameForMappingID(mids[i])) ,targetSynth.getParamValueFromName(candidateSynth.getNameForMappingID(mids[i+1]))); i+=2; typeListLog.push_back(int(XYPAD)); }else if ( (*elit)->getType() == SLIDER){ if(i >= mids.size()){ cout << "ERROR ERROR: too many controls for mapping IDs: " << mids.size() << endl; } ButtronSlider* theSlider = (ButtronSlider*)(*elit); mapControlToParam((*elit), mids[i]); theSlider->setValueAndScale(candidateSynth.getParamValueForID(mids[i])); cout << "Hint Value " << targetSynth.getParamValueFromName(candidateSynth.getNameForMappingID(mids[i])) << endl; theSlider->setHintValue(targetSynth.getParamValueFromName(candidateSynth.getNameForMappingID(mids[i]))); i++; typeListLog.push_back(int(SLIDER)); }else if ( (*elit)->getType() == LEAP3D ){ set3Dbox((Leap3DBoxGL*)(*elit)); // UH string nameX = candidateSynth.getNameForMappingID(mids[i]); box3D->setHintValue(0,targetSynth.getParamValueFromName(nameX)); box3D->setValueAndScale(0, candidateSynth.getParamValueForID(mids[i])); i++; string nameY = candidateSynth.getNameForMappingID(mids[i]); box3D->setHintValue(1,targetSynth.getParamValueFromName(nameY)); box3D->setValueAndScale(1, candidateSynth.getParamValueForID(mids[i])); i++; string nameZ = candidateSynth.getNameForMappingID(mids[i]); box3D->setHintValue(2,targetSynth.getParamValueFromName(nameZ)); box3D->setValueAndScale(2, candidateSynth.getParamValueForID(mids[i])); i++; box3D->setLabels(nameX,nameY,nameZ); typeListLog.push_back(int(LEAP3D)); }else{ cout << "ERROR ERROR SEARCHMSGORG: ui type not handled my mapping function !" << endl; } } eventLogger.logEvent(CONTROL_LIST,typeListLog); }; // TODO - no, triggering playback needs to be logged void startAlternatingPlayback(){ cout << "start alt playback" << endl; // use our special timer to fire off play to pd // sets off timed alternating playback playAlternating(); playingAlternating = true; }; void stopAlternatingPlayback(){ cout << "stop alt playback" << endl; // kill the alternation timeController.cancelEvent(currentSoundPlayTimer); playingAlternating = false; }; void playAlternating(){ static bool alt; int nextTime; if (alt){ targetSynth.trigger(); // flash the target thingy targetSymbol->flash(); nextTime = alternationSpeed*1.503; // gap after target }else{ sendSynthValuesAgain(); // and again and again candidateSynth.trigger(); controlPanel->flash(); nextTime = alternationSpeed; } alt = !alt; candidateSynth.setNoteLength(alternationSpeed); targetSynth.setNoteLength(alternationSpeed); // could be user alterable currentSoundPlayTimer = timeController.scheduleEvent(boost::bind(&SearchMessageOrganiser::playAlternating,this), nextTime); }; void delayedShowNewTest(){ newTestButton->show(); // JUST IN CASE IT CRASHES near end... //eventLogger.saveSessionToFile(); }; void submitSingleControl(){ // if last one // submitPressed() // else // grey out that slider, // activate next slider and show it's button (same button but moved!???) }; void submitPressed(){ // depending on mode go to next control // if(testController->getCurrentPanelType() == SEQUENTIAL){ // submitSingleControl(); // return; // } // otherwise do this other - or call okToGetLeapMidi = false; TimerMillisec timeTaken = timeController.stopStopwatch(); vector<int> answer = candidateSynth.getAllParamValues(); eventLogger.logEvent(SUBMIT_PRESSED, answer); //, answer, scoreRunningTotal, time taken (why not?)); TestResult result = testController->submitAnswer(answer, timeTaken); // TODO returns all the results vector<int> logResult; logResult.push_back(result.realDistanceToTarget*1000); // measured in milliCC !??! logResult.push_back(result.timeTaken); // milliseconds logResult.push_back(result.score); logResult.push_back(result.targetBandHit); logResult.push_back(result.timeWindowHit); eventLogger.logEvent(DISTANCE_TIME_SCORE, logResult); // gui stuff - different controller? controlPanel->setActive(false); controlPanel->showHint(true); // add some encouraging feedback to hint bottomPanel->hide(); showScoreForTest(result); stopAlternatingPlayback(); // was it the final sumbit? if(testController->isLastTest()){ // thats it - show a final score screen etc timeController.scheduleEvent(boost::bind(&SearchMessageOrganiser::testsFinished, this), 500); return; }else{ timeController.scheduleEvent(boost::bind(&SearchMessageOrganiser::delayedShowNewTest, this), 300); } }; void showScoreForTest(TestResult result){ scorePanel->setText(result.displayText); scorePanel->show(); ofColor c; if(result.targetBandHit == 1){ // yellow red blue c = ofColor(255,255,0,255); }else if(result.targetBandHit == 2){ c = ofColor(255,0,0,255); }else if(result.targetBandHit == 3){ c = ofColor(45,45,255,255); }else if(result.targetBandHit == 4){ c = ofColor(0,255,0,255); }else{ c = ofColor(150,235,200,255); } scorePanel->setColor(c); controlPanel->setHintColor(c); }; TimeController altPlaybackController; TestController* testController; Buttron* newTestButton; //Buttron* submitButton; Buttron* targetPlayButton; // so we can hide target in memory test. this pointer stuff is getting out of hand CountdownText* countdownPanel; TargetSymbol* targetSymbol; Leap3DBoxGL* box3D; TextPanel* scorePanel; TextPanel* finishPanel; //int scoreRunningTotal; TimerID currentSoundPlayTimer; int alternationSpeed; // ms between cand and target bool playingAlternating; bool okToGetLeapMidi; }; #endif /* defined(__riftathon__SearchMessageOrganiser__) */