00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
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 <SDL/SDL_mixer.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
00070 #ifndef INVT_HAVE_LIBSDL_IMAGE
00071 #include <cstdio>
00072 int main()
00073 {
00074 fprintf(stderr, "The SDL_image library must be installed to use this program\n");
00075 return 1;
00076 }
00077
00078 #else
00079
00080
00081
00082 using namespace std;
00083
00084
00085
00086 ModelManager manager("Psycho-Math-Op");
00087 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager));
00088 map<uint,uint> testMap ;
00089 map<string,string> argMap ;
00090 map<string,vector<SDL_Rect*>*> clipsmap;
00091
00092
00093
00094
00095 template <class T> std::string stringify(T i)
00096 {
00097 ostringstream o ;
00098 o << i ;
00099 return o.str();
00100 }
00101
00102 bool itIsInThere(int x , vector<int> bag){
00103 for( uint i=0 ; i < bag.size(); i++ ){
00104 if(x == bag[i]) return true ;
00105 }
00106 return false ;
00107 }
00108
00109
00110
00111 int getdir (string dir, vector<string> &files)
00112 {
00113 DIR *dp;
00114 struct dirent *dirp;
00115 if((dp = opendir(dir.c_str())) == NULL) {
00116 cout << "Error(" << errno << ") opening " << dir << endl;
00117 return errno;
00118 }
00119 string fn = "" ;
00120 size_t found;
00121 string extension = "" ;
00122 while ((dirp = readdir(dp)) != NULL) {
00123 fn = string(dirp->d_name) ;
00124 found = fn.find_last_of(".");
00125 if(found > 0 && found <1000){
00126 extension = fn.substr(found) ;
00127 if(extension.compare(".wav")== 0 )
00128 files.push_back(dir+"/"+fn);
00129 }
00130 }
00131 closedir(dp);
00132 return 0;
00133 }
00134
00135
00136
00137
00138
00139 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){
00140 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS);
00141 textIm.clear(bgcolor);
00142 writeText(textIm, Point2D<int>((size.i - label.length()*10)/2,(size.j-20) /2),label.c_str(),txtcolor,bgcolor);
00143 SDL_Surface *surf = d->makeBlittableSurface(textIm , true);
00144 Uint32 bc = d->getUint32color(bordercolor);
00145 drawRectangle(surf,bc,0,0,size.i -1,size.j -1 ,border);
00146 SDL_Surface* blank =getABlankSurface(size.i , size.j);
00147 SDL_Rect clip;
00148 clip.x = 0 ;
00149 clip.y = 0 ;
00150 clip.w = size.i ;
00151 clip.h = size.j ;
00152 apply_surface(0,0,*surf,*blank,clip);
00153 dumpSurface(surf) ;
00154 return blank ;
00155 }
00156
00157
00158
00159
00160
00161
00162 SDL_Surface* getKeyPad(string alphabet,map<string , SDL_Rect>& buttmap){
00163 SDL_Surface* pad= getABlankSurface(d->getWidth()/4,d->getHeight()/3);
00164 SDL_Rect clip;
00165 clip.x=0;
00166 clip.y=0;
00167 int numofrows = alphabet.size()/3 +1;
00168 if(alphabet.size()%3 != 0 ) numofrows++ ;
00169 int numofcolumns = 3 ;
00170 clip.w= pad->w / numofcolumns ;
00171 clip.h = pad->h / numofrows ;
00172
00173
00174 for( int i = 0 ; i < numofrows*3 ; i++){
00175 SDL_Surface* but ;
00176 if((uint)i < alphabet.size()){
00177 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);
00178 }else{
00179 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);
00180 }
00181
00182 SDL_Rect cl ;
00183 cl.x = ((i)%numofcolumns)*(pad->w)/numofcolumns ; cl.y= ((i)/numofcolumns)*((pad->h)/numofrows) ;
00184 cl.w = clip.w ;
00185 cl.h = clip.h ;
00186 apply_surface( cl.x , cl.y ,*but,*pad,clip);
00187 if((uint)i < alphabet.size()) buttmap[alphabet.substr(i,1)] = cl ;
00188 dumpSurface(but);
00189 }
00190 SDL_Rect cl1 ;
00191 cl1.x = 0 ; cl1.y= (numofrows-1)*((pad->h)/numofrows) ;
00192 cl1.w = clip.w ;
00193 cl1.h = clip.h ;
00194 buttmap["!"] = cl1 ;
00195 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);
00196 apply_surface(0, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip);
00197 dumpSurface(but);
00198 SDL_Rect cl2 ;
00199 cl2.x = (pad->w)/numofcolumns ; cl2.y= (numofrows-1)*((pad->h)/numofrows) ;
00200 cl2.w = clip.w ;
00201 cl2.h = clip.h ;
00202 buttmap[" "] = cl2 ;
00203 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);
00204 apply_surface((pad->w)/numofcolumns, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip);
00205 dumpSurface(but);
00206 SDL_Rect cl3 ;
00207 cl3.x = 2*(pad->w)/numofcolumns ; cl3.y= (numofrows-1)*((pad->h)/numofrows) ;
00208 cl3.w = clip.w ;
00209 cl3.h = clip.h ;
00210 buttmap["*"] = cl3 ;
00211 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);
00212 apply_surface(2*(pad->w)/numofcolumns, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip);
00213 dumpSurface(but);
00214 return pad ;
00215 }
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225 string getPressedButtonCommand(map<string , SDL_Rect>& buttmap,Point2D<int> offset=Point2D<int>(0,0)){
00226 int quit = 0 ;
00227 string s ;
00228 SDL_Event event ;
00229 while( quit!=2 ){
00230 while( SDL_PollEvent( &event ) ) {
00231 if(event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT ){
00232 for( map<string , SDL_Rect>::iterator it = buttmap.begin() ; it!=buttmap.end() ; ++it){
00233 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) {
00234 quit = 2 ;
00235 s = it->first ;
00236 break;
00237 }
00238
00239 }
00240 }
00241
00242 }
00243 }
00244 return s ;
00245
00246 }
00247
00248
00249
00250
00251
00252
00253
00254 string getDigitSequenceFromSubject(string alphabet="0123456789" , uint maxl = 7 ){
00255 d->showCursor(true) ;
00256
00257 map<string , SDL_Rect>* buttmap = new map<string , SDL_Rect>();
00258
00259 SDL_Surface * keypad = getKeyPad(alphabet,*buttmap);
00260
00261 SDL_Rect offset ;
00262 offset.x = (d->getWidth() - keypad->w) /2;
00263 offset.y = (d-> getHeight() - keypad->h) /2;
00264
00265 d->displaySDLSurfacePatch(keypad , &offset,NULL , -2,false, true);
00266
00267 string p = string("") ;
00268
00269 string tp = string("");
00270
00271 while( tp.compare("*")!=0 ){
00272
00273 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) ;
00274 SDL_Rect offs ; offs.x = (d->getWidth() - dp->w) /2 ; offs.y = d->getHeight()/6 ;
00275 d->displaySDLSurfacePatch(dp , &offs , NULL , -2 , false ,true ) ;
00276
00277 tp = getPressedButtonCommand(*buttmap,Point2D<int>(offset.x,offset.y)) ;
00278 dumpSurface(dp) ;
00279 if(tp.compare("!")==0 && p.size()>=0 ) {
00280 if (p.size()>0) p = p.substr(0,p.size()-1) ;
00281 }else{
00282 if(p.size() < maxl && tp.compare("*")!=0) {
00283 p +=tp ;
00284 }
00285
00286 }
00287
00288 }
00289 buttmap = 0 ;
00290 dumpSurface(keypad) ;
00291 d->clearScreen() ;
00292 return p ;
00293
00294 }
00295
00296
00297
00298 int addArgument(const string st,const string delim="="){
00299 int i = st.find(delim) ;
00300 argMap[st.substr(0,i)] = st.substr(i+1);
00301
00302 return 0 ;
00303 }
00304
00305 std::string getArgumentValue(string arg){
00306 return argMap[arg] ;
00307 }
00308
00309 std::vector<int> getDigits(int n , string zs="n" , string rs="n" ){
00310 if(rs.compare("n")==0){
00311 if(zs.compare("n")==0 && n >9 ) {LINFO( "come on! what do you expect?!") ; exit(-1) ;}
00312 if(zs.compare("y")==0 && n >10 ) {LINFO( "come on! what do you expect?!") ; exit(-1) ;}
00313 }
00314 vector<int> digits ;
00315 int dig = 0 ;
00316 while( digits.size() < (uint)n ){
00317 if(zs.compare("n")==0) {dig = 1+(random()%9);}else{dig = random()%10;}
00318 if(rs.compare("y")==0){digits.push_back(dig);}else{if(!itIsInThere(dig,digits)) digits.push_back(dig);}
00319 }
00320 return digits ;
00321 }
00322
00323 std::string getUsageComment(){
00324
00325 string com = string("\nlist of arguments : \n");
00326
00327 com += "\nlogfile=[logfilename.psy] {default = psycho-stroop-concurrent.psy}\n" ;
00328 com += "\nmemo=[a_string_without_white_space]\n";
00329 com += "\nnum-of-digits=[>0](the size of string){default=} \n";
00330 com += "\nsubject=[subject_name] \n" ;
00331 com += "\ntest-rounds=[>1] (number of tests ) {default=10}\n";
00332 com += "\nalphabet=[a string of characters](a string of characters){default=0123456789}\n";
00333 com += "\nrecall-prb=[a number between 0 to 1], probability of challenging the subject with a memorization task, default=0.4\n" ;
00334 com += "\ncue-wait-frames=[<0](number of frames to show the cue){default=0}\n";
00335 com += "\ncue-onset-frames=[<0](number of frames to show the cue onset){default=3}\n";
00336 com += "\nsound-dir=[path to wav files directory]{default=..}\n";
00337 com += "\ndigit-repeat=[y/n](whether digits can repeat, y for yes , n for no){default=n}\n" ;
00338 com += "\ninclude-zero=[y/n](whether zero be included in the presented digits, y for yes , n for no){default=n}\n";
00339 return com ;
00340 }
00341
00342
00343 extern "C" int main(const int argc, char** argv)
00344 {
00345
00346 MYLOGVERB = LOG_INFO;
00347
00348 argMap["experiment"]="math-operation-with-played-numbers";
00349 argMap["logfile"]="psycho-math-op.psy" ;
00350 argMap["num-of-digits"]="3" ;
00351 argMap["test-rounds"]="10";
00352 argMap["subject"]="" ;
00353 argMap["memo"]="" ;
00354 argMap["alphabet"]="0123456789";
00355 argMap["recall-prb"]="0.4" ;
00356 argMap["cue-wait-frames"]="0" ;
00357 argMap["cue-onset-frames"] = "3" ;
00358 argMap["white-space"] = "20" ;
00359 argMap["sound-dir"]="..";
00360 argMap["include-zero"]="n";
00361 argMap["digit-repeat"]="n" ;
00362
00363 manager.addSubComponent(d);
00364 nub::soft_ref<EventLog> el(new EventLog(manager));
00365 manager.addSubComponent(el);
00366 d->setEventLog(el);
00367 nub::soft_ref<EyeTrackerConfigurator>
00368 etc(new EyeTrackerConfigurator(manager));
00369 manager.addSubComponent(etc);
00370
00371 if (manager.parseCommandLine(argc, argv,
00372 "at least one argument needed", 1, -1)==false){
00373 cout<<getUsageComment()<<endl;
00374 return(1);
00375 }
00376
00377 for(uint i = 0 ; i < manager.numExtraArgs() ; i++){
00378 addArgument(manager.getExtraArg(i),std::string("=")) ;
00379 }
00380
00381 manager.setOptionValString(&OPT_EventLogFileName, argMap["logfile"]);
00382 manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN");
00383 nub::soft_ref<EyeTracker> eyet = etc->getET();
00384 d->setEyeTracker(eyet);
00385 eyet->setEventLog(el);
00386
00387
00388 if( Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 4096 ) == -1 ){
00389 LINFO( "did not open the mix-audio") ;
00390 return -1 ;
00391 }
00392
00393 map<int,Mix_Music*> audioMap ;
00394 for( int i = 0 ; i < 10 ; i++ ){
00395 string str = argMap["sound-dir"]+"/"+stringify(i)+".wav" ;
00396 audioMap[i] = Mix_LoadMUS(str.c_str());
00397 }
00398
00399 int numOfDigits = atoi(argMap["num-of-digits"].c_str());
00400 int cue_onset_frames = atoi(argMap["cue-onset-frames"].c_str()) ;
00401 int cue_wait_frames = atoi(argMap["cue-wait-frames"].c_str()) ;
00402
00403
00404 manager.start();
00405 for(map<string,string>::iterator it= argMap.begin(); it!= argMap.end() ; ++it) d->pushEvent("arg:"+ it->first+" value:"+it->second ) ;
00406
00407 d->clearScreen();
00408 d->displayISCANcalib();
00409 d->waitForMouseClick();
00410 d->displayText("Here the experiment starts! click to start!");
00411 d->waitForMouseClick();
00412 d->clearScreen();
00413
00414 int numOfTests = atoi(argMap["test-rounds"].c_str()) ;
00415
00416 float memPrb = atof(argMap["recall-prb"].c_str()) ;
00417
00418
00419 d->displayText("CLICK LEFT button to calibrate; RIGHT to skip");
00420 int cl = d->waitForMouseClick();
00421 if (cl == 1) d->displayEyeTrackerCalibration(3,5,1 , true);
00422 d->clearScreen();
00423
00424 int cr = 0 ;
00425 while( cr <numOfTests ){
00426 d->showCursor(true);
00427 d->displayText("click one of the mouse buttons to start!");
00428 d->waitForMouseClick() ;
00429 d->showCursor(false) ;
00430 d->clearScreen() ;
00431 d->displayFixationBlink();
00432 float mP = (float) rand()/RAND_MAX ;
00433 vector<int> digits = getDigits(numOfDigits,argMap["include-zero"],argMap["digit-repeat"]);
00434 int counter = 0 ;
00435 while( counter < numOfDigits ){
00436 if(Mix_PlayingMusic() == 0 ){
00437
00438 if( Mix_PlayMusic( audioMap[digits[counter]], 0 ) == -1 ) { return 1; }
00439 d->pushEvent("the "+stringify(counter)+"th : " +stringify(digits[counter]));
00440 counter++ ;
00441 }
00442 }
00443
00444 while( Mix_PlayingMusic() == 1 ){}
00445
00446
00447 if(mP > memPrb){
00448 cr++;
00449 d->pushEvent("**************************************") ;
00450 if(cue_wait_frames != 0) d->waitFrames(cue_wait_frames) ;
00451 std::string imst = "===== Showing image: def"+ stringify(cr)+ ".png =====";
00452 d->pushEvent(imst);
00453 eyet->track(true);
00454 d->displayRedDotFixation();
00455 d->waitFrames(cue_onset_frames);
00456 long st = d->getTimerValue() ;
00457 d->clearScreen() ;
00458 d->pushEvent("manipulation starts");
00459 d->waitForMouseClick() ;
00460 long et = d->getTimerValue();
00461 eyet->track(false);
00462 d->pushEvent("manipulation ends") ;
00463 d->pushEvent("manipulation time:"+stringify(et-st));
00464 string answer = getDigitSequenceFromSubject(argMap["alphabet"] , numOfDigits);
00465 d->pushEvent("subject keyed : "+answer);
00466
00467 }else{
00468 d->pushEvent("+++++++++++++++++++++++++++++++++++++++") ;
00469 if(cue_wait_frames != 0) d->waitFrames(cue_wait_frames) ;
00470 d->displayFixationBlink(d->getWidth()/2,d->getHeight()/2,1,cue_onset_frames);
00471 d->pushEvent("subject is being challenged for simple momorization");
00472 string answer = getDigitSequenceFromSubject(argMap["alphabet"] , numOfDigits);
00473 d->pushEvent("subject keyed : "+answer);
00474 }
00475 }
00476
00477 d->clearScreen();
00478 d->displayText("Experiment complete. Thank you!");
00479 d->waitForMouseClick();
00480
00481
00482
00483 manager.stop();
00484
00485
00486 for( int i = 0 ; i < 10 ; i++ ){
00487 Mix_FreeMusic(audioMap[i]);
00488 }
00489
00490 Mix_CloseAudio();
00491
00492 return 0;
00493 }
00494
00495 #endif // INVT_HAVE_LIBSDL_IMAGE
00496