00001 /*!@file AppPsycho/psychoWM.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/psychoWM-M.C $ 00035 // $Id: psychoWM-M.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 <stdio.h> 00059 #include <stdlib.h> 00060 #include <sstream> 00061 #include <time.h> 00062 #include "Image/DrawOps.H" 00063 #include "GameBoard/resize.h" 00064 #include <iostream> 00065 #include <fstream> 00066 #include <set> 00067 #include <algorithm> 00068 #include <ctime> 00069 #include "Devices/SimpleMotor.H" 00070 #include <SDL/SDL_mixer.h> 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 nub::soft_ref<SimpleMotor> motor(new SimpleMotor(manager)); 00091 map<uint,uint> testMap ; 00092 map<string,string> argMap ; 00093 Mix_Chunk *audio_chunk = NULL; 00094 00095 ////////////////////////////////////////////// 00096 // a functionf for stringigying things 00097 ////////////////////////////////////////////// 00098 template <class T> std::string stringify(T i) 00099 { 00100 ostringstream o ; 00101 o << i ; 00102 return o.str(); 00103 } 00104 00105 00106 00107 00108 bool itIsInThere(int x , vector<int> bag){ 00109 for( uint i=0 ; i < bag.size(); i++ ){ 00110 if(x == bag[i]) return true ; 00111 } 00112 return false ; 00113 } 00114 00115 00116 double getAvarage(vector<long> v){ 00117 double f = 0.0 ; 00118 for( uint i = 0 ; i < v.size() ; i++ ){ 00119 f += v[i] ; 00120 } 00121 if (v.size()!=0) return f/v.size() ; 00122 return -1 ; 00123 } 00124 00125 double getVariance(vector<long> v){ 00126 double m = getAvarage(v); 00127 double var = 0.0 ; 00128 for( uint i = 0 ; i < v.size(); i++ ){ 00129 var += (v[i]-m)*(v[i]-m) ; 00130 } 00131 if (v.size()!=0) return var/v.size() ; 00132 return -1 ; 00133 } 00134 00135 00136 00137 00138 00139 //////////////////////////////////////////////////////////////////// 00140 //// gets a string as the argument and returns a string composed of 00141 //// characters of the first string sorted in the ascending order 00142 /////////////////////////////////////////////////////////////////// 00143 string ascSort(string st) 00144 { 00145 string res = "" ; 00146 vector<string> v = vector<string>(); 00147 for(uint i = 0 ; i < st.size() ; i++) v.push_back(st.substr(i,1)) ; 00148 00149 std::sort(v.begin(), v.end()); 00150 00151 for ( uint i = 0 ; i < v.size() ; i++ ){ 00152 res += v[i] ; 00153 } 00154 return res; 00155 } 00156 00157 00158 00159 //////////////////////////////////////////////////////////////////// 00160 //// gets a string as the argument and returns a string composed of 00161 //// characters of the first string sorted in the descending order 00162 /////////////////////////////////////////////////////////////////// 00163 string desSort(string st) 00164 { 00165 string res = "" ; 00166 vector<string> v = vector<string>(); 00167 for(uint i = 0 ; i < st.size() ; i++) v.push_back(st.substr(i,1)) ; 00168 std::sort(v.begin(), v.end()); 00169 std::reverse(v.begin(), v.end()); 00170 for ( uint i = 0 ; i < v.size() ; i++ ){ 00171 res += v[i] ; 00172 } 00173 return res; 00174 } 00175 00176 00177 ///////////////////////////////////////////////////////////// 00178 //this function checks how many subblocks of the sorted string can be found in 00179 //original string, the bigger chunks found the bigger number will be return 00180 //////////////////////////////////////////////////////////// 00181 00182 int mydist(string str , string sorted){ 00183 size_t found; 00184 int m = 0 ; 00185 for(uint i = 2 ; i <= sorted.size() ; i++ ){ 00186 for(uint j = 0 ; j <= sorted.size()-i ; j++ ) { 00187 found = str.find(sorted.substr(j,i)); 00188 if (found!=string::npos) m += i ; 00189 } 00190 } 00191 return m ; 00192 } 00193 00194 ///////////////////////////////////////////////////////////// 00195 //this function checks out the difficulty of sorting the string assigns a number which 00196 //reflects how many moves are needed for sorting, 00197 //////////////////////////////////////////////////////////// 00198 00199 int getDisMetric(string st){ 00200 int m = 0 ; 00201 size_t found; 00202 string asString = ascSort(st) ; 00203 for(uint i = 0 ; i < st.size() ; i++ ){ 00204 found = asString.find(st.substr(i,1)); 00205 m += abs((int)i-int(found)) ; 00206 } 00207 00208 return m- 2*mydist(st,asString) ; 00209 } 00210 00211 00212 00213 //////////////////////////////////////////////////////// 00214 ///// 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 00215 //highest metric value in 1000000 times try will be returned 00216 //////////////////////////////////////////////////////// 00217 00218 string getARandomString(uint l, string alphabet="0123456789" , int thresh=0){ 00219 00220 string test = string("") ; 00221 string retString ; 00222 int maxDist = -1000000; 00223 int it = 0 ; 00224 int d = 0 ; 00225 do{ 00226 test = "" ; 00227 string tp = string("") ; 00228 vector<int> pickedones = vector<int>() ; 00229 for(uint i = 0 ; i < l ; i++){ 00230 int nd; 00231 do{ nd= rand()% alphabet.size() ; }while(itIsInThere(nd,pickedones) && pickedones.size() <= alphabet.size()) ; 00232 pickedones.push_back(nd); 00233 tp = alphabet.substr(nd,1) ; 00234 test += tp ; 00235 } 00236 it++ ; 00237 d = getDisMetric(test); 00238 maxDist=max(maxDist,d) ; 00239 if (d==maxDist) retString = test ; 00240 00241 }while( maxDist<thresh && it < 1000000); 00242 00243 return retString ; 00244 } 00245 00246 /////////////////////////////////////////////////////// 00247 //this function is not called in this program, but it generates a random string and it will show it in 00248 //a random place on the screen. 00249 ////////////////////////////////////////////////////// 00250 string digitMemorizationTask(uint l, string alphabet="0123456789" , int displayFrame = 10 ){ 00251 d->clearScreen() ; 00252 vector<int> pickedones = vector<int>() ; 00253 string test = string("") ; 00254 string tp = string("") ; 00255 for(uint i = 0 ; i < l ; i++){ 00256 int nd; 00257 do{ nd= rand()% alphabet.size() ; }while(itIsInThere(nd,pickedones) && pickedones.size() <= alphabet.size()) ; 00258 pickedones.push_back(nd); 00259 tp = alphabet.substr(nd,1) ; 00260 test += tp ; 00261 } 00262 d->displayText(test,true,0) ; 00263 d->waitFrames(displayFrame) ; 00264 d->clearScreen() ; 00265 return test ; 00266 } 00267 00268 00269 //////////////////////////////////////////////////////// 00270 ///////this will change the order of elements in a vector to a random order 00271 //////////////////////////////////////////////////////// 00272 void scramble(vector<string>& v){ 00273 vector<string> tv = vector<string>() ; 00274 while(v.size()>0){ 00275 tv.push_back(v[0]); 00276 v.erase(v.begin()); 00277 } 00278 int i = 0 ; 00279 while(tv.size()>0){ 00280 i = rand()%tv.size() ; 00281 v.push_back(tv[i]); 00282 tv.erase(tv.begin()+i); 00283 } 00284 } 00285 00286 00287 //////////////////////////////////////////////////////////////// 00288 ////This is our button factory 00289 //////////////////////////////////////////////////////////////// 00290 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){ 00291 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00292 textIm.clear(bgcolor); 00293 writeText(textIm, Point2D<int>((size.i - label.length()*10)/2,(size.j-20) /2),label.c_str(),txtcolor,bgcolor); 00294 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00295 Uint32 bc = d->getUint32color(bordercolor); 00296 drawRectangle(surf,bc,0,0,size.i -1,size.j -1 ,border); 00297 SDL_Surface* blank =getABlankSurface(size.i , size.j); 00298 SDL_Rect clip; 00299 clip.x = 0 ; 00300 clip.y = 0 ; 00301 clip.w = size.i ; 00302 clip.h = size.j ; 00303 apply_surface(0,0,*surf,*blank,clip); 00304 dumpSurface(surf) ; 00305 return blank ; 00306 } 00307 00308 //////////////////////////////////////////////////////////////////////// 00309 ////This is the function for creating the keypad, in fact it generates 00310 ////12 buttons and associates the actions to the region for each button 00311 //////////////////////////////////////////////////////////////////////// 00312 00313 SDL_Surface* getKeyPad(string alphabet,map<string , SDL_Rect>& buttmap){ 00314 SDL_Surface* pad= getABlankSurface(d->getWidth()/4,d->getHeight()/3); 00315 SDL_Rect clip; 00316 clip.x=0; 00317 clip.y=0; 00318 int numofrows = alphabet.size()/3 +1; 00319 if(alphabet.size()%3 != 0 ) numofrows++ ; 00320 int numofcolumns = 3 ; 00321 clip.w= pad->w / numofcolumns ; 00322 clip.h = pad->h / numofrows ; 00323 00324 //keys for 1 to 9 00325 for( int i = 0 ; i < numofrows*3 ; i++){ 00326 SDL_Surface* but ; 00327 if((uint)i < alphabet.size()){ 00328 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); 00329 }else{ 00330 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); 00331 } 00332 00333 SDL_Rect cl ; 00334 cl.x = ((i)%numofcolumns)*(pad->w)/numofcolumns ; cl.y= ((i)/numofcolumns)*((pad->h)/numofrows) ; 00335 cl.w = clip.w ; 00336 cl.h = clip.h ; 00337 apply_surface( cl.x , cl.y ,*but,*pad,clip); 00338 if((uint)i < alphabet.size()) buttmap[alphabet.substr(i,1)] = cl ; 00339 dumpSurface(but); 00340 } 00341 SDL_Rect cl1 ; 00342 cl1.x = 0 ; cl1.y= (numofrows-1)*((pad->h)/numofrows) ; 00343 cl1.w = clip.w ; 00344 cl1.h = clip.h ; 00345 buttmap["!"] = cl1 ; 00346 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); 00347 apply_surface(0, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00348 dumpSurface(but); 00349 SDL_Rect cl2 ; 00350 cl2.x = (pad->w)/numofcolumns ; cl2.y= (numofrows-1)*((pad->h)/numofrows) ; 00351 cl2.w = clip.w ; 00352 cl2.h = clip.h ; 00353 buttmap[" "] = cl2 ; 00354 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); 00355 apply_surface((pad->w)/numofcolumns, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00356 dumpSurface(but); 00357 SDL_Rect cl3 ; 00358 cl3.x = 2*(pad->w)/numofcolumns ; cl3.y= (numofrows-1)*((pad->h)/numofrows) ; 00359 cl3.w = clip.w ; 00360 cl3.h = clip.h ; 00361 buttmap["*"] = cl3 ; 00362 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); 00363 apply_surface(2*(pad->w)/numofcolumns, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00364 dumpSurface(but); 00365 return pad ; 00366 } 00367 00368 00369 00370 00371 /////////////////////////////////////////////////////////////////////////// 00372 /////this function listens to mouse clicks and then finds the region of the screen 00373 /////associated with the action, buttmap is the map of the region, offset is the offset of 00374 /////buttons 00375 /////////////////////////////////////////////////////////////////////////// 00376 string getPressedButtonCommand(map<string , SDL_Rect>& buttmap,Point2D<int> offset=Point2D<int>(0,0)){ 00377 int quit = 0 ; 00378 string s ; 00379 SDL_Event event ; 00380 while( quit!=2 ){ 00381 while( SDL_PollEvent( &event ) ) { 00382 if(event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT ){ 00383 for( map<string , SDL_Rect>::iterator it = buttmap.begin() ; it!=buttmap.end() ; ++it){ 00384 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) { 00385 quit = 2 ; 00386 s = it->first ; 00387 break; 00388 } 00389 00390 } 00391 } 00392 00393 } 00394 } 00395 return s ; 00396 00397 } 00398 00399 00400 //////////////////////////////////////////////////// 00401 ////This function creates a virtual keypad, creates a map of buttons 00402 ////and their representation area and listens to the button press and at 00403 ////the end returns the keyed digits 00404 //////////////////////////////////////////////////// 00405 string getDigitSequenceFromSubject(string alphabet="0123456789" , uint maxl = 7 ){ 00406 d->showCursor(true) ; 00407 //let's creat a map to map actions to regions of the screen, each region is represented as an SDL_Rect 00408 map<string , SDL_Rect>* buttmap = new map<string , SDL_Rect>(); 00409 //now let's get the keypad surface while we get the actions map to regions 00410 SDL_Surface * keypad = getKeyPad(alphabet,*buttmap); 00411 //this will be the offset of displaying the keypad on the screen 00412 SDL_Rect offset ; 00413 offset.x = (d->getWidth() - keypad->w) /2; 00414 offset.y = (d-> getHeight() - keypad->h) /2; 00415 //now let's display the keypad 00416 d->displaySDLSurfacePatch(keypad , &offset,NULL , -2,false, true); 00417 //this will hold the final string keyed be the subject 00418 string p = string("") ; 00419 //this is a temporary string holding the last action related to the pressed key 00420 string tp = string(""); 00421 //now let's record subject's key press 00422 while( tp.compare("*")!=0 ){ 00423 //this button is actually the display for the current string 00424 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) ; 00425 SDL_Rect offs ; offs.x = (d->getWidth() - dp->w) /2 ; offs.y = d->getHeight()/6 ; 00426 d->displaySDLSurfacePatch(dp , &offs , NULL , -2 , false ,true ) ; 00427 //now let's listen to button events 00428 tp = getPressedButtonCommand(*buttmap,Point2D<int>(offset.x,offset.y)) ; 00429 dumpSurface(dp) ; 00430 if(tp.compare("!")==0 && p.size()>=0 ) { 00431 if (p.size()>0) p = p.substr(0,p.size()-1) ; 00432 }else{ 00433 if(p.size() < maxl && tp.compare("*")!=0) { 00434 p +=tp ; 00435 } 00436 00437 } 00438 00439 } 00440 buttmap = 0 ; 00441 dumpSurface(keypad) ; 00442 d->clearScreen() ; 00443 return p ; 00444 00445 } 00446 00447 //and this is the function which creates and displays a mask of randomly positioned numbers 00448 void showMask(int frames, string alphabet="0123456789"){ 00449 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00450 PixRGB<byte> bgcolor = PixRGB<byte>(128,128,128); 00451 PixRGB<byte> txtcolor = PixRGB<byte>(0,0,0); 00452 textIm.clear(bgcolor); 00453 for(int i = 0 ; i < 200 ; i++) 00454 writeText(textIm, Point2D<int>((int)random()%(d->getWidth()),(int)random()%(d->getHeight())),alphabet.substr(random()%(int)alphabet.size(),1).c_str(),txtcolor,bgcolor); 00455 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00456 SDL_Rect offs ; offs.x = 0 ; offs.y = 0 ; 00457 d->displaySDLSurfacePatch(surf , &offs , NULL , -2 , false ,true ) ; 00458 d->waitFrames(frames) ; 00459 d->clearScreen(); 00460 dumpSurface(surf) ; 00461 } 00462 /////////////////////////////////////////////////////////////// 00463 //////gets the test string, answer and the mode and identifies if 00464 //////the answer matches the thing it should be, mode=0 checks if 00465 //////if the answer and test string simply the same, mode=1 matches 00466 //////the answer against the ascending sorted string of the test string 00467 //////mode=2 compares the answer against the descending sorted of 00468 //////the test string 00469 /////////////////////////////////////////////////////////////// 00470 bool isAnswerCorrect(string test , string answer , int mode){ 00471 00472 if(mode == 0 && answer.compare(test)==0) return true ; 00473 00474 if(mode == 1 && answer.compare(ascSort(test))==0) return true ; 00475 00476 if(mode == 2 && answer.compare(desSort(test))==0) return true ; 00477 00478 return false; 00479 } 00480 00481 00482 00483 int addArgument(const string st,const string delim="="){ 00484 int i = st.find(delim) ; 00485 argMap[st.substr(0,i)] = st.substr(i+1); 00486 00487 return 0 ; 00488 } 00489 00490 std::string getArgumentValue(string arg){ 00491 return argMap[arg] ; 00492 } 00493 00494 std::string getUsageComment(){ 00495 00496 string com = string("\nlist of arguments : \n"); 00497 com += "\nlogfile=[logfilename.psy] {default =psycho-wm-m.psy}\n" ; 00498 com += "\nmemo=[a_string_without_white_space]\n"; 00499 com += "\nstring-size=[>0](the size of string){default=5} \n"; 00500 com += "\nsubject=[subject_name] \n" ; 00501 com += "\ntest-rounds=[>1] (number of tests ) {default=10}\n"; 00502 com += "\ndigit-onset=[>1] (number of frames that the string will remain onset ){default=10}\n"; 00503 com += "\nalphabet=[a string of characters](a string of characters){default=0123456789}\n"; 00504 com += "\nmetric-thresholdt=[>-30 for string of lenght of 5](a string of characters){default=10}\n"; 00505 com += "\nmaintain-prb=[a number between 0 to 1], probability of challenging the subject with a memorization task, default=0.2\n" ; 00506 com += "\nmin-reaction-time=[>0](minimum value for avarage reaction time in microsecond in order to consider a trial valid){default=1000000}\n" ; 00507 com += "\nmax-miss=[>0](maximum misses in a trial in order to be considered as a valid one){default=0}"; 00508 com += "\nmax-false-click=[>0](maximum false clicks in a trial in order to be considered as a valid one){default=0}"; 00509 com += "\ninterrupt-time-range=[x-y](this defines a range of uniform radom distribution by which the perceptual interruption happens){default=500000-5000000}\n" ; 00510 com += "\ncue-wait-frames=[<0](number of frames to show the cue){default=0}\n"; 00511 com += "\ncue-onset-frames=[<0](number of frames to show the cue onset){default=3}\n"; 00512 com += "\nmask=[y/n](whether present a mask after presentation, n for no, y for yes ){default=n}\n" ; 00513 com += "\nmask-onset-frames=[<0](number of frames that mask will be onset){default=0}\n"; 00514 com += "\nsound-dir=[path to wav files directory]{default=..}\n"; 00515 com += "\audio-file=[white noise file]{default=audio.wav}\n"; 00516 com += "\npuase-frames=[number of frames for stopping the the audio playback]{default=5}\n"; 00517 return com ; 00518 } 00519 00520 int myCheckForMouseClick() 00521 { 00522 SDL_Event event; 00523 00524 while(SDL_PollEvent(&event)) 00525 { 00526 if (event.type == SDL_MOUSEBUTTONDOWN) 00527 { 00528 if(event.button.button == SDL_BUTTON_LEFT) { 00529 return 1 ; 00530 } 00531 if(event.button.button == SDL_BUTTON_RIGHT) { 00532 return 2 ; 00533 } 00534 00535 } 00536 // ignore other events 00537 } 00538 00539 // there was no event in the event queue: 00540 return -1; 00541 } 00542 00543 00544 int getClick(){ 00545 // while (myCheckForMouseClick() != -1) ; 00546 SDL_Event event; 00547 bool report = false ; 00548 int i = 0; // will be returned if any other button than left or right 00549 do { 00550 do { SDL_WaitEvent(&event); } while (event.type != SDL_MOUSEBUTTONDOWN); 00551 if (event.button.button == SDL_BUTTON_LEFT) { 00552 i = 0 ; 00553 report = true ; 00554 } 00555 if (event.button.button == SDL_BUTTON_RIGHT) { 00556 i = 1 ; 00557 report = true ; 00558 } 00559 00560 }while(!report) ; 00561 00562 return i ; 00563 } 00564 00565 int getAllKindOfClick(){ 00566 // while (myCheckForMouseClick() != -1) ; 00567 SDL_Event event; 00568 bool report = false ; 00569 int i = 0; // will be returned if any other button than left or right 00570 do { 00571 do { SDL_WaitEvent(&event); } while (event.type != SDL_MOUSEBUTTONDOWN); 00572 long st = d->getTimerValue(); 00573 long et = st ; 00574 00575 if (event.button.button == SDL_BUTTON_LEFT) { 00576 i = 0 ; 00577 report = true ; 00578 while( et-st < 300000){ 00579 et = d->getTimerValue() ; 00580 if(myCheckForMouseClick()==1) return 2 ; 00581 } 00582 } 00583 if (event.button.button == SDL_BUTTON_RIGHT) { 00584 i = 1 ; 00585 report = true ; 00586 } 00587 00588 }while(!report) ; 00589 00590 return i ; 00591 00592 } 00593 00594 int getNext(int i){ 00595 00596 int r = 1 ; 00597 if(i == 0 || i == 2) return 1 ; 00598 if(i==1) return 0; 00599 return r ; 00600 } 00601 00602 extern "C" int main(const int argc, char** argv) 00603 { 00604 00605 MYLOGVERB = LOG_INFO; // suppress debug messages 00606 //let's push the initial value for the parameters 00607 argMap["experiment"]="sorting_strings_in_working_memory-with-somatosensory-task"; 00608 argMap["logfile"]="psycho-wm-m.psy" ; 00609 argMap["string-size"]="5" ; 00610 argMap["test-rounds"]="10"; 00611 argMap["subject"]="" ; 00612 argMap["memo"]="" ; 00613 argMap["digit-onset"]="10" ; 00614 argMap["alphabet"]="0123456789"; 00615 argMap["metric-threshold"]="10" ; 00616 argMap["maintain-prb"]="0.2" ; 00617 argMap["min-reaction-time"]="1000000" ; 00618 argMap["max-miss"]="0" ; 00619 argMap["interrupt-time-range"]= "500000-5000000"; 00620 argMap["cue-wait-frames"]="0" ; 00621 argMap["mask"]="n" ; 00622 argMap["mask-onset-frames"]="0"; 00623 argMap["cue-onset-frames"] = "3" ; 00624 argMap["sound-dir"]=".."; 00625 argMap["audio-file"]="audio.wav"; 00626 argMap["pause-frames"]="5" ; 00627 argMap["max-false-click"]="0"; 00628 manager.addSubComponent(d); 00629 manager.addSubComponent(motor) ; 00630 nub::soft_ref<EventLog> el(new EventLog(manager)); 00631 manager.addSubComponent(el); 00632 d->setEventLog(el); 00633 //mmanager.parseCommandLine(argc, argv, "", 0,0); 00634 //mmanager.start(); 00635 00636 if (manager.parseCommandLine(argc, argv, 00637 "at least one argument needed", 1, -1)==false){ 00638 cout<<getUsageComment()<<endl; 00639 return(1); 00640 } 00641 00642 for(uint i = 0 ; i < manager.numExtraArgs() ; i++){ 00643 addArgument(manager.getExtraArg(i),std::string("=")) ; 00644 } 00645 00646 manager.setOptionValString(&OPT_EventLogFileName, argMap["logfile"]); 00647 00648 if( Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 4096 ) == -1 ){ 00649 LINFO( "did not open the mix-audio") ; 00650 return -1 ; 00651 } 00652 string noisestr = argMap["sound-dir"] + "/" + argMap["audio-file"]; 00653 audio_chunk = Mix_LoadWAV(noisestr.c_str()); 00654 if( audio_chunk == NULL ) 00655 { 00656 LINFO("did not find the indicated wav files!"); 00657 return -1; 00658 } 00659 00660 00661 // let's get all our ModelComponent instances started: 00662 manager.start(); 00663 for(map<string,string>::iterator it= argMap.begin(); it!= argMap.end() ; ++it) d->pushEvent("arg:"+ it->first+" value:"+it->second ) ; 00664 SDL_Rect offs ; offs.x = 0 ; offs.y = 0 ; 00665 00666 // let's display an ISCAN calibration grid: 00667 d->clearScreen(); 00668 d->displayISCANcalib(); 00669 d->waitForMouseClick(); 00670 d->displayText("Here the experiment starts! click to start!"); 00671 d->waitForMouseClick(); 00672 d->clearScreen(); 00673 //let's see in what mode the user like to run the program 00674 00675 int numOfTests = atoi(argMap["test-rounds"].c_str()) ; 00676 int stringSize = atoi(argMap["string-size"].c_str()); 00677 int meticThreshold = atoi(argMap["metric-threshold"].c_str()) ; 00678 int onsetDel = atoi(argMap["digit-onset"].c_str()) ; 00679 float memPrb = atof(argMap["maintain-prb"].c_str()) ; 00680 int max_miss = atoi(argMap["max-miss"].c_str()); 00681 int max_wrong = atoi(argMap["max-false-click"].c_str()) ; 00682 int in = argMap["interrupt-time-range"].find("-") ; 00683 long iub = atol(argMap["interrupt-time-range"].substr(in+1).c_str()); 00684 long ilb = atol(argMap["interrupt-time-range"].substr(0,in).c_str()) ; 00685 long min_reaction_time = atol(argMap["min-reaction-time"].c_str()) ; 00686 int cue_onset_frames = atoi(argMap["cue-onset-frames"].c_str()) ; 00687 int cue_wait_frames = atoi(argMap["cue-wait-frames"].c_str()) ; 00688 int mask_onset_frames = atoi(argMap["mask-onset-frames"].c_str()) ; 00689 int pause_frames = atoi(argMap["pause-frames"].c_str()); 00690 vector<int> speedVector; 00691 speedVector.push_back(110) ; 00692 speedVector.push_back(-110) ; 00693 speedVector.push_back(150) ; 00694 Mix_PlayChannel( -1, audio_chunk , 500 ) ;////Mix_Pause(-1); 00695 int cr = 0 ; 00696 int fm =0 ; //keeps number of failed memory tests 00697 int sm = 0 ; //keeps number of successful memory tests 00698 int ssfr=0 ; //keeps number of successful sorts but failed reactions 00699 int fssr=0 ; //keeps number of failed sorting and suuccessful reaction 00700 int sssr=0 ; //keeps number of successful sorting and successful reaction 00701 int fsfr=0 ; //keeps number of failed sorting and failed reactions 00702 vector<long> correctAnswersTiming; 00703 vector<long> incorrectAnswersTiming; 00704 vector<long> allTiming ; 00705 while( cr <numOfTests ){ 00706 float mP = (float) rand()/RAND_MAX ; 00707 if(mP > memPrb){ 00708 00709 d->pushEvent("**************************************") ; 00710 d->showCursor(true); 00711 d->displayText("click one of the mouse buttons to start!"); 00712 d->waitForMouseClick() ; 00713 d->showCursor(false) ; 00714 string testString ; 00715 vector<long> reactionTimes ; 00716 testString = getARandomString(stringSize, argMap["alphabet"] , meticThreshold);// digitMemorizationTask(stringSize, argMap["alphabet"] , wr , hr , onsetDel) ; 00717 d->clearScreen() ; 00718 d->displayFixationBlink(); 00719 d->displayText(testString,true,0) ; 00720 d->waitFrames(onsetDel) ; 00721 d->clearScreen() ; 00722 if(argMap["mask"].compare("y")==0) showMask(mask_onset_frames,argMap["alphabet"]); 00723 if(cue_wait_frames != 0) d->waitFrames(cue_wait_frames) ; 00724 d->displayRedDotFixation(); 00725 d->waitFrames(cue_onset_frames); 00726 int cs = 0 ;//this is the index of the speed presented initially starts from 0 00727 //Mix_Resume(-1) ; 00728 motor->setMotor(speedVector[cs]) ; 00729 long st = d->getTimerValue() ; 00730 d->clearScreen() ; 00731 d->pushEvent("manipulation starts"); 00732 d->pushEvent("the sequence for manipulation is : "+testString) ; 00733 long tst =0 ; 00734 long tet =0 ; 00735 long dst = 0 ; 00736 long det = 0 ; 00737 long dl = 0 ; 00738 dl = ilb+ random() % (iub-ilb);//we get a value for next stop 00739 dst = d->getTimerValue() ; 00740 det = dst ; 00741 int missed = 0 ; 00742 bool exitFlag = false ; 00743 bool clickFlag = false ; 00744 int ms = -1 ;//holds mouseclick status 00745 int wrongclick = 0 ; 00746 while( !exitFlag ){ 00747 00748 if (det - dst > dl ){ 00749 cs = getNext(cs) ;//choose the index of next speed 00750 motor->setMotor(0) ; 00751 d->waitFrames(pause_frames); 00752 motor->setMotor(speedVector[cs]) ; 00753 tst = d->getTimerValue() ; 00754 det=tst ; 00755 if(clickFlag){ 00756 missed++ ; 00757 d->pushEvent("missed one change"); 00758 } 00759 clickFlag=true ; 00760 dst = det ; 00761 dl = ilb+ random() % (iub-ilb);//we get a value for next stop 00762 } 00763 ms = myCheckForMouseClick() ; 00764 if(ms==2) exitFlag = true ; 00765 det = d->getTimerValue() ; 00766 00767 if(clickFlag && ms==1){ 00768 clickFlag = false ; 00769 tet = d->getTimerValue() ; 00770 reactionTimes.push_back(tet-tst); 00771 d->pushEvent("reaction time :" + stringify(tet-tst)); 00772 }else{if(ms==1) wrongclick++ ;} 00773 } 00774 00775 long et = d->getTimerValue(); 00776 motor->setMotor(0) ; 00777 //Mix_Pause(-1); 00778 d->pushEvent("manipulation ends") ; 00779 d->pushEvent("maniupulation time : "+stringify(et-st)) ;allTiming.push_back(et-st); 00780 d->clearScreen(); 00781 string answer = getDigitSequenceFromSubject(argMap["alphabet"] , testString.size()); 00782 00783 bool af = false ; 00784 af = isAnswerCorrect(testString,answer,1); 00785 d->pushEvent("subject keyed : "+answer); 00786 d->pushEvent("avarage reaction time : "+ stringify(getAvarage(reactionTimes))) ; 00787 d->pushEvent("number of missed events : "+stringify(missed)); 00788 d->pushEvent("number of caught events : "+stringify(reactionTimes.size())) ; 00789 if(missed <= max_miss && getAvarage(reactionTimes)<= min_reaction_time && wrongclick <= max_wrong){ 00790 cr++; 00791 d->pushEvent("valid trial"); 00792 if(af){ 00793 d->pushEvent("answer was correct");sssr++;correctAnswersTiming.push_back(et-st) ; 00794 }else{ 00795 d->pushEvent("answer was incorrect");fssr++; incorrectAnswersTiming.push_back(et-st); 00796 } 00797 }else{ 00798 if(wrongclick > max_wrong) { 00799 d->displayText("Trial failed, too many FALSE REPORT! Click to start over!"); 00800 d->waitForMouseClick(); 00801 } 00802 if(missed > max_miss) { 00803 d->displayText("Trial failed, too many events missed! Click to start over!"); 00804 d->waitForMouseClick(); 00805 } 00806 if(getAvarage(reactionTimes) > min_reaction_time){ 00807 d->displayText("Trial failed, reaction slower than limit! Click to start over!"); 00808 d->waitForMouseClick(); 00809 } 00810 if(af){ 00811 d->pushEvent("answer was correct");ssfr++; 00812 }else{ 00813 d->pushEvent("answer was incorrect");fsfr++; 00814 } 00815 d->pushEvent("invalid trial"); 00816 } 00817 00818 }else{ 00819 d->pushEvent("+++++++++++++++++++++++++++++++++++++++") ; 00820 d->showCursor(true); 00821 d->displayText("click one of the mouse buttons to start!"); 00822 d->waitForMouseClick() ; 00823 d->showCursor(false) ; 00824 string testString ; 00825 testString = getARandomString(stringSize, argMap["alphabet"] , meticThreshold);// digitMemorizationTask(stringSize, argMap["alphabet"] , wr , hr , onsetDel) ; 00826 d->clearScreen() ; 00827 d->displayFixationBlink(); 00828 d->displayText(testString,true,0) ; 00829 d->waitFrames(onsetDel) ; 00830 d->clearScreen() ; 00831 if(argMap["mask"].compare("y")==0) showMask(mask_onset_frames,argMap["alphabet"]); 00832 if(cue_wait_frames != 0) d->waitFrames(cue_wait_frames) ; 00833 d->displayFixationBlink(d->getWidth()/2,d->getHeight()/2,1,3); 00834 d->pushEvent("the memorization sequence is : "+testString) ; 00835 00836 d->pushEvent("subject is being challenged for simple momorization"); 00837 d->clearScreen(); 00838 00839 string answer = getDigitSequenceFromSubject(argMap["alphabet"] , testString.size()); 00840 00841 bool af = false ; 00842 af = isAnswerCorrect(testString,answer,0); 00843 d->pushEvent("subject keyed : "+answer); 00844 if(af){ 00845 d->pushEvent("correct answer"); 00846 sm++; 00847 }else{ 00848 d->pushEvent("incorrect answer"); 00849 fm++ ; 00850 } 00851 00852 } 00853 } 00854 00855 d->pushEvent("number of successful memory tests :" + stringify(sm)); 00856 d->pushEvent("number of failed memory tests :" + stringify(fm)) ; 00857 d->pushEvent("number of successful sorting and successful reaction trials :"+stringify(sssr)); 00858 d->pushEvent("number of successful sorting and failed reaction trials :"+stringify(ssfr)); 00859 d->pushEvent("number of failed sorting and successful reaction trials :"+stringify(fssr)); 00860 d->pushEvent("number of failed sorting and failed reaction trials :"+stringify(fsfr)); 00861 d->pushEvent("avarage time for respond :"+ stringify(getAvarage(allTiming))); 00862 d->pushEvent("variance of respond :"+ stringify(getVariance(allTiming))); 00863 d->pushEvent("avarage time for correct answers "+stringify(getAvarage(correctAnswersTiming))) ; 00864 d->pushEvent("variance of correct responds :"+ stringify(getVariance(correctAnswersTiming))); 00865 d->clearScreen(); 00866 d->displayText("Experiment complete. Thank you!"); 00867 d->waitForMouseClick(); 00868 Mix_FreeChunk( audio_chunk ); 00869 Mix_CloseAudio(); 00870 // stop all our ModelComponents 00871 manager.stop(); 00872 00873 00874 // all done! 00875 return 0; 00876 } 00877 00878 #endif // INVT_HAVE_LIBSDL_IMAGE 00879