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