00001 /*!@file AppPsycho/psycho-concurrent-still.C Psychophysics display of still for concurrent task images */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppPsycho/psycho-auditory-concurrent.C $ 00035 // $Id: psycho-auditory-concurrent.C 10794 2009-02-08 06:21:09Z itti $ 00036 // 00037 00038 #include "Component/ModelManager.H" 00039 #include "Image/Image.H" 00040 #include "Psycho/PsychoDisplay.H" 00041 #include "Psycho/EyeTrackerConfigurator.H" 00042 #include "Psycho/EyeTracker.H" 00043 #include "Psycho/PsychoOpts.H" 00044 #include "Component/EventLog.H" 00045 #include "Component/ComponentOpts.H" 00046 #include "Raster/Raster.H" 00047 #include "Util/MathFunctions.H" 00048 #include "Util/Types.H" 00049 #include "GameBoard/basic-graphics.H" 00050 #include <sys/types.h> 00051 #include <dirent.h> 00052 #include <errno.h> 00053 #include <vector> 00054 #include <string> 00055 #include <iostream> 00056 #include <SDL/SDL.h> 00057 #include <SDL/SDL_image.h> 00058 #include <SDL/SDL_mixer.h> 00059 #include <stdio.h> 00060 #include <stdlib.h> 00061 #include <sstream> 00062 #include <time.h> 00063 #include "Image/DrawOps.H" 00064 #include "GameBoard/resize.h" 00065 00066 00067 00068 00069 #ifndef INVT_HAVE_LIBSDL_IMAGE 00070 #include <cstdio> 00071 int main() 00072 { 00073 fprintf(stderr, "The SDL_image library must be installed to use this program\n"); 00074 return 1; 00075 } 00076 00077 #else 00078 00079 00080 00081 using namespace std; 00082 // ###################################################################### 00083 ModelManager manager("Psycho Auditory"); 00084 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager)); 00085 map<uint,uint> testMap ; 00086 map<string,string> argMap ; 00087 Mix_Chunk *highchunk = NULL; 00088 Mix_Chunk *mediumchunk = NULL; 00089 Mix_Chunk *lowchunk = NULL; 00090 00091 ////////////////////////////////////////////// 00092 00093 // a functionf for stringigying things 00094 template <class T> std::string stringify(T i) 00095 { 00096 ostringstream o ; 00097 o << i ; 00098 return o.str(); 00099 } 00100 00101 ////////////////////////////////////////////// 00102 00103 //pushes back the name of files in the directory into the given vector 00104 int getdir (string dir, vector<string> &files) 00105 { 00106 DIR *dp; 00107 struct dirent *dirp; 00108 if((dp = opendir(dir.c_str())) == NULL) { 00109 cout << "Error(" << errno << ") opening " << dir << endl; 00110 return errno; 00111 } 00112 string fn = "" ; 00113 size_t found; 00114 string extension = "" ; 00115 while ((dirp = readdir(dp)) != NULL) { 00116 fn = string(dirp->d_name) ; 00117 found = fn.find_last_of("."); 00118 if(found > 0 && found <1000){ 00119 extension = fn.substr(found) ; 00120 if(extension.compare(".png")== 0 || extension.compare(".jpg")==0 ) 00121 files.push_back(dir+"/"+fn); 00122 } 00123 } 00124 closedir(dp); 00125 return 0; 00126 } 00127 00128 void getMouseEvent(){ 00129 bool quit = false ; 00130 SDL_Event event ; 00131 while( quit == false ) { 00132 while( SDL_PollEvent( &event ) ) { 00133 if( event.type == SDL_MOUSEBUTTONDOWN ) { quit = true; } 00134 } 00135 } 00136 } 00137 00138 00139 vector<int> getAuditoryTask(string ts){ 00140 //0 stands for the first highchunk (high pitch) 00141 //1 stands for the second chunk (medium pitch) 00142 //2 stands for the third chunk (low pitch) 00143 string::size_type position = ts.find(":"); 00144 int minTaskSize = atoi(ts.substr(0,position).c_str()) ; 00145 int maxTaskSize = atoi(ts.substr(position+1).c_str()) ; 00146 int taskSize = rand()%((maxTaskSize-minTaskSize)/2); 00147 taskSize += (minTaskSize-1)/2 ; 00148 taskSize = 2*taskSize +1 ; 00149 vector<int> task = vector<int>() ; 00150 for(int i = 0 ; i < taskSize ; i++){ 00151 int current_task = rand()%3; 00152 task.push_back(current_task) ; 00153 } 00154 00155 return task ; 00156 } 00157 00158 00159 void scramble(vector<string>& v){ 00160 vector<string> tv = vector<string>() ; 00161 while(v.size()>0){ 00162 tv.push_back(v[0]); 00163 v.erase(v.begin()); 00164 } 00165 int i = 0 ; 00166 while(tv.size()>0){ 00167 i = rand()%tv.size() ; 00168 v.push_back(tv[i]); 00169 tv.erase(tv.begin()+i); 00170 } 00171 } 00172 //this function is used for the memory task, it takes in two lists of file names, one as the target list and 00173 //the second as test images, then it scramble the aggragated list and displays a random array of images, upon 00174 //click on one image a fram apears around the image and by clicking on the framed image the image is selected 00175 //as subject's choice, the choice and correctness will be logged 00176 bool memoryTest(vector<string> dil , vector<string> cil){ 00177 d->showCursor(true); 00178 bool flag = false ; 00179 //here we decide what is size of grid of images, number of rows and columns are equal 00180 int sf = (int)sqrt(dil.size()+cil.size()) ; 00181 if((uint)(sf*sf) < dil.size()+cil.size() ) sf++ ; 00182 float sizefactor = 1.0f/(float)sf ; 00183 //fls is the aggregated list of file names 00184 vector<string>* fls = new vector<string>() ; 00185 //let's put everything in fls 00186 for(uint i = 0 ; i < dil.size() ; i++){ 00187 fls->push_back(dil[i]); 00188 } 00189 for(uint i = 0 ; i < cil.size() ; i++){ 00190 fls->push_back(cil[i]); 00191 } 00192 // and then scramble the list in a random fashion 00193 scramble(*fls) ; 00194 //this surface is used for final display 00195 SDL_Surface* blank = getABlankSurface(d->getWidth(),d->getHeight()) ; 00196 //this surface keeps the original display images in the case that we need to refresh the 00197 //the display with original image this one will be copied to blank 00198 SDL_Surface* oblank = getABlankSurface(d->getWidth(),d->getHeight()) ; 00199 d->displayText("Time for a memory test!",true, 1); 00200 //cout<<cil.size()<< " "<<dil.size()<<" "<<fls->size()<<endl; 00201 00202 //this surface is used as the progress bar 00203 SDL_Surface* pbar = getABlankSurface((d->getWidth())/2,(d->getHeight())/25); 00204 SDL_Rect pbarOffset = SDL_Rect(); 00205 pbarOffset.x = (d->getWidth() - pbar->w )/2 ; 00206 pbarOffset.y = (d->getHeight() - pbar->h)/2 ; 00207 d->displaySDLSurfacePatch(pbar , &pbarOffset,NULL , -2,false, true); 00208 00209 //Now let's load up the images, resize them and put them in the right place of the display 00210 int c = 0 ; 00211 for(int i = 0 ; i < sf ; i++){ 00212 for(int j = 0 ; j < sf ; j++){ 00213 if((uint)(j*sf + i) < fls->size()){ 00214 c++ ; 00215 //let's load the image 00216 SDL_Surface* ts = load_image((*fls)[j*sf + i]); 00217 sizefactor = min(((float)(d->getWidth()))/sf/((float)(ts->w)),((float)(d->getHeight()))/sf/((float)(ts->h))); 00218 //here we resize the image 00219 ts = SDL_Resize(ts,sizefactor,5) ; 00220 //cout<<(j*sf + i)<<" " <<(*fls)[j*sf + i]<<endl 00221 SDL_Rect* clip = new SDL_Rect() ; 00222 clip->x = 0 ; 00223 clip->y = 0 ; 00224 clip->w = ts->w ; 00225 clip->h = ts->h ; 00226 SDL_Rect offset; 00227 offset.x = i*(d->getWidth())/sf + ((d->getWidth())/sf - ts->w)/2; 00228 offset.y = j*(d->getHeight())/sf + ((d->getHeight())/sf - ts->h)/2; 00229 00230 //here we apply the surface patch on both copies of the displaying image 00231 apply_surface(offset.x, offset.y,*ts,*blank ,*clip); 00232 apply_surface(offset.x, offset.y,*ts,*oblank ,*clip); 00233 //let's free up the pointers 00234 dumpSurface(ts); 00235 delete clip ; 00236 //let's draw the progress bar 00237 Uint32 color = d->getUint32color(PixRGB<byte>(255, 98 , 25)); 00238 fillRectangle(pbar,color,0,0,(int)((float)((j*sf + i + 1)*(pbar->w))/(float)(fls->size())) , pbar->h); 00239 fillRectangle(pbar,color,0,0,(int)((float)c/float(fls->size())) , pbar->h); 00240 d->displaySDLSurfacePatch(pbar , &pbarOffset,NULL , -2,false, true); 00241 } 00242 00243 00244 } 00245 } 00246 //here we are ready for displaying the image so let's ask the subject to continue 00247 d->displayText("Click to start!",true); 00248 SDL_Rect offset; 00249 offset.x = 0; 00250 offset.y = 0; 00251 getMouseEvent() ; 00252 d->displaySDLSurfacePatch(blank , &offset,NULL , -2,false, true); 00253 uint quit = 0 ; 00254 SDL_Event event ; 00255 int fmx = 0 ; 00256 int fmy = 0 ; 00257 int smx = 0 ; 00258 int smy = 0 ; 00259 int choice1 = 0 ; 00260 int choice2 = 0 ; 00261 //here we interact with the subject in order to get the subject's choice 00262 while( quit != 2 ) { 00263 while( SDL_PollEvent( &event ) ) { 00264 00265 if( event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT 00266 && event.button.x > offset.x && event.button.x <= offset.x + blank->w 00267 && event.button.y > offset.y && event.button.y <= offset.y + blank->h 00268 && quit == 1 00269 ) { 00270 smx = event.button.x ; 00271 smy = event.button.y ; 00272 choice2 = (int)(sf*(smx-offset.x)/(d->getWidth())) + sf*(int)(sf*(smy-offset.y)/(d->getHeight())) ; 00273 if(choice1 == choice2){ 00274 if((uint)choice1 < fls->size()){ 00275 quit = 2 ; 00276 d->pushEvent("memory test choice : "+(*fls)[choice1]); 00277 00278 for(uint f = 0 ; f < dil.size() ; f++){ 00279 if((*fls)[choice1].compare(dil[f])==0) { 00280 flag = true ; 00281 break ; 00282 } 00283 } 00284 00285 if (flag==true){ 00286 d->pushEvent("memory test result : correct" ); 00287 }else{ 00288 d->pushEvent("memory test result : incorrect" ); 00289 } 00290 00291 cout<< "second choice "<< choice2 <<endl; 00292 }else{ 00293 quit = 3 ; 00294 SDL_Rect* clip = new SDL_Rect() ; 00295 clip->x = 0 ; 00296 clip->y = 0 ; 00297 clip->w = d->getWidth() ; 00298 clip->h = d->getHeight() ; 00299 apply_surface(0,0,*oblank,*blank,*clip) ; 00300 delete clip ; 00301 d->displaySDLSurfacePatch(blank , &offset,NULL , -2,false, true); 00302 00303 } 00304 00305 }else{ 00306 quit = 3 ; 00307 SDL_Rect* clip = new SDL_Rect() ; 00308 clip->x = 0 ; 00309 clip->y = 0 ; 00310 clip->w = d->getWidth() ; 00311 clip->h = d->getHeight() ; 00312 apply_surface(0,0,*oblank,*blank,*clip) ; 00313 delete clip ; 00314 d->displaySDLSurfacePatch(blank , &offset,NULL , -2,false, true); 00315 } 00316 } 00317 00318 if( event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT 00319 && event.button.x > offset.x && event.button.x <= offset.x + blank->w 00320 && event.button.y > offset.y && event.button.y <= offset.y + blank->h 00321 && quit == 0 00322 ) { 00323 SDL_Rect* clip = new SDL_Rect() ; 00324 clip->x = 0 ; 00325 clip->y = 0 ; 00326 clip->w = d->getWidth() ; 00327 clip->h = d->getHeight() ; 00328 apply_surface(0,0,*oblank,*blank,*clip) ; 00329 delete clip ; 00330 quit = 1; 00331 fmx = event.button.x ; 00332 fmy = event.button.y ; 00333 int i = sf*(fmx-offset.x)/(d->getWidth()) ; 00334 int j = sf*(fmy-offset.y)/(d->getHeight()); 00335 cout<<"("<<sf*(fmx-offset.x)/(d->getWidth())<<","<<sf*(fmy-offset.y)/(d->getHeight())<<")"<<endl ; 00336 choice1 = (int)(sf*(fmx-offset.x)/(d->getWidth())) + sf*(int)(sf*(fmy-offset.y)/(d->getHeight())) ; 00337 cout<<"first choice:" << choice1 <<endl; 00338 Uint32 color = d->getUint32color(PixRGB<byte>(255, 98 , 25)); 00339 drawRectangle(blank , color , i*(d->getWidth())/sf , j*(d->getHeight())/sf ,(d->getWidth())/sf , (d->getHeight())/sf , 5) ; 00340 d->displaySDLSurfacePatch(blank , &offset,NULL , -2,false, true); 00341 } 00342 00343 if(quit==3) quit=0 ; 00344 00345 } 00346 } 00347 00348 00349 //d->waitFrames(200 ); 00350 dumpSurface(blank); 00351 dumpSurface(oblank); 00352 dumpSurface(pbar) ; 00353 delete fls ; 00354 return flag ; 00355 } 00356 00357 00358 void firstTask(const uint l){ 00359 Uint32 green = d->getUint32color(PixRGB<byte>(0, 255, 0)); 00360 Uint32 blue = d->getUint32color(PixRGB<byte>(0, 0, 255)); 00361 Uint32 red = d->getUint32color(PixRGB<byte>(255,0,0)); 00362 Uint32 color = 0 ; 00363 int c = 0 ; 00364 SDL_Rect offset; 00365 d->clearScreen() ; 00366 //Give the offsets to the rectangle 00367 SDL_Surface* blankSurface = getABlankSurface(d->getWidth(),d->getHeight()) ; 00368 offset.x = (d->getWidth() - blankSurface->w) /2; 00369 offset.y = (d-> getHeight() - blankSurface->h) /2; 00370 for (uint i = 0 ; i < l ; i++){ 00371 c = rand()%3 ; 00372 switch(c){ 00373 case 0 : color = red ;break; 00374 case 1 : color = green ; break ; 00375 case 2 : color = blue ; break ; 00376 } 00377 00378 fillQuadricRadiant(blankSurface,color,rand()%(blankSurface->w -100 ) + 50 ,rand()%(blankSurface->h -100)+50,20) ; 00379 d->displaySDLSurfacePatch(blankSurface , &offset,NULL , -2,false, true); 00380 d->waitFrames(10); 00381 } 00382 dumpSurface(blankSurface) ; 00383 } 00384 00385 /////////////////////////////////////////////////////////////////// 00386 void volumeAdjustment(const int randBase , const string extraMessage = "continue" ){ 00387 int rndBase = randBase+1 ; 00388 map<int,string> imap = map<int,string>(); 00389 imap[0] = "high"; 00390 imap[1] = "medium" ; 00391 imap[2] = "low" ; 00392 imap[3] = extraMessage ; 00393 d->clearScreen(); 00394 d->pushEvent(std::string("voluem adjustment called")); 00395 d->displayText(std::string("click on the botton to play or cancel?"),true,1); 00396 //we need the subject be able to interact with the mouse 00397 d->showCursor(true); 00398 SDL_Surface* blank =getABlankSurface((d->getWidth())/2 , d->getHeight()/10); 00399 //we make a scrap image to write down the numbers on 00400 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00401 textIm.clear(PixRGB<byte>(182, 145, 225)); 00402 //here we write the numbers 00403 for(int i = 0 ; i < rndBase ; i ++){ 00404 writeText(textIm, Point2D<int>((blank->w)/(2*rndBase) -2,10+100*i), imap[i].c_str()); 00405 } 00406 //and here we make a blittabl surface out of that 00407 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00408 //and take out differnt clips out of that 00409 SDL_Rect clip; 00410 clip.x = 0 ; 00411 clip.w = (blank->w)/rndBase - 2 ; 00412 clip.h =blank->h ; 00413 for(int i = 0 ; i < rndBase ; i++){ 00414 clip.y = i*100 ; 00415 apply_surface(i*(clip.w + 2),0,*surf,*blank,clip); 00416 } 00417 00418 SDL_Rect offset; 00419 offset.x = (d->getWidth() - blank->w) /2; 00420 offset.y = (d-> getHeight() - blank->h) /2; 00421 d->pushEvent("the button panel is going up"); 00422 d->displaySDLSurfacePatch(blank , &offset,NULL , -2,false, true); 00423 00424 bool quit = false ; 00425 SDL_Event event ; 00426 int mx = 0 ; 00427 int my = 0 ; 00428 while( quit == false ) { 00429 while( SDL_PollEvent( &event ) ) { 00430 if( event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT 00431 && event.button.x > offset.x && event.button.x <= offset.x + blank->w 00432 && event.button.y > offset.y && event.button.y <= offset.y + blank->h 00433 ) { 00434 //quit = true; 00435 mx = event.button.x ; 00436 my = event.button.y ; 00437 switch( (mx - offset.x) / ((blank->w)/rndBase) ){ 00438 case 0 : Mix_PlayChannel( -1, highchunk, 0 ) ;break ; 00439 case 1 : Mix_PlayChannel( -1, mediumchunk, 0 ) ;break ; 00440 case 2 : Mix_PlayChannel( -1, lowchunk, 0 ) ;break ; 00441 case 3 : quit=true ; break ; 00442 } 00443 } 00444 } 00445 00446 } 00447 00448 dumpSurface(blank); 00449 dumpSurface(surf) ; 00450 d->showCursor(false); 00451 00452 } 00453 00454 00455 00456 /////////////////////////////////////////////////////////////////// 00457 void quiz(const int rndBase , const int answer ){ 00458 map<int,string> imap = map<int,string>(); 00459 imap[0] = "high"; 00460 imap[2] = "low" ; 00461 imap[1] = "medium" ; 00462 //let's display the number in a random place 00463 //>displayText(stringify(confNum),true,-2); 00464 //>waitFrames(delay); 00465 d->clearScreen(); 00466 d->pushEvent(std::string("asking for confirmation number")); 00467 d->displayText(std::string("which one was played more?"),true,1); 00468 //we need the subject be able to interact with the mouse 00469 d->showCursor(true); 00470 SDL_Surface* blank =getABlankSurface((d->getWidth())/2 , d->getHeight()/10); 00471 //we make a scrap image to write down the numbers on 00472 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00473 textIm.clear(PixRGB<byte>(255, 156, 120)); 00474 //here we write the numbers 00475 for(int i = 0 ; i < rndBase ; i ++){ 00476 writeText(textIm, Point2D<int>((blank->w)/(2*rndBase) -2,10+100*i), imap[i].c_str()); 00477 } 00478 //and here we make a blittabl surface out of that 00479 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00480 //and take out differnt clips out of that 00481 SDL_Rect clip; 00482 clip.x = 0 ; 00483 clip.w = (blank->w)/rndBase - 2 ; 00484 clip.h =blank->h ; 00485 for(int i = 0 ; i < rndBase ; i++){ 00486 clip.y = i*100 ; 00487 apply_surface(i*(clip.w + 2),0,*surf,*blank,clip); 00488 } 00489 00490 SDL_Rect offset; 00491 offset.x = (d->getWidth() - blank->w) /2; 00492 offset.y = (d-> getHeight() - blank->h) /2; 00493 d->pushEvent("the button panel is going up"); 00494 d->displaySDLSurfacePatch(blank , &offset,NULL , -2,false, true); 00495 00496 bool quit = false ; 00497 SDL_Event event ; 00498 int mx = 0 ; 00499 int my = 0 ; 00500 while( quit == false ) { 00501 while( SDL_PollEvent( &event ) ) { 00502 if( event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT 00503 && event.button.x > offset.x && event.button.x <= offset.x + blank->w 00504 && event.button.y > offset.y && event.button.y <= offset.y + blank->h 00505 ) { 00506 quit = true; 00507 mx = event.button.x ; 00508 my = event.button.y ; 00509 } 00510 } 00511 } 00512 00513 switch( (mx - offset.x) / ((blank->w)/rndBase) ){ 00514 case 0 : d->pushEvent("answered high") ; break ; 00515 case 1 : d->pushEvent("answered medium") ; break ; 00516 case 2 : d->pushEvent("answered low") ; break ; 00517 } 00518 //d->pushEvent("confirmed: " + stringify((mx - offset.x) / ((blank->w)/rndBase))) ; 00519 if((mx - offset.x) / ((blank->w)/rndBase) == answer) { 00520 d->pushEvent("correct answer") ; 00521 }else{ 00522 d->pushEvent("incorrect answer") ; 00523 } 00524 00525 dumpSurface(blank); 00526 dumpSurface(surf) ; 00527 d->showCursor(false); 00528 00529 } 00530 00531 /////////////////////////////////////////////////////////////////// 00532 00533 //displays 0 or 1 in a random place on the screen 00534 void finalTask(const int rndBase = 2 , const uint delay = 10 ){ 00535 int confNum = rand() % rndBase ; 00536 d->pushEvent(std::string("confirmation number : ")+stringify(confNum)); 00537 //let's display the number in a random place 00538 d->displayText(stringify(confNum),true,-2); 00539 d->waitFrames(delay); 00540 d->clearScreen(); 00541 d->pushEvent(std::string("asking for confirmation number")); 00542 d->displayText(std::string("what was the number ? "),true,1); 00543 //we need the subject be able to interact with the mouse 00544 d->showCursor(true); 00545 SDL_Surface* blank =getABlankSurface((d->getWidth())/2 , d->getHeight()/10); 00546 //we make a scrap image to write down the numbers on 00547 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00548 textIm.clear(PixRGB<byte>(255, 255, 255)); 00549 //here we write the numbers 00550 for(int i = 0 ; i < rndBase ; i ++){ 00551 writeText(textIm, Point2D<int>((blank->w)/(2*rndBase) -2,10+100*i), stringify(i).c_str()); 00552 } 00553 //and here we make a blittabl surface out of that 00554 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00555 //and take out differnt clips out of that 00556 SDL_Rect clip; 00557 clip.x = 0 ; 00558 clip.w = (blank->w)/rndBase - 2 ; 00559 clip.h =blank->h ; 00560 for(int i = 0 ; i < rndBase ; i++){ 00561 clip.y = i*100 ; 00562 apply_surface(i*(clip.w + 2),0,*surf,*blank,clip); 00563 } 00564 00565 SDL_Rect offset; 00566 offset.x = (d->getWidth() - blank->w) /2; 00567 offset.y = (d-> getHeight() - blank->h) /2; 00568 d->pushEvent("the button panel is going up"); 00569 d->displaySDLSurfacePatch(blank , &offset,NULL , -2,false, true); 00570 00571 bool quit = false ; 00572 SDL_Event event ; 00573 int mx = 0 ; 00574 int my = 0 ; 00575 while( quit == false ) { 00576 while( SDL_PollEvent( &event ) ) { 00577 if( event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT 00578 && event.button.x > offset.x && event.button.x <= offset.x + blank->w 00579 && event.button.y > offset.y && event.button.y <= offset.y + blank->h 00580 ) { 00581 quit = true; 00582 mx = event.button.x ; 00583 my = event.button.y ; 00584 } 00585 } 00586 } 00587 00588 d->pushEvent("confirmed: " + stringify((mx - offset.x) / ((blank->w)/rndBase))) ; 00589 if((mx - offset.x) / ((blank->w)/rndBase) == (int)confNum) { 00590 d->pushEvent("correct confirmation") ; 00591 }else{ 00592 d->pushEvent("incorrect confirmation") ; 00593 } 00594 00595 dumpSurface(blank); 00596 dumpSurface(surf) ; 00597 d->showCursor(false); 00598 00599 } 00600 00601 00602 00603 int addArgument(const string st,const string delim="="){ 00604 int i = st.find(delim) ; 00605 argMap[st.substr(0,i)] = st.substr(i+1); 00606 00607 return 0 ; 00608 } 00609 00610 std::string getArgumentValue(string arg){ 00611 return argMap[arg] ; 00612 } 00613 00614 std::string getUsageComment(){ 00615 00616 string com = string("\nlist of arguments : \n"); 00617 00618 com += "\nconf-num=[2..10] (random numbers in confirmation task) {default=2} \n" ; 00619 com += "\nconf-delay=[>1] (the delay in showing the confirmation number) {default=10}\n"; 00620 com += "\ndelay-interval=[>1]:[>1] (the interval for random delay after stroop task) {default=20:30}\n"; 00621 com += "\nfixation-blink=[y/n] (show the blink for fixation after stroop task or no) {defaule y}\n"; 00622 com += "\nimage-dir=[path to image directory] (needed for mode 2 and 3) {default=60:160} \n" ; 00623 com += "\nlogfile=[logfilename.psy] {default = psycho-stroop-concurrent.psy}\n" ; 00624 com += "\nmemo=[a_string_without_white_space]\n"; 00625 com += "\nmode=[1..6] (1 for auditory test only, 2 for auditory test + image display , " 00626 "3 for image display only ,4 for volume adjustment, 5 for volume adjustment and then auditory test" 00627 " , 6 for volume adjustment and then auditory test + image display ) {default=1}\n"; 00628 com += "\ntask-size=[>1]:[>1](number of beats in a round of task){default=7:17} \n" ; 00629 com += "\nsubject=[subject_name] \n" ; 00630 com += "\ntest-rounds=[>1] (needed for mode1) {default=5}\n"; 00631 com += "\nsound-dir=[path to wav files directory]{default=y}\n"; 00632 com += "\nhigh-chunk=[first chunk sound]{default=high.wav}\n"; 00633 com += "\nmedium-chunk=[second chunk sound]{default=medium.wav}\n"; 00634 com += "\nlow-chunk=[third chunk sound]{default=low.wav}\n"; 00635 com += "\nimage-onset-num=[>=0 and <=task-size] {default=2}" ; 00636 return com ; 00637 } 00638 00639 00640 extern "C" int main(const int argc, char** argv) 00641 { 00642 00643 MYLOGVERB = LOG_INFO; // suppress debug messages 00644 argMap["mode"] = "1" ; 00645 argMap["logfile"]="psycho-stroop-concurrent.psy" ; 00646 argMap["conf-number"] = "2" ; 00647 argMap["task-size"]="7:17" ; 00648 argMap["image-dir"]=".."; 00649 argMap["conf-delay"]="10" ; 00650 argMap["test-rounds"]="5"; 00651 argMap["delay-interval"]="20:30" ; 00652 argMap["subject"]="" ; 00653 argMap["memo"]="" ; 00654 argMap["fixation-blink"]="y" ; 00655 argMap["sound-dir"]=".."; 00656 argMap["high-chunk"]="high.wav"; 00657 argMap["medium-chunk"]="medium.wav"; 00658 argMap["low-chunk"]="low.wav"; 00659 argMap["image-onset-num"]="2"; 00660 00661 manager.addSubComponent(d); 00662 nub::soft_ref<EventLog> el(new EventLog(manager)); 00663 manager.addSubComponent(el); 00664 nub::soft_ref<EyeTrackerConfigurator> etc(new EyeTrackerConfigurator(manager)); 00665 manager.addSubComponent(etc); 00666 00667 if (manager.parseCommandLine(argc, argv, 00668 "at least one argument needed", 1, -1)==false){ 00669 //since the length of string that can be passed to LINFO is limited and our message is longer than this limit 00670 //we have to use std::cout for displaying the message 00671 cout<<getUsageComment()<<endl; 00672 return(1); 00673 } 00674 00675 for(uint i = 0 ; i < manager.numExtraArgs() ; i++){ 00676 addArgument(manager.getExtraArg(i),std::string("=")) ; 00677 } 00678 if( Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 4096 ) == -1 ){ 00679 LINFO( "did not open the mix-audio") ; 00680 return -1 ; 00681 } 00682 string highstr = argMap["sound-dir"] + "/" + argMap["high-chunk"]; 00683 string mediumstr = argMap["sound-dir"] + "/" + argMap["medium-chunk"]; 00684 string lowstr = argMap["sound-dir"] + "/" + argMap["low-chunk"]; 00685 highchunk = Mix_LoadWAV(highstr.c_str()); 00686 mediumchunk = Mix_LoadWAV(mediumstr.c_str()); 00687 lowchunk = Mix_LoadWAV(lowstr.c_str()); 00688 if( ( highchunk == NULL ) || ( mediumchunk == NULL ) || ( lowchunk == NULL ) ) 00689 { 00690 LINFO("did not find the indicated wav files!"); 00691 return -1; 00692 } 00693 manager.setOptionValString(&OPT_EventLogFileName, argMap["logfile"]); 00694 manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN"); 00695 // hook our various babies up and do post-command-line configs: 00696 nub::soft_ref<EyeTracker> et = etc->getET(); 00697 d->setEyeTracker(et); 00698 d->setEventLog(el); 00699 et->setEventLog(el); 00700 00701 00702 // let's get all our ModelComponent instances started: 00703 manager.start(); 00704 for(map<string,string>::iterator it= argMap.begin(); it!= argMap.end() ; ++it) d->pushEvent("arg:"+ it->first+" value:"+it->second ) ; 00705 00706 // let's display an ISCAN calibration grid: 00707 d->clearScreen(); 00708 d->displayISCANcalib(); 00709 d->waitForKey(); 00710 00711 // let's do an eye tracker calibration: 00712 d->displayText("<SPACE> to calibrate; other key to skip"); 00713 int c = d->waitForKey(); 00714 if (c == ' ') d->displayEyeTrackerCalibration(3,3); 00715 00716 d->clearScreen(); 00717 d->displayText("<SPACE> for random play; other key for ordered"); 00718 c = d->waitForKey(); 00719 00720 int mode = atoi(argMap["mode"].c_str()) ; 00721 00722 if(mode == 1 || mode == 5){ 00723 string::size_type position = argMap["delay-interval"].find(":"); 00724 int minDel = atoi(argMap["delay-interval"].substr(0,position).c_str()) ; 00725 int maxDel = atoi(argMap["delay-interval"].substr(position+1).c_str()) ; 00726 int numOfTests = atoi(argMap["test-rounds"].c_str()) ; 00727 int confNum = atoi(argMap["conf-number"].c_str()) ; 00728 int confDelay = atoi(argMap["conf-delay"].c_str()) ; 00729 //this is for the volume adjustment 00730 if(mode == 5){ 00731 volumeAdjustment(3,"continue") ; 00732 } 00733 for(int i = 0 ; i < numOfTests ; i++){ 00734 d->clearScreen() ; 00735 d->pushEvent("**************************************") ; 00736 d->showCursor(true); 00737 d->displayText("click one of the mouse buttons to start!"); 00738 getMouseEvent() ; 00739 d->showCursor(false); 00740 d->clearScreen() ; 00741 vector<int> task = getAuditoryTask(argMap["task-size"]) ; 00742 string ts = string(""); 00743 int high = 0 ; 00744 int medium = 0 ; 00745 int low = 0 ; 00746 int answ = 0 ; 00747 for( uint j = 0 ; j < task.size() ; j++){ 00748 ts = ts + stringify(task[j]) ; 00749 switch( task[j] ){ 00750 case 0 : high++;break ; 00751 case 1 : medium++;break; 00752 case 2 : low++;break ; 00753 } 00754 } 00755 int m = max(max(low,medium),high); 00756 if( m == high) answ = 0 ; 00757 if (m == medium ) answ = 1 ; 00758 if (m == low ) answ = 2 ; 00759 d->pushEvent("task sequence : "+ts); 00760 for( uint j = 0 ; j < task.size() ; j++ ){ 00761 switch( task[j] ){ 00762 case 0 : Mix_PlayChannel( -1, highchunk , 0 ) ;break ; 00763 case 1 : Mix_PlayChannel( -1, mediumchunk , 0 ); break ; 00764 case 2 : Mix_PlayChannel( -1, lowchunk , 0 ) ;break ; 00765 } 00766 d->waitFrames((rand()%(maxDel-minDel)) +minDel); 00767 } 00768 finalTask(confNum,confDelay) ; 00769 quiz(3,answ) ; 00770 00771 } 00772 } 00773 00774 if(mode == 2 || mode == 6){ 00775 string::size_type position = argMap["delay-interval"].find(":"); 00776 int minDel = atoi(argMap["delay-interval"].substr(0,position).c_str()) ; 00777 int maxDel = atoi(argMap["delay-interval"].substr(position+1).c_str()) ; 00778 string dir = argMap["image-dir"]; 00779 vector<string> files = vector<string>(); 00780 getdir(dir,files); 00781 int confNum = atoi(argMap["conf-number"].c_str()) ; 00782 int confDelay = atoi(argMap["conf-delay"].c_str()) ; 00783 //this is for the volume adjustment 00784 if(mode == 6){ 00785 volumeAdjustment(3,"continue") ; 00786 } 00787 while(files.size()>0){ 00788 int imageIndex = rand()%files.size() ; 00789 SDL_Surface *surf = load_image(files[imageIndex]); 00790 float r1 = (float)d->getWidth()/(float)surf->w ; 00791 float r2 = (float)d->getHeight() / (float)surf->h ; 00792 surf = SDL_Resize(surf ,min(r1,r2) , 5 ); 00793 SDL_Rect offset; 00794 offset.x = (d->getWidth() - surf->w) /2; 00795 offset.y = (d-> getHeight() - surf->h) /2; 00796 d->pushEvent("**************************************") ; 00797 d->showCursor(true); 00798 d->displayText("click a mouse button to start!"); 00799 getMouseEvent() ; 00800 d->showCursor(false); 00801 d->clearScreen() ; 00802 vector<int> task = getAuditoryTask(argMap["task-size"]) ; 00803 string ts = string(""); 00804 int high = 0 ; 00805 int medium = 0 ; 00806 int low = 0 ; 00807 int answ = 0 ; 00808 for( uint j = 0 ; j < task.size() ; j++){ 00809 ts = ts + stringify(task[j]) ; 00810 switch( task[j] ){ 00811 case 0 : high++;break ; 00812 case 1 : medium++;break; 00813 case 2 : low++;break ; 00814 } 00815 } 00816 int m = max(max(low,medium),high); 00817 if( m == high) answ = 0 ; 00818 if (m == medium ) answ = 1 ; 00819 if (m == low ) answ = 2 ; 00820 d->pushEvent("task sequence : "+ts); 00821 for( uint j = 0 ; j < task.size() ; j++ ){ 00822 switch( task[j] ){ 00823 case 0 : Mix_PlayChannel( -1, highchunk , 0 ) ;break ; 00824 case 1 : Mix_PlayChannel( -1, mediumchunk , 0 ); break ; 00825 case 2 : Mix_PlayChannel( -1, lowchunk , 0 ) ;break ; 00826 } 00827 00828 if (j==2){ 00829 d->waitNextRequestedVsync(false, true); 00830 d->pushEvent(std::string("===== Showing image: ") + 00831 files[imageIndex] + " ====="); 00832 00833 // start the eye tracker: 00834 et->track(true); 00835 //blink the fixation: 00836 if(argMap["fixation-blink"].compare("y")==0) d->displayFixationBlink(); 00837 00838 d->displaySDLSurfacePatch(surf , &offset,NULL , -2,false, true); 00839 files.erase(files.begin()+imageIndex); 00840 }else{ 00841 d->waitFrames((rand()%(maxDel-minDel)) +minDel); 00842 } 00843 } 00844 00845 00846 dumpSurface(surf); 00847 // stop the eye tracker: 00848 usleep(50000); 00849 et->track(false); 00850 //see if the subject was looking at the screen! 00851 finalTask(confNum,confDelay) ; 00852 quiz(3,answ) ; 00853 d->clearScreen() ; 00854 //now quiz time! 00855 d->clearScreen() ; 00856 } 00857 } 00858 00859 if(mode == 3){ 00860 string::size_type position = argMap["delay-interval"].find(":"); 00861 int minDel = atoi(argMap["delay-interval"].substr(0,position).c_str()) ; 00862 int maxDel = atoi(argMap["delay-interval"].substr(position+1).c_str()) ; 00863 string dir = argMap["image-dir"]; 00864 vector<string> files = vector<string>(); 00865 getdir(dir,files); 00866 int c = 0 ; 00867 00868 while(files.size()>0){ 00869 c++ ; 00870 int imageIndex = rand()%files.size() ; 00871 //this block turned out to be buggy! so I decided to switch to working with SDL_Surface instead 00872 //Image< PixRGB<byte> > image = 00873 //Raster::ReadRGB(files[imageIndex]); 00874 00875 //SDL_Surface *surf = d->makeBlittableSurface(image, true); 00876 SDL_Surface *surf = load_image(files[imageIndex]); 00877 float r1 = (float)d->getWidth()/(float)surf->w ; 00878 float r2 = (float)d->getHeight() / (float)surf->h ; 00879 surf = SDL_Resize(surf ,min(r1,r2) , 5 ); 00880 SDL_Rect offset; 00881 offset.x = (d->getWidth() - surf->w) /2; 00882 offset.y = (d-> getHeight() - surf->h) /2; 00883 d->waitNextRequestedVsync(false, true); 00884 d->pushEvent(std::string("===== Showing image: ") + 00885 files[imageIndex] + " ====="); 00886 00887 // start the eye tracker: 00888 et->track(true); 00889 //blink the fixation: 00890 if(argMap["fixation-blink"].compare("y")==0) d->displayFixationBlink(); 00891 d->displaySDLSurfacePatch(surf , &offset,NULL , -2,false, true); 00892 d->waitFrames((rand()%(maxDel-minDel)) +minDel ); 00893 dumpSurface(surf); 00894 // stop the eye tracker: 00895 usleep(50000); 00896 et->track(false); 00897 d->clearScreen() ; 00898 files.erase(files.begin()+imageIndex); 00899 } 00900 00901 } 00902 //for the case that the subject wants to adjust the volume 00903 if(mode == 4){ 00904 volumeAdjustment(3,"exit") ; 00905 } 00906 00907 00908 d->clearScreen(); 00909 d->displayText("Experiment complete. Thank you!"); 00910 d->waitForKey(); 00911 //getEvent(); 00912 // stop all our ModelComponents 00913 manager.stop(); 00914 //Quit SDL_mixer 00915 Mix_FreeChunk( highchunk ); 00916 Mix_FreeChunk( lowchunk ); 00917 Mix_FreeChunk( mediumchunk ); 00918 Mix_CloseAudio(); 00919 // all done! 00920 return 0; 00921 } 00922 00923 #endif // INVT_HAVE_LIBSDL_IMAGE 00924