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
00038 #include "Component/ModelManager.H"
00039 #include "Image/Image.H"
00040 #include "Image/DrawOps.H"
00041 #include "Image/SimpleFont.H"
00042 #include "Psycho/PsychoDisplay.H"
00043 #include "Psycho/EyeTrackerConfigurator.H"
00044 #include "Psycho/EyeTracker.H"
00045 #include "Psycho/PsychoOpts.H"
00046 #include "Component/EventLog.H"
00047 #include "Component/ComponentOpts.H"
00048 #include "Util/Types.H"
00049 #include "Util/StringConversions.H"
00050 #include "Util/StringUtil.H"
00051 #include "Psycho/MPlayerWrapper.H"
00052 #include "Devices/SimpleLED.H"
00053 #include <fstream>
00054
00055 #define HDEG 54.9
00056
00057 typedef struct trial
00058 {
00059 std::string itsClip;
00060 std::string itsQuestion;
00061 std::vector<std::string> itsChoices;
00062 Image<PixRGB<byte> > itsQimage;
00063 Image<PixRGB<byte> > itsSimage;
00064 int itsFamily;
00065 } SearchTrial;
00066
00067
00068 int submain(const int argc, char** argv)
00069 {
00070
00071
00072
00073
00074
00075 MYLOGVERB = LOG_INFO;
00076
00077
00078 ModelManager manager("Psycho Text");
00079
00080
00081 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager));
00082 manager.addSubComponent(d);
00083
00084 nub::soft_ref<EyeTrackerConfigurator>
00085 etc(new EyeTrackerConfigurator(manager));
00086 manager.addSubComponent(etc);
00087
00088 nub::soft_ref<EventLog> el(new EventLog(manager));
00089 manager.addSubComponent(el);
00090
00091 nub::soft_ref<MPlayerWrapper> player(new MPlayerWrapper(manager));
00092 manager.addSubComponent(player);
00093
00094 nub::soft_ref<SimpleLED> recordLight(new SimpleLED(manager));
00095 manager.addSubComponent(recordLight);
00096
00097 manager.setOptionValString(&OPT_EventLogFileName, "psychodata.psy");
00098 manager.setOptionValString(&OPT_EyeTrackerType, "ISCAN");
00099
00100
00101 if (manager.parseCommandLine(argc, argv,
00102 "<textfile> visual-angle-of-single-character grid-rows grid-columns",
00103 4, 4)==false)
00104 return(1);
00105
00106
00107
00108
00109
00110
00111
00112 std::ifstream *itsFile;
00113 itsFile = new std::ifstream(manager.getExtraArg(0).c_str());
00114
00115
00116 if (itsFile->is_open() == false)
00117 LFATAL("Cannot open '%s' for reading",manager.getExtraArg(0).c_str());
00118
00119
00120 std::string line;
00121 std::string clipstem = "";
00122 std::vector<SearchTrial> expt(100);
00123 uint num_trials = 0, num_stems = 0;
00124 std::vector<uint> curr_stem_index;
00125
00126
00127 while (!itsFile->eof())
00128 {
00129 getline(*itsFile, line, '\n');
00130
00131
00132 if (line[0] == '>')
00133 {
00134 line.erase(0,1);
00135 expt[num_trials].itsClip = line;
00136
00137
00138 if(line.compare(0,line.size()-5,clipstem) != 0)
00139 {
00140 num_stems++;
00141 clipstem = line.substr(0,line.size()-5);
00142 curr_stem_index.push_back(num_trials);
00143 }
00144 expt[num_trials].itsFamily = num_stems;
00145 num_trials++;
00146 }
00147 else if (line[0] == '#')
00148 {
00149 line.erase(0,1);
00150 expt[num_trials-1].itsQuestion = line;
00151 }
00152 else if (line[0] == '!')
00153 {
00154 line.erase(0,1);
00155 expt[num_trials-1].itsChoices.push_back(line);
00156 }
00157 else if (line[0] == '&')
00158 {
00159
00160 }
00161 else
00162 {
00163 expt[num_trials-1].itsChoices.push_back(line);
00164 }
00165 }
00166 itsFile->close();
00167
00168
00169 int w = d->getWidth();
00170 int h = d->getHeight();
00171
00172 double fontsize = fromStr<double>(manager.getExtraArg(1));
00173 uint fontwidth = uint(fontsize * w / HDEG);
00174 SimpleFont fnt = SimpleFont::fixedMaxWidth(fontwidth);
00175
00176
00177 const uint gridrows = fromStr<uint>(manager.getExtraArg(2));
00178 const uint gridcols = fromStr<uint>(manager.getExtraArg(3));
00179 const uint gridslots = gridrows*gridcols;
00180 std::vector<int> x_coords(gridslots);
00181 std::vector<int> y_coords(gridslots);
00182 for (uint i = 0; i < gridrows; i++)
00183 {
00184 for(uint j = 0; j < gridcols; j++)
00185 {
00186 x_coords[gridcols*i+j] = (int( double(w*(j+1)) / (gridcols+1)));
00187 y_coords[gridcols*i+j] = (int( double(h*(i+1)) / (gridrows+1)));
00188 }
00189 }
00190
00191 Point2D<int> tanchor;
00192 for (uint i = 0; i < num_trials; i++)
00193 {
00194 int space = 0;
00195 int hanchor = int(h/2) - int(fnt.h()/2);
00196 expt[i].itsQimage.resize(w,h);
00197 expt[i].itsQimage.clear(d->getGrey());
00198
00199 space = int( double(w - fnt.w() * expt[i].itsQuestion.size()) / 2.0 );
00200 tanchor = Point2D<int>(space, hanchor);
00201
00202 writeText(expt[i].itsQimage,tanchor,expt[i].itsQuestion.c_str(),
00203 PixRGB<byte>(0,0,0),
00204 d->getGrey(),
00205 fnt);
00206
00207 expt[i].itsSimage.resize(w,h);
00208 expt[i].itsSimage.clear(d->getGrey());
00209 for (uint j = 0; j < expt[i].itsChoices.size(); j++)
00210 {
00211
00212 if(j >= gridslots)
00213 {
00214 LDEBUG("Trial %d, clip %s: Too many answer choices for the grid", i, expt[i].itsClip.c_str());
00215 break;
00216 }
00217 space = x_coords[j] - int( double(fnt.w() * expt[i].itsChoices[j].length()) / 2.0);
00218 hanchor = y_coords[j] - int(fnt.h()/2);
00219 tanchor = Point2D<int>(space, hanchor);
00220
00221 writeText(expt[i].itsSimage,tanchor,expt[i].itsChoices[j].c_str(),
00222 PixRGB<byte>(0,0,0),
00223 d->getGrey(),
00224 fnt);
00225 }
00226 }
00227
00228
00229 nub::soft_ref<EyeTracker> et = etc->getET();
00230 d->setEyeTracker(et);
00231 d->setEventLog(el);
00232 et->setEventLog(el);
00233 player->setEventLog(el);
00234
00235
00236 manager.start();
00237
00238
00239 recordLight->turnOn();
00240 el->pushEvent("===== pilot light on =====");
00241
00242
00243 et->calibrate(d);
00244
00245 d->clearScreen();
00246 d->displayText("<space> for random order, other key for ordered play.");
00247 int c = d->waitForKey();
00248 d->clearScreen();
00249
00250 int plan[num_trials];
00251 for (uint i = 0; i < num_trials; i++) plan[i] = i;
00252 if (c == ' ')
00253 {
00254 LINFO("Randomizing trials...");
00255
00256 for(uint i = 0; i < num_trials; i++)
00257 plan[i] = expt[i].itsFamily-1;
00258 randShuffle(plan, num_trials);
00259
00260 for(uint i = 0; i < num_trials; i++)
00261 plan[i]=curr_stem_index[plan[i]]++;
00262
00263 }
00264
00265
00266 recordLight->turnOff();
00267 el->pushEvent("===== pilot light off =====");
00268
00269 std::string currvideo;
00270
00271 for (uint ii = 0; ii < num_trials; ii ++)
00272 {
00273 currvideo = expt[plan[ii]].itsClip;
00274
00275
00276 LDEBUG("Playing '%s'...",currvideo.c_str());
00277 player->setSourceVideo(currvideo);
00278
00279
00280 sleep(1); if (system("/bin/sync")) LERROR("error in sunc()");
00281
00282
00283 recordLight->turnOff();
00284 el->pushEvent("pilot light off");
00285
00286
00287 d->displayFixation();
00288
00289
00290 d->waitForKey(true);
00291 d->displayFixationBlink();
00292
00293
00294 et->track(true);
00295
00296
00297 d->waitNextRequestedVsync(false, true);
00298 el->pushEvent(std::string("===== Playing movie: ") +
00299 currvideo + " =====");
00300 player->runfromSDL(d);
00301
00302
00303 recordLight->turnOn();
00304 el->pushEvent("pilot light on");
00305
00306 et->track(false);
00307
00308 d->clearScreen();
00309 d->displayFixation();
00310 Image<PixRGB<byte> > image;
00311
00312
00313 image = expt[plan[ii]].itsQimage;
00314 SDL_Surface* surf = d->makeBlittableSurface(image, true);
00315 LINFO("question '%d' ready.", ii);
00316
00317
00318 d->waitForKey();
00319 d->waitNextRequestedVsync(false, true);
00320
00321 d->pushEvent(std::string("===== Showing Question: question#") +
00322 toStr<int>(plan[ii]) + " =====");
00323
00324 et->track(true);
00325
00326 d->displayFixationBlink();
00327
00328
00329 d->displaySurface(surf, -2);
00330
00331
00332 c = d->waitForKey();
00333
00334
00335 SDL_FreeSurface(surf);
00336
00337
00338 d->clearScreen();
00339
00340
00341 image = expt[plan[ii]].itsSimage;
00342 surf = d->makeBlittableSurface(image, true);
00343
00344 LINFO("sentence '%d' ready.", plan[ii]);
00345
00346 d->displayFixation();
00347
00348
00349 d->waitForKey();
00350 d->waitNextRequestedVsync(false, true);
00351
00352 d->pushEvent(std::string("===== Showing Answer Grid: answer#") +
00353 toStr<int>(plan[ii]) + " =====");
00354
00355
00356 d->displayFixationBlink();
00357
00358
00359 d->displaySurface(surf, -2);
00360
00361
00362 c = d->waitForKey();
00363
00364
00365 SDL_FreeSurface(surf);
00366
00367
00368 d->clearScreen();
00369
00370
00371 usleep(50000);
00372 et->track(false);
00373
00374
00375 et->recalibrate(d,15);
00376 d->clearScreen();
00377 }
00378
00379 d->clearScreen();
00380 d->displayText("Experiment complete. Thank you!");
00381 d->waitForKey();
00382
00383
00384
00385 recordLight->turnOff();
00386 el->pushEvent("===== pilot light off =====");
00387
00388
00389 manager.stop();
00390
00391
00392 return 0;
00393 }
00394
00395 extern "C" int main(const int argc, char** argv)
00396 {
00397
00398
00399
00400
00401 try
00402 {
00403 return submain(argc, argv);
00404 }
00405 catch (...)
00406 {
00407 REPORT_CURRENT_EXCEPTION;
00408 }
00409
00410 return 1;
00411 }
00412
00413
00414
00415
00416
00417