Package VisionEgg :: Module FlowControl
[frames] | no frames]

Source Code for Module VisionEgg.FlowControl

   1  # The Vision Egg: FlowControl 
   2  # 
   3  # Copyright (C) 2001-2004 Andrew Straw. 
   4  # Copyright (C) 2008 California Institute of Technology 
   5  # 
   6  # URL: <http://www.visionegg.org/> 
   7  # 
   8  # Distributed under the terms of the GNU Lesser General Public License 
   9  # (LGPL). See LICENSE.TXT that came with this file. 
  10   
  11  """ 
  12  Flow control for the Vision Egg. 
  13   
  14  """ 
  15   
  16  import logging 
  17  import logging.handlers 
  18   
  19  import VisionEgg 
  20  import VisionEgg.GL as gl # get all OpenGL stuff in one namespace 
  21  import VisionEgg.ParameterTypes as ve_types 
  22  import numpy.oldnumeric as Numeric, math, types 
  23  import pygame 
  24   
  25  #################################################################### 
  26  # 
  27  #        Presentation 
  28  # 
  29  #################################################################### 
  30   
31 -class Presentation(VisionEgg.ClassWithParameters):
32 """Handles the timing and coordination of stimulus presentation. 33 34 This class is the key to the real-time operation of the Vision 35 Egg. It contains the main 'go' loop, and maintains the association 36 between 'controllers', instances of the Controller class, and the 37 parameters they control. 38 39 During the main 'go' loop and at other specific times, the 40 parameters are updated via function calls to the controllers. 41 42 Between entries into the 'go' loop, a Vision Egg application 43 should call the method between_presentations as often as possible 44 to ensure parameter values are kept up to date and any 45 housekeeping done by controllers is done. 46 47 No OpenGL environment I know of can guarantee that a new frame is 48 drawn and the double buffers swapped before the monitor's next 49 vertical retrace sync pulse. Still, although one can worry 50 endlessly about this problem, it works. In other words, on a fast 51 computer with a fast graphics card running even a pre-emptive 52 multi-tasking operating system (see below for specific 53 information), a new frame is drawn before every monitor update. If 54 this did become a problem, the go() method could be re-implemented 55 in C, along with the functions it calls. This would probably 56 result in speed gains, but without skipping frames at 200 Hz, why 57 bother? 58 59 Parameters 60 ========== 61 check_events -- allow input event checking during 'go' loop? (Boolean) 62 Default: True 63 collect_timing_info -- log timing statistics during go loop? (Boolean) 64 Default: True 65 enter_go_loop -- test used by run_forever() to enter go loop (Boolean) 66 Default: False 67 go_duration -- Tuple to specify 'go' loop duration. Either (value,units) or ('forever',) (Sequence of AnyOf(Real or String)) 68 Default: (5.0, 'seconds') 69 handle_event_callbacks -- List of tuples to handle events. (event_type,event_callback_func) (Sequence of Sequence2 of AnyOf(Integer or Callable)) 70 Default: (determined at runtime) 71 override_t_abs_sec -- Override t_abs. Set only when reconstructing experiments. (units: seconds) (Real) 72 Default: (determined at runtime) 73 quit -- quit the run_forever loop? (Boolean) 74 Default: False 75 trigger_armed -- test trigger on go loop? (Boolean) 76 Default: True 77 trigger_go_if_armed -- trigger go loop? (Boolean) 78 Default: True 79 viewports -- list of Viewport instances to draw. Order is important. (Sequence of Instance of <class 'VisionEgg.ClassWithParameters'>) 80 Default: (determined at runtime) 81 warn_longest_frame_threshold -- threshold to print frame skipped warning (units: factor of inter-frame-interval) (Real) 82 Default: 2.0 83 warn_mean_fps_threshold -- threshold to print observered vs. expected frame rate warning (fraction units) (Real) 84 Default: 0.01 85 """ 86 parameters_and_defaults = { 87 'viewports' : (None, 88 # XXX should really require VisionEgg.Core.Viewport 89 # but that would lead to circular import problem 90 ve_types.Sequence(ve_types.Instance(VisionEgg.ClassWithParameters)), 91 'list of Viewport instances to draw. Order is important.'), 92 'collect_timing_info' : (True, 93 ve_types.Boolean, 94 'log timing statistics during go loop?'), 95 'go_duration' : ((5.0,'seconds'), 96 ve_types.Sequence(ve_types.AnyOf(ve_types.Real, 97 ve_types.String)), 98 "Tuple to specify 'go' loop duration. Either (value,units) or ('forever',)"), 99 'check_events' : (True, # May cause slight performance hit, but probably negligible 100 ve_types.Boolean, 101 "allow input event checking during 'go' loop?"), 102 'handle_event_callbacks' : (None, 103 ve_types.Sequence(ve_types.Sequence2(ve_types.AnyOf(ve_types.Integer,ve_types.Callable))), 104 "List of tuples to handle events. (event_type,event_callback_func)"), 105 'trigger_armed':(True, 106 ve_types.Boolean, 107 "test trigger on go loop?"), 108 'trigger_go_if_armed':(True, 109 ve_types.Boolean, 110 "trigger go loop?"), 111 'enter_go_loop':(False, 112 ve_types.Boolean, 113 "test used by run_forever() to enter go loop"), 114 'quit':(False, 115 ve_types.Boolean, 116 "quit the run_forever loop?"), 117 'warn_mean_fps_threshold':(0.01, # fraction (0.1 = 10%) 118 ve_types.Real, 119 "threshold to print observered vs. expected frame rate warning (fraction units)"), 120 'warn_longest_frame_threshold': (2.0, # fraction (set to 2.0 for no false positives) 121 ve_types.Real, 122 "threshold to print frame skipped warning (units: factor of inter-frame-interval)"), 123 'override_t_abs_sec':(None, # override t_abs (in seconds) -- set only when reconstructing experiments 124 ve_types.Real, 125 "Override t_abs. Set only when reconstructing experiments. (units: seconds)"), 126 } 127 128 __slots__ = ( 129 'controllers', 130 'num_frame_controllers', 131 'frame_draw_times', 132 'time_sec_absolute', 133 'frames_absolute', 134 'in_go_loop', 135 'frames_dropped_in_last_go_loop', 136 'last_go_loop_start_time_absolute_sec', 137 'time_sec_since_go', 138 'frames_since_go', 139 ) 140
141 - def __init__(self,**kw):
142 VisionEgg.ClassWithParameters.__init__(self,**kw) 143 144 if self.parameters.viewports is None: 145 self.parameters.viewports = [] 146 147 if self.parameters.handle_event_callbacks is None: 148 self.parameters.handle_event_callbacks = [] 149 150 self.controllers = [] 151 self.num_frame_controllers = 0 # reference counter for controllers that are called on frame by frame basis 152 153 # A list that optionally records when frames were drawn by go() method. 154 self.frame_draw_times = [] 155 156 self.time_sec_absolute=VisionEgg.time_func() 157 self.frames_absolute=0 158 159 self.in_go_loop = False 160 self.frames_dropped_in_last_go_loop = False 161 self.last_go_loop_start_time_absolute_sec = None
162
163 - def add_controller( self, class_with_parameters, parameter_name, controller ):
164 """Add a controller""" 165 # Check if type checking needed 166 if type(class_with_parameters) != types.NoneType and type(parameter_name) != types.NoneType: 167 # Check if return type of controller eval is same as parameter type 168 if class_with_parameters.is_constant_parameter(parameter_name): 169 raise TypeError("Attempt to control constant parameter '%s' of class %s."%(parameter_name,class_with_parameters)) 170 require_type = class_with_parameters.get_specified_type(parameter_name) 171 try: 172 ve_types.assert_type(controller.returns_type(),require_type) 173 except TypeError: 174 raise TypeError("Attempting to control parameter '%s' of type %s with controller that returns type %s"%( 175 parameter_name, 176 require_type, 177 controller.returns_type())) 178 if not hasattr(class_with_parameters.parameters,parameter_name): 179 raise AttributeError("%s has no instance '%s'"%parameter_name) 180 self.controllers.append( (class_with_parameters.parameters,parameter_name, controller) ) 181 else: # At least one of class_with_parameters or parameter_name is None. 182 # Make sure they both are None. 183 if not (type(class_with_parameters) == types.NoneType and type(parameter_name) == types.NoneType): 184 raise ValueError("Neither or both of class_with_parameters and parameter_name must be None.") 185 self.controllers.append( (None,None,controller) ) 186 if controller.temporal_variables & (FRAMES_SINCE_GO|FRAMES_ABSOLUTE): 187 self.num_frame_controllers = self.num_frame_controllers + 1
188
189 - def remove_controller( self, class_with_parameters, parameter_name, controller=None ):
190 """Remove one (or more--see below) controller(s). 191 192 If controller is None, all controllers affecting the 193 specified parameter are removed. 194 195 If class_with_parameters and paramter_name are None, the 196 controller is removed completely 197 198 If class_with_parameters, paramter_name, and controller are 199 all None, all controllers are removed. 200 201 """ 202 203 if class_with_parameters is None and parameter_name is None: 204 if not isinstance(controller,Controller) and controller != None: 205 206 raise TypeError( "When deleting a controller, specify an " 207 "instance of VisionEgg.FlowControl.Controller class!") 208 209 if controller == None: #Added by Tony, May30/2005 210 self.controllers = [] 211 212 i = 0 213 while i < len(self.controllers): 214 orig_parameters,orig_parameter_name,orig_controller = self.controllers[i] 215 if controller == orig_controller: 216 del self.controllers[i] 217 else: 218 i = i + 1 219 return 220 if controller is None: 221 # The controller function is not specified: 222 # Delete all controllers that control the parameter specified. 223 if class_with_parameters is None or parameter_name is None: 224 raise ValueError("Must specify parameter from which controller should be removed.") 225 i = 0 226 while i < len(self.controllers): 227 orig_parameters,orig_parameter_name,orig_controller = self.controllers[i] 228 if (orig_parameters == class_with_parameters.parameters and 229 orig_parameter_name == parameter_name): 230 controller = self.controllers[i][2] 231 if controller.temporal_variables & (FRAMES_SINCE_GO|FRAMES_ABSOLUTE): 232 self.num_frame_controllers = self.num_frame_controllers - 1 233 del self.controllers[i] 234 else: 235 i = i + 1 236 else: # controller is specified 237 # Delete only that specific controller 238 i = 0 239 while i < len(self.controllers): 240 orig_parameters,orig_parameter_name,orig_controller = self.controllers[i] 241 if (orig_parameters == class_with_parameters.parameters and 242 orig_parameter_name == parameter_name and 243 orig_controller == controller): 244 if controller.temporal_variables & (FRAMES_SINCE_GO|FRAMES_ABSOLUTE): 245 self.num_frame_controllers = self.num_frame_controllers - 1 246 else: 247 i = i + 1
248
249 - def __call_controllers(self, 250 go_started=None, 251 doing_transition=None):
252 done_once = [] # list of ONCE contollers to switch status of 253 for (parameters_instance, parameter_name, controller) in self.controllers: 254 evaluate = 0 255 if controller.eval_frequency & ONCE: 256 evaluate = 1 257 done_once.append(controller) 258 elif doing_transition and (controller.eval_frequency & TRANSITIONS): 259 evaluate = 1 260 elif controller.eval_frequency & EVERY_FRAME: 261 evaluate = 1 262 263 if evaluate: 264 if controller.temporal_variables & TIME_SEC_ABSOLUTE: 265 controller.time_sec_absolute = self.time_sec_absolute 266 if controller.temporal_variables & FRAMES_ABSOLUTE: 267 controller.frames_absolute = self.frames_absolute 268 269 if go_started: 270 if not (controller.eval_frequency & NOT_DURING_GO): 271 if controller.temporal_variables & TIME_SEC_SINCE_GO: 272 controller.time_sec_since_go = self.time_sec_since_go 273 if controller.temporal_variables & FRAMES_SINCE_GO: 274 controller.frames_since_go = self.frames_since_go 275 result = controller.during_go_eval() 276 if parameter_name is not None: 277 setattr(parameters_instance, parameter_name, result) 278 else: 279 if not (controller.eval_frequency & NOT_BETWEEN_GO): 280 if controller.temporal_variables & TIME_SEC_SINCE_GO: 281 controller.time_sec_since_go = None 282 if controller.temporal_variables & FRAMES_SINCE_GO: 283 controller.frames_since_go = None 284 result = controller.between_go_eval() 285 if parameter_name is not None: 286 setattr(parameters_instance, parameter_name, result) 287 288 for controller in done_once: 289 #Unset ONCE flag 290 controller.eval_frequency = controller.eval_frequency & ~ONCE 291 if isinstance(controller,EncapsulatedController): 292 controller.contained_controller.eval_frequency = controller.contained_controller.eval_frequency & ~ONCE
293
294 - def is_in_go_loop(self):
295 """Queries if the presentation is in a go loop. 296 297 This is useful to check the state of the Vision Egg 298 application from a remote client over Pyro.""" 299 return self.in_go_loop
300
302 return self.frames_dropped_in_last_go_loop
303
305 return self.last_go_loop_start_time_absolute_sec
306
307 - def go(self):
308 """Main control loop during stimulus presentation. 309 310 This is the heart of realtime control in the Vision Egg, and 311 contains the main loop during a stimulus presentation. This 312 coordinates the timing of calling the controllers. 313 314 In the main loop, the current time (in absolute seconds, 315 go-loop-start-relative seconds, and go-loop-start-relative 316 frames) is computed, the appropriate controllers are called 317 with this information, the screen is cleared, each viewport is 318 drawn to the back buffer (while the video card continues 319 painting the front buffer on the display), and the buffers are 320 swapped. 321 322 """ 323 import VisionEgg.Core # here to prevent circular import 324 self.in_go_loop = 1 325 326 swap_buffers = VisionEgg.Core.swap_buffers # shorthand 327 328 # Clear boolean indicator 329 self.frames_dropped_in_last_go_loop = False 330 331 # Create shorthand notation, which speeds the main loop 332 # slightly by not performing name lookup each time. 333 p = self.parameters 334 335 if p.collect_timing_info: 336 frame_timer = VisionEgg.Core.FrameTimer() 337 338 while (not p.trigger_armed) or (not p.trigger_go_if_armed): 339 self.between_presentations() 340 341 # Go! 342 343 self.time_sec_absolute=VisionEgg.time_func() 344 345 if p.override_t_abs_sec is not None: 346 raise NotImplementedError("Cannot override absolute time yet") 347 348 self.last_go_loop_start_time_absolute_sec = self.time_sec_absolute 349 self.time_sec_since_go = 0.0 350 self.frames_since_go = 0 351 352 synclync_connection = VisionEgg.config._SYNCLYNC_CONNECTION # create shorthand 353 if synclync_connection: 354 import synclync 355 synclync_connection.next_control_packet.action_flags += (synclync.SL_CLEAR_VSYNC_COUNT + 356 synclync.SL_CLEAR_NOTIFY_SWAPPED_COUNT + 357 synclync.SL_CLEAR_FRAMESKIP_COUNT) 358 synclync_hack_done_once = 0 359 360 # Tell transitional controllers a presentation is starting 361 self.__call_controllers( 362 go_started=1, 363 doing_transition=1) 364 365 # Do the main loop 366 start_time_absolute = self.time_sec_absolute 367 if p.go_duration[0] == 'forever': # forever 368 current_duration_value = 0 369 elif p.go_duration[1] == 'seconds': # duration units 370 current_duration_value = self.time_sec_since_go 371 elif p.go_duration[1] == 'frames': # duration units 372 current_duration_value = self.frames_since_go 373 else: 374 raise RuntimeError("Unknown duration unit '%s'"%p.go_duration[1]) 375 376 while (current_duration_value < p.go_duration[0]): 377 # Get list of screens 378 screens = [] 379 for viewport in p.viewports: 380 s = viewport.parameters.screen 381 if s not in screens: 382 screens.append(s) 383 384 # Clear the screen(s) 385 for screen in screens: 386 screen.clear() 387 388 # Update all the realtime parameters 389 self.__call_controllers( 390 go_started=1, 391 doing_transition=0) 392 393 # Draw each viewport 394 for viewport in p.viewports: 395 viewport.draw() 396 397 # Swap the buffers 398 if synclync_connection: 399 if not synclync_hack_done_once: 400 synclync_connection.next_control_packet.action_flags += (synclync.SL_NOTIFY_SWAPPED_BUFFERS + 401 synclync.SL_NOTIFY_IN_GO_LOOP) 402 synclync_connection.send_control_packet() 403 synclync_hack_done_once = 1 404 data_packet = synclync_connection.get_latest_data_packet() 405 swap_buffers() 406 407 # Set the time variables for the next frame 408 self.time_sec_absolute=VisionEgg.time_func() 409 last_time_sec_since_go = self.time_sec_since_go 410 self.time_sec_since_go = self.time_sec_absolute - start_time_absolute 411 self.frames_absolute += 1 412 self.frames_since_go += 1 413 414 if p.collect_timing_info: 415 frame_timer.tick() 416 417 # Make sure we use the right value to check if we're done 418 if p.go_duration[0] == 'forever': # forever 419 pass # current_duration_value already set to 0 420 elif p.go_duration[1] == 'seconds': 421 current_duration_value = self.time_sec_since_go 422 elif p.go_duration[1] == 'frames': 423 current_duration_value = self.frames_since_go 424 else: 425 raise RuntimeError("Unknown duration unit '%s'"%p.go_duration[1]) 426 427 # Check events if requested 428 if p.check_events: 429 for event in pygame.event.get(): 430 for event_type, event_callback in p.handle_event_callbacks: 431 if event.type is event_type: 432 event_callback(event) 433 434 # Tell transitional controllers a presentation has ended 435 self.__call_controllers( 436 go_started=0, 437 doing_transition=1) 438 439 # Tell SyncLync we're not in go loop anymore 440 if synclync_connection: 441 synclync_connection.send_control_packet() # nothing in action_flags -- finishes go loop 442 443 # Check to see if frame by frame control was desired 444 # but OpenGL not syncing to vertical retrace 445 try: 446 mean_frame_time_sec = frame_timer.get_average_ifi_sec() 447 calculated_fps = 1.0/mean_frame_time_sec 448 except: 449 # the above fails when no frames were drawn 450 mean_frame_time_sec = 0.0 451 calculated_fps = 0.0 452 453 if self.num_frame_controllers: # Frame by frame control desired 454 impossibly_fast_frame_rate = 210.0 455 if calculated_fps > impossibly_fast_frame_rate: # Let's assume no monitor can exceed impossibly_fast_frame_rate 456 logger = logging.getLogger('VisionEgg.FlowControl') 457 logger.error("Frame by frame control desired, but " 458 "average frame rate was %.2f frames per " 459 "second-- faster than any display device " 460 "(that I know of). Set your drivers to " 461 "sync buffer swapping to vertical " 462 "retrace. (platform/driver " 463 "dependent)"%(calculated_fps)) 464 # Warn if > warn_mean_fps_threshold error in frame rate 465 if abs(calculated_fps-VisionEgg.config.VISIONEGG_MONITOR_REFRESH_HZ) / float(VisionEgg.config.VISIONEGG_MONITOR_REFRESH_HZ) > self.parameters.warn_mean_fps_threshold: 466 logger = logging.getLogger('VisionEgg.FlowControl') 467 logger.warning("Calculated frames per second was %.3f, " 468 "while the VISIONEGG_MONITOR_REFRESH_HZ " 469 "variable is %s."%(calculated_fps, 470 VisionEgg.config.VISIONEGG_MONITOR_REFRESH_HZ)) 471 frame_skip_fraction = self.parameters.warn_longest_frame_threshold 472 inter_frame_inteval = 1.0/VisionEgg.config.VISIONEGG_MONITOR_REFRESH_HZ 473 474 if p.collect_timing_info: 475 longest_frame_draw_time_sec = frame_timer.get_longest_frame_duration_sec() 476 if longest_frame_draw_time_sec is not None: 477 logger = logging.getLogger('VisionEgg.FlowControl') 478 if longest_frame_draw_time_sec >= (frame_skip_fraction*inter_frame_inteval): 479 self.frames_dropped_in_last_go_loop = True 480 logger.warning("One or more frames took %.1f msec, " 481 "which is signficantly longer than the " 482 "expected inter frame interval of %.1f " 483 "msec for your frame rate (%.1f Hz)."%( 484 longest_frame_draw_time_sec*1000.0, 485 inter_frame_inteval*1000.0, 486 VisionEgg.config.VISIONEGG_MONITOR_REFRESH_HZ)) 487 else: 488 logger.debug("Longest frame update was %.1f msec. " 489 "Your expected inter frame interval is " 490 "%f msec."%(longest_frame_draw_time_sec*1000.0, 491 inter_frame_inteval*1000.0)) 492 frame_timer.log_histogram() 493 494 self.in_go_loop = 0
495
496 - def export_movie_go(self, frames_per_sec=12.0, filename_suffix=".tif", filename_base="visionegg_movie", path="."):
497 """Emulates method 'go' but saves a movie.""" 498 import VisionEgg.Core # here to prevent circular import 499 import Image # Could import this at the beginning of the file, but it breaks sometimes! 500 import os # Could also import this, but this is the only place its needed 501 502 # Create shorthand notation, which speeds the main loop 503 # slightly by not performing name lookup each time. 504 p = self.parameters 505 506 # Switch function VisionEgg.time_func 507 self.time_sec_absolute=VisionEgg.time_func() # Set for real once 508 true_time_func = VisionEgg.time_func 509 def fake_time_func(): 510 return self.time_sec_absolute
511 VisionEgg.time_func = fake_time_func 512 513 logger = logging.getLogger('VisionEgg.FlowControl') 514 515 # Go! 516 517 self.time_sec_absolute=VisionEgg.time_func() 518 self.time_sec_since_go = 0.0 519 self.frames_since_go = 0 520 521 # Tell transitional controllers a presentation is starting 522 self.__call_controllers( 523 go_started=1, 524 doing_transition=1) 525 526 # Do the main loop 527 image_no = 1 528 if p.go_duration[0] == 'forever': # forever 529 current_duration_value = 0 530 elif p.go_duration[1] == 'seconds': # duration units 531 current_duration_value = self.time_sec_since_go 532 elif p.go_duration[1] == 'frames': # duration units 533 current_duration_value = self.frames_since_go 534 else: 535 raise RuntimeError("Unknown duration unit '%s'"%p.go_duration[1]) 536 while (current_duration_value < p.go_duration[0]): 537 # Get list of screens 538 screens = [] 539 for viewport in p.viewports: 540 s = viewport.parameters.screen 541 if s not in screens: 542 screens.append(s) 543 544 # Clear the screen(s) 545 for screen in screens: 546 screen.clear() 547 548 # Update all the realtime parameters 549 self.__call_controllers( 550 go_started=1, 551 doing_transition=0) 552 553 # Draw each viewport 554 for viewport in p.viewports: 555 viewport.draw() 556 557 # Swap the buffers 558 VisionEgg.Core.swap_buffers() 559 560 # Now save the contents of the framebuffer 561 fb_image = screen.get_framebuffer_as_image(buffer='front',format=gl.GL_RGB) 562 filename = "%s%04d%s"%(filename_base,image_no,filename_suffix) 563 savepath = os.path.join( path, filename ) 564 logger.info("Saving '%s'"%filename) 565 fb_image.save( savepath ) 566 image_no = image_no + 1 567 568 # Set the time variables for the next frame 569 self.time_sec_absolute += 1.0/frames_per_sec 570 self.time_sec_since_go += 1.0/frames_per_sec 571 self.frames_absolute += 1 572 self.frames_since_go += 1 573 574 # Make sure we use the right value to check if we're done 575 if p.go_duration[0] == 'forever': 576 pass # current_duration_value already set to 0 577 elif p.go_duration[1] == 'seconds': 578 current_duration_value = self.time_sec_since_go 579 elif p.go_duration[1] == 'frames': 580 current_duration_value = self.frames_since_go 581 else: 582 raise RuntimeError("Unknown duration unit '%s'"%p.go_duration[1]) 583 584 # Check events if requested 585 if p.check_events: 586 for event in pygame.event.get(): 587 for event_type, event_callback in p.handle_event_callbacks: 588 if event.type is event_type: 589 event_callback(event) 590 591 # Tell transitional controllers a presentation has ended 592 self.__call_controllers( 593 go_started=0, 594 doing_transition=1) 595 596 if len(screens) > 1: 597 logger.warning("Only saved movie from last screen.") 598 599 scp = screen.constant_parameters 600 if scp.red_bits is not None: 601 warn_about_movie_depth = 0 602 if scp.red_bits > 8: 603 warn_about_movie_depth = 1 604 elif scp.green_bits > 8: 605 warn_about_movie_depth = 1 606 elif scp.blue_bits > 8: 607 warn_about_movie_depth = 1 608 if warn_about_movie_depth: 609 logger.warning("Only saved 8 bit per pixel movie, even " 610 "though your framebuffer supports more!") 611 # Restore VisionEgg.time_func 612 VisionEgg.time_func = true_time_func
613
614 - def run_forever(self):
615 """Main control loop between go loops.""" 616 p = self.parameters 617 # enter with transitional contoller call 618 self.__call_controllers( 619 go_started=0, 620 doing_transition=1) 621 while not p.quit: 622 self.between_presentations() 623 if self.parameters.enter_go_loop: 624 self.parameters.enter_go_loop = False 625 self.go() 626 if p.check_events: 627 for event in pygame.event.get(): 628 for event_type, event_callback in p.handle_event_callbacks: 629 if event.type is event_type: 630 event_callback(event)
631
632 - def between_presentations(self):
633 """Maintain display while between stimulus presentations. 634 635 This function gets called as often as possible when in the 636 'run_forever' loop except when execution has shifted to the 637 'go' loop. 638 639 Other than the difference in the time variable passed to the 640 controllers, this routine is very similar to the inside of the 641 main loop in the go method. 642 """ 643 import VisionEgg.Core # here to prevent circular import 644 645 self.time_sec_absolute=VisionEgg.time_func() 646 647 self.__call_controllers( 648 go_started=0, 649 doing_transition=0) 650 651 viewports = self.parameters.viewports 652 653 # Get list of screens 654 screens = [] 655 for viewport in viewports: 656 s = viewport.parameters.screen 657 if s not in screens: 658 screens.append(s) 659 660 # Clear the screen(s) 661 for screen in screens: 662 screen.clear() 663 # Draw each viewport, including each stimulus 664 for viewport in viewports: 665 viewport.draw() 666 VisionEgg.Core.swap_buffers() 667 self.frames_absolute += 1
668 669 #################################################################### 670 # 671 # Controller 672 # 673 #################################################################### 674
675 -class Controller(object):
676 """Control parameters. 677 678 This abstract base class defines the interface to any controller. 679 680 Methods: 681 682 returns_type() -- Get the type of the value returned by the eval functions 683 during_go_eval() -- Evaluate controller during the main 'go' loop. 684 between_go_eval() -- Evaluate controller between runs of the main 'go' loop. 685 686 The during_go_eval() and between_go_eval() methods are called to 687 update a particular parameter such as the position of a stimulus 688 on the screen. These methods must return a value specified by the 689 returns_type() method. These methods are called at particular 690 intervals as specified by eval_frequency and with temporal 691 parameters specified by temporal_variables (see below for more 692 details). Also, see the documentation for the Presentation class. 693 694 Attributes: 695 696 return_type -- type of the value returned by the eval functions 697 eval_frequency -- when eval functions called (see above) 698 temporal_variables -- what time variables used (see above) 699 700 A Controller instance's attribute "eval_frequency" controls when a 701 controller is evaluated. This variable is a bitwise "or" (the | 702 operator) of the following flags: 703 704 EVERY_FRAME -- every frame 705 TRANSITIONS -- on enter and exit from go loop 706 ONCE -- at the next chance possible (see below) 707 NOT_DURING_GO -- as above, but never during go loop (see below) 708 NOT_BETWEEN_GO -- as above, but never between go loops (see below) 709 710 The ONCE flag is automatically unset after evaluation, 711 hence its name. As an example, if eval_frequency is set to 712 ONCE | TRANSITIONS, it will be evaluated 713 before drawing the next frame and then only before and after the 714 go loop. 715 716 NOT_DURING_GO and NOT_BETWEEN_GO modify other behavior. For 717 example, to evaluate a controller on every frame during go loops 718 but not between go loops: 719 720 eval_frequency = EVERY_FRAME | NOT_BETWEEN_GO 721 722 If none of the above flags is set, the value is: 723 724 NEVER -- this controller is never called 725 726 A Controller instance's attribute "temporal_variables" controls 727 what time variables are set for use. This variable is a bitwise 728 "or" of the following flags: 729 730 TIME_SEC_ABSOLUTE -- seconds, continuously increasing 731 TIME_SEC_SINCE_GO -- seconds, reset to 0.0 each go loop 732 FRAMES_ABSOLUTE -- frames, continuously increasing 733 FRAMES_SINCE_GO -- frames, reset to 0 each go loop 734 735 If none of these flags is set, the value is: 736 737 TIME_INDEPENDENT -- No temporal variables. 738 739 When the eval methods (during_go_eval and between_go_eval) are 740 called, attributes are set depending on the temporal variables 741 used: 742 743 temporal_variable attribute set 744 ----------------- ------------- 745 TIME_SEC_ABSOLUTE self.time_sec_absolute 746 TIME_SEC_SINCE_GO self.time_sec_since_go 747 FRAMES_ABSOLUTE self.frames_absolute 748 FRAMES_SINCE_GO self.frames_since_go 749 750 Other information: 751 752 Instances of Controller are called by instances of the 753 Presentation class. during_go_eval() is called during a go() 754 loop, and between_go_eval() is called by between_presentations() 755 (during run_forever(), for example). Before calling these 756 methods, attributes of the controller are set accoring to 757 \attribute{temporal_variables}. 758 759 """ 760 # temporal_variables flags: 761 TIME_INDEPENDENT = 0x00 762 TIME_SEC_ABSOLUTE = 0x01 763 TIME_SEC_SINCE_GO = 0x02 764 FRAMES_ABSOLUTE = 0x04 765 FRAMES_SINCE_GO = 0x08 766 767 # eval_frequency flags: 768 NEVER = 0x00 769 EVERY_FRAME = 0x01 770 TRANSITIONS = 0x02 771 ONCE = 0x04 772 NOT_DURING_GO = 0x08 773 NOT_BETWEEN_GO = 0x10 774 775 flag_dictionary = { 776 'TIME_INDEPENDENT' : TIME_INDEPENDENT, 777 'TIME_SEC_ABSOLUTE' : TIME_SEC_ABSOLUTE, 778 'TIME_SEC_SINCE_GO' : TIME_SEC_SINCE_GO, 779 'FRAMES_ABSOLUTE' : FRAMES_ABSOLUTE, 780 'FRAMES_SINCE_GO' : FRAMES_SINCE_GO, 781 782 'NEVER' : NEVER, 783 'EVERY_FRAME' : EVERY_FRAME, 784 'TRANSITIONS' : TRANSITIONS, 785 'ONCE' : ONCE, 786 'NOT_DURING_GO' : NOT_DURING_GO, 787 'NOT_BETWEEN_GO' : NOT_BETWEEN_GO} 788
789 - def __init__(self, 790 eval_frequency = EVERY_FRAME, 791 temporal_variables = TIME_SEC_SINCE_GO, 792 return_type = None):
793 """Create instance of Controller. 794 795 Arguments: 796 797 eval_frequency -- Int, bitwise "or" of flags 798 temporal_variables -- Int, bitwise "or" of flags 799 return_type -- Set to type() of the parameter under control 800 801 """ 802 if return_type is None: # Can be types.NoneType, but not None! 803 raise ValueError("Must set argument 'return_type' in Controller.") 804 if not ve_types.is_parameter_type_def(return_type): 805 if type(return_type) == types.TypeType: 806 raise TypeError("Argument 'return_type' in Controller must be a VisionEgg parameter type definition. Hint: use VisionEgg.ParameterTypes.get_type() to get the type of your value") 807 raise TypeError("Argument 'return_type' in Controller must be a VisionEgg parameter type definition") 808 self.return_type = return_type 809 810 self.temporal_variables = temporal_variables 811 self.eval_frequency = eval_frequency
812
813 - def evaluate_now(self):
814 """Call this after updating the values of a controller if it's not evaluated EVERY_FRAME.""" 815 self.eval_frequency = self.eval_frequency | ONCE
816
817 - def set_eval_frequency(self,eval_frequency):
818 self.eval_frequency = eval_frequency
819
820 - def returns_type(self):
821 """Called by Presentation. Get the return type of this controller.""" 822 return self.return_type
823
824 - def during_go_eval(self):
825 """Called by Presentation. Evaluate during the main 'go' loop. 826 827 Override this method in subclasses.""" 828 raise RuntimeError("%s: Definition of during_go_eval() in abstract base class Contoller must be overriden."%(str(self),))
829
830 - def between_go_eval(self):
831 """Called by Presentation. Evaluate between runs of the main 'go' loop. 832 833 Override this method in subclasses.""" 834 raise RuntimeError("%s: Definition of between_go_eval() in abstract base class Controller must be overriden."%(str(self),))
835
836 - def _test_self(self,go_started):
837 """Test whether a controller works. 838 839 This method performs everything the Presentation go() or 840 run_forever() methods do when calling controllers, except that 841 the temporal variables are set to -1 and that the return value 842 is not used to set parameters.""" 843 844 if self.temporal_variables & TIME_SEC_ABSOLUTE: 845 self.time_sec_absolute = -1.0 846 if self.temporal_variables & FRAMES_ABSOLUTE: 847 self.frames_absolute = -1 848 849 if go_started: 850 if not (self.eval_frequency & NOT_DURING_GO): 851 if self.temporal_variables & TIME_SEC_SINCE_GO: 852 self.time_sec_since_go = -1.0 853 if self.temporal_variables & FRAMES_SINCE_GO: 854 self.frames_since_go = -1 855 return self.during_go_eval() 856 else: 857 if not (self.eval_frequency & NOT_BETWEEN_GO): 858 if self.temporal_variables & TIME_SEC_SINCE_GO: 859 self.time_sec_since_go = None 860 if self.temporal_variables & FRAMES_SINCE_GO: 861 self.frames_since_go = None 862 return self.between_go_eval()
863
864 -class ConstantController(Controller):
865 """Set parameters to a constant value."""
866 - def __init__(self, 867 during_go_value = None, 868 between_go_value = None, 869 **kw 870 ):
871 kw.setdefault('return_type',ve_types.get_type(during_go_value)) 872 kw.setdefault('eval_frequency',ONCE | TRANSITIONS) 873 Controller.__init__(self,**kw) 874 if self.return_type is not types.NoneType and during_go_value is None: 875 raise ValueError("Must specify during_go_value") 876 if between_go_value is None: 877 between_go_value = during_go_value 878 ve_types.assert_type(ve_types.get_type(during_go_value),self.return_type) 879 ve_types.assert_type(ve_types.get_type(between_go_value),self.return_type) 880 self.during_go_value = during_go_value 881 self.between_go_value = between_go_value
882
883 - def set_during_go_value(self,during_go_value):
884 ve_types.assert_type(ve_types.get_type(during_go_value),self.return_type) 885 self.during_go_value = during_go_value
886 ## if ve_types.get_type(during_go_value) is not self.return_type: 887 ## raise TypeError("during_go_value must be %s"%str(self.return_type)) 888 ## else: 889 ## self.during_go_value = during_go_value 890
891 - def get_during_go_value(self):
892 return self.during_go_value
893
894 - def set_between_go_value(self,between_go_value):
895 ve_types.assert_type(ve_types.get_type(between_go_value),self.return_type) 896 self.between_go_value = between_go_value
897 ## if ve_types.get_type(between_go_value) is not self.return_type: 898 ## raise TypeError("between_go_value must be %s"%str(self.return_type)) 899 ## else: 900 ## self.between_go_value = between_go_value 901
902 - def get_between_go_value(self):
903 return self.between_go_value
904
905 - def during_go_eval(self):
906 """Called by Presentation. Overrides method in Controller base class.""" 907 return self.during_go_value
908
909 - def between_go_eval(self):
910 """Called by Presentation. Overrides method in Controller base class.""" 911 return self.between_go_value
912
913 -class EvalStringController(Controller):
914 """Set parameters using dynamically interpreted Python string. 915 916 The string, when evaluated as Python code, becomes the value used. 917 For example, the string "1.0" would set parameter values to 1.0. 918 919 To increase speed, the string is compiled to Python's bytecode 920 format. 921 922 The string can make use of temporal variables, which are made 923 available depending on the controller's temporal_variables 924 attribute. Note that only the absolute temporal variables are 925 available when the go loop is not running. 926 927 flag(s) present variable description 928 929 TIME_SEC_ABSOLUTE t_abs seconds, continuously increasing 930 TIME_SEC_SINCE_GO t seconds, reset to 0.0 each go loop 931 FRAMES_ABSOLUTE f_abs frames, continuously increasing 932 FRAMES_SINCE_GO f frames, reset to 0 each go loop 933 934 """
935 - def __init__(self, 936 during_go_eval_string = None, 937 between_go_eval_string = None, 938 **kw 939 ):
940 import VisionEgg.Core # here to prevent circular import 941 942 # Create a namespace for eval_strings to use 943 self.eval_globals = {} 944 945 if during_go_eval_string is None: 946 raise ValueError("'during_go_eval_string' is a required argument") 947 948 # Make Numeric and math modules available 949 self.eval_globals['Numeric'] = Numeric 950 self.eval_globals['math'] = math 951 # Make Numeric and math modules available without module name 952 for key in dir(Numeric): 953 self.eval_globals[key] = getattr(Numeric,key) 954 for key in dir(math): 955 self.eval_globals[key] = getattr(math,key) 956 957 self.during_go_eval_code = compile(during_go_eval_string,'<string>','eval') 958 self.during_go_eval_string = during_go_eval_string 959 not_between_go = 0 960 if between_go_eval_string is None: 961 not_between_go = 1 962 else: 963 self.between_go_eval_code = compile(between_go_eval_string,'<string>','eval') 964 self.between_go_eval_string = between_go_eval_string 965 966 # Check to make sure return_type is set 967 set_return_type = 0 968 if not kw.has_key('return_type'): 969 set_return_type = 1 970 kw['return_type'] = types.NoneType 971 972 # Call base class __init__ 973 Controller.__init__(self,**kw) 974 if not_between_go: 975 self.eval_frequency = self.eval_frequency|NOT_BETWEEN_GO 976 if set_return_type: 977 logger = logging.getLogger('VisionEgg.FlowControl') 978 if not (self.eval_frequency & NOT_DURING_GO): 979 logger.debug( 'Executing "%s" to test for return type.'%(during_go_eval_string,)) 980 self.return_type = ve_types.get_type(self._test_self(go_started=1)) 981 elif not (self.eval_frequency & NOT_BETWEEN_GO): 982 logger.debug('Executing "%s" to test for return type.'%(between_go_eval_string,)) 983 self.return_type = ve_types.get_type(self._test_self(go_started=0))
984
985 - def set_during_go_eval_string(self,during_go_eval_string):
986 self.during_go_eval_code = compile(during_go_eval_string,'<string>','eval') 987 self.during_go_eval_string = during_go_eval_string
988
989 - def get_during_go_eval_string(self):
990 return self.during_go_eval_string
991
992 - def set_between_go_eval_string(self,between_go_eval_string):
993 self.between_go_eval_code = compile(between_go_eval_string,'<string>','eval') 994 self.between_go_eval_string = between_go_eval_string 995 self.eval_frequency = self.eval_frequency & ~NOT_BETWEEN_GO
996
997 - def get_between_go_eval_string(self):
998 if hasattr(self,"between_go_eval_string"): 999 return self.between_go_eval_string 1000 else: 1001 return None
1002
1003 - def during_go_eval(self):
1004 """Called by Presentation. Overrides method in Controller base class.""" 1005 eval_locals = {} 1006 if self.temporal_variables & TIME_SEC_ABSOLUTE: 1007 eval_locals['t_abs'] = self.time_sec_absolute 1008 if self.temporal_variables & TIME_SEC_SINCE_GO: 1009 eval_locals['t'] = self.time_sec_since_go 1010 if self.temporal_variables & FRAMES_ABSOLUTE: 1011 eval_locals['f_abs'] = self.frames_absolute 1012 if self.temporal_variables & FRAMES_SINCE_GO: 1013 eval_locals['f'] = self.frames_since_go 1014 return eval(self.during_go_eval_code,self.eval_globals,eval_locals)
1015
1016 - def between_go_eval(self):
1017 """Called by Presentation. Overrides method in Controller base class.""" 1018 eval_locals = {} 1019 if self.temporal_variables & TIME_SEC_ABSOLUTE: 1020 eval_locals['t_abs'] = self.time_sec_absolute 1021 if self.temporal_variables & FRAMES_ABSOLUTE: 1022 eval_locals['f_abs'] = self.frames_absolute 1023 return eval(self.between_go_eval_code,self.eval_globals,eval_locals)
1024
1025 -class ExecStringController(Controller):
1026 """Set parameters using potentially complex Python string. 1027 1028 You can execute arbitrarily complex Python code with this 1029 controller. The return value must be contained within the 1030 variable "x". In other words, this string must assign the 1031 variable x, so setting the string to "x=1.0" would set the 1032 parameter under control to 1.0. 1033 1034 To increase speed, the string is compiled to Python's 1035 bytecode format. 1036 1037 The string can make use of temporal variables, which are made 1038 available depending on the controller's temporal_variables 1039 attribute. Note that only the absolute temporal variables are 1040 available when the go loop is not running. 1041 1042 flag(s) present variable description 1043 ----------------- -------- ---------------------------------- 1044 TIME_SEC_ABSOLUTE t_abs seconds, continuously increasing 1045 TIME_SEC_SINCE_GO t seconds, reset to 0.0 each go loop 1046 FRAMES_ABSOLUTE f_abs frames, continuously increasing 1047 FRAMES_SINCE_GO f frames, reset to 0 each go loop 1048 1049 """
1050 - def __init__(self, 1051 during_go_exec_string = None, 1052 between_go_exec_string = None, 1053 restricted_namespace = 1, 1054 **kw 1055 ):
1056 import VisionEgg.Core # here to prevent circular import 1057 1058 # Create a namespace for eval_strings to use 1059 self.eval_globals = {} 1060 1061 if during_go_exec_string is None: 1062 raise ValueError, "'during_go_exec_string' is a required argument" 1063 1064 self.restricted_namespace = restricted_namespace 1065 1066 if self.restricted_namespace: 1067 # Make Numeric and math modules available 1068 self.eval_globals['Numeric'] = Numeric 1069 self.eval_globals['math'] = math 1070 # Make Numeric and math modules available without module name 1071 for key in dir(Numeric): 1072 self.eval_globals[key] = getattr(Numeric,key) 1073 for key in dir(math): 1074 self.eval_globals[key] = getattr(math,key) 1075 1076 self.during_go_exec_code = compile(during_go_exec_string,'<string>','exec') 1077 self.during_go_exec_string = during_go_exec_string 1078 not_between_go = 0 1079 if between_go_exec_string is None: 1080 not_between_go = 1 1081 else: 1082 self.between_go_exec_code = compile(between_go_exec_string,'<string>','exec') 1083 self.between_go_exec_string = between_go_exec_string 1084 1085 # Check to make sure return_type is set 1086 set_return_type = 0 1087 if not kw.has_key('return_type'): 1088 set_return_type = 1 1089 kw['return_type'] = types.NoneType 1090 1091 # Call base class __init__ 1092 Controller.__init__(self,**kw) 1093 if not_between_go: 1094 self.eval_frequency = self.eval_frequency|NOT_BETWEEN_GO 1095 if set_return_type: 1096 logger = logging.getLogger('VisionEgg.FlowControl') 1097 if not (self.eval_frequency & NOT_DURING_GO): 1098 logger.debug('Executing "%s" to test for return type.'%(during_go_exec_string,)) 1099 self.return_type = ve_types.get_type(self._test_self(go_started=1)) 1100 elif not (self.eval_frequency & NOT_BETWEEN_GO): 1101 logger.debug('Executing "%s" to test for return type.'%(between_go_exec_string,)) 1102 self.return_type = ve_types.get_type(self._test_self(go_started=0))
1103
1104 - def set_during_go_exec_string(self,during_go_exec_string):
1105 self.during_go_exec_code = compile(during_go_exec_string,'<string>','exec') 1106 self.during_go_exec_string = during_go_exec_string
1107
1108 - def get_during_go_exec_string(self):
1109 return self.during_go_exec_string
1110
1111 - def set_between_go_exec_string(self,between_go_exec_string):
1112 self.between_go_exec_code = compile(between_go_exec_string,'<string>','exec') 1113 self.between_go_exec_string = between_go_exec_string 1114 self.eval_frequency = self.eval_frequency & ~NOT_BETWEEN_GO
1115
1116 - def get_between_go_exec_string(self):
1117 if hasattr(self,"between_go_exec_string"): 1118 return self.between_go_exec_string 1119 else: 1120 return None
1121
1122 - def during_go_eval(self):
1123 """Called by Presentation. Overrides method in Controller base class.""" 1124 eval_locals = {} 1125 if self.temporal_variables & TIME_SEC_ABSOLUTE: 1126 eval_locals['t_abs'] = self.time_sec_absolute 1127 if self.temporal_variables & TIME_SEC_SINCE_GO: 1128 eval_locals['t'] = self.time_sec_since_go 1129 if self.temporal_variables & FRAMES_ABSOLUTE: 1130 eval_locals['f_abs'] = self.frames_absolute 1131 if self.temporal_variables & FRAMES_SINCE_GO: 1132 eval_locals['f'] = self.frames_since_go 1133 if self.restricted_namespace: 1134 exec self.during_go_exec_code in self.eval_globals,eval_locals 1135 return eval_locals['x'] 1136 else: 1137 setup_locals_str = "\n" 1138 for local_variable_name in eval_locals.keys(): 1139 setup_locals_str = setup_locals_str + local_variable_name + "=" + repr(eval_locals[local_variable_name]) + "\n" 1140 exec setup_locals_str 1141 exec self.during_go_exec_code 1142 return x
1143
1144 - def between_go_eval(self):
1145 """Called by Presentation. Overrides method in Controller base class.""" 1146 eval_locals = {} 1147 if self.temporal_variables & TIME_SEC_ABSOLUTE: 1148 eval_locals['t_abs'] = self.time_sec_absolute 1149 if self.temporal_variables & FRAMES_ABSOLUTE: 1150 eval_locals['f_abs'] = self.frames_absolute 1151 if self.restricted_namespace: 1152 exec self.between_go_exec_code in self.eval_globals,eval_locals 1153 return eval_locals['x'] 1154 else: 1155 setup_locals_str = "\n" 1156 for local_variable_name in eval_locals.keys(): 1157 setup_locals_str = setup_locals_str + local_variable_name + "=" + repr(eval_locals[local_variable_name]) + "\n" 1158 exec setup_locals_str 1159 exec self.between_go_exec_code 1160 return x # x should be assigned by the exec string
1161
1162 -class FunctionController(Controller):
1163 """Set parameters using a Python function. 1164 1165 This is a very commonly used subclass of Controller, because it is 1166 very intuitive and requires a minimum of code to set up. Many of 1167 the Vision Egg demo programs create instances of 1168 FunctionController. 1169 1170 A number of parameters are passed to the function depending on the 1171 value of temporal_variables: 1172 1173 The function can make use of temporal variables, which are made 1174 available by passingkeyword argument(s) depending on the 1175 controller's temporal_variables attribute. Note that only the 1176 absolute temporal variables are available when the go loop is not 1177 running. 1178 1179 flag(s) present argument description 1180 ----------------- -------- ---------------------------------- 1181 TIME_SEC_ABSOLUTE t_abs seconds, continuously increasing 1182 TIME_SEC_SINCE_GO t seconds, reset to 0.0 each go loop 1183 FRAMES_ABSOLUTE f_abs frames, continuously increasing 1184 FRAMES_SINCE_GO f frames, reset to 0 each go loop 1185 1186 """
1187 - def __init__(self, 1188 during_go_func = None, 1189 between_go_func = None, 1190 **kw 1191 ):
1192 """Create an instance of FunctionController. 1193 1194 Arguments: 1195 1196 during_go_func -- function evaluted during go loop 1197 between_go_func -- function evaluted not during go loop 1198 1199 """ 1200 import VisionEgg.Core # here to prevent circular import 1201 1202 if during_go_func is None: 1203 raise ValueError("Must specify during_go_func") 1204 1205 # Set default value if not set 1206 kw.setdefault('temporal_variables',TIME_SEC_SINCE_GO) # default value 1207 1208 # Check to make sure return_type is set 1209 if not kw.has_key('return_type'): 1210 logger = logging.getLogger('VisionEgg.FlowControl') 1211 logger.debug('Evaluating %s to test for return type.'%(str(during_go_func),)) 1212 call_args = {} 1213 if kw['temporal_variables'] & TIME_SEC_ABSOLUTE: 1214 call_args['t_abs'] = VisionEgg.time_func() 1215 if kw['temporal_variables'] & TIME_SEC_SINCE_GO: 1216 call_args['t'] = 0.0 1217 if kw['temporal_variables'] & FRAMES_ABSOLUTE: 1218 call_args['f_abs'] = 0 1219 if kw['temporal_variables'] & FRAMES_SINCE_GO: 1220 call_args['f'] = 0 1221 # Call the function with time variables 1222 kw['return_type'] = ve_types.get_type(during_go_func(**call_args)) 1223 Controller.__init__(self,**kw) 1224 self.during_go_func = during_go_func 1225 self.between_go_func = between_go_func 1226 if between_go_func is None: 1227 self.eval_frequency = self.eval_frequency|NOT_BETWEEN_GO
1228
1229 - def during_go_eval(self):
1230 """Called by Presentation. Overrides method in Controller base class.""" 1231 call_args = {} 1232 if self.temporal_variables & TIME_SEC_ABSOLUTE: 1233 call_args['t_abs'] = self.time_sec_absolute 1234 if self.temporal_variables & TIME_SEC_SINCE_GO: 1235 call_args['t'] = self.time_sec_since_go 1236 if self.temporal_variables & FRAMES_ABSOLUTE: 1237 call_args['f_abs'] = self.frames_absolute 1238 if self.temporal_variables & FRAMES_SINCE_GO: 1239 call_args['f'] = self.frames_since_go 1240 return self.during_go_func(**call_args)
1241
1242 - def between_go_eval(self):
1243 """Called by Presentation. Overrides method in Controller base class.""" 1244 call_args = {} 1245 if self.temporal_variables & TIME_SEC_ABSOLUTE: 1246 call_args['t_abs'] = self.time_sec_absolute 1247 if self.temporal_variables & FRAMES_ABSOLUTE: 1248 call_args['f_abs'] = self.frames_absolute 1249 return self.between_go_func(**call_args)
1250
1251 -class EncapsulatedController(Controller):
1252 """Set parameters by encapsulating another Controller. 1253 1254 Allows a new instance of Controller to control the same parameter 1255 as an old instance. 1256 1257 You probably won't ever have to use this class directly. Both the 1258 VisionEgg.TCPController.TCPController and 1259 VisionEgg.PyroHelpers.PyroEncapsulatedController classes subclass 1260 this class. 1261 1262 """
1263 - def __init__(self,initial_controller):
1264 # Initialize base class without raising error for no return_type 1265 Controller.__init__(self,**{'return_type':types.NoneType}) 1266 self.contained_controller = initial_controller 1267 self.__sync_mimic()
1268
1269 - def __sync_mimic(self):
1270 self.return_type = self.contained_controller.return_type 1271 self.temporal_variables = self.contained_controller.temporal_variables 1272 self.eval_frequency = self.contained_controller.eval_frequency
1273
1274 - def set_new_controller(self,new_controller):
1275 """Call this to encapsulate a (new) controller.""" 1276 self.contained_controller = new_controller 1277 self.__sync_mimic()
1278
1279 - def during_go_eval(self):
1280 """Called by Presentation. Overrides method in Controller base class.""" 1281 import VisionEgg.Core # here to prevent circular import 1282 if self.temporal_variables & TIME_SEC_ABSOLUTE: 1283 self.contained_controller.time_sec_absolute = self.time_sec_absolute 1284 if self.temporal_variables & TIME_SEC_SINCE_GO: 1285 self.contained_controller.time_sec_since_go = self.time_sec_since_go 1286 if self.temporal_variables & FRAMES_ABSOLUTE: 1287 self.contained_controller.frames_absolute = self.frames_absolute 1288 if self.temporal_variables & FRAMES_SINCE_GO: 1289 self.contained_controller.frames_since_go = self.frames_since_go 1290 return self.contained_controller.during_go_eval()
1291
1292 - def between_go_eval(self):
1293 """Called by Presentation. Overrides method in Controller base class.""" 1294 import VisionEgg.Core # here to prevent circular import 1295 import VisionEgg.FlowControl 1296 if self.temporal_variables & TIME_SEC_ABSOLUTE: 1297 self.contained_controller.time_sec_absolute = self.time_sec_absolute 1298 if self.temporal_variables & FRAMES_ABSOLUTE: 1299 self.contained_controller.frames_absolute = self.frames_absolute 1300 return self.contained_controller.between_go_eval()
1301 1302 # Constants (These are a copy of the static class variables from the 1303 # Controller class into the module-level namespace. This is done for 1304 # convenience.) 1305 # temporal_variables flags: 1306 TIME_INDEPENDENT = Controller.TIME_INDEPENDENT 1307 TIME_SEC_ABSOLUTE = Controller.TIME_SEC_ABSOLUTE 1308 TIME_SEC_SINCE_GO = Controller.TIME_SEC_SINCE_GO 1309 FRAMES_ABSOLUTE = Controller.FRAMES_ABSOLUTE 1310 FRAMES_SINCE_GO = Controller.FRAMES_SINCE_GO 1311 # eval_frequency flags: 1312 NEVER = Controller.NEVER 1313 EVERY_FRAME = Controller.EVERY_FRAME 1314 TRANSITIONS = Controller.TRANSITIONS 1315 ONCE = Controller.ONCE 1316 NOT_DURING_GO = Controller.NOT_DURING_GO 1317 NOT_BETWEEN_GO = Controller.NOT_BETWEEN_GO 1318