00001 /*!@file AppPsycho/psycho-spatial-orientation-sorting.C Psychophysics test to measure the effect of executive tasks on spatial memory */ 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-spatial-memory.C $ 00035 // $Id: psycho-spatial-memory.C 13040 2010-03-23 03:59:25Z nnoori $ 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-Spatial-Orientation"); 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 ////////////////////////////////////////////// 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 //////////////////////////////////////////////////////////////////// 00133 //// gets a string as the argument and returns a string composed of 00134 //// characters of the first string sorted in the ascending order 00135 /////////////////////////////////////////////////////////////////// 00136 string ascSort(string st) 00137 { 00138 string res = "" ; 00139 vector<string> v = vector<string>(); 00140 for(uint i = 0 ; i < st.size() ; i++) v.push_back(st.substr(i,1)) ; 00141 00142 std::sort(v.begin(), v.end()); 00143 00144 for ( uint i = 0 ; i < v.size() ; i++ ){ 00145 res += v[i] ; 00146 } 00147 return res; 00148 } 00149 00150 00151 00152 //////////////////////////////////////////////////////////////////// 00153 //// gets a string as the argument and returns a string composed of 00154 //// characters of the first string sorted in the descending order 00155 /////////////////////////////////////////////////////////////////// 00156 string desSort(string st) 00157 { 00158 string res = "" ; 00159 vector<string> v = vector<string>(); 00160 for(uint i = 0 ; i < st.size() ; i++) v.push_back(st.substr(i,1)) ; 00161 std::sort(v.begin(), v.end()); 00162 std::reverse(v.begin(), v.end()); 00163 for ( uint i = 0 ; i < v.size() ; i++ ){ 00164 res += v[i] ; 00165 } 00166 return res; 00167 } 00168 00169 00170 //////////////////////////////////////////////////////// 00171 ///// simply generates a sequence of characters out of master string 00172 //////////////////////////////////////////////////////// 00173 00174 string getARandomString(uint l, string alphabet="0123456789" ){ 00175 00176 string test = string("") ; 00177 string retString ; 00178 test = "" ; 00179 string tp = string("") ; 00180 vector<int> pickedones = vector<int>() ; 00181 for(uint i = 0 ; i < l ; i++){ 00182 int nd; 00183 do{ nd= rand()% alphabet.size() ; }while(itIsInThere(nd,pickedones)) ; 00184 pickedones.push_back(nd); 00185 tp = alphabet.substr(nd,1) ; 00186 test += tp ; 00187 } 00188 retString = test ; 00189 return retString ; 00190 } 00191 00192 00193 00194 /////////////////////////////////////////////////////// 00195 //this function is not called in this program, but it generates a random string and it will show it in 00196 //a random place on the screen. 00197 ////////////////////////////////////////////////////// 00198 string digitMemorizationTask(uint l, string alphabet="0123456789" , int displayFrame = 10 ){ 00199 d->clearScreen() ; 00200 vector<int> pickedones = vector<int>() ; 00201 string test = string("") ; 00202 string tp = string("") ; 00203 for(uint i = 0 ; i < l ; i++){ 00204 int nd; 00205 do{ nd= rand()% alphabet.size() ; }while(itIsInThere(nd,pickedones) && pickedones.size() <= alphabet.size()) ; 00206 pickedones.push_back(nd); 00207 tp = alphabet.substr(nd,1) ; 00208 test += tp ; 00209 } 00210 d->displayText(test,true,0) ; 00211 d->waitFrames(displayFrame) ; 00212 d->clearScreen() ; 00213 return test ; 00214 } 00215 00216 00217 //////////////////////////////////////////////////////// 00218 ///////this will change the order of elements in a vector to a random order 00219 //////////////////////////////////////////////////////// 00220 void scramble(vector<string>& v){ 00221 vector<string> tv = vector<string>() ; 00222 while(v.size()>0){ 00223 tv.push_back(v[0]); 00224 v.erase(v.begin()); 00225 } 00226 int i = 0 ; 00227 while(tv.size()>0){ 00228 i = rand()%tv.size() ; 00229 v.push_back(tv[i]); 00230 tv.erase(tv.begin()+i); 00231 } 00232 } 00233 00234 void scramble(vector<int>& v){ 00235 vector<int> tv = vector<int>() ; 00236 while(v.size()>0){ 00237 tv.push_back(v[0]); 00238 v.erase(v.begin()); 00239 } 00240 int i = 0 ; 00241 while(tv.size()>0){ 00242 i = rand()%tv.size() ; 00243 v.push_back(tv[i]); 00244 tv.erase(tv.begin()+i); 00245 } 00246 } 00247 00248 //////////////////////////////////////////////////////////////// 00249 ////This is our button factory 00250 //////////////////////////////////////////////////////////////// 00251 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){ 00252 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00253 textIm.clear(bgcolor); 00254 writeText(textIm, Point2D<int>((size.i - label.length()*10)/2,(size.j-20) /2),label.c_str(),txtcolor,bgcolor); 00255 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00256 Uint32 bc = d->getUint32color(bordercolor); 00257 drawRectangle(surf,bc,0,0,size.i -1,size.j -1 ,border); 00258 SDL_Surface* blank =getABlankSurface(size.i , size.j); 00259 SDL_Rect clip; 00260 clip.x = 0 ; 00261 clip.y = 0 ; 00262 clip.w = size.i ; 00263 clip.h = size.j ; 00264 apply_surface(0,0,*surf,*blank,clip); 00265 dumpSurface(surf) ; 00266 return blank ; 00267 } 00268 00269 //////////////////////////////////////////////////////////////////////// 00270 ////This is the function for creating the keypad, in fact it generates 00271 ////12 buttons and associates the actions to the region for each button 00272 //////////////////////////////////////////////////////////////////////// 00273 00274 SDL_Surface* getKeyPad(string alphabet,map<string , SDL_Rect>& buttmap){ 00275 SDL_Surface* pad= getABlankSurface(d->getWidth()/4,d->getHeight()/3); 00276 SDL_Rect clip; 00277 clip.x=0; 00278 clip.y=0; 00279 int numofrows = alphabet.size()/3 +1; 00280 if(alphabet.size()%3 != 0 ) numofrows++ ; 00281 int numofcolumns = 3 ; 00282 clip.w= pad->w / numofcolumns ; 00283 clip.h = pad->h / numofrows ; 00284 00285 //keys for 1 to 9 00286 for( int i = 0 ; i < numofrows*3 ; i++){ 00287 SDL_Surface* but ; 00288 if((uint)i < alphabet.size()){ 00289 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); 00290 }else{ 00291 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); 00292 } 00293 00294 SDL_Rect cl ; 00295 cl.x = ((i)%numofcolumns)*(pad->w)/numofcolumns ; cl.y= ((i)/numofcolumns)*((pad->h)/numofrows) ; 00296 cl.w = clip.w ; 00297 cl.h = clip.h ; 00298 apply_surface( cl.x , cl.y ,*but,*pad,clip); 00299 if((uint)i < alphabet.size()) buttmap[alphabet.substr(i,1)] = cl ; 00300 dumpSurface(but); 00301 } 00302 SDL_Rect cl1 ; 00303 cl1.x = 0 ; cl1.y= (numofrows-1)*((pad->h)/numofrows) ; 00304 cl1.w = clip.w ; 00305 cl1.h = clip.h ; 00306 buttmap["!"] = cl1 ; 00307 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); 00308 apply_surface(0, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00309 dumpSurface(but); 00310 SDL_Rect cl2 ; 00311 cl2.x = (pad->w)/numofcolumns ; cl2.y= (numofrows-1)*((pad->h)/numofrows) ; 00312 cl2.w = clip.w ; 00313 cl2.h = clip.h ; 00314 buttmap[" "] = cl2 ; 00315 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); 00316 apply_surface((pad->w)/numofcolumns, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00317 dumpSurface(but); 00318 SDL_Rect cl3 ; 00319 cl3.x = 2*(pad->w)/numofcolumns ; cl3.y= (numofrows-1)*((pad->h)/numofrows) ; 00320 cl3.w = clip.w ; 00321 cl3.h = clip.h ; 00322 buttmap["*"] = cl3 ; 00323 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); 00324 apply_surface(2*(pad->w)/numofcolumns, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00325 dumpSurface(but); 00326 return pad ; 00327 } 00328 00329 00330 00331 00332 /////////////////////////////////////////////////////////////////////////// 00333 /////this function listens to mouse clicks and then finds the region of the screen 00334 /////associated with the action, buttmap is the map of the region, offset is the offset of 00335 /////buttons 00336 /////////////////////////////////////////////////////////////////////////// 00337 string getPressedButtonCommand(map<string , SDL_Rect>& buttmap,Point2D<int> offset=Point2D<int>(0,0)){ 00338 int quit = 0 ; 00339 string s ; 00340 SDL_Event event ; 00341 while( quit!=2 ){ 00342 while( SDL_PollEvent( &event ) ) { 00343 if(event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT ){ 00344 for( map<string , SDL_Rect>::iterator it = buttmap.begin() ; it!=buttmap.end() ; ++it){ 00345 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) { 00346 quit = 2 ; 00347 s = it->first ; 00348 break; 00349 } 00350 00351 } 00352 } 00353 00354 } 00355 } 00356 return s ; 00357 00358 } 00359 00360 00361 //////////////////////////////////////////////////// 00362 ////This function creates a virtual keypad, creates a map of buttons 00363 ////and their representation area and listens to the button press and at 00364 ////the end returns the keyed digits 00365 //////////////////////////////////////////////////// 00366 string getDigitSequenceFromSubject(string alphabet="0123456789" , uint maxl = 7 , string message=""){ 00367 d->showCursor(true) ; 00368 //let's creat a map to map actions to regions of the screen, each region is represented as an SDL_Rect 00369 map<string , SDL_Rect>* buttmap = new map<string , SDL_Rect>(); 00370 //now let's get the keypad surface while we get the actions map to regions 00371 SDL_Surface * keypad = getKeyPad(alphabet,*buttmap); 00372 //this will be the offset of displaying the keypad on the screen 00373 SDL_Rect offset ; 00374 offset.x = (d->getWidth() - keypad->w) /2; 00375 offset.y = (d-> getHeight() - keypad->h) /2; 00376 //d->displayText(message, Point2D<int>(d->getWidth()/3,d->getHeight()*2 /16) , PixRGB<byte>(0,0,0) ,PixRGB<byte>(127,127,127)) ; 00377 SDL_Surface* msgp = getButtonImage(message ,PixRGB<byte>(195,60,12) ,PixRGB<byte>(127,127,127) ,Point2D<int>(d->getWidth()/6,d->getHeight() /15) ,PixRGB<byte>(127,127,127) , 4) ; 00378 SDL_Rect msgoffs ; msgoffs.x = (d->getWidth() - msgp->w) /2 ; msgoffs.y = 2*d->getHeight()/9 ; 00379 d->displaySDLSurfacePatch(msgp , &msgoffs , NULL , -2 , false ,true ) ; 00380 dumpSurface(msgp) ; 00381 //now let's display the keypad 00382 d->displaySDLSurfacePatch(keypad , &offset,NULL , -2,false, true); 00383 //this will hold the final string keyed be the subject 00384 string p = string("") ; 00385 //this is a temporary string holding the last action related to the pressed key 00386 string tp = string(""); 00387 //now let's record subject's key press 00388 while( tp.compare("*")!=0 ){ 00389 //this button is actually the display for the current string 00390 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) ; 00391 SDL_Rect offs ; offs.x = (d->getWidth() - dp->w) /2 ; offs.y = d->getHeight()/6 ; 00392 d->displaySDLSurfacePatch(dp , &offs , NULL , -2 , false ,true ) ; 00393 //now let's listen to button events 00394 tp = getPressedButtonCommand(*buttmap,Point2D<int>(offset.x,offset.y)) ; 00395 dumpSurface(dp) ; 00396 if(tp.compare("!")==0 && p.size()>=0 ) { 00397 if (p.size()>0) p = p.substr(0,p.size()-1) ; 00398 }else{ 00399 if(p.size() < maxl && tp.compare("*")!=0) { 00400 p +=tp ; 00401 } 00402 00403 } 00404 00405 } 00406 00407 buttmap = 0 ; 00408 dumpSurface(keypad) ; 00409 d->clearScreen() ; 00410 return p ; 00411 00412 } 00413 00414 00415 00416 /////////////////////////////////////////////////////////////// 00417 //////gets the test string, answer and the mode and identifies if 00418 //////the answer matches the thing it should be, mode=0 checks if 00419 //////if the answer and test string simply the same, mode=1 matches 00420 //////the answer against the ascending sorted string of the test string 00421 //////mode=2 compares the answer against the descending sorted of 00422 //////the test string 00423 /////////////////////////////////////////////////////////////// 00424 bool isAnswerCorrect(string test , string answer , int mode){ 00425 00426 if(mode == 0 && answer.compare(test)==0) return true ; 00427 00428 if(mode == 1 && answer.compare(ascSort(test))==0) return true ; 00429 00430 if(mode == 2 && answer.compare(desSort(test))==0) return true ; 00431 00432 return false; 00433 } 00434 00435 00436 00437 int addArgument(const string st,const string delim="="){ 00438 int i = st.find(delim) ; 00439 argMap[st.substr(0,i)] = st.substr(i+1); 00440 00441 return 0 ; 00442 } 00443 00444 std::string getArgumentValue(string arg){ 00445 return argMap[arg] ; 00446 } 00447 00448 00449 void displayWholeNumber(string s , int onsetTime , int wsd){ 00450 int x = (d->getWidth()-s.size()*wsd)/2 ; 00451 int y = (d->getHeight())/2 -10; 00452 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00453 textIm.clear(PixRGB<byte>(128,128,128)); 00454 for( uint k = 0 ; k < s.size() ; k++ ){ 00455 // d->displayText(s.substr(k,1),Point2D<int>(x,y+k*10),PixRGB<byte>(0,0,0),PixRGB<byte>(128,128,128),true) ; 00456 writeText(textIm, Point2D<int>(x+k*wsd,y),s.substr(k,1).c_str(),PixRGB<byte>(0,0,0),PixRGB<byte>(128,128,128)); 00457 } 00458 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00459 SDL_Rect offs ; offs.x = 0 ; offs.y = 0 ; 00460 d->displaySDLSurfacePatch(surf , &offs , NULL , -2 , false ,true ) ; 00461 dumpSurface(surf); 00462 d->waitFrames(onsetTime); 00463 d->clearScreen() ; 00464 } 00465 00466 void displayWholeNumberVertically(string s , int onsetTime , int wsd){ 00467 int x = (d->getWidth())/2 ; 00468 int y = (d->getHeight()-s.size()*wsd)/2 ; 00469 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00470 textIm.clear(PixRGB<byte>(128,128,128)); 00471 for( uint k = 0 ; k < s.size() ; k++ ){ 00472 // d->displayText(s.substr(k,1),Point2D<int>(x,y+k*10),PixRGB<byte>(0,0,0),PixRGB<byte>(128,128,128),true) ; 00473 writeText(textIm, Point2D<int>(x,y+k*wsd),s.substr(k,1).c_str(),PixRGB<byte>(0,0,0),PixRGB<byte>(128,128,128)); 00474 } 00475 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00476 SDL_Rect offs ; offs.x = 0 ; offs.y = 0 ; 00477 d->displaySDLSurfacePatch(surf , &offs , NULL , -2 , false ,true ) ; 00478 dumpSurface(surf); 00479 d->waitFrames(onsetTime); 00480 d->clearScreen() ; 00481 } 00482 00483 void displayRandom(string s , int onsetTime){ 00484 for( uint k = 0 ; k < s.size() ; k++ ){ 00485 int x = 9*d->getWidth()/20 + rand()%(d->getWidth()/10); 00486 int y = 9*d->getHeight()/20 + rand()%(d->getHeight()/10) ; 00487 d->displayText(s.substr(k,1),Point2D<int>(x,y),PixRGB<byte>(0,0,0),PixRGB<byte>(128,128,128),true) ; 00488 d->waitFrames(onsetTime); 00489 d->clearScreen() ; 00490 } 00491 } 00492 00493 void displayLinear(string s , int onsetTime){ 00494 int x = (d->getWidth()-s.size()*40)/2 ; 00495 int y = d->getHeight()/2 - 10; 00496 for( uint k = 0 ; k < s.size() ; k++ ){ 00497 d->displayText(s.substr(k,1),Point2D<int>(x+k*40,y),PixRGB<byte>(0,0,0),PixRGB<byte>(128,128,128),true) ; 00498 d->waitFrames(onsetTime); 00499 d->clearScreen() ; 00500 } 00501 } 00502 00503 void displayLinearReverse(string s , int onsetTime){ 00504 int x = (d->getWidth()-s.size()*10)/2 ; 00505 int y = d->getHeight()/2 - 10; 00506 for( uint k = 0 ; k < s.size() ; k++ ){ 00507 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) ; 00508 d->waitFrames(onsetTime); 00509 d->clearScreen() ; 00510 } 00511 } 00512 void displayLinearRandom(string s , int onsetTime){ 00513 int x = (d->getWidth()-s.size()*10)/2 ; 00514 int y = d->getHeight()/2 - 10; 00515 for( uint k = 0 ; k < s.size() ; k++ ){ 00516 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) ; 00517 d->waitFrames(onsetTime); 00518 d->clearScreen() ; 00519 } 00520 } 00521 00522 void displayLinearRandomVertically(string s , int onsetTime){ 00523 int x = (d->getWidth())/2 ; 00524 int y = (d->getHeight()-s.size()*10)/2 - 10; 00525 for( uint k = 0 ; k < s.size() ; k++ ){ 00526 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) ; 00527 d->waitFrames(onsetTime); 00528 d->clearScreen() ; 00529 } 00530 } 00531 00532 void displayLinearRandomNoRepeating(string s , int onsetTime){ 00533 int x = (d->getWidth()-s.size()*10)/2 ; 00534 int y = d->getHeight()/2 - 10; 00535 for( uint k = 0 ; k < s.size() ; k++ ){ 00536 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) ; 00537 d->waitFrames(onsetTime); 00538 d->clearScreen() ; 00539 } 00540 } 00541 00542 //and this is the function which creates and displays a mask of randomly positioned numbers 00543 void showMask(int frames, string alphabet="0123456789"){ 00544 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00545 PixRGB<byte> bgcolor = PixRGB<byte>(128,128,128); 00546 PixRGB<byte> txtcolor = PixRGB<byte>(0,0,0); 00547 textIm.clear(bgcolor); 00548 for(int i = 0 ; i < 200 ; i++) 00549 writeText(textIm, Point2D<int>((int)random()%(d->getWidth()),(int)random()%(d->getHeight())),alphabet.substr(random()%(int)alphabet.size(),1).c_str(),txtcolor,bgcolor); 00550 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00551 SDL_Rect offs ; offs.x = 0 ; offs.y = 0 ; 00552 d->displaySDLSurfacePatch(surf , &offs , NULL , -2 , false ,true ) ; 00553 d->waitFrames(frames) ; 00554 d->clearScreen(); 00555 dumpSurface(surf) ; 00556 } 00557 00558 string get0213x(string is){ 00559 string sst = ascSort(is); 00560 string tail= ""; 00561 if(is.size()>4) tail = sst.substr(4,sst.size()-4); 00562 string rSt= sst.substr(0,1)+sst.substr(2,1)+sst.substr(1,1)+sst.substr(3,1) +tail; 00563 return rSt ; 00564 } 00565 00566 string get3120x(string is){ 00567 string sst = ascSort(is); 00568 string tail= ""; 00569 if(is.size()>4) tail = sst.substr(4,sst.size()-4); 00570 string rSt= sst.substr(3,1)+sst.substr(1,1)+sst.substr(2,1)+sst.substr(0,1) +tail; 00571 return rSt ; 00572 } 00573 00574 string get3021x(string is){ 00575 string sst = ascSort(is); 00576 string tail= ""; 00577 if(is.size()>4) tail = sst.substr(4,sst.size()-4); 00578 string rSt= sst.substr(3,1)+sst.substr(0,1)+sst.substr(2,1)+sst.substr(1,1) +tail; 00579 return rSt ; 00580 } 00581 00582 string get1203x(string is){ 00583 string sst = ascSort(is); 00584 string tail= ""; 00585 if(is.size()>4) tail = sst.substr(4,sst.size()-4); 00586 string rSt= sst.substr(1,1)+sst.substr(2,1)+sst.substr(0,1)+sst.substr(3,1) +tail; 00587 return rSt ; 00588 } 00589 00590 string get1032x(string is){ 00591 string sst = ascSort(is); 00592 string tail= ""; 00593 if(is.size()>4) tail = sst.substr(4,sst.size()-4); 00594 string rSt= sst.substr(1,1)+sst.substr(0,1)+sst.substr(3,1)+sst.substr(2,1) +tail; 00595 return rSt ; 00596 } 00597 00598 string get2301x(string is){ 00599 string sst = ascSort(is); 00600 string tail= ""; 00601 if(is.size()>4) tail = sst.substr(4,sst.size()-4); 00602 string rSt= sst.substr(2,1)+sst.substr(3,1)+sst.substr(0,1)+sst.substr(1,1) +tail; 00603 return rSt ; 00604 } 00605 00606 00607 vector<int> spatial_memory_task(int onsetTime, int isd , int dir , int ma=30 ,int Ma=120){ 00608 00609 int w = d->getWidth(); 00610 int h = d->getHeight(); 00611 int neg = rand()%(Ma-ma) +ma ; 00612 int pos = rand()%(Ma-ma) +ma ; 00613 //d->displayFixation(); 00614 if(dir==0) { 00615 d->displayRedDotFixation(w/2+pos,h/2); 00616 d->waitFrames(onsetTime); 00617 d->clearScreen(); 00618 d->waitFrames(isd); 00619 d->displayRedDotFixation(w/2-neg,h/2); 00620 d->waitFrames(onsetTime); 00621 d->clearScreen(); 00622 } 00623 if(dir==1) { 00624 d->displayRedDotFixation(w/2,h/2+pos); 00625 d->waitFrames(onsetTime); 00626 d->clearScreen(); 00627 d->waitFrames(isd); 00628 d->displayRedDotFixation(w/2,h/2-neg); 00629 d->waitFrames(onsetTime); 00630 d->clearScreen(); 00631 } 00632 vector<int> locations; 00633 locations.push_back(neg); 00634 locations.push_back(pos); 00635 return locations ; 00636 } 00637 00638 int spatial_memory_retrival(vector<int> dotsVector,int dir ,int ma=30 , int Ma=120 ,int ds=30 ){ 00639 00640 int w = d->getWidth(); 00641 int h = d->getHeight(); 00642 int change = rand()%2; 00643 int neg = dotsVector.at(0); int pos = dotsVector.at(1); 00644 switch( change ){ 00645 case 0 : d->pushEvent("same target");break; 00646 case 1 : d->pushEvent("target changed");break; 00647 } 00648 if(change == 1){ 00649 int chDir = rand()%2; 00650 int c=0; 00651 if(chDir==0){ 00652 c =((rand()%2 -0.5)/0.5 ); 00653 if( neg+ ds > Ma ) c = -1 ; 00654 if(neg -ds < ma ) c=+1 ; 00655 neg = neg + c*ds ; 00656 } 00657 if(chDir==1){ 00658 c =((rand()%2 -0.5)/0.5 ); 00659 if( pos+ ds > Ma ) c = -1 ; 00660 if(pos -ds < ma ) c=+1 ; 00661 pos = pos + c*ds ; 00662 } 00663 } 00664 00665 d->pushEvent("for retrieval dots showed at negative side :"+ stringify(neg)+" positive side:" + stringify(pos)); 00666 if(dir == 0){ 00667 d->displayRedDotFixation(w/2+pos,h/2); 00668 d->displayRedDotFixation(w/2-neg,h/2); 00669 } 00670 if(dir == 1){ 00671 d->displayRedDotFixation(w/2,h/2+pos); 00672 d->displayRedDotFixation(w/2,h/2-neg); 00673 } 00674 d->waitFrames(30); 00675 d->clearScreen(); 00676 string ans = getDigitSequenceFromSubject("yn-",1); 00677 int res = 0 ; 00678 if(change==0 && ans.compare("y")==0) res=1; 00679 if(change==1 && ans.compare("n")==0) res=1; 00680 return res ; 00681 } 00682 00683 int playTone(Mix_Music* tone ){ 00684 if(Mix_PlayMusic(tone,0)==-1){return -1;} 00685 while(Mix_PlayingMusic()==1){} ; 00686 return 0 ; 00687 } 00688 00689 00690 00691 00692 std::string getUsageComment(){ 00693 00694 string com = string("\nlist of arguments : \n"); 00695 00696 com += "\nlogfile=[logfilename.psy] {default = psycho-sm-or.psy}\n" ; 00697 com += "\nmemo=[a_string_without_white_space]\n"; 00698 com += "\nstring-size=[>0](the size of counter string){default=4} \n"; 00699 com += "\nsubject=[subject_name] \n" ; 00700 com += "\nnum-of-trials=[>1] (number of trials ) {default=10}\n"; 00701 com += "\nalphabet=[a string of characters](a string of characters){default=abcdefghijklmnopqrstuvwxyz}\n"; 00702 com += "\nmode=[1,2,3](1 for spatial memory task 2 for single counter task, 2 for concurrent task){default=1}\n"; 00703 com += "\nsingle-dot-onset=[>1](number of frames that the single dot should be presented){default=16}\n"; 00704 com += "\ndots_ISI=[>1](number of frames between dots presentations){default=16}\n"; 00705 com += "\ndots-radius=[>1](the radius for circle of dots in pixel){default=100}\n"; 00706 com += "\ndots-min-radius=[>0](minimum distance of dots from center){default=32}\n"; 00707 com += "\ndots-max-radius=[>0] (maximum distance of dots from center){default=158}\n"; 00708 com += "\nspatial-delay=[>0](number of frames for spatial memory task ){default=180}\n"; 00709 com += "\n spatial-counter-ISI=[>1](numer of frames between last dot presentation and start of counter task){default=16}\n"; 00710 com += "\n counter-length=[>1](total lenght of counter experiment in frames){default=300}\n"; 00711 com += "\n counter-spatial-query-ISI=[>1](the delay between end of counter trail and start of spatial memory query in number of frames){default=16}\n"; 00712 com += "\n spatial-query-length=[>1](the total length for showing the spatial memory test in number of frames){default=60}\n"; 00713 com += "\n spatial-query-counter-query-ISI=[>1](number of frames between the unspeeded spatial memory query and showing the counter query){default=30}\n"; 00714 com += "\n counter-query-length=[>1](number of frames for presenting the counter query){default=60}\n"; 00715 com += "\n cue-onset-frames=[>1](){default=3}\n";; 00716 com += "\nsound-dir=[path to wav files directory]{default=..}\n"; 00717 com += "\ntone1=[a valid file name](name of wav file without extension for tone 1){default=sin}\n"; 00718 com += "\ntone2=[a valid file name](name of wav file without extension for tone 2){default=square}\n"; 00719 com += "\ndot-shift=[>1](amount of shift in dots position in pixel)[default=16]\n"; 00720 com +="\nsorting-delay=[>1](the delay for sorting in number of frames){default=360}\n"; 00721 return com ; 00722 } 00723 00724 extern "C" int main(const int argc, char** argv) 00725 { 00726 00727 MYLOGVERB = LOG_INFO; // suppress debug messages 00728 //let's push the initial value for the parameters 00729 argMap["experiment"]="spatial-memory-test"; 00730 argMap["logfile"]="psycho-sm.psy" ; 00731 argMap["string-size"]="5" ; 00732 argMap["num-of-trials"]="5"; 00733 argMap["subject"]="" ; 00734 argMap["memo"]="" ; 00735 argMap["single-dot-onset"]="16" ; 00736 argMap["dots-ISI"]="16"; 00737 argMap["spatial-delay"]="180"; 00738 argMap["spatial-counter-ISI"]="16"; 00739 argMap["counter-length"]="300"; 00740 argMap["counter-spatial-query-ISI"]="16"; 00741 argMap["spatial-query-length"]="60"; 00742 argMap["spatial-query-counter-query-ISI"]="30"; 00743 argMap["counter-query-length"]="60"; 00744 argMap["alphabet"]="0123456789"; 00745 argMap["mode"]="0" ; 00746 argMap["cue-onset-frames"] = "3" ; 00747 argMap["sound-dir"]=".."; 00748 argMap["tone1"]="sine"; 00749 argMap["tone2"]="square"; 00750 argMap["cue-file"]="cue1"; 00751 argMap["min-tone-wait"]="50"; 00752 argMap["max-tone-wait"]="80"; 00753 argMap["dots-min-radius"]="32"; 00754 argMap["dots-max-radius"]="158"; 00755 argMap["dot-shift"] = "32"; 00756 argMap["sorting-delay"]="300"; 00757 manager.addSubComponent(d); 00758 nub::soft_ref<EventLog> el(new EventLog(manager)); 00759 manager.addSubComponent(el); 00760 d->setEventLog(el); 00761 nub::soft_ref<EyeTrackerConfigurator> 00762 etc(new EyeTrackerConfigurator(manager)); 00763 manager.addSubComponent(etc); 00764 00765 if (manager.parseCommandLine(argc, argv, 00766 "at least one argument needed", 1, -1)==false){ 00767 cout<<getUsageComment()<<endl; 00768 return(1); 00769 } 00770 00771 for(uint i = 0 ; i < manager.numExtraArgs() ; i++){ 00772 addArgument(manager.getExtraArg(i),std::string("=")) ; 00773 } 00774 00775 manager.setOptionValString(&OPT_EventLogFileName, argMap["logfile"]); 00776 //+manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN"); 00777 //+nub::soft_ref<EyeTracker> eyet = etc->getET(); 00778 //+d->setEyeTracker(eyet); 00779 //+eyet->setEventLog(el); 00780 00781 00782 // let's get all our ModelComponent instances started: 00783 manager.start(); 00784 for(map<string,string>::iterator it= argMap.begin(); it!= argMap.end() ; ++it) d->pushEvent("arg:"+ it->first+" value:"+it->second ) ; 00785 // let's display an ISCAN calibration grid: 00786 d->clearScreen(); 00787 d->displayISCANcalib(); 00788 d->waitForMouseClick(); 00789 d->displayText("Here the experiment starts! click to start!"); 00790 d->waitForMouseClick(); 00791 d->clearScreen(); 00792 //let's see in what mode the user like to run the program 00793 //int mode = atoi(argMap["mode"].c_str()); 00794 string masterString=argMap["alphabet"]; 00795 00796 int mode = atoi(argMap["mode"].c_str()); 00797 int numOfTests = atoi(argMap["num-of-trials"].c_str()) ; 00798 int stringSize = atoi(argMap["string-size"].c_str()); 00799 int dots_ISI = atoi(argMap["dots-ISI"].c_str()) ; 00800 int dot_onset = atoi(argMap["single-dot-onset"].c_str()); 00801 int dots_min_radius = atoi(argMap["dots-min-radius"].c_str()); 00802 int dots_max_radius = atoi(argMap["dots-max-radius"].c_str()); 00803 int delayForSorting = atoi(argMap["sorting-delay"].c_str()); 00804 //int mode = atoi(argMap["mode"].c_str()); 00805 // int counter_length = atoi(argMap["counter-length"].c_str()); 00806 //int min_tone_wait = atoi(argMap["min-tone-wait"].c_str()); 00807 //int max_tone_wait = atoi(argMap["max-tone-wait"].c_str()); 00808 int dot_max_change = atoi(argMap["dot-shift"].c_str()); 00809 vector<int> orientation_task_Vector; 00810 for( int i = 0 ; i< numOfTests ; i++ ){ 00811 orientation_task_Vector.push_back(0); 00812 orientation_task_Vector.push_back(1); 00813 //orientation_task_Vector.push_back(2); 00814 //orientation_task_Vector.push_back(3); 00815 } 00816 00817 scramble(orientation_task_Vector); 00818 //let's do calibration 00819 00820 00821 d->clearScreen(); 00822 00823 cout<< stringify(d->getWidth())<<" x "<<stringify(d->getHeight())<<endl; 00824 // Mix_Music* cueMusic = NULL;//this is the cue for the start of trial 00825 Mix_Music* tone1 = NULL;//tone 1 00826 Mix_Music* tone2 = NULL;//tone 2 00827 map<int,Mix_Music*> audio_map ;//we will have access to the audios for stimulus presentation using this map 00828 map<string,int> charmap ; 00829 map<int,string> charinvmap ; 00830 //now let's open the audio channel 00831 if( Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 4096 ) == -1 ){ 00832 LINFO( "did not open the mix-audio") ; 00833 return -1 ; 00834 } 00835 //now that everyting is ok, let's load the main string audio files and push them in a map 00836 for(uint i = 0; i < masterString.size() ; i++){ 00837 string str = argMap["sound-dir"]+"/"+masterString.substr(i,1)+".wav"; 00838 audio_map[i]=Mix_LoadMUS(str.c_str()); 00839 charmap[masterString.substr(i,1)]=i; 00840 charinvmap[i]=masterString.substr(i,1) ; 00841 } 00842 00843 for( uint i=10;i<100 ;i++ ){ 00844 charmap[stringify(i)]=i; 00845 charinvmap[i]=stringify(i); 00846 } 00847 00848 00849 string tmpstr = argMap["sound-dir"]+"/"+argMap["tone1"]+".wav"; 00850 tone1 = Mix_LoadMUS(tmpstr.c_str()); 00851 tmpstr = argMap["sound-dir"]+"/"+argMap["tone2"]+".wav"; 00852 tone2 = Mix_LoadMUS(tmpstr.c_str()); 00853 00854 int cr = numOfTests ;//this is the counter for number of rounds 00855 d->showCursor(true); 00856 d->displayText("click one of the mouse buttons to start!"); 00857 d->waitForMouseClick() ; 00858 d->showCursor(false); 00859 00860 map<int,int> correctSPMMap;correctSPMMap[0]=0;correctSPMMap[1]=0;correctSPMMap[2]=0;correctSPMMap[3]=0; 00861 map<int,int> incorrectSPMMap;incorrectSPMMap[0]=0;incorrectSPMMap[1]=0;incorrectSPMMap[2]=0;incorrectSPMMap[3]=0; 00862 cr=0; 00863 while( cr < 2*numOfTests ){ 00864 string inStr = getARandomString(stringSize,argMap["alphabet"]); 00865 00866 string testString="" ; 00867 int flp = rand()%6; 00868 switch( flp ){ 00869 case 0 : testString = get0213x(ascSort(inStr)); break; 00870 case 1 : testString = get3120x(ascSort(inStr)); break; 00871 case 2 : testString = get3021x(ascSort(inStr)); break; 00872 case 3 : testString = get1203x(ascSort(inStr)); break; 00873 case 4 : testString = get1032x(ascSort(inStr)); break; 00874 case 5 : testString = get2301x(ascSort(inStr)); break; 00875 } 00876 d->showCursor(false); 00877 d->clearScreen() ; 00878 d->clearScreen() ; 00879 d->displayFixationBlink(); 00880 d->pushEvent("**************************************") ; 00881 d->pushEvent("initial string :" + testString); 00882 for( int i = 0 ; i < stringSize ; i++ ){ 00883 playTone(audio_map[charmap[testString.substr(i,1)]]); 00884 d->waitFrames(5); 00885 } 00886 //displayRandom(testString,15); 00887 //displayWholeNumber(testString,60,20); 00888 showMask(4,"abcdefghijklmnopqrstuvwxyz"); 00889 d->waitFrames(30); 00890 d->displayFixation(); 00891 d->waitFrames(10); 00892 d->clearScreen() ; 00893 d->pushEvent("presentation orientation: " + stringify((int)(orientation_task_Vector.at(cr)%2))); 00894 vector<int> dotsVector = spatial_memory_task(dot_onset,dots_ISI,(int)(orientation_task_Vector.at(cr)%2),dots_min_radius,dots_max_radius); 00895 d->pushEvent("dots showed at negative:"+ stringify(dotsVector.at(0))+" positive:" + stringify(dotsVector.at(1))); 00896 00897 d->displayFixation(); 00898 d->waitFrames(15); 00899 int currentTask=mode; 00900 /*switch(orientation_task_Vector.at(cr)){ 00901 case 0 : currentTask=0 ;break; 00902 case 1 : currentTask=1 ;break; 00903 case 2 : currentTask=0 ;break; 00904 case 3 : currentTask=1 ;break; 00905 } */ 00906 if(currentTask==0){ 00907 d->pushEvent("task : memorization"); 00908 playTone(tone1); 00909 } 00910 if(currentTask==1){ 00911 d->pushEvent("task : sorting"); 00912 playTone(tone1); 00913 } 00914 d->waitFrames(delayForSorting); 00915 playTone(tone2); 00916 d->waitFrames(30); 00917 00918 int spMemAns = spatial_memory_retrival(dotsVector,(int)(orientation_task_Vector.at(cr)%2),dots_min_radius,dots_max_radius,dot_max_change); 00919 switch( spMemAns ){ 00920 case 0: incorrectSPMMap[orientation_task_Vector.at(cr)]= incorrectSPMMap[orientation_task_Vector.at(cr)]+1;d->pushEvent("incorrect spatial memory answer");break; 00921 case 1: correctSPMMap[orientation_task_Vector.at(cr)]= correctSPMMap[orientation_task_Vector.at(cr)]+1;d->pushEvent("correct spatial memory answer");break; 00922 } 00923 00924 string ans1 = getDigitSequenceFromSubject(argMap["alphabet"],stringSize,""); 00925 d->pushEvent("string answer: "+ans1); 00926 if(mode==0){ 00927 if(ans1.compare(testString)==0){ 00928 d->pushEvent("correct string recall"); 00929 d->displayText(":)"); 00930 d->waitFrames(15); 00931 }else{ 00932 d->pushEvent("incorrect string recall"); 00933 d->displayText(":("); 00934 d->waitFrames(15); 00935 } 00936 } 00937 00938 if(mode==1){ 00939 if(ans1.compare(ascSort(testString))==0){ 00940 d->pushEvent("correct string sorting"); 00941 d->displayText(":)"); 00942 d->waitFrames(15); 00943 }else{ 00944 d->pushEvent("incorrect string sorting"); 00945 d->displayText(":("); 00946 d->waitFrames(15); 00947 } 00948 } 00949 00950 00951 cr++; 00952 } 00953 00954 d->pushEvent("horizontal, memory correct:"+stringify(correctSPMMap[0])); 00955 d->pushEvent("vertical, memory correct:"+stringify(correctSPMMap[1])); 00956 d->pushEvent("horizontal, memory incorrect:"+stringify(incorrectSPMMap[0])); 00957 d->pushEvent("vertical, memory incorrect:"+stringify(incorrectSPMMap[1])); 00958 00959 d->displayText("Experiment complete. Thank you!"); 00960 d->waitForMouseClick(); 00961 00962 // stop all our ModelComponents 00963 manager.stop(); 00964 00965 00966 // all done! 00967 return 0; 00968 } 00969 00970 #endif // INVT_HAVE_LIBSDL_IMAGE 00971