psycho-narrator.C

Go to the documentation of this file.
00001 /*!@file AppPsycho/psycho-narrator.C Psychophysics interactive display of
00002       still images or movies with speech recording */
00003 
00004 // //////////////////////////////////////////////////////////////////// //
00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00006 // University of Southern California (USC) and the iLab at USC.         //
00007 // See http://iLab.usc.edu for information about this project.          //
00008 // //////////////////////////////////////////////////////////////////// //
00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00011 // in Visual Environments, and Applications'' by Christof Koch and      //
00012 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00013 // pending; application number 09/912,225 filed July 23, 2001; see      //
00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00015 // //////////////////////////////////////////////////////////////////// //
00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00017 //                                                                      //
00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00019 // redistribute it and/or modify it under the terms of the GNU General  //
00020 // Public License as published by the Free Software Foundation; either  //
00021 // version 2 of the License, or (at your option) any later version.     //
00022 //                                                                      //
00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00026 // PURPOSE.  See the GNU General Public License for more details.       //
00027 //                                                                      //
00028 // You should have received a copy of the GNU General Public License    //
00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00031 // Boston, MA 02111-1307 USA.                                           //
00032 // //////////////////////////////////////////////////////////////////// //
00033 //
00034 // Primary maintainer for this file: Jinyong Lee <jinyongl@usc.edu>
00035 // $HeadURL:
00036 // $Id: psycho-narrator.C
00037 //
00038 
00039 #include "Component/ModelManager.H"
00040 #include "Component/ComponentOpts.H"
00041 #include "Component/ModelOptionDef.H"
00042 #include "Component/EventLog.H"
00043 
00044 #include "Image/Image.H"
00045 #include "Raster/Raster.H"
00046 #include "Video/VideoFrame.H"
00047 #include "Util/Types.H"
00048 #include "Util/MathFunctions.H"
00049 #include "Util/FileUtil.H"
00050 #include "Util/sformat.H"
00051 #include "rutz/time.h"
00052 
00053 #include "Psycho/PsychoDisplay.H"
00054 #include "Psycho/EyeTrackerConfigurator.H"
00055 #include "Psycho/EyeTracker.H"
00056 #include "Psycho/PsychoOpts.H"
00057 #include "GUI/GUIOpts.H"
00058 
00059 #include "Devices/AudioGrabber.H"
00060 #include "Devices/AudioMixer.H"
00061 #include "Devices/DeviceOpts.H"
00062 #include "Audio/AudioWavFile.H"
00063 
00064 #include "Media/MPEGStream.H"
00065 #include "Media/MediaOpts.H"
00066 #include "Neuro/NeuroOpts.H"
00067 
00068 #include <vector>
00069 #include <pthread.h>
00070 #include <signal.h>
00071 
00072 
00073 // ######################################################################
00074 // Definitions & Constants
00075 
00076 #define CACHELEN                                                150
00077 
00078 // supported visual stimulus file extensions (adopted from "Media/MediaOpts.C")
00079 // needed to be constantly updated unless there's a way to check automatically
00080 //
00081 const char *imageExtensions[] = { ".pnm", ".pgm", ".ppm", ".pbm", ".pfm", ".png", ".jpeg", ".jpg", ".dpx", NULL };
00082 const char *movieExtensions[] = { ".avi", ".mpg", ".mpeg", ".m4v", ".m2v", ".mov", ".flv", ".dv", NULL };
00083 
00084 // experiment procedure type
00085 #define PROC_NORMAL                                             0
00086 #define PROC_EXP1                                               1               // online-offline switch
00087 #define PROC_EXP2                                               2               // scene pairs & online-offline switch
00088 #define PROC_EXP3                                               3               // change blindness paradigm
00089 #define PROC_EXP4                                               4               // scene pairs & low-high threshold switch
00090 #define PROC_INVALID                                    -1
00091 
00092 // input stimulus type
00093 #define STIM_IMAGE                                              0
00094 #define STIM_MOVIE                                              1
00095 #define STIM_UNKNOWN                                    -1
00096 
00097 
00098 // recording styles
00099 #define REC_NONE                                                0
00100 #define REC_DURING                                              (1 << 0)
00101 #define REC_AFTER                                               (1 << 1)
00102 #define REC_ALL                                                 (REC_DURING | REC_AFTER)
00103 
00104 
00105 // session structures
00106 struct SESSION_EXP12
00107 {
00108         uint    index;
00109         uint    staticPeriod;
00110         uint    blankPeriod;
00111         
00112         const char* flag;
00113         const char* message;
00114 };
00115 
00116 struct SESSION_EXP3
00117 {
00118         uint    index;
00119         uint    style;
00120 
00121         const char* flag;
00122 };
00123 
00124 struct SESSION_EXP4
00125 {
00126         uint    index;
00127         uint    task;
00128         bool    practice;
00129 
00130         const char* flag;
00131         const char* reminder;
00132 };
00133 
00134 //
00135 // psycho-narrator options
00136 //
00137 
00138 static const ModelOptionDef OPT_ProcedureType =
00139         { MODOPT_ARG_STRING, "ProcedureType", &MOC_DISPLAY, OPTEXP_CORE,
00140                 "Use experiment specific procedure types that would override relevant parameter settings.",
00141             "proc-type", '\0', "<Normal|Exp1|Exp2|Exp3|Exp4>", "Normal" };
00142 
00143 static const ModelOptionDef OPT_EyeTrackerRecalib =
00144         { MODOPT_ARG(uint), "EyeTrackerRecalibration", &MOC_EYETRACK, OPTEXP_CORE,
00145                 "Recalibration frequency of EyeTracker. Set 0 if you don't want recalibration at all."
00146                 "If you set to 1, then recalibration will be done after every single image session.",
00147                 "et-recalib", '\0', "<int>", "0" };
00148 
00149 static const ModelOptionDef OPT_ShuffleOrder =
00150         { MODOPT_FLAG, "ShuffleOrder", &MOC_DISPLAY, OPTEXP_CORE,
00151                 "Whether shuffle the order of input stimuli or not.",
00152                 "shuffle", '\0', "<bool>", "false" };
00153 
00154 static const ModelOptionDef OPT_MouseInput =
00155         { MODOPT_FLAG, "MouseInput", &MOC_DISPLAY, OPTEXP_CORE,
00156                 "Make mouse input available and use it instead of key presses.",
00157                 "mouse-input", '\0', "<bool>", "false" };
00158 
00159 static const ModelOptionDef OPT_BlankPeriod =
00160         { MODOPT_ARG(uint), "BlankPeriod", &MOC_DISPLAY, OPTEXP_CORE,
00161                 "The period (in sec) of the blank sessions between the visual stimulus presentations. "
00162                 "If set to 0, no blank session will be presented. If set bigger than 999,"
00163                 "blank session continues until the user presses mouse button or a key.",
00164                 "blank-period", '\0', "<int>", "5" };
00165 
00166 static const ModelOptionDef OPT_StaticPeriod =
00167         { MODOPT_ARG(uint), "StaticImagePeriod", &MOC_DISPLAY, OPTEXP_CORE,
00168                 "The period (in sec) of static images (if the currently showing image is a raster file) "
00169                 "during which they are presented on the screen. For video clips, this option is ignored.",
00170                 "static-period", '\0', "<int>", "5" };
00171 
00172 static const ModelOptionDef OPT_EyeTrackerRec =
00173         { MODOPT_ARG_STRING, "EyeTrackerRecordStyle", &MOC_EYETRACK, OPTEXP_SAVE,
00174                 "During when eye-tracker data should be grabbed and recorded. "
00175                 "'During' means the recording is done only during the stimulus presentation whereas "
00176                 "'All' is done even after the presentation - i.e. including the blank presentation.",
00177                 "et-rec", '\0', "<During|All>", "During" };
00178 
00179 static const ModelOptionDef OPT_AudRec =
00180         { MODOPT_ARG_STRING, "AudioRecordStyle", &MOC_DISPLAY, OPTEXP_SAVE,
00181                 "During when audio(speech) should be grabbed and recorded. "
00182                 "'During' means the recording is done only during the stimulus presentation whereas "
00183                 "'After' is done only after the presentation - i.e. during the blank sessions.",
00184                 "aud-rec", '\0', "<None|During|After|All>", "All" };
00185 /*
00186 static const ModelOptionDef OPT_ExpName =
00187         { MODOPT_ARG_STRING, "ExperimentName", &MOC_DISPLAY, OPTEXP_SAVE,
00188                 "The name of experiment. "
00189                 "Event log and recorded speech will be saved as the name specified by this option.",
00190                 "exp-name", '\0', "<name>", "exp_narrator" };
00191 */
00192 
00193 
00194 // thread mutex variable key for audio recording
00195 static pthread_mutex_t audMutexKey = PTHREAD_MUTEX_INITIALIZER;
00196 volatile bool audExit = false;                                  // audio thread exit flag
00197 volatile bool audRec = false;                                   // grabbed audio recording flag
00198 
00199 std::vector< AudioBuffer<byte> > rec;                   // grabbed audio buffer
00200 
00201 
00202 // ######################################################################
00203 // Submodules
00204 
00205 // case insensitive conversion of record style
00206 int readRecordStyle( const std::string& recStr )
00207 {
00208         if( strcasecmp( recStr.c_str(), "During" ) == 0 )
00209                 return REC_DURING;
00210         
00211         if( strcasecmp( recStr.c_str(), "After" ) == 0 )
00212                 return REC_AFTER;
00213         
00214         if( strcasecmp( recStr.c_str(), "All" ) == 0 )
00215                 return REC_ALL;
00216         
00217         return REC_NONE;        // no-recording by default
00218 }
00219 
00220 // case insensitive conversion of procedure type
00221 int readProcType( const std::string& procType )
00222 {
00223         if( strcasecmp( procType.c_str(), "Normal" ) == 0 )
00224                 return PROC_NORMAL;
00225         
00226         if( strcasecmp( procType.c_str(), "Exp1" ) == 0 )
00227                 return PROC_EXP1;
00228         
00229         if( strcasecmp( procType.c_str(), "Exp2" ) == 0 )
00230                 return PROC_EXP2;
00231 
00232         if( strcasecmp( procType.c_str(), "Exp3" ) == 0 )
00233                 return PROC_EXP3;
00234 
00235         if( strcasecmp( procType.c_str(), "Exp4" ) == 0 )
00236                 return PROC_EXP4;
00237         
00238         return PROC_INVALID;    // invalid procedure type
00239 }
00240 
00241 // get stimulus file type according to the extension
00242 int getStimulusType( const std::string& fname )
00243 {
00244         // check if it is a raster file
00245         for( int i = 0; imageExtensions[i]; i ++ )
00246                 if( hasExtension( fname, imageExtensions[i] ))
00247                         return STIM_IMAGE;
00248         
00249         // check if it is a movie file
00250         for( int i = 0; movieExtensions[i]; i ++ )
00251                 if( hasExtension( fname, movieExtensions[i] ))
00252                         return STIM_MOVIE;
00253         
00254         return STIM_UNKNOWN;    // unknown file type
00255 }
00256 
00257 // extract stimulus name field only
00258 void getStimulusName( const std::string &stimPath, std::string &stimName )
00259 {
00260                 std::string name, path;
00261                 splitPath( stimPath, path, name );
00262                 std::string::size_type dot = name.rfind( '.' );
00263                 if( dot != name.npos ) name.erase( dot );
00264 
00265                 stimName = name;
00266 }
00267 
00268 // pause until a key/mouse button pressed
00269 void pause( bool mouse, nub::soft_ref<PsychoDisplay>& d )
00270 {
00271         if( mouse )
00272                 d->waitForMouseClick();
00273         else
00274                 d->waitForKey();
00275 }
00276 
00277 // sleep while checking key press
00278 void snooze( uint sec, nub::soft_ref<PsychoDisplay>& d )
00279 {
00280         if( sec < 1 ) return;
00281         
00282         rutz::time start = rutz::time::wall_clock_now();
00283         rutz::time stop;
00284         
00285         do {
00286                 d->checkForKey();
00287                 usleep( 50000 );        // wait for 0.05 sec
00288                 stop = rutz::time::wall_clock_now();
00289         
00290         } while( (uint)(stop-start).sec() < sec );
00291 }
00292 
00293 // start/stop eye-tracking
00294 void trackEyes( bool trk, nub::soft_ref<EyeTracker>& et, nub::soft_ref<PsychoDisplay>& d )
00295 {
00296         if( trk )
00297         {
00298                 if( !et->isTracking() )
00299                 {
00300                         // start the eye tracker
00301                         et->track( true );
00302                         
00303                         // blink the fixation point at the center
00304                         d->displayFixationBlink();
00305                 }
00306         } else
00307         {
00308                 if( et->isTracking() )
00309                 {
00310                         // stop the eye tracker
00311                         usleep( 50000 );        // wait for 0.05 sec
00312                         et->track( false );
00313                 }
00314         }
00315 }
00316 
00317 // start/stop audio recording
00318 void recordAudio( bool rec, nub::soft_ref<PsychoDisplay>& d )
00319 {
00320         if( rec )
00321         {
00322                 if( !audRec ) d->pushEvent( "---- Audio Recording Start ----" );
00323                 audRec = true;
00324         } else
00325         {
00326                 if( audRec ) d->pushEvent( "---- Audio Recording Stop ----" );
00327                 audRec = false;
00328         }
00329 }
00330 
00331 // calibrate ISCAN
00332 void calibrateISCAN( bool mouse, nub::soft_ref<PsychoDisplay>& d )
00333 {
00334         /*
00335         et->calibrate(d);
00336         d->clearScreen();
00337         */
00338 
00339         d->clearScreen();
00340         d->displayText( "ISCAN calibration" );
00341         pause( mouse, d );
00342 
00343         // display ISCAN calibration grid
00344         d->clearScreen();
00345         d->displayISCANcalib();
00346         pause( mouse, d );
00347 
00348         // run 15-point calibration
00349         d->clearScreen();
00350         
00351         if( mouse )
00352         {
00353                 d->displayText( "click LEFT button to calibrate or RIGHT button to skip" );
00354                 int ret = d->waitForMouseClick();
00355                 if( ret == 1 ) d->displayEyeTrackerCalibration( 3, 5, 1, true );
00356         } else
00357         {
00358                 d->displayText( "press SPACE key to calibrate or other key to skip" );
00359                 int ret = d->waitForKey();
00360                 if( ret == ' ' ) d->displayEyeTrackerCalibration( 3, 5, 1 );
00361         }
00362         
00363         d->clearScreen();
00364 }
00365 
00366 // buffering movie frames
00367 static bool cacheFrame( nub::soft_ref<InputMPEGStream>& mp, std::deque<VideoFrame>& cache )
00368 {
00369         const VideoFrame frame = mp->readVideoFrame();
00370         if( !frame.initialized() )
00371                 return false;   // end of stream
00372         
00373         cache.push_front( frame );
00374         return true;
00375 }
00376 
00377 // save recorded speech into a wave file
00378 void saveAudioRecord( const std::string &wavname, nub::soft_ref<PsychoDisplay>& d )
00379 {
00380         pthread_mutex_lock( &audMutexKey );
00381         
00382         if( rec.size() > 0 )    // if there is some record to write
00383         {
00384                 LINFO("Saving '%s'...", wavname.c_str());
00385 
00386                 // write audio file
00387                 d->pushEventBegin( std::string("writeAudioFile: '") + wavname + "'" );
00388                 writeAudioWavFile( wavname, rec );
00389                 d->pushEventEnd( "writeAudioFile" );
00390                 
00391                 rec.clear();    // reset recorded audio
00392         }
00393 
00394         pthread_mutex_unlock( &audMutexKey );
00395 }
00396 
00397 // audio grabbing thread function
00398 static void *grabAudio( void *arg )
00399 {
00400         LINFO("Initiating the audio-grabbing thread...");
00401 
00402         AudioGrabber *pAgb = (AudioGrabber*)arg;
00403         
00404         // mask all allowed signals
00405         sigset_t mask;  
00406         sigfillset( &mask );
00407         if( pthread_sigmask( SIG_BLOCK, &mask, NULL ) != 0 )
00408                 LINFO("Failed to mask signals for the audio-grabbing thread!");
00409 
00410         // grab audio data endlessly
00411         while( !audExit )
00412         {
00413                 // grab audio data from input buffer
00414                 AudioBuffer<byte> data;
00415                 pAgb->grab( data );
00416 
00417                 // record grabbed audio
00418                 if( audRec )
00419                 {
00420                         pthread_mutex_lock( &audMutexKey );
00421                         rec.push_back( data );
00422                         pthread_mutex_unlock( &audMutexKey );
00423                 }
00424         }
00425         
00426         LINFO("Quitting the audio-grabbing thread...");
00427         
00428         return NULL;
00429 }
00430 
00431 
00432 // ######################################################################
00433 // psycho-narrator main function
00434 //
00435 
00436 static int submain( const int argc, char** argv )
00437 {
00438         MYLOGVERB = LOG_INFO;  // suppress debug messages
00439 
00440         // create ModelManager
00441         ModelManager manager( "Psycho Narrator" );
00442 
00443         // hook up newly created psycho-narrator options
00444         OModelParam<std::string> procTypeStr( &OPT_ProcedureType, &manager );
00445         OModelParam<uint> etRecalib( &OPT_EyeTrackerRecalib, &manager );
00446         OModelParam<bool> shuffle( &OPT_ShuffleOrder, &manager );
00447         OModelParam<bool> mouseInput( &OPT_MouseInput, &manager );
00448         OModelParam<uint> blankPeriod( &OPT_BlankPeriod, &manager );
00449         OModelParam<uint> staticPeriod( &OPT_StaticPeriod, &manager );
00450         OModelParam<std::string> audRecStr( &OPT_AudRec, &manager );
00451         OModelParam<std::string> etRecStr( &OPT_EyeTrackerRec, &manager );
00452 //      OModelParam<std::string> expName( &OPT_ExpName, &manager );
00453 
00454         //
00455         // create various ModelComponents
00456         //
00457 
00458         // display
00459         nub::soft_ref<PsychoDisplay> d( new PsychoDisplay(manager) );
00460         manager.addSubComponent( d );
00461 
00462         // event log
00463         nub::soft_ref<EventLog> el( new EventLog(manager) );
00464         manager.addSubComponent( el );
00465 
00466         // eye-tracker configurator
00467         nub::soft_ref<EyeTrackerConfigurator> etc( new EyeTrackerConfigurator(manager) );
00468         manager.addSubComponent( etc );
00469 
00470         // MPEG stream
00471         nub::soft_ref<InputMPEGStream> mp( new InputMPEGStream(manager, "Input MPEG Stream", "InputMPEGStream") );
00472         manager.addSubComponent( mp );
00473 
00474         // audio mixer
00475         nub::soft_ref<AudioMixer> amx( new AudioMixer(manager) );
00476         manager.addSubComponent( amx );
00477 
00478         // audio grabber
00479         nub::soft_ref<AudioGrabber> agb( new AudioGrabber(manager) );
00480         manager.addSubComponent( agb );
00481 
00482         // audio buffer
00483         std::vector< AudioBuffer<byte> > rec;
00484 
00485         // set option defaults
00486         manager.setOptionValString( &OPT_SDLdisplayDims, "1920x1080" );
00487         manager.setOptionValString( &OPT_EventLogFileName, "narrator.psy" );
00488         manager.setOptionValString( &OPT_EyeTrackerType, "ISCAN" );
00489         manager.setOptionValString( &OPT_InputMPEGStreamPreload, "true" );
00490         manager.setOptionValString( &OPT_AudioMixerLineIn, "false" );
00491         manager.setOptionValString( &OPT_AudioMixerCdIn, "false" );
00492         manager.setOptionValString( &OPT_AudioMixerMicIn, "true" );
00493         manager.setOptionValString( &OPT_AudioGrabberBits, "8" );
00494         manager.setOptionValString( &OPT_AudioGrabberFreq, "11025" );
00495         manager.setOptionValString( &OPT_AudioGrabberBufSamples, "256" );
00496         manager.setOptionValString( &OPT_AudioGrabberChans, "1" );
00497 
00498         // parse command-line
00499         if( manager.parseCommandLine( argc, argv, "<stimulus 1> ... <stimulus N>", 1, -1 ) == false )
00500                 return 1;
00501 
00502 //      manager.setOptionValString( &OPT_EventLogFileName, expName.getVal() + ".psy" );
00503                 
00504         int etRecStyle = readRecordStyle( etRecStr.getVal() );
00505         int audRecStyle = readRecordStyle( audRecStr.getVal() );
00506         
00507         int procType = readProcType( procTypeStr.getVal() );
00508         if( procType == PROC_INVALID )
00509                 LFATAL("Invalid procedure type '%s'", procTypeStr.getVal().c_str());            
00510 
00511         // hook up ModelComponents
00512         nub::soft_ref<EyeTracker> et = etc->getET();
00513         d->setEyeTracker( et );
00514         d->setEventLog( el );
00515         et->setEventLog( el );
00516 
00517         if( !(audRecStyle & REC_ALL) )   // if no audio recording, remove audio components
00518         {
00519                 manager.removeSubComponent( *amx, true );
00520                 manager.removeSubComponent( *agb, true );
00521         }
00522 
00523         // initiate ModelComponent instances
00524         manager.start();
00525 
00526         // create audio-grabbing thread
00527         // NOTE: audio thread should start here right after the grabber started
00528         pthread_t audGrbId;
00529         if( audRecStyle & REC_ALL )             // if audio recording, initiate the audio thread
00530         {
00531                 pthread_create( &audGrbId, NULL, &grabAudio, (void*)agb.get() );
00532         }
00533         
00534         //
00535         // begin experiment
00536         //
00537 
00538         // eye tracker calibration
00539         calibrateISCAN( mouseInput.getVal(), d );
00540 
00541         //
00542         // start experiment procedure
00543         //
00544         switch( procType )
00545         {
00546                 
00547         //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  
00548         case PROC_NORMAL:
00549                 LINFO("Normal experiment procedure...");
00550 
00551                 {
00552                         uint recalibCount = 0;
00553                         uint stimNum = manager.numExtraArgs();
00554                         uint stimIndices[stimNum];
00555                         for( uint i = 0; i < stimNum; i ++ ) stimIndices[i] = i;
00556                         if( shuffle.getVal() )
00557                         {
00558                                 LINFO("Shuffling stimulus display order...");
00559                                 randShuffle( stimIndices, stimNum );
00560                         }
00561 
00562                         // session loop
00563                         for( uint i = 0; i < stimNum; i ++ )
00564                         {
00565                                 // get the type of stimulus file according to its extension
00566                                 std::string stimPath = manager.getExtraArg(stimIndices[i]);
00567                                 std::string stimName;
00568                                 getStimulusName( stimPath, stimName );
00569                                 int stimType = getStimulusType( stimPath );
00570                                 if( stimType == STIM_UNKNOWN )
00571                                         LFATAL("Unknown stimulus file extension '%s'", stimPath.c_str());
00572 
00573                                 SDL_Surface *surf = NULL;
00574                                 std::deque<VideoFrame> cache;
00575                                 bool streaming = true;
00576                 
00577                                 d->clearScreen();
00578                 
00579                                 // load visual stimulus
00580                                 if( stimType == STIM_IMAGE )
00581                                 {
00582                                         // load raster image
00583                                         LINFO("Loading '%s'...", stimPath.c_str());
00584                                         Image< PixRGB<byte> > image = Raster::ReadRGB( stimPath );
00585                                         surf = d->makeBlittableSurface( image, true );          
00586                                 } else
00587                                 {
00588                                         // cache initial movie frames
00589                                         LINFO("Buffering '%s'...", stimPath.c_str());
00590                                         mp->setFileName( stimPath );
00591                                         for( uint j = 0; j < CACHELEN; j ++ )
00592                                         {
00593                                                 streaming = cacheFrame( mp, cache );
00594                                                 if( streaming == false ) break;  // all movie frames got cached!
00595                                         }
00596                                 }
00597                                 LINFO("'%s' ready.", stimPath.c_str());
00598                 
00599                                 // give a chance to other processes (useful on single-CPU machines)
00600                                 snooze( 1, d );
00601                                 system( "sync" );
00602                 
00603                                 // start session
00604                                 d->displayText( sformat( "Session %04d", i + 1 ) );
00605                                 pause( mouseInput.getVal(), d );
00606                 
00607                                 d->waitNextRequestedVsync( false, true );
00608                                 if( stimType == STIM_IMAGE )
00609                                         d->pushEvent( std::string("===== Showing image: ") + stimPath + " =====" );
00610                                 else
00611                                         d->pushEvent( std::string("===== Playing movie: ") + stimPath + " =====" );
00612                 
00613                                 // start eye tracking
00614                                 trackEyes( true, et, d );
00615 
00616                                 // show visual stimulus
00617                                 if( stimType == STIM_IMAGE )
00618                                 {
00619                                         // display image
00620                                         d->displaySurface( surf, -2 );
00621 
00622                                         // speech recording during image presentation
00623                                         recordAudio( audRecStyle & REC_DURING, d );
00624 
00625                                         // wait for a while as image is being displayed
00626                                         snooze( staticPeriod.getVal(), d );
00627 
00628                                         SDL_FreeSurface( surf );
00629 
00630                                 } else
00631                                 {
00632                                         // create an overlay
00633                                         d->createVideoOverlay( VIDFMT_YUV420P, mp->getWidth(), mp->getHeight() );
00634                 
00635                                         // play movie
00636                                         uint frame = 0;
00637                                         rutz::time start = rutz::time::wall_clock_now();        // start time
00638                 
00639                                         while( cache.size() )
00640                                         {
00641                                                 d->checkForKey();
00642                                                 
00643                                                 // cache one more frame
00644                                                 if( streaming )
00645                                                         streaming = cacheFrame( mp, cache );
00646                                                 
00647                                                 // get next frame to display and put it into overlay
00648                                                 VideoFrame vidframe = cache.back();
00649                                                 d->displayVideoOverlay( vidframe, frame, SDLdisplay::NEXT_VSYNC );
00650                                                 cache.pop_back();
00651                                                 
00652                                                 // speech recording during video play
00653                                                 recordAudio( audRecStyle & REC_DURING, d );
00654                                                 
00655                                                 frame ++;
00656                                         }
00657                                         rutz::time stop = rutz::time::wall_clock_now();         // end time
00658                                         double secs = (stop - start).sec();
00659                                         LINFO("%d frames in %.02f sec (~%.02f fps)", frame, secs, frame / secs);
00660                 
00661                                         // destroy the overlay. Somehow, mixing overlay displays and
00662                                         // normal displays does not work. With a single overlay created
00663                                         // before this loop and never destroyed, the first movie plays
00664                                         // ok but the other ones don't show up
00665                                         d->destroyYUVoverlay();
00666                                         d->clearScreen();  // sometimes 2 clearScreen() are necessary
00667                                 }
00668                         
00669                                 d->clearScreen();
00670                 
00671                                 // display blank
00672                                 if( blankPeriod.getVal() > 0 )
00673                                 {
00674                                         d->pushEvent( std::string("===== Presenting blank =====") );
00675                 
00676                                         // eye tracking during blank
00677                                         trackEyes( etRecStyle & REC_AFTER, et, d );
00678                                 
00679                                         // speech recording during blank
00680                                         recordAudio( audRecStyle & REC_AFTER, d );
00681                                 
00682                                         // wait for a while as blank is being presented
00683                                         if( blankPeriod.getVal() < 1000 )
00684                                         {
00685                                                 snooze( blankPeriod.getVal(), d );
00686                                         } else
00687                                         {
00688                                                 pause( mouseInput.getVal(), d );
00689                                         }
00690                                 }
00691 
00692                                 // stop eye tracking
00693                                 trackEyes( false, et, d );
00694                         
00695                                 // stop speech recording
00696                                 recordAudio( false, d );
00697 
00698                                 // save recorded speech to a wave file
00699 //                              std::string wavname( sformat("%s-%04d.wav", expName.getVal().c_str(), i + 1) );
00700                                 saveAudioRecord( stimName + ".wav", d );
00701                 
00702                                 // eye tracker recalibration
00703                                 if( etRecalib.getVal() > 0 )
00704                                 {
00705                                         recalibCount ++;
00706                                         if( recalibCount == etRecalib.getVal() )
00707                                         {
00708                                                 recalibCount = 0;
00709                                                 calibrateISCAN( mouseInput.getVal(), d );
00710                                         }
00711                                 }
00712                         }
00713                 }
00714                 break;
00715                 
00716         //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////          
00717         case PROC_EXP1:
00718         case PROC_EXP2:
00719                 if( procType == PROC_EXP1 )
00720                         LINFO("Experiment 1 procedure...");
00721                 else
00722                         LINFO("Experiment 2 procedure...");
00723                         
00724                 {
00725                         uint sessionNum;
00726                         uint pairNum[2];
00727 
00728                         if( procType == PROC_EXP1 )
00729                         {
00730                                 sessionNum = manager.numExtraArgs();
00731                         } else
00732                         {
00733                                 for( int i = 0; i < 2; i ++ )
00734                                 {
00735                                         pairNum[i] = (uint)atoi( manager.getExtraArg(i).c_str() );
00736                                         if( pairNum[i] < 1 )
00737                                                 LFATAL("Invalid stimulus information '%s'", manager.getExtraArg(i).c_str());
00738                                 }
00739                                 sessionNum = pairNum[0] + pairNum[1];
00740                         }
00741                         
00742                         SESSION_EXP12 sessions[sessionNum];
00743 
00744                         if( procType == PROC_EXP1 )
00745                         {
00746                                 // switching between online and offline for a pair of scenes
00747                                 for( uint i = 0; i < sessionNum; i += 2 )
00748                                 {
00749                                         uint i1, i2;
00750                                         if( randomUpToNotIncluding( 2 ) )
00751                                         {
00752                                                 i1 = i;
00753                                                 i2 = i + 1;
00754                                         } else
00755                                         {
00756                                                 i1 = i + 1;
00757                                                 i2 = i;
00758                                         }
00759 
00760                                         sessions[i1].index = i1;
00761                                         sessions[i1].staticPeriod = 15;
00762                                         sessions[i1].blankPeriod = 5;
00763                                         sessions[i1].flag = "ON";
00764                                         sessions[i1].message = "On-line Description";
00765 
00766                                         sessions[i2].index = i2;
00767                                         sessions[i2].staticPeriod = 10;
00768                                         sessions[i2].blankPeriod = 15;
00769                                         sessions[i2].flag = "OFF";
00770                                         sessions[i2].message = "Post-scene Description";
00771                                 }
00772                         } else
00773                         {
00774                                 // select one among a pair of scenes and switch between online and offline
00775                                 uint idx = 0;
00776                                 for( int i = 0; i < 2; i ++ )
00777                                 {
00778                                         int offset[pairNum[i]];
00779                                         int task[pairNum[i]];
00780                                         for( uint j = 0; j < pairNum[i]; j ++ )
00781                                         {
00782                                                 if( j < pairNum[i] / 2 )
00783                                                         offset[j] = task[j] = 0;
00784                                                 else
00785                                                         offset[j] = task[j] = 1;
00786                                         }
00787                                         randShuffle( offset, pairNum[i] );
00788                                         randShuffle( task, pairNum[i] );
00789                                         
00790                                         for( uint j = 0; j < pairNum[i]; j ++ )
00791                                         {                                               
00792                                                 sessions[idx].index = 2 + idx * 2 + offset[j];
00793                                                 if( task[j] == 0 )                                                                                              
00794                                                 {
00795                                                         sessions[idx].staticPeriod = 12;
00796                                                         sessions[idx].blankPeriod = 5;
00797                                                         sessions[idx].flag = "ON";
00798                                                         sessions[idx].message = "Describe as soon as possible";
00799                                                 } else
00800                                                 {
00801                                                         sessions[idx].staticPeriod = 7;
00802                                                         sessions[idx].blankPeriod = 10;
00803                                                         sessions[idx].flag = "OFF";
00804                                                         sessions[idx].message = "Describe in one sentence";
00805                                                 }
00806                                                 
00807                                                 idx ++;
00808                                         }
00809                                 }       
00810                         }
00811 
00812                         // randomize session order
00813                         randShuffle( sessions, sessionNum );
00814 
00815                         // session loop
00816                         for( uint i = 0; i < sessionNum; i ++ )
00817                         {
00818                                 d->clearScreen();
00819 
00820                                 // load raster image
00821                                 std::string stimPath = manager.getExtraArg(sessions[i].index);
00822                                 std::string stimName;
00823                                 getStimulusName( stimPath, stimName );
00824                                 LINFO("Loading '%s'...", stimPath.c_str());
00825                                 Image< PixRGB<byte> > image = Raster::ReadRGB( stimPath );
00826                                 SDL_Surface *surf = d->makeBlittableSurface( image, true );
00827                                 LINFO("'%s' ready.", stimPath.c_str());
00828 
00829                                 // give a chance to other processes (useful on single-CPU machines)
00830                                 snooze( 1, d );
00831                                 system( "sync" );
00832                 
00833                                 // start session
00834                                 d->displayText( sformat( "%s", sessions[i].message ) );
00835                                 pause( mouseInput.getVal(), d );
00836                 
00837                                 d->waitNextRequestedVsync( false, true );
00838                                 d->pushEvent( std::string("===== Showing image: ") + stimPath + " " + sessions[i].flag + " =====" );
00839 
00840                                 // start eye tracking
00841                                 trackEyes( true, et, d );
00842 
00843                                 // start speech recording
00844                                 recordAudio( true, d );
00845 
00846                                 // display image
00847                                 d->displaySurface( surf, -2 );
00848 
00849                                 // wait for a while as image is being displayed
00850                                 snooze( sessions[i].staticPeriod, d );
00851 
00852                                 SDL_FreeSurface( surf );
00853                                 d->clearScreen();
00854 
00855                                 // display blank
00856                                 d->pushEvent( std::string("===== Presenting blank =====") );
00857 
00858                                 // wait for a while as blank is being presented
00859                                 snooze( sessions[i].blankPeriod, d );
00860 
00861                                 // stop eye tracking
00862                                 trackEyes( false, et, d );
00863 
00864                                 // stop speech recording
00865                                 recordAudio( false, d );
00866 
00867                                 // save recorded speech to a wave file
00868                                 saveAudioRecord( stimName + ".wav", d );
00869                         }
00870                 }
00871                 break;
00872 
00873         //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////          
00874         case PROC_EXP3:
00875                 LINFO("Experiment 3 procedure...");
00876                 
00877                 {
00878                         uint sessionNum;
00879                         uint pairNum[3];
00880 
00881                         for( int i = 0; i < 3; i ++ )
00882                         {
00883                                 pairNum[i] = (uint)atoi( manager.getExtraArg(i).c_str() );
00884                                 if( pairNum[i] < 1 )
00885                                         LFATAL("Invalid stimulus information '%s'", manager.getExtraArg(i).c_str());
00886                         }
00887                         sessionNum = pairNum[0] + pairNum[1] + pairNum[2];
00888 
00889                         SESSION_EXP3 sessions[sessionNum];
00890 
00891                         uint idx = 0;
00892                         for( int i = 0; i < 3; i ++ )
00893                         {
00894                                 int offset[pairNum[i]];
00895                                 for( uint j = 0; j < pairNum[i]; j ++ )
00896                                 {
00897                                         if( j < pairNum[i] / 2 )
00898                                                 offset[j] = 0;          // normal scene
00899                                         else
00900                                                 offset[j] = 1;          // faded scene
00901                                 }
00902                                 randShuffle( offset, pairNum[i] );
00903 
00904                                 for( uint j = 0; j < pairNum[i]; j ++ )
00905                                 {
00906                                         sessions[idx].style = i;
00907                                         switch( sessions[idx].style )
00908                                         {
00909                                         case 0:         // practice
00910                                                 sessions[idx].index = 3 + j;
00911                                                 sessions[idx].flag = "PRACTICE";
00912                                                 break;
00913 
00914                                         case 1:         // standard
00915                                                 sessions[idx].index = 3 + pairNum[0] + j * 2;
00916                                                 if( offset[j] == 1 ) sessions[idx].index ++;
00917                                                 sessions[idx].flag = "STD";
00918                                                 break;
00919 
00920                                         case 2:         // change blindness
00921                                                 sessions[idx].index = 3 + pairNum[0] + pairNum[1] * 2 + j * 4;
00922                                                 if( offset[j] == 1 ) sessions[idx].index += 2;
00923                                                 sessions[idx].flag = "CHG";
00924                                                 break;
00925                                         }
00926 
00927                                         idx ++;
00928                                 }
00929                         }
00930 
00931                         // randomize session order (practice sessions excluded)
00932                         randShuffle( &sessions[pairNum[0]], sessionNum - pairNum[0] );
00933 
00934                         //
00935                         // session loop
00936                         //
00937                         uint sessCnt = 1;
00938                         uint pracCnt = 1;
00939                         for( uint i = 0; i < sessionNum; i ++ )
00940                         {
00941                                 d->clearScreen();
00942 
00943                                 // load raster image(s)
00944                                 std::string stimPath = manager.getExtraArg(sessions[i].index);
00945                                 std::string stimName;
00946                                 getStimulusName( stimPath, stimName );
00947                                 LINFO("Loading '%s'...", stimPath.c_str());
00948                                 Image< PixRGB<byte> > image = Raster::ReadRGB( stimPath );
00949                                 SDL_Surface *surf = d->makeBlittableSurface( image, true );
00950                                 SDL_Surface *surf_ch = NULL;
00951                                 if( sessions[i].style == 2 )
00952                                 {
00953                                         Image< PixRGB<byte> > image_ch = Raster::ReadRGB( manager.getExtraArg(sessions[i].index + 1) );
00954                                         surf_ch = d->makeBlittableSurface( image_ch, true );
00955                                 }
00956                                 LINFO("'%s' ready.", stimPath.c_str());
00957 
00958                                 // give a chance to other processes (useful on single-CPU machines)
00959                                 snooze( 1, d );
00960                                 system( "sync" );
00961 
00962                                 // start session
00963                                 if( sessions[i].style == 0 )
00964                                         d->displayText( sformat( "Pactice %04d", pracCnt ) );
00965                                 else
00966                                         d->displayText( sformat( "Session %04d", sessCnt ) );
00967                                 pause( mouseInput.getVal(), d );
00968 
00969                                 d->displayText( "Describe the event(s) of scene as quickly as possible." );
00970                                 pause( mouseInput.getVal(), d );
00971 
00972                                 d->waitNextRequestedVsync( false, true );
00973                                 d->pushEvent( std::string("===== Showing image: ") + stimPath + " " + sessions[i].flag + " =====" );
00974 
00975                                 if( sessions[i].style != 0 )
00976                                 {
00977                                         // start eye tracking
00978                                         trackEyes( true, et, d );
00979         
00980                                         // start speech recording
00981                                         recordAudio( true, d );
00982                                 } else
00983                                 {
00984                                         // blink the fixation point at the center
00985                                         d->displayFixationBlink();
00986                                 }
00987 
00988                                 for( int j = 0; j < 10; j ++ )
00989                                 {
00990                                         // display image
00991                                         if( sessions[i].style == 2 && j >= 3 && j <= 6 )        // show changed scene from 4.5 sec to 10.5 sec (for 6 sec)
00992                                                 d->displaySurface( surf_ch );           // apply change
00993                                         else
00994                                                 d->displaySurface( surf, j == 0 ? -2 : -1 );
00995                                         usleep( 1000000 );      // wait for 1 sec
00996                                         
00997                                         // display field blank
00998                                         d->SDLdisplay::clearScreen( PixRGB<byte>(0, 0, 0), true );
00999                                         usleep( 500000 );       // wait for 0.5 sec
01000 
01001                                         d->checkForKey();
01002                                 }
01003 
01004                                 SDL_FreeSurface( surf );
01005                                 if( surf_ch ) SDL_FreeSurface( surf_ch );
01006                                 d->SDLdisplay::clearScreen( PixRGB<byte>(0, 0, 0), true );
01007 
01008                                 // display blank
01009                                 d->pushEvent( std::string("===== Presenting blank =====") );
01010 
01011                                 // wait for a while as blank is being presented
01012                                 snooze( 5, d );
01013 
01014                                 if( sessions[i].style != 0 )
01015                                 {
01016                                         // stop eye tracking
01017                                         trackEyes( false, et, d );
01018 
01019                                         // stop speech recording
01020                                         recordAudio( false, d );
01021 
01022                                         // save recorded speech to a wave file
01023                                         saveAudioRecord( stimName + ".wav", d );
01024                                 }
01025 
01026                                 d->displayText( "Describe what you have seen with as much detail as possible." );
01027                                 pause( mouseInput.getVal(), d );
01028                                 d->clearScreen();
01029 
01030                                 if( sessions[i].style != 0 )
01031                                 {
01032                                         // start speech recording
01033                                         recordAudio( true, d );
01034                                 }
01035                                 snooze( 3, d );         // 3 sec of grace time for press mistakes
01036                                 pause( mouseInput.getVal(), d );
01037 
01038                                 if( sessions[i].style != 0 )
01039                                 {
01040                                         // stop speech recording
01041                                         recordAudio( false, d );
01042 
01043                                         // save recorded speech to a wave file
01044                                         saveAudioRecord( stimName + "_post.wav", d );
01045                                 }
01046                                 
01047                                 if( sessions[i].style != 0 )
01048                                         sessCnt ++;
01049                                 else
01050                                         pracCnt ++;
01051                         }
01052                 }
01053                 break;
01054                 
01055         //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////          
01056         case PROC_EXP4:
01057                 LINFO("Experiment 4 procedure...");
01058                 
01059                 {
01060                         uint sessionNum;
01061                         uint qckSessionNum, frmSessionNum;
01062                         uint qckPracNum, frmPracNum;
01063                         uint stimNum[3];
01064 
01065                         for( int i = 0; i < 3; i ++ )
01066                         {
01067                                 stimNum[i] = (uint)atoi( manager.getExtraArg(i).c_str() );
01068                                 if( stimNum[i] < 1 )
01069                                         LFATAL("Invalid stimulus information '%s'", manager.getExtraArg(i).c_str());
01070                         }
01071                         sessionNum = stimNum[0] + stimNum[1] + stimNum[2];                      
01072                         qckSessionNum = (stimNum[0] / 2) + (stimNum[1] / 2) + (stimNum[2] / 2);
01073                         frmSessionNum = sessionNum - qckSessionNum;
01074                         qckPracNum = stimNum[0] / 2;
01075                         frmPracNum = stimNum[0] - qckPracNum;                   
01076 
01077                         SESSION_EXP4 sessions[sessionNum];
01078 
01079                         uint qckIdx = 0;
01080                         uint frmIdx = qckSessionNum;
01081                         for( int i = 0; i < 3; i ++ )
01082                         {
01083                                 int offset = 3;
01084                                 for( int j = 0; j < i; j ++ )
01085                                         offset += stimNum[j];
01086 
01087                                 int task[stimNum[i]];
01088                                 for( uint j = 0; j < stimNum[i]; j ++ )
01089                                         task[j] = (j < stimNum[i] / 2) ? 0 : 1;
01090                                 randShuffle( task, stimNum[i] );
01091 
01092                                 for( uint j = 0; j < stimNum[i]; j ++ )
01093                                 {
01094                                         if( task[j] == 0 )
01095                                         {
01096                                                 // as quickly as possible
01097                                                 sessions[qckIdx].index = j + offset;
01098                                                 sessions[qckIdx].practice = (i == 0);
01099                                                 sessions[qckIdx].task = 0;
01100                                                 sessions[qckIdx].flag = "QCK";
01101                                                 sessions[qckIdx].reminder = "Describe the event(s) of the scene AS QUICKLY AS POSSIBLE while watching.";
01102                                                 
01103                                                 qckIdx ++;
01104                                         } else
01105                                         {
01106                                                 // complete and well-formed
01107                                                 sessions[frmIdx].index = j + offset;
01108                                                 sessions[frmIdx].practice = (i == 0);
01109                                                 sessions[frmIdx].task = 1;
01110                                                 sessions[frmIdx].flag = "FRM";
01111                                                 sessions[frmIdx].reminder = "Describe the event(s) of the scene in COMPLETE AND WELL-FORMED SENTENCES while watching.";
01112                                                 
01113                                                 frmIdx ++;
01114                                         }
01115                                 }
01116                         }
01117 
01118                         // randomize session order (practice sessions excluded)
01119                         randShuffle( &sessions[qckPracNum], qckSessionNum - qckPracNum );
01120                         randShuffle( &sessions[qckSessionNum + frmPracNum], frmSessionNum - frmPracNum );
01121 
01122                         //
01123                         // session loop
01124                         //
01125                         uint curTask = 100;
01126                         for( uint i = 0; i < sessionNum; i ++ )
01127                         {
01128                                 d->clearScreen();
01129 
01130                                 // load raster image(s)
01131                                 std::string stimPath = manager.getExtraArg(sessions[i].index);
01132                                 std::string stimName;
01133                                 getStimulusName( stimPath, stimName );
01134                                 LINFO("Loading '%s'...", stimPath.c_str());
01135                                 Image< PixRGB<byte> > image = Raster::ReadRGB( stimPath );
01136                                 SDL_Surface *surf = d->makeBlittableSurface( image, true );
01137                                 LINFO("'%s' ready.", stimPath.c_str());
01138 
01139                                 // give a chance to other processes (useful on single-CPU machines)
01140                                 snooze( 1, d );
01141                                 system( "sync" );
01142                                 
01143                                 // task description
01144                                 if( curTask != sessions[i].task )
01145                                 {
01146                                         d->displayText( sformat( "Task Description") );
01147                                         pause( mouseInput.getVal(), d );
01148                                         switch( sessions[i].task )
01149                                         {
01150                                         case 0:
01151                                                 d->displayText( "The task is to describe the event(s) of the scene AS QUICKLY AS POSSIBLE." );
01152                                                 pause( mouseInput.getVal(), d );
01153                                                 d->displayText( "Note that in this task, you don't have to worry about" );
01154                                                 pause( mouseInput.getVal(), d );
01155                                                 d->displayText( "the well-formedness or grammatical correctness of the sentence." );
01156                                                 pause( mouseInput.getVal(), d );
01157                                                 break;
01158                                                 
01159                                         case 1:
01160                                                 d->displayText( "The task is to describe the event(s) of the scene in COMPLETE AND WELL-FORMED SENTENCES." );
01161                                                 pause( mouseInput.getVal(), d );
01162                                                 d->displayText( "Note that in this task, you don't have to speak quickly." );
01163                                                 pause( mouseInput.getVal(), d );
01164                                                 d->displayText( "Focus on the sentence structure while taking as much time as you want." );
01165                                                 pause( mouseInput.getVal(), d );
01166                                                 break;
01167                                         }
01168                                         curTask = sessions[i].task;
01169                                 }
01170 
01171                                 // start session
01172                                 if( sessions[i].practice )
01173                                         d->displayText( sformat( "Session %04d (Practice)", i + 1 ) );
01174                                 else
01175                                         d->displayText( sformat( "Session %04d", i + 1 ) );
01176                                 pause( mouseInput.getVal(), d );
01177 
01178                                 // task reminder
01179                                 d->displayText( sessions[i].reminder );
01180                                 pause( mouseInput.getVal(), d );
01181 
01182                                 d->waitNextRequestedVsync( false, true );                               
01183                                 if( sessions[i].practice == false )
01184                                 {
01185                                         d->pushEvent( std::string("===== Showing image: ") + stimPath + " " + sessions[i].flag + " =====" );
01186 
01187                                         // start eye tracking
01188                                         trackEyes( true, et, d );
01189         
01190                                         // start speech recording
01191                                         recordAudio( true, d );
01192                                 } else
01193                                 {
01194                                         d->pushEvent( std::string("===== Showing image: ") + stimPath + " PRACTICE =====" );
01195 
01196                                         // blink the fixation point at the center
01197                                         d->displayFixationBlink();
01198                                 }
01199 
01200                                 // display image
01201                                 d->displaySurface( surf, -2 );
01202 
01203                                 // wait until description speech is done
01204                                 snooze( 3, d );         // 3 sec of grace time for press mistakes
01205                                 pause( mouseInput.getVal(), d );
01206 
01207                                 SDL_FreeSurface( surf );
01208                                 d->clearScreen();
01209 
01210                                 if( sessions[i].practice == false )
01211                                 {
01212                                         // stop eye tracking
01213                                         trackEyes( false, et, d );
01214 
01215                                         // stop speech recording
01216                                         recordAudio( false, d );
01217 
01218                                         // save recorded speech to a wave file
01219                                         saveAudioRecord( stimName + ".wav", d );
01220                                 }
01221 
01222                                 // display blank
01223                                 d->pushEvent( std::string("===== Presenting blank =====") );
01224 
01225                                 // wait for a while as blank is being presented
01226                                 snooze( 2, d );
01227                         }
01228                 }
01229                 break;
01230 
01231         //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
01232         }
01233 
01234         //
01235         // finish experiment
01236         //
01237         d->clearScreen();
01238         d->displayText( "Experiment complete." );
01239         pause( mouseInput.getVal(), d );
01240 
01241         // kill audio grabbing thread
01242         audExit = true;
01243         if( audRecStyle & REC_ALL )
01244                 pthread_join( audGrbId, NULL );
01245 
01246         // stop all ModelComponents
01247         manager.stop();
01248 
01249         return 0;
01250 }
01251 
01252 
01253 
01254 // ######################################################################
01255 // psycho-narrator dummy main function
01256 //
01257 
01258 extern "C" int main(const int argc, char** argv)
01259 {
01260         // simple wrapper around submain() to catch exceptions (because we
01261         // want to allow PsychoDisplay to shut down cleanly; otherwise if we
01262         // abort while SDL is in fullscreen mode, the X server won't return
01263         // to its original resolution)
01264 
01265         try
01266         {
01267                 return submain( argc, argv );
01268         }
01269         catch (...)
01270         {
01271                 REPORT_CURRENT_EXCEPTION;
01272         }
01273 
01274         return 1;
01275 }
01276 
Generated on Sun May 8 08:04:12 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3