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