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/psychoWMS-M.C $ 00035 // $Id: psychoWMS-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 map<string,vector<SDL_Rect*>*> clipsmap; 00094 Mix_Chunk *whitenoise_chunk = NULL; 00095 00096 ////////////////////////////////////////////// 00097 // a functionf for stringigying things 00098 ////////////////////////////////////////////// 00099 template <class T> std::string stringify(T i) 00100 { 00101 ostringstream o ; 00102 o << i ; 00103 return o.str(); 00104 } 00105 00106 00107 00108 double getAvarage(vector<long> v){ 00109 double f = 0.0 ; 00110 for( uint i = 0 ; i < v.size() ; i++ ){ 00111 f += v[i] ; 00112 } 00113 if (v.size()!=0) return f/v.size() ; 00114 return -1 ; 00115 } 00116 00117 double getVariance(vector<long> v){ 00118 double m = getAvarage(v); 00119 double var = 0.0 ; 00120 for( uint i = 0 ; i < v.size(); i++ ){ 00121 var += (v[i]-m)*(v[i]-m) ; 00122 } 00123 if (v.size()!=0) return var/v.size() ; 00124 return -1 ; 00125 } 00126 00127 00128 //pushes back the name of files in the directory into the given vector 00129 int getdir (string dir, vector<string> &files) 00130 { 00131 DIR *dp; 00132 struct dirent *dirp; 00133 if((dp = opendir(dir.c_str())) == NULL) { 00134 cout << "Error(" << errno << ") opening " << dir << endl; 00135 return errno; 00136 } 00137 string fn = "" ; 00138 size_t found; 00139 string extension = "" ; 00140 while ((dirp = readdir(dp)) != NULL) { 00141 fn = string(dirp->d_name) ; 00142 found = fn.find_last_of("."); 00143 if(found > 0 && found <1000){ 00144 extension = fn.substr(found) ; 00145 if(extension.compare(".png")== 0 || extension.compare(".jpg")==0 ) 00146 files.push_back(dir+"/"+fn); 00147 } 00148 } 00149 closedir(dp); 00150 return 0; 00151 } 00152 00153 00154 00155 //////////////////////////////////////////////////////////////// 00156 ////This is our button factory 00157 //////////////////////////////////////////////////////////////// 00158 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){ 00159 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00160 textIm.clear(bgcolor); 00161 writeText(textIm, Point2D<int>((size.i - label.length()*10)/2,(size.j-20) /2),label.c_str(),txtcolor,bgcolor); 00162 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00163 Uint32 bc = d->getUint32color(bordercolor); 00164 drawRectangle(surf,bc,0,0,size.i -1,size.j -1 ,border); 00165 SDL_Surface* blank =getABlankSurface(size.i , size.j); 00166 SDL_Rect clip; 00167 clip.x = 0 ; 00168 clip.y = 0 ; 00169 clip.w = size.i ; 00170 clip.h = size.j ; 00171 apply_surface(0,0,*surf,*blank,clip); 00172 dumpSurface(surf) ; 00173 return blank ; 00174 } 00175 00176 //////////////////////////////////////////////////////////////////////// 00177 ////This is the function for creating the keypad, in fact it generates 00178 ////12 buttons and associates the actions to the region for each button 00179 //////////////////////////////////////////////////////////////////////// 00180 00181 SDL_Surface* getKeyPad(string alphabet,map<string , SDL_Rect>& buttmap){ 00182 SDL_Surface* pad= getABlankSurface(d->getWidth()/4,d->getHeight()/3); 00183 SDL_Rect clip; 00184 clip.x=0; 00185 clip.y=0; 00186 int numofrows = alphabet.size()/3 +1; 00187 if(alphabet.size()%3 != 0 ) numofrows++ ; 00188 int numofcolumns = 3 ; 00189 clip.w= pad->w / numofcolumns ; 00190 clip.h = pad->h / numofrows ; 00191 00192 //keys for 1 to 9 00193 for( int i = 0 ; i < numofrows*3 ; i++){ 00194 SDL_Surface* but ; 00195 if((uint)i < alphabet.size()){ 00196 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); 00197 }else{ 00198 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); 00199 } 00200 00201 SDL_Rect cl ; 00202 cl.x = ((i)%numofcolumns)*(pad->w)/numofcolumns ; cl.y= ((i)/numofcolumns)*((pad->h)/numofrows) ; 00203 cl.w = clip.w ; 00204 cl.h = clip.h ; 00205 apply_surface( cl.x , cl.y ,*but,*pad,clip); 00206 if((uint)i < alphabet.size()) buttmap[alphabet.substr(i,1)] = cl ; 00207 dumpSurface(but); 00208 } 00209 SDL_Rect cl1 ; 00210 cl1.x = 0 ; cl1.y= (numofrows-1)*((pad->h)/numofrows) ; 00211 cl1.w = clip.w ; 00212 cl1.h = clip.h ; 00213 buttmap["!"] = cl1 ; 00214 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); 00215 apply_surface(0, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00216 dumpSurface(but); 00217 SDL_Rect cl2 ; 00218 cl2.x = (pad->w)/numofcolumns ; cl2.y= (numofrows-1)*((pad->h)/numofrows) ; 00219 cl2.w = clip.w ; 00220 cl2.h = clip.h ; 00221 buttmap[" "] = cl2 ; 00222 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); 00223 apply_surface((pad->w)/numofcolumns, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00224 dumpSurface(but); 00225 SDL_Rect cl3 ; 00226 cl3.x = 2*(pad->w)/numofcolumns ; cl3.y= (numofrows-1)*((pad->h)/numofrows) ; 00227 cl3.w = clip.w ; 00228 cl3.h = clip.h ; 00229 buttmap["*"] = cl3 ; 00230 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); 00231 apply_surface(2*(pad->w)/numofcolumns, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00232 dumpSurface(but); 00233 return pad ; 00234 } 00235 00236 00237 00238 00239 /////////////////////////////////////////////////////////////////////////// 00240 /////this function listens to mouse clicks and then finds the region of the screen 00241 /////associated with the action, buttmap is the map of the region, offset is the offset of 00242 /////buttons 00243 /////////////////////////////////////////////////////////////////////////// 00244 string getPressedButtonCommand(map<string , SDL_Rect>& buttmap,Point2D<int> offset=Point2D<int>(0,0)){ 00245 int quit = 0 ; 00246 string s ; 00247 SDL_Event event ; 00248 while( quit!=2 ){ 00249 while( SDL_PollEvent( &event ) ) { 00250 if(event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT ){ 00251 for( map<string , SDL_Rect>::iterator it = buttmap.begin() ; it!=buttmap.end() ; ++it){ 00252 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) { 00253 quit = 2 ; 00254 s = it->first ; 00255 break; 00256 } 00257 00258 } 00259 } 00260 00261 } 00262 } 00263 return s ; 00264 00265 } 00266 00267 00268 //////////////////////////////////////////////////// 00269 ////This function creates a virtual keypad, creates a map of buttons 00270 ////and their representation area and listens to the button press and at 00271 ////the end returns the keyed digits 00272 //////////////////////////////////////////////////// 00273 string getDigitSequenceFromSubject(string alphabet="0123456789" , uint maxl = 7 ){ 00274 d->showCursor(true) ; 00275 //let's creat a map to map actions to regions of the screen, each region is represented as an SDL_Rect 00276 map<string , SDL_Rect>* buttmap = new map<string , SDL_Rect>(); 00277 //now let's get the keypad surface while we get the actions map to regions 00278 SDL_Surface * keypad = getKeyPad(alphabet,*buttmap); 00279 //this will be the offset of displaying the keypad on the screen 00280 SDL_Rect offset ; 00281 offset.x = (d->getWidth() - keypad->w) /2; 00282 offset.y = (d-> getHeight() - keypad->h) /2; 00283 //now let's display the keypad 00284 d->displaySDLSurfacePatch(keypad , &offset,NULL , -2,false, true); 00285 //this will hold the final string keyed be the subject 00286 string p = string("") ; 00287 //this is a temporary string holding the last action related to the pressed key 00288 string tp = string(""); 00289 //now let's record subject's key press 00290 while( tp.compare("*")!=0 ){ 00291 //this button is actually the display for the current string 00292 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) ; 00293 SDL_Rect offs ; offs.x = (d->getWidth() - dp->w) /2 ; offs.y = d->getHeight()/6 ; 00294 d->displaySDLSurfacePatch(dp , &offs , NULL , -2 , false ,true ) ; 00295 //now let's listen to button events 00296 tp = getPressedButtonCommand(*buttmap,Point2D<int>(offset.x,offset.y)) ; 00297 dumpSurface(dp) ; 00298 if(tp.compare("!")==0 && p.size()>=0 ) { 00299 if (p.size()>0) p = p.substr(0,p.size()-1) ; 00300 }else{ 00301 if(p.size() < maxl && tp.compare("*")!=0) { 00302 p +=tp ; 00303 } 00304 00305 } 00306 00307 } 00308 buttmap = 0 ; 00309 dumpSurface(keypad) ; 00310 d->clearScreen() ; 00311 return p ; 00312 00313 } 00314 00315 00316 00317 00318 int addArgument(const string st,const string delim="="){ 00319 int i = st.find(delim) ; 00320 argMap[st.substr(0,i)] = st.substr(i+1); 00321 00322 return 0 ; 00323 } 00324 00325 std::string getArgumentValue(string arg){ 00326 return argMap[arg] ; 00327 } 00328 00329 std::string getUsageComment(){ 00330 00331 string com = string("\nlist of arguments : \n"); 00332 00333 com += "\nlogfile=[logfilename.psy] {default = psycho-stroop-concurrent.psy}\n" ; 00334 com += "\nmemo=[a_string_without_white_space]\n"; 00335 com += "\nrange=[x-y](the size of string){default=200-500} \n"; 00336 com += "\nsubject=[subject_name] \n" ; 00337 com += "\ndelay=[>0] (number of frames that subject should do subtraction operation){default=30000000}\n"; 00338 com += "\ntest-rounds=[>1] (number of tests ) {default=5}\n"; 00339 com += "\ndigit-onset=[>1] (number of frames that the string will remain onset ){default=10}\n"; 00340 com += "\nsubtraction-step=[>0] (the subtraction number){default=3} "; 00341 com += "\nsound-dir=[path to wav files directory]{default=..}\n"; 00342 com += "\nnoise-file=[white noise file]{default=whitenoise.wav}\n"; 00343 com += "\npuase-frames=[number of frames for stopping the motor]{default=5}\n"; 00344 com += "\nmin-reaction-time=[>0](minimum value for avarage reaction time in microsecond in order to consider a trial valid){default=1000000}\n" ; 00345 com += "\nmax-miss=[>0](maximum misses in a trial in order to be considered as a valid one){default=10}\n"; 00346 com += "\ninterrupt-time-range=[x-y](this defines a range of uniform radom distribution by which the perceptual interruption happens){default=500000-5000000}\n" ; 00347 return com ; 00348 } 00349 00350 int myCheckForMouseClick() 00351 { 00352 SDL_Event event; 00353 00354 while(SDL_PollEvent(&event)) 00355 { 00356 if (event.type == SDL_MOUSEBUTTONDOWN) 00357 { 00358 if(event.button.button == SDL_BUTTON_LEFT) { 00359 return 1 ; 00360 } 00361 if(event.button.button == SDL_BUTTON_RIGHT) { 00362 return 2 ; 00363 } 00364 00365 } 00366 // ignore other events 00367 } 00368 00369 // there was no event in the event queue: 00370 return -1; 00371 } 00372 00373 00374 00375 int getClick(){ 00376 // while (myCheckForMouseClick() != -1) ; 00377 SDL_Event event; 00378 bool report = false ; 00379 int i = 0; // will be returned if any other button than left or right 00380 do { 00381 do { SDL_WaitEvent(&event); } while (event.type != SDL_MOUSEBUTTONDOWN); 00382 if (event.button.button == SDL_BUTTON_LEFT) { 00383 i = 0 ; 00384 report = true ; 00385 } 00386 if (event.button.button == SDL_BUTTON_RIGHT) { 00387 i = 1 ; 00388 report = true ; 00389 } 00390 00391 }while(!report) ; 00392 00393 return i ; 00394 00395 } 00396 00397 int getAllKindOfClick(){ 00398 // while (myCheckForMouseClick() != -1) ; 00399 SDL_Event event; 00400 bool report = false ; 00401 int i = 0; // will be returned if any other button than left or right 00402 do { 00403 do { SDL_WaitEvent(&event); } while (event.type != SDL_MOUSEBUTTONDOWN); 00404 long st = d->getTimerValue(); 00405 long et = st ; 00406 00407 if (event.button.button == SDL_BUTTON_LEFT) { 00408 i = 0 ; 00409 report = true ; 00410 while( et-st < 300000){ 00411 et = d->getTimerValue() ; 00412 if(myCheckForMouseClick()==1) return 2 ; 00413 } 00414 } 00415 if (event.button.button == SDL_BUTTON_RIGHT) { 00416 i = 1 ; 00417 report = true ; 00418 } 00419 00420 }while(!report) ; 00421 00422 return i ; 00423 00424 } 00425 00426 int getNext(int i){ 00427 00428 int r = 1 ; 00429 if(i == 0 || i == 2) return 1 ; 00430 if(i==1) return 0; 00431 return r ; 00432 } 00433 00434 extern "C" int main(const int argc, char** argv) 00435 { 00436 00437 MYLOGVERB = LOG_INFO; // suppress debug messages 00438 //let's push the initial value for the parameters 00439 argMap["experiment"]="subtraction-working-memory"; 00440 argMap["logfile"]="psycho-ws-m.psy" ; 00441 argMap["string-size"]="5" ; 00442 argMap["test-rounds"]="5"; 00443 argMap["subject"]="" ; 00444 argMap["memo"]="" ; 00445 argMap["digit-onset"]="10" ; 00446 argMap["range"]="200-500"; 00447 argMap["delay"]="30000000" ; 00448 argMap["subtraction-step"]="3" ; 00449 argMap["sound-dir"]=".."; 00450 argMap["noise-file"]="whitenoise.wav"; 00451 argMap["pause-frames"]="5" ; 00452 argMap["min-reaction-time"]="1000000" ; 00453 argMap["max-miss"]="10" ; 00454 argMap["interrupt-time-range"]= "500000-5000000"; 00455 argMap["mode"]="1"; 00456 00457 manager.addSubComponent(d); 00458 manager.addSubComponent(motor) ; 00459 nub::soft_ref<EventLog> el(new EventLog(manager)); 00460 manager.addSubComponent(el); 00461 d->setEventLog(el); 00462 00463 if (manager.parseCommandLine(argc, argv, 00464 "at least one argument needed", 1, -1)==false){ 00465 cout<<getUsageComment()<<endl; 00466 return(1); 00467 } 00468 00469 for(uint i = 0 ; i < manager.numExtraArgs() ; i++){ 00470 addArgument(manager.getExtraArg(i),std::string("=")) ; 00471 } 00472 00473 manager.setOptionValString(&OPT_EventLogFileName, argMap["logfile"]); 00474 00475 if( Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 4096 ) == -1 ){ 00476 LINFO( "did not open the mix-audio") ; 00477 return -1 ; 00478 } 00479 string noisestr = argMap["sound-dir"] + "/" + argMap["noise-file"]; 00480 whitenoise_chunk = Mix_LoadWAV(noisestr.c_str()); 00481 if( whitenoise_chunk == NULL ) 00482 { 00483 LINFO("did not find the indicated wav files!"); 00484 return -1; 00485 } 00486 00487 00488 00489 // let's get all our ModelComponent instances started: 00490 manager.start(); 00491 for(map<string,string>::iterator it= argMap.begin(); it!= argMap.end() ; ++it) d->pushEvent("arg:"+ it->first+" value:"+it->second ) ; 00492 // let's display an ISCAN calibration grid: 00493 d->clearScreen(); 00494 d->displayISCANcalib(); 00495 d->waitForMouseClick(); 00496 d->displayText("Here the experiment starts! click to start!"); 00497 d->waitForMouseClick(); 00498 d->clearScreen(); 00499 //let's see in what mode the user like to run the program 00500 00501 int numOfTests = atoi(argMap["test-rounds"].c_str()) ; 00502 int onsetDel = atoi(argMap["digit-onset"].c_str()) ; 00503 int opDelay = atoi(argMap["delay"].c_str()); 00504 int in = argMap["range"].find("-") ; 00505 int rangeU = atoi( argMap["range"].substr(in+1).c_str()) ; 00506 int rangeL = atoi(argMap["range"].substr(0,in).c_str()) ; 00507 int step = atoi(argMap["subtraction-step"].c_str()); 00508 int max_miss = atoi(argMap["max-miss"].c_str()); 00509 in = argMap["interrupt-time-range"].find("-") ; 00510 long iub = atol(argMap["interrupt-time-range"].substr(in+1).c_str()); 00511 long ilb = atol(argMap["interrupt-time-range"].substr(0,in).c_str()) ; 00512 long min_reaction_time = atol(argMap["min-reaction-time"].c_str()) ; 00513 //let's count the rounds 00514 int cr = 0 ; 00515 vector<int> speedVector; 00516 speedVector.push_back(110) ; 00517 speedVector.push_back(-110) ; 00518 speedVector.push_back(150) ; 00519 int pause_frames = atoi(argMap["pause-frames"].c_str()); 00520 if(argMap["mode"].compare("2")==0){ 00521 while( cr <numOfTests ){ 00522 00523 vector<long> reactionTimes ; 00524 int missed = 0 ; 00525 d->pushEvent("**************************************") ; 00526 d->showCursor(true); 00527 d->displayText("click one of the mouse buttons to start!"); 00528 d->waitForMouseClick() ; 00529 d->showCursor(false) ; 00530 int initialNum = rangeL+ random()%(rangeU-rangeL) ; 00531 d->clearScreen() ; 00532 d->displayFixationBlink(); 00533 d->pushEvent("the initial number is: "+stringify(initialNum)) ; 00534 d->displayText(stringify(initialNum),true,0) ; 00535 d->pushEvent("manupulation starts") ; 00536 d->waitFrames(onsetDel) ; 00537 Mix_PlayChannel( -1, whitenoise_chunk , 300 ) ; 00538 d->clearScreen() ; 00539 long dst = 0 ;//keeps the start of each color set 00540 long det = 0 ;//keeps the current time to be compared with dl 00541 long dl = 0 ;//this is the number of microseconds for a color display 00542 int cs = 0 ;//this is the index of the speed presented initially starts from 0 00543 motor->setMotor(speedVector[cs]) ; 00544 dl = ilb+ random() % (iub-ilb);//let's get a value for the the first color display 00545 dst = d->getTimerValue() ;//this is the initial time of display of the first color 00546 det = dst ; 00547 long tst = 0 ;//tst keeps track of the time new color is presented 00548 long tet = 0 ;//after tst tet is sampled from clock to see how long it will take for the subject to respond 00549 long st = d->getTimerValue(); //this will be a sample of clock at the start of the test round 00550 long et = st ;//this is the current time of process if et-st becomes more than opDelay then we should challenge the subject 00551 bool clickFlag = false ; 00552 00553 while( et - st < opDelay ){ 00554 00555 if (det - dst > dl ){//if we get to a point that the interrupt should be made 00556 00557 cs = getNext(cs) ;//choose the index of next speed 00558 motor->setMotor(0) ; 00559 d->waitFrames(pause_frames); 00560 motor->setMotor(speedVector[cs]) ; 00561 00562 tst = d->getTimerValue() ;//start keeping track of the timer to see how fast the subject will respond 00563 if(clickFlag){ 00564 missed++ ; 00565 d->pushEvent("missed one change"); 00566 } 00567 clickFlag = true ; 00568 dst = tst ; 00569 det = dst ; //let's make sure that a new round is set 00570 dl = ilb+ random() % (iub-ilb);//we get a value for next stop 00571 et= tst ; 00572 } 00573 det = d->getTimerValue() ; 00574 et = det ; 00575 if(clickFlag){// && (myCheckForMouseClick()==1 || myCheckForMouseClick()==2)){ 00576 int c = myCheckForMouseClick() ; 00577 if(c==1 || c==2){ 00578 clickFlag = false ; 00579 tet = d->getTimerValue() ; 00580 d->pushEvent("reaction time :" + stringify(tet-tst)); 00581 reactionTimes.push_back(tet-tst) ; 00582 } 00583 00584 }else{ 00585 myCheckForMouseClick() ;//let's get rid of the queue of the non-related events including the wrong clicks 00586 } 00587 00588 } 00589 d->pushEvent("manipulation ends") ; 00590 motor->setMotor(0) ; 00591 Mix_Pause(-1); 00592 d->clearScreen(); 00593 string answer = getDigitSequenceFromSubject("0123456789" , 3); 00594 d->pushEvent("the reported number: "+answer); 00595 int finalNum = atoi(answer.c_str()) ; 00596 d->pushEvent("number of operations: "+stringify((initialNum-finalNum)/step)); 00597 d->pushEvent("avarage reaction time : "+ stringify(getAvarage(reactionTimes))) ; 00598 d->pushEvent("number of missed events : "+stringify(missed)); 00599 d->pushEvent("number of caught events : "+stringify(reactionTimes.size())) ; 00600 if(missed < max_miss && getAvarage(reactionTimes)<= min_reaction_time ){ 00601 cr++; 00602 d->pushEvent("valid trial"); 00603 }else{ 00604 if(missed >= max_miss) { 00605 d->displayText("Trial failed, too many events missed! Click to start over!"); 00606 d->waitForMouseClick(); 00607 } 00608 if(getAvarage(reactionTimes) > min_reaction_time){ 00609 d->displayText("Trial failed, reaction slower than limit! Click to start over!"); 00610 d->waitForMouseClick(); 00611 } 00612 d->pushEvent("invalid trial"); 00613 } 00614 } 00615 } 00616 00617 if(argMap["mode"].compare("1")==0){ 00618 while( cr <numOfTests ){ 00619 00620 vector<long> reactionTimes ; 00621 int missed = 0 ; 00622 d->pushEvent("**************************************") ; 00623 d->showCursor(true); 00624 d->displayText("click one of the mouse buttons to start!"); 00625 d->waitForMouseClick() ; 00626 d->showCursor(false) ; 00627 d->clearScreen() ; 00628 d->displayFixationBlink(); 00629 d->pushEvent("manupulation starts") ; 00630 Mix_PlayChannel( -1, whitenoise_chunk , 300 ) ; 00631 00632 d->clearScreen() ; 00633 long dst = 0 ;//keeps the start of each color set 00634 long det = 0 ;//keeps the current time to be compared with dl 00635 long dl = 0 ;//this is the number of microseconds for a color display 00636 int cs = 0 ;//this is the index of the speed presented initially starts from 0 00637 motor->setMotor(speedVector[cs]) ; 00638 dl = ilb+ random() % (iub-ilb);//let's get a value for the the first color display 00639 dst = d->getTimerValue() ;//this is the initial time of display of the first color 00640 det = dst ; 00641 long tst = 0 ;//tst keeps track of the time new color is presented 00642 long tet = 0 ;//after tst tet is sampled from clock to see how long it will take for the subject to respond 00643 long st = d->getTimerValue(); //this will be a sample of clock at the start of the test round 00644 long et = st ;//this is the current time of process if et-st becomes more than opDelay then we should challenge the subject 00645 bool clickFlag = false ; 00646 00647 while( et - st < opDelay ){ 00648 00649 if (det - dst > dl ){//if we get to a point that the bloop should be made 00650 cs = getNext(cs) ;//choose the index of next speed 00651 motor->setMotor(0) ; 00652 d->waitFrames(pause_frames); 00653 motor->setMotor(speedVector[cs]) ; 00654 00655 tst = d->getTimerValue() ;//start keeping track of the timer to see how fast the subject will respond 00656 if(clickFlag){ 00657 missed++ ; 00658 d->pushEvent("missed one change"); 00659 } 00660 clickFlag = true ; 00661 dst = tst ; 00662 det = dst ; //let's make sure that a new round is set 00663 dl = ilb+ random() % (iub-ilb);//we get a value for next stop 00664 et= tst ; 00665 } 00666 det = d->getTimerValue() ; 00667 et = det ; 00668 if(clickFlag){// && (myCheckForMouseClick()==1 || myCheckForMouseClick()==2)){ 00669 int c = myCheckForMouseClick() ; 00670 if(c==1 || c==2){ 00671 clickFlag = false ; 00672 tet = d->getTimerValue() ; 00673 d->pushEvent("reaction time :" + stringify(tet-tst)); 00674 reactionTimes.push_back(tet-tst) ; 00675 } 00676 00677 }else{ 00678 myCheckForMouseClick() ;//let's get rid of the queue of the non-related events including the wrong clicks 00679 } 00680 00681 } 00682 d->pushEvent("manipulation ends") ; 00683 motor->setMotor(0) ; 00684 Mix_Pause(-1); 00685 d->clearScreen(); 00686 d->pushEvent("avarage reaction time : "+ stringify(getAvarage(reactionTimes))) ; 00687 d->pushEvent("number of missed events : "+stringify(missed)); 00688 d->pushEvent("number of caught events : "+stringify(reactionTimes.size())) ; 00689 if(missed < max_miss && getAvarage(reactionTimes)<= min_reaction_time ){ 00690 cr++; 00691 d->pushEvent("valid trial"); 00692 }else{ 00693 if(missed >= max_miss) { 00694 d->displayText("Trial failed, too many events missed! Click to start over!"); 00695 d->waitForMouseClick(); 00696 } 00697 if(getAvarage(reactionTimes) > min_reaction_time){ 00698 d->displayText("Trial failed, reaction slower than limit! Click to start over!"); 00699 d->waitForMouseClick(); 00700 } 00701 d->pushEvent("invalid trial"); 00702 } 00703 } 00704 } 00705 00706 d->clearScreen(); 00707 d->displayText("Experiment complete. Thank you!"); 00708 d->waitForMouseClick(); 00709 Mix_FreeChunk( whitenoise_chunk ); 00710 Mix_CloseAudio(); 00711 // stop all our ModelComponents 00712 manager.stop(); 00713 00714 00715 // all done! 00716 return 0; 00717 } 00718 00719 #endif // INVT_HAVE_LIBSDL_IMAGE 00720