00001 /*!@file AppPsycho/psycho-msc.C Psychophysics test to measure the influence of eyemovement on memory task performance 00002 this is an new version of psycho-sc.C which supports words instead of characters for the memory task */ 00003 00004 // //////////////////////////////////////////////////////////////////// // 00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00006 // University of Southern California (USC) and the iLab at USC. // 00007 // See http://iLab.usc.edu for information about this project. // 00008 // //////////////////////////////////////////////////////////////////// // 00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00011 // in Visual Environments, and Applications'' by Christof Koch and // 00012 // Laurent Itti, California Institute of Technology, 2001 (patent // 00013 // pending; application number 09/912,225 filed July 23, 2001; see // 00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00015 // //////////////////////////////////////////////////////////////////// // 00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00017 // // 00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00019 // redistribute it and/or modify it under the terms of the GNU General // 00020 // Public License as published by the Free Software Foundation; either // 00021 // version 2 of the License, or (at your option) any later version. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00026 // PURPOSE. See the GNU General Public License for more details. // 00027 // // 00028 // You should have received a copy of the GNU General Public License // 00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00031 // Boston, MA 02111-1307 USA. // 00032 // //////////////////////////////////////////////////////////////////// // 00033 // 00034 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppPsycho/psycho-msc.C $ 00036 // $Id: psycho-msc.C 12962 2010-03-06 02:13:53Z irock $ 00037 // 00038 00039 #include "Component/ModelManager.H" 00040 #include "Image/Image.H" 00041 #include "Psycho/PsychoDisplay.H" 00042 #include "Psycho/EyeTrackerConfigurator.H" 00043 #include "Psycho/EyeTracker.H" 00044 #include "Psycho/PsychoOpts.H" 00045 #include "Component/EventLog.H" 00046 #include "Component/ComponentOpts.H" 00047 #include "Raster/Raster.H" 00048 #include "Util/MathFunctions.H" 00049 #include "Util/Types.H" 00050 #include "GameBoard/basic-graphics.H" 00051 #include <sys/types.h> 00052 #include <dirent.h> 00053 #include <errno.h> 00054 #include <vector> 00055 #include <string> 00056 #include <iostream> 00057 #include <SDL/SDL.h> 00058 #include <SDL/SDL_image.h> 00059 #include <SDL/SDL_mixer.h> 00060 #include <stdio.h> 00061 #include <stdlib.h> 00062 #include <sstream> 00063 #include <time.h> 00064 #include "Image/DrawOps.H" 00065 #include "GameBoard/resize.h" 00066 #include <iostream> 00067 #include <fstream> 00068 #include <set> 00069 #include <algorithm> 00070 #include <ctime> 00071 00072 #ifndef INVT_HAVE_LIBSDL_IMAGE 00073 #include <cstdio> 00074 int main() 00075 { 00076 fprintf(stderr, "The SDL_image library must be installed to use this program\n"); 00077 return 1; 00078 } 00079 00080 #else 00081 00082 00083 00084 using namespace std; 00085 00086 // ###################################################################### 00087 00088 ModelManager manager("Psycho-Concurrent-Digit"); 00089 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager)); 00090 map<uint,uint> testMap ; 00091 map<string,string> argMap ; 00092 map<string,vector<SDL_Rect*>*> clipsmap; 00093 00094 ////////////////////////////////////////////// 00095 // a functionf for stringigying things 00096 ////////////////////////////////////////////// 00097 template <class T> std::string stringify(T i) 00098 { 00099 ostringstream o ; 00100 o << i ; 00101 return o.str(); 00102 } 00103 00104 00105 double getAvarage(vector<long> v){ 00106 double f = 0.0 ; 00107 for( uint i = 0 ; i < v.size() ; i++ ){ 00108 f += v[i] ; 00109 } 00110 if (v.size()!=0) return f/v.size() ; 00111 return -1 ; 00112 } 00113 00114 double getVariance(vector<long> v){ 00115 double m = getAvarage(v); 00116 double var = 0.0 ; 00117 for( uint i = 0 ; i < v.size(); i++ ){ 00118 var += (v[i]-m)*(v[i]-m) ; 00119 } 00120 if (v.size()!=0) return var/v.size() ; 00121 return -1 ; 00122 } 00123 00124 bool itIsInThere(int x , vector<int> bag){ 00125 for( uint i=0 ; i < bag.size(); i++ ){ 00126 if(x == bag[i]) return true ; 00127 } 00128 return false ; 00129 } 00130 00131 00132 string get0321(string s){ 00133 string t = ""; 00134 t = s.substr(0,1)+s.substr(3,1)+s.substr(2,1)+s.substr(1,1); 00135 return t ; 00136 } 00137 00138 string get1230(string s){ 00139 string t = ""; 00140 t = s.substr(1,1)+s.substr(2,1)+s.substr(3,1)+s.substr(0,1); 00141 return t ; 00142 } 00143 00144 string get3012(string s){ 00145 string t = ""; 00146 t = s.substr(3,1)+s.substr(0,1)+s.substr(1,1)+s.substr(2,1); 00147 return t ; 00148 } 00149 00150 string get2103(string s){ 00151 string t = ""; 00152 t = s.substr(2,1)+s.substr(1,1)+s.substr(0,1)+s.substr(3,1); 00153 return t ; 00154 } 00155 00156 string get34012(string s){ 00157 string t = ""; 00158 t = s.substr(3,1)+s.substr(4,1)+s.substr(0,1)+s.substr(1,1)+s.substr(2,1); 00159 return t ; 00160 } 00161 00162 string get21043(string s){ 00163 string t = ""; 00164 t = s.substr(2,1)+s.substr(1,1)+s.substr(0,1)+s.substr(4,1)+s.substr(3,1); 00165 return t ; 00166 } 00167 00168 string get41230(string s){ 00169 string t = ""; 00170 t = s.substr(4,1)+s.substr(1,1)+s.substr(2,1)+s.substr(3,1)+s.substr(0,1); 00171 return t ; 00172 } 00173 00174 string get03214(string s){ 00175 string t = ""; 00176 t = s.substr(0,1)+s.substr(3,1)+s.substr(2,1)+s.substr(1,1)+s.substr(4,1); 00177 return t ; 00178 } 00179 00180 string get42130(string s){ 00181 string t=""; 00182 t = s.substr(4,1)+s.substr(2,1)+s.substr(1,1)+s.substr(3,1)+s.substr(0,1); 00183 return t ; 00184 } 00185 00186 00187 string get03124(string s){ 00188 string t = "" ; 00189 t = s.substr(0,1)+s.substr(3,1)+s.substr(1,2)+s.substr(2,1)+s.substr(4,1); 00190 return t ; 00191 } 00192 //////////////////////////////////////////////////////////////////// 00193 //// gets a string as the argument and returns a string composed of 00194 //// characters of the first string sorted in the ascending order 00195 /////////////////////////////////////////////////////////////////// 00196 string ascSort(string st) 00197 { 00198 string res = "" ; 00199 vector<string> v = vector<string>(); 00200 for(uint i = 0 ; i < st.size() ; i++) v.push_back(st.substr(i,1)) ; 00201 00202 std::sort(v.begin(), v.end()); 00203 00204 for ( uint i = 0 ; i < v.size() ; i++ ){ 00205 res += v[i] ; 00206 } 00207 return res; 00208 } 00209 00210 00211 00212 //////////////////////////////////////////////////////////////////// 00213 //// gets a string as the argument and returns a string composed of 00214 //// characters of the first string sorted in the descending order 00215 /////////////////////////////////////////////////////////////////// 00216 string desSort(string st) 00217 { 00218 string res = "" ; 00219 vector<string> v = vector<string>(); 00220 for(uint i = 0 ; i < st.size() ; i++) v.push_back(st.substr(i,1)) ; 00221 std::sort(v.begin(), v.end()); 00222 std::reverse(v.begin(), v.end()); 00223 for ( uint i = 0 ; i < v.size() ; i++ ){ 00224 res += v[i] ; 00225 } 00226 return res; 00227 } 00228 00229 00230 00231 00232 00233 //////////////////////////////////////////////////////// 00234 ///// simply generates a sequence of digits with given alphabet with length of l with given threshold, if the given threshold is not achieved the best answer with 00235 //highest metric value in 1000000 times try will be returned 00236 //////////////////////////////////////////////////////// 00237 00238 string getARandomString(uint l, string alphabet="0123456789"){ 00239 00240 string test = string("") ; 00241 test = "" ; 00242 string tp = string("") ; 00243 vector<int> pickedones = vector<int>() ; 00244 for(uint i = 0 ; i < l ; i++){ 00245 int nd; 00246 do{ nd= rand()% alphabet.size() ; }while(itIsInThere(nd,pickedones) && pickedones.size() <= alphabet.size()) ; 00247 pickedones.push_back(nd); 00248 tp = alphabet.substr(nd,1) ; 00249 test += tp ; 00250 } 00251 00252 return test ; 00253 } 00254 00255 /////////////////////////////////////////////////////// 00256 //this function is not called in this program, but it generates a random string and it will show it in 00257 //a random place on the screen. 00258 ////////////////////////////////////////////////////// 00259 string digitMemorizationTask(uint l, string alphabet="0123456789" , int displayFrame = 10 ){ 00260 d->clearScreen() ; 00261 vector<int> pickedones = vector<int>() ; 00262 string test = string("") ; 00263 string tp = string("") ; 00264 for(uint i = 0 ; i < l ; i++){ 00265 int nd; 00266 do{ nd= rand()% alphabet.size() ; }while(itIsInThere(nd,pickedones) && pickedones.size() <= alphabet.size()) ; 00267 pickedones.push_back(nd); 00268 tp = alphabet.substr(nd,1) ; 00269 test += tp ; 00270 } 00271 d->displayText(test,true,0) ; 00272 d->waitFrames(displayFrame) ; 00273 d->clearScreen() ; 00274 return test ; 00275 } 00276 00277 00278 //////////////////////////////////////////////////////// 00279 ///////this will change the order of elements in a vector to a random order 00280 //////////////////////////////////////////////////////// 00281 void scramble(vector<string>& v){ 00282 vector<string> tv = vector<string>() ; 00283 while(v.size()>0){ 00284 tv.push_back(v[0]); 00285 v.erase(v.begin()); 00286 } 00287 int i = 0 ; 00288 while(tv.size()>0){ 00289 i = rand()%tv.size() ; 00290 v.push_back(tv[i]); 00291 tv.erase(tv.begin()+i); 00292 } 00293 } 00294 00295 void scramble(vector<int>& v){ 00296 vector<int> tv = vector<int>() ; 00297 while(v.size()>0){ 00298 tv.push_back(v[0]); 00299 v.erase(v.begin()); 00300 } 00301 int i = 0 ; 00302 while(tv.size()>0){ 00303 i = rand()%tv.size() ; 00304 v.push_back(tv[i]); 00305 tv.erase(tv.begin()+i); 00306 } 00307 } 00308 00309 string transformString(string pattern , vector<string>* wl, int white_space_distance){ 00310 string st; 00311 for( uint i = 0 ; i < pattern.size() ; i++ ){ 00312 int ind = atoi(pattern.substr(i,1).c_str()); 00313 st += wl->at(ind); 00314 if(i != pattern.size()-1){ 00315 for( int j = 0 ; j< white_space_distance ; j++){ 00316 st += " "; 00317 } 00318 } 00319 00320 } 00321 return st ; 00322 } 00323 00324 00325 //////////////////////////////////////////////////////////////// 00326 ////This is our button factory 00327 //////////////////////////////////////////////////////////////// 00328 SDL_Surface* getButtonImage(string label , PixRGB<byte> txtcolor=PixRGB<byte>(0,0,0) , PixRGB<byte> bgcolor=PixRGB<byte>(255,255,255) ,Point2D<int> size = Point2D<int>(100,100) ,PixRGB<byte> bordercolor=PixRGB<byte>(0,0,0) , int border=3){ 00329 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00330 textIm.clear(bgcolor); 00331 writeText(textIm, Point2D<int>((size.i - label.length()*10)/2,(size.j-20) /2),label.c_str(),txtcolor,bgcolor); 00332 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00333 Uint32 bc = d->getUint32color(bordercolor); 00334 drawRectangle(surf,bc,0,0,size.i -1,size.j -1 ,border); 00335 SDL_Surface* blank =getABlankSurface(size.i , size.j); 00336 SDL_Rect clip; 00337 clip.x = 0 ; 00338 clip.y = 0 ; 00339 clip.w = size.i ; 00340 clip.h = size.j ; 00341 apply_surface(0,0,*surf,*blank,clip); 00342 dumpSurface(surf) ; 00343 return blank ; 00344 } 00345 00346 //////////////////////////////////////////////////////////////////////// 00347 ////This is the function for creating the keypad, in fact it generates 00348 ////12 buttons and associates the actions to the region for each button 00349 //////////////////////////////////////////////////////////////////////// 00350 00351 SDL_Surface* getKeyPad(string alphabet,vector<string>* wl ,map<string , SDL_Rect>& buttmap){ 00352 SDL_Surface* pad= getABlankSurface(d->getWidth()/4,d->getHeight()/3); 00353 SDL_Rect clip; 00354 clip.x=0; 00355 clip.y=0; 00356 int numofrows = alphabet.size()/3 +1; 00357 if(alphabet.size()%3 != 0 ) numofrows++ ; 00358 int numofcolumns = 3 ; 00359 clip.w= pad->w / numofcolumns ; 00360 clip.h = pad->h / numofrows ; 00361 00362 //keys for 1 to 9 00363 for( int i = 0 ; i < numofrows*3 ; i++){ 00364 SDL_Surface* but ; 00365 if((uint)i < alphabet.size()){ 00366 but = getButtonImage(wl->at(i),PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / numofcolumns , pad->h / numofrows),PixRGB<byte>(255, 98 , 25),3); 00367 }else{ 00368 but = getButtonImage(" ",PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / numofcolumns , pad->h / numofrows),PixRGB<byte>(255, 98 , 25),3); 00369 } 00370 00371 SDL_Rect cl ; 00372 cl.x = ((i)%numofcolumns)*(pad->w)/numofcolumns ; cl.y= ((i)/numofcolumns)*((pad->h)/numofrows) ; 00373 cl.w = clip.w ; 00374 cl.h = clip.h ; 00375 apply_surface( cl.x , cl.y ,*but,*pad,clip); 00376 if((uint)i < alphabet.size()) buttmap[alphabet.substr(i,1)] = cl ; 00377 dumpSurface(but); 00378 } 00379 SDL_Rect cl1 ; 00380 cl1.x = 0 ; cl1.y= (numofrows-1)*((pad->h)/numofrows) ; 00381 cl1.w = clip.w ; 00382 cl1.h = clip.h ; 00383 buttmap["!"] = cl1 ; 00384 SDL_Surface* but = getButtonImage(string("<-"),PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / numofcolumns , pad->h / numofrows),PixRGB<byte>(255, 98 , 25),3); 00385 apply_surface(0, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00386 dumpSurface(but); 00387 SDL_Rect cl2 ; 00388 cl2.x = (pad->w)/numofcolumns ; cl2.y= (numofrows-1)*((pad->h)/numofrows) ; 00389 cl2.w = clip.w ; 00390 cl2.h = clip.h ; 00391 buttmap[" "] = cl2 ; 00392 but = getButtonImage(string("spc"),PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / numofcolumns , pad->h / numofrows),PixRGB<byte>(255, 98 , 25),3); 00393 apply_surface((pad->w)/numofcolumns, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00394 dumpSurface(but); 00395 SDL_Rect cl3 ; 00396 cl3.x = 2*(pad->w)/numofcolumns ; cl3.y= (numofrows-1)*((pad->h)/numofrows) ; 00397 cl3.w = clip.w ; 00398 cl3.h = clip.h ; 00399 buttmap["*"] = cl3 ; 00400 but = getButtonImage(string("Ok"),PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / numofcolumns , pad->h / numofrows),PixRGB<byte>(255, 98 , 25),3); 00401 apply_surface(2*(pad->w)/numofcolumns, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00402 dumpSurface(but); 00403 return pad ; 00404 } 00405 00406 00407 00408 00409 /////////////////////////////////////////////////////////////////////////// 00410 /////this function listens to mouse clicks and then finds the region of the screen 00411 /////associated with the action, buttmap is the map of the region, offset is the offset of 00412 /////buttons 00413 /////////////////////////////////////////////////////////////////////////// 00414 string getPressedButtonCommand(map<string , SDL_Rect>& buttmap,Point2D<int> offset=Point2D<int>(0,0)){ 00415 int quit = 0 ; 00416 string s ; 00417 SDL_Event event ; 00418 while( quit!=2 ){ 00419 while( SDL_PollEvent( &event ) ) { 00420 if(event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT ){ 00421 for( map<string , SDL_Rect>::iterator it = buttmap.begin() ; it!=buttmap.end() ; ++it){ 00422 if(event.button.x >= (it->second).x + offset.i && event.button.x <= (it->second).x + (it->second).w + offset.i && event.button.y >= (it->second).y+ offset.j && event.button.y <= (it->second).y + (it->second).h + offset.j) { 00423 quit = 2 ; 00424 s = it->first ; 00425 break; 00426 } 00427 00428 } 00429 } 00430 00431 } 00432 } 00433 return s ; 00434 00435 } 00436 00437 00438 //////////////////////////////////////////////////// 00439 ////This function creates a virtual keypad, creates a map of buttons 00440 ////and their representation area and listens to the button press and at 00441 ////the end returns the keyed digits 00442 //////////////////////////////////////////////////// 00443 string getDigitSequenceFromSubject(string alphabet,vector<string>* wl , uint maxl ){ 00444 d->showCursor(true) ; 00445 //let's creat a map to map actions to regions of the screen, each region is represented as an SDL_Rect 00446 map<string , SDL_Rect>* buttmap = new map<string , SDL_Rect>(); 00447 //now let's get the keypad surface while we get the actions map to regions 00448 SDL_Surface * keypad = getKeyPad(alphabet,wl,*buttmap); 00449 //this will be the offset of displaying the keypad on the screen 00450 SDL_Rect offset ; 00451 offset.x = (d->getWidth() - keypad->w) /2; 00452 offset.y = (d-> getHeight() - keypad->h) /2; 00453 //now let's display the keypad 00454 d->displaySDLSurfacePatch(keypad , &offset,NULL , -2,false, true); 00455 //this will hold the final string keyed be the subject 00456 string p = string("") ; 00457 //this is a temporary string holding the last action related to the pressed key 00458 string tp = string(""); 00459 //now let's record subject's key press 00460 while( tp.compare("*")!=0 ){ 00461 //this button is actually the display for the current string 00462 SDL_Surface* dp = getButtonImage(transformString(p,wl,1) ,PixRGB<byte>(195,60,12) ,PixRGB<byte>(255,255,255) ,Point2D<int>(d->getWidth()/2,d->getHeight() /15) ,PixRGB<byte>(0,25,180) , 4) ; 00463 SDL_Rect offs ; offs.x = (d->getWidth() - dp->w) /2 ; offs.y = d->getHeight()/6 ; 00464 d->displaySDLSurfacePatch(dp , &offs , NULL , -2 , false ,true ) ; 00465 //now let's listen to button events 00466 tp = getPressedButtonCommand(*buttmap,Point2D<int>(offset.x,offset.y)) ; 00467 dumpSurface(dp) ; 00468 if(tp.compare("!")==0 && p.size()>=0 ) { 00469 if (p.size()>0) p = p.substr(0,p.size()-1) ; 00470 }else{ 00471 if(p.size() < maxl && tp.compare("*")!=0) { 00472 p +=tp ; 00473 } 00474 00475 } 00476 00477 } 00478 buttmap = 0 ; 00479 dumpSurface(keypad) ; 00480 d->clearScreen() ; 00481 return p ; 00482 00483 } 00484 00485 00486 00487 /////////////////////////////////////////////////////////////// 00488 //////gets the test string, answer and the mode and identifies if 00489 //////the answer matches the thing it should be, mode=0 checks if 00490 //////if the answer and test string simply the same, mode=1 matches 00491 //////the answer against the ascending sorted string of the test string 00492 //////mode=2 compares the answer against the descending sorted of 00493 //////the test string 00494 /////////////////////////////////////////////////////////////// 00495 bool isAnswerCorrect(string test , string answer , int mode){ 00496 00497 if(mode == 0 && answer.compare(test)==0) return true ; 00498 00499 if(mode == 1 && answer.compare(ascSort(test))==0) return true ; 00500 00501 if(mode == 2 && answer.compare(desSort(test))==0) return true ; 00502 00503 return false; 00504 } 00505 00506 00507 00508 int addArgument(const string st,const string delim="="){ 00509 int i = st.find(delim) ; 00510 argMap[st.substr(0,i)] = st.substr(i+1); 00511 00512 return 0 ; 00513 } 00514 00515 std::string getArgumentValue(string arg){ 00516 return argMap[arg] ; 00517 } 00518 00519 std::string getUsageComment(){ 00520 00521 string com = string("\nlist of arguments : \n"); 00522 00523 com += "\nlogfile=[logfilename.psy] {default = psycho-stroop-concurrent.psy}\n" ; 00524 com += "\nmemo=[a_string_without_white_space]\n"; 00525 com += "\nstring-size=[>0](the size of string){default=4} \n"; 00526 com += "\nsubject=[subject_name] \n" ; 00527 com += "\nnum-of-sorting-trials=[>1](number of trials){default=10}\n"; 00528 com += "\nnum-of-mem-trials=[>1](number of trials){default=10}\n"; 00529 com += "\nstimulus-onset=[>1] (number of frames that the string will remain onset ){default=60}\n"; 00530 com += "\nalphabet=[a string of characters](a string of characters){default=0123456789}\n"; 00531 com += "\nmode=[1,2](1 for displaying the whole string, 2 displaying one character at a time ){default=1}\n"; 00532 com += "\ncue-wait-frames=[<0](number of frames to show the cue){default=0}\n"; 00533 com += "\nmask=[y/n](whether present a mask after presentation, n for no, y for yes ){default=n}\n" ; 00534 com += "\nmask-onset-frames=[<0](number of frames that mask will be onset){default=0}\n"; 00535 com += "\nwhite-space=[>0](the distance between digits in number of space characters){default=5}\n" ; 00536 com += "\ncue-type=[a/v](a for audio v for visual){default=v}\n"; 00537 com += "\nsound-dir=[path to wav files directory]{default=..}\n"; 00538 com += "\nwords-file=[path to a text file that has words one in each line]{default=./words1.txt}\n"; 00539 com += "\nrefresh-calibration=[y/n] {default=n}\n"; 00540 00541 return com ; 00542 } 00543 00544 00545 void displayWholeNumber(string s , int onsetTime , int wsd){ 00546 int x = (d->getWidth()-s.size()*wsd)/2 ; 00547 int y = (d->getHeight())/2 -10; 00548 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00549 textIm.clear(PixRGB<byte>(128,128,128)); 00550 for( uint k = 0 ; k < s.size() ; k++ ){ 00551 // d->displayText(s.substr(k,1),Point2D<int>(x,y+k*10),PixRGB<byte>(0,0,0),PixRGB<byte>(128,128,128),true) ; 00552 writeText(textIm, Point2D<int>(x+k*wsd,y),s.substr(k,1).c_str(),PixRGB<byte>(0,0,0),PixRGB<byte>(128,128,128)); 00553 } 00554 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00555 SDL_Rect offs ; offs.x = 0 ; offs.y = 0 ; 00556 d->displaySDLSurfacePatch(surf , &offs , NULL , -2 , false ,true ) ; 00557 dumpSurface(surf); 00558 d->waitFrames(onsetTime); 00559 d->clearScreen() ; 00560 } 00561 00562 void displayHorizontal(string s , int onsetTime){ 00563 int wsd=10 ; 00564 int x = (d->getWidth()-s.size()*wsd)/2 ; 00565 int y = (d->getHeight())/2 -10; 00566 d->displayText(s,Point2D<int>(x,y),PixRGB<byte>(0,0,0),PixRGB<byte>(128,128,128),true) ; 00567 d->waitFrames(onsetTime); 00568 d->clearScreen() ; 00569 } 00570 00571 00572 00573 00574 00575 00576 void displayLinear(string s , int onsetTime){ 00577 int x = (d->getWidth()-s.size()*10)/2 ; 00578 int y = d->getHeight()/2 - 10; 00579 for( uint k = 0 ; k < s.size() ; k++ ){ 00580 d->displayText(s.substr(k,1),Point2D<int>(x+k*10,y),PixRGB<byte>(0,0,0),PixRGB<byte>(128,128,128),true) ; 00581 d->waitFrames(onsetTime); 00582 d->clearScreen() ; 00583 } 00584 } 00585 00586 00587 00588 00589 //and this is the function which creates and displays a mask of randomly positioned numbers 00590 void showMask(int frames, string alphabet){ 00591 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00592 PixRGB<byte> bgcolor = PixRGB<byte>(128,128,128); 00593 PixRGB<byte> txtcolor = PixRGB<byte>(0,0,0); 00594 textIm.clear(bgcolor); 00595 for(int i = 0 ; i < 800 ; i++) 00596 writeText(textIm, Point2D<int>((int)random()%(d->getWidth()),(int)random()%(d->getHeight())),alphabet.substr(random()%(int)alphabet.size(),1).c_str(),txtcolor,bgcolor); 00597 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00598 SDL_Rect offs ; offs.x = 0 ; offs.y = 0 ; 00599 d->displaySDLSurfacePatch(surf , &offs , NULL , -2 , false ,true ) ; 00600 d->waitFrames(frames) ; 00601 d->clearScreen(); 00602 dumpSurface(surf) ; 00603 } 00604 00605 vector<string> getARandomArray(uint l, vector<string>* wl){ 00606 vector<string> testArray; 00607 vector<int> pickedones = vector<int>() ; 00608 for(uint i = 0 ; i < l ; i++){ 00609 int nd; 00610 do{ nd= rand()% wl->size() ; }while(itIsInThere(nd,pickedones)) ; 00611 pickedones.push_back(nd); 00612 testArray.push_back(wl->at(nd)); 00613 } 00614 return testArray ; 00615 } 00616 00617 00618 int readWordFile(const char* filename, vector<string>* wl){ 00619 ifstream inFile(filename, ios::in); 00620 if (! inFile) 00621 { 00622 return -1; 00623 } 00624 00625 char ch[1000]; 00626 while (inFile.getline(ch , 500)){ 00627 string line = ch; 00628 LINFO("profile reader reads : '%s'...", line.c_str()); 00629 wl->push_back(line); 00630 } 00631 00632 return 0 ; 00633 } 00634 00635 00636 00637 string switch_neighbors(string s){ 00638 string os ; 00639 uint p = random()%(s.size()-1); 00640 if(p < s.size()-2){ 00641 os = s.substr(0,p)+s.substr(p+1,1)+s.substr(p,1)+s.substr(p+2) ; 00642 }else{ 00643 os = s.substr(0,p)+s.substr(p+1,1)+s.substr(p,1) ; 00644 } 00645 00646 00647 return os ; 00648 } 00649 00650 string replaceOne(string s,string alphabet="0123456789"){ 00651 vector<int> pickedones ; 00652 for( uint i = 0 ; i < s.size() ;i++ ){ 00653 pickedones.push_back(atoi(s.substr(i,1).c_str())); 00654 } 00655 int nd; 00656 do{ nd= rand()% alphabet.size() ; }while(itIsInThere(nd,pickedones)); 00657 string os; 00658 os = stringify(nd); 00659 os += s.substr(1); 00660 return os ; 00661 } 00662 00663 extern "C" int main(const int argc, char** argv) 00664 { 00665 00666 MYLOGVERB = LOG_INFO; // suppress debug messages 00667 //let's push the initial value for the parameters 00668 argMap["experiment"]="working memory single task - sorting"; 00669 argMap["logfile"]="psycho-sorting-const.psy" ; 00670 argMap["string-size"]="4" ; 00671 argMap["subject"]="" ; 00672 argMap["memo"]="" ; 00673 argMap["stimulus-onset"]="60" ; 00674 argMap["challenge-onset"]="20" ; 00675 argMap["alphabet"]="0123456789"; 00676 argMap["mode"]="1" ; 00677 argMap["cue-wait-frames"]="0" ; 00678 argMap["mask"]="n" ; 00679 argMap["cue-onset-frames"] = "3" ; 00680 argMap["white-space"] = "5" ; 00681 argMap["cue-type"] = "v" ; 00682 argMap["sound-dir"]=".."; 00683 argMap["num-of-sorting-trials"] = "10" ; 00684 argMap["num-of-mem-trials"] = "10" ; 00685 argMap["words-file"]="./words1.txt"; 00686 argMap["refresh-calibration"]="n"; 00687 manager.addSubComponent(d); 00688 nub::soft_ref<EventLog> el(new EventLog(manager)); 00689 manager.addSubComponent(el); 00690 d->setEventLog(el); 00691 nub::soft_ref<EyeTrackerConfigurator> 00692 etc(new EyeTrackerConfigurator(manager)); 00693 manager.addSubComponent(etc); 00694 00695 if (manager.parseCommandLine(argc, argv, 00696 "at least one argument needed", 1, -1)==false){ 00697 cout<<getUsageComment()<<endl; 00698 return(1); 00699 } 00700 00701 for(uint i = 0 ; i < manager.numExtraArgs() ; i++){ 00702 addArgument(manager.getExtraArg(i),std::string("=")) ; 00703 } 00704 00705 manager.setOptionValString(&OPT_EventLogFileName, argMap["logfile"]); 00706 manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN"); 00707 nub::soft_ref<EyeTracker> eyet = etc->getET(); 00708 d->setEyeTracker(eyet); 00709 eyet->setEventLog(el); 00710 00711 00712 // let's get all our ModelComponent instances started: 00713 manager.start(); 00714 for(map<string,string>::iterator it= argMap.begin(); it!= argMap.end() ; ++it) d->pushEvent("arg:"+ it->first+" value:"+it->second ) ; 00715 // let's display an ISCAN calibration grid: 00716 d->clearScreen(); 00717 d->displayISCANcalib(); 00718 d->waitForMouseClick(); 00719 d->displayText("Here the experiment starts! click to start!"); 00720 d->waitForMouseClick(); 00721 d->clearScreen(); 00722 //let's see in what mode the user like to run the program 00723 int mode = atoi(argMap["mode"].c_str()); 00724 vector<long> correctAnswersTiming; 00725 vector<long> incorrectAnswersTiming; 00726 vector<long> allTiming ; 00727 vector<string>* wordsList = new vector<string>(); 00728 int correctMemory = 0 ; 00729 int incorrectMemory = 0 ; 00730 int stringSize = atoi(argMap["string-size"].c_str()); 00731 int onsetDel = atoi(argMap["stimulus-onset"].c_str()) ; 00732 //int ch_onsetDel = atoi(argMap["challenge-onset"].c_str()) ; 00733 int cue_wait_frames = atoi(argMap["cue-wait-frames"].c_str()) ; 00734 int mask_onset_frames = atoi(argMap["mask-onset-frames"].c_str()) ; 00735 int white_space_distance = atoi(argMap["white-space"].c_str()); 00736 int num_of_sorting_task = atoi(argMap["num-of-sorting-trials"].c_str()) ; 00737 int num_of_mem_task = atoi(argMap["num-of-mem-trials"].c_str()) ; 00738 string wordsFile = argMap["words-file"]; 00739 if(readWordFile(wordsFile.c_str(),wordsList)==-1) { 00740 cout<<"can\'t find the words file"; 00741 return(1); 00742 } 00743 00744 //let's do calibration 00745 d->displayText("CLICK LEFT button to calibrate; RIGHT to skip"); 00746 int cl = d->waitForMouseClick(); 00747 if (cl == 1) d->displayEyeTrackerCalibration(3,5,1 , true); 00748 d->clearScreen() ; 00749 00750 Mix_Music* recallCueMusic = NULL; 00751 Mix_Music* sortCueMusic = NULL; 00752 if(argMap["cue-type"].compare("a")==0){ 00753 //now let's open the audio channel 00754 if( Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 4096 ) == -1 ){ 00755 LINFO( "did not open the mix-audio") ; 00756 return -1 ; 00757 } 00758 00759 string str = argMap["sound-dir"]+"/recall.wav" ; 00760 recallCueMusic = Mix_LoadMUS(str.c_str()); 00761 str = argMap["sound-dir"]+"/sort.wav" ; 00762 sortCueMusic = Mix_LoadMUS(str.c_str()); 00763 } 00764 vector<int>* taskVector = new vector<int>(); 00765 for(int i = 0 ; i < (int)(num_of_sorting_task/4) ; i++) { 00766 taskVector->push_back(1); 00767 taskVector->push_back(2); 00768 taskVector->push_back(3); 00769 taskVector->push_back(4); 00770 //taskVector->push_back(5); 00771 //taskVector->push_back(6); 00772 00773 } 00774 for(int i = 0 ; i < num_of_mem_task ; i++) taskVector->push_back(0); 00775 scramble(*taskVector); 00776 for( int r = 0 ; (int)r < (int)taskVector->size() ; r++ ){ 00777 if(argMap["refresh-calibration"].compare("y")==0 && r ==(int)taskVector->size()/2){ 00778 d->displayText("STOP HERE AND STRETCH A little BIT!"); 00779 cl = d->waitForMouseClick(); 00780 d->displayText("Click if you are ready."); 00781 cl = d->waitForMouseClick(); 00782 //let's do calibration 00783 d->displayText("CLICK LEFT button to calibrate; RIGHT to skip"); 00784 cl = d->waitForMouseClick(); 00785 if (cl == 1) d->displayEyeTrackerCalibration(3,5,1 , true); 00786 d->clearScreen() ; 00787 00788 } 00789 00790 int task = taskVector->at(r) ; 00791 d->pushEvent("**************************************") ; 00792 d->showCursor(true); 00793 d->displayText("click one of the mouse buttons to start!"); 00794 d->waitForMouseClick() ; 00795 d->showCursor(false) ; 00796 string testString ; 00797 testString = getARandomString(stringSize, "0123456789"); 00798 if(stringSize == 5){ 00799 switch( task ){ 00800 case 1 : testString = get34012(ascSort(testString));break ; 00801 case 2 : testString = get21043(ascSort(testString));break ; 00802 case 3 : testString = get41230(ascSort(testString));break ; 00803 case 4 : testString = get03214(ascSort(testString));break ; 00804 case 5 : testString = get42130(ascSort(testString));break ; 00805 case 6 : testString = get03124(ascSort(testString));break ; 00806 } 00807 } 00808 if(stringSize == 4){ 00809 switch( task ){ 00810 case 1 : testString = get0321(ascSort(testString));break ; 00811 case 2 : testString = get1230(ascSort(testString));break ; 00812 case 3 : testString = get3012(ascSort(testString));break ; 00813 case 4 : testString = get2103(ascSort(testString));break ; 00814 } 00815 } 00816 00817 d->clearScreen() ; 00818 d->displayFixationBlink(); 00819 switch( mode ){ 00820 case 1 : displayHorizontal(transformString(testString,wordsList,white_space_distance),onsetDel);break ; 00821 case 2 : displayLinear(transformString(testString,wordsList,white_space_distance),onsetDel) ; break ; 00822 } 00823 if(argMap["mask"].compare("y")==0) showMask(mask_onset_frames,"abcdefghijklmnopqrstuvwxyz"); 00824 if(cue_wait_frames != 0) d->waitFrames(cue_wait_frames) ; 00825 d->displayFixation() ; 00826 if(argMap["cue-type"].compare("v")==0){ 00827 d->displayRedDotFixation(); 00828 }else{ 00829 if(task == 0){if( Mix_PlayMusic( recallCueMusic, 0 ) == -1 ) { return 1; } 00830 while( Mix_PlayingMusic() == 1 ){} 00831 }else{ 00832 if( Mix_PlayMusic( sortCueMusic, 0 ) == -1 ) { return 1; } 00833 while( Mix_PlayingMusic() == 1 ){} 00834 } 00835 00836 } 00837 00838 00839 d->clearScreen() ; 00840 string imst ; 00841 string chstr; 00842 if(task!=0){ 00843 imst= "===== Showing image: def_"+stringify(task)+"_"+testString+".png ====="; 00844 d->pushEvent("the sequence for operation is : "+testString) ; 00845 d->pushEvent(imst); 00846 eyet->track(true); 00847 d->waitForMouseClick(); 00848 eyet->track(false); 00849 d->pushEvent("task ends") ; 00850 string answer = getDigitSequenceFromSubject("0123456789",wordsList , stringSize); 00851 d->pushEvent("subject keyed : "+answer); 00852 if(answer.compare(ascSort(testString))==0){ 00853 d->pushEvent("answer was correct"); 00854 }else{ 00855 d->pushEvent("answer was incorrect"); 00856 } 00857 }else{ 00858 string answer = getDigitSequenceFromSubject("0123456789",wordsList , stringSize); 00859 d->pushEvent("subject keyed : "+answer); 00860 if(answer.compare(testString)==0){ 00861 d->pushEvent("recall was correct"); 00862 correctMemory++ ; 00863 }else{ 00864 d->pushEvent("recall was incorrect"); 00865 incorrectMemory++ ; 00866 } 00867 } 00868 /*if(task!=0){ 00869 imst= "===== Showing image: def_"+stringify(task)+"_"+testString+".png ====="; 00870 d->pushEvent("the sequence for operation is : "+testString) ; 00871 d->pushEvent(imst); 00872 eyet->track(true); 00873 d->waitForMouseClick(); 00874 eyet->track(false); 00875 d->pushEvent("task ends") ; 00876 int challenge = random()%2 ; 00877 00878 if(challenge == 0 ) { 00879 chstr = ascSort(testString); 00880 displayHorizontal(transformString(chstr,wordsList,white_space_distance),ch_onsetDel); 00881 }else{ 00882 chstr = ascSort(replaceOne(testString)); 00883 displayHorizontal(transformString(chstr,wordsList,white_space_distance),ch_onsetDel); 00884 } 00885 d->pushEvent("subject was challenged by "+chstr); 00886 string answer = getDigitSequenceFromSubject("0123456789",wordsList , stringSize); 00887 d->pushEvent("subject keyed : "+answer); 00888 if(answer.compare("Y")==0){ 00889 if(challenge==0){ 00890 d->pushEvent("answer was correct"); 00891 }else{ 00892 d->pushEvent("answer was incorrect"); 00893 } 00894 } 00895 if(answer.compare("N")==0){ 00896 if(challenge==1){ 00897 d->pushEvent("answer was correct"); 00898 }else{ 00899 d->pushEvent("answer was incorrect"); 00900 } 00901 } 00902 if(answer.compare("~")==0){ 00903 d->pushEvent("confused"); 00904 } 00905 }else{ 00906 d->pushEvent("the sequence for recall task is : "+testString) ; 00907 int challenge = random()%2 ; 00908 if(challenge == 0 ) { 00909 chstr = testString; 00910 displayHorizontal(transformString(chstr,wordsList,white_space_distance),ch_onsetDel); 00911 }else{ 00912 chstr = switch_neighbors(testString); 00913 displayHorizontal(transformString(chstr,wordsList,white_space_distance),ch_onsetDel); 00914 } 00915 d->pushEvent("subject was challenged by "+chstr); 00916 string answer = getDigitSequenceFromSubject("0123456789",wordsList , stringSize); 00917 d->pushEvent("subject keyed : "+answer); 00918 if(answer.compare("Y")==0){ 00919 if(challenge==0){ 00920 correctMemory++; 00921 d->pushEvent("answer was correct"); 00922 }else{ 00923 incorrectMemory++ ; 00924 d->pushEvent("answer was incorrect"); 00925 } 00926 } 00927 if(answer.compare("N")==0){ 00928 if(challenge==1){ 00929 correctMemory++; 00930 d->pushEvent("recall was correct"); 00931 }else{ 00932 d->pushEvent("recall was incorrect"); 00933 incorrectMemory++ ; 00934 } 00935 } 00936 if(answer.compare("~")==0){ 00937 d->pushEvent("confused"); 00938 incorrectMemory++ ; 00939 } 00940 }*/ 00941 00942 } 00943 d->pushEvent("number of correct memory recall : "+ stringify(correctMemory)) ; 00944 d->pushEvent("number of incorrect memory recall : "+ stringify(incorrectMemory)) ; 00945 d->clearScreen(); 00946 d->displayText("Experiment complete. Thank you!"); 00947 d->waitForMouseClick(); 00948 taskVector = 0 ; 00949 // stop all our ModelComponents 00950 manager.stop(); 00951 00952 00953 // all done! 00954 return 0; 00955 } 00956 00957 #endif // INVT_HAVE_LIBSDL_IMAGE 00958