Skip to content
This repository has been archived by the owner on Mar 5, 2022. It is now read-only.

Commit

Permalink
Reworked EyeWindow so that it uses a reasonable amount of CPU time
Browse files Browse the repository at this point in the history
  • Loading branch information
cstawarz committed Jun 9, 2010
1 parent 591876b commit cf079db
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 123 deletions.
6 changes: 3 additions & 3 deletions EyeWindow/MWEyeSamplePlotElement.h
Expand Up @@ -14,16 +14,16 @@

NSPoint position;
int is_saccading; // during a saccade or not?
mw::MWorksTime time;
NSTimeInterval time;

}

- (id)initWithTime:(mw::MWorksTime)_time
- (id)initWithTime:(NSTimeInterval)_time
position:(NSPoint)position
isSaccading:(int)_is_saccading;

@property(readonly) NSPoint position;
@property(readonly) mw::MWorksTime time;
@property(readonly) NSTimeInterval time;
@property(readonly) int saccading;

@end
2 changes: 1 addition & 1 deletion EyeWindow/MWEyeSamplePlotElement.m
Expand Up @@ -10,7 +10,7 @@


@implementation MWEyeSamplePlotElement
- (id)initWithTime:(mw::MWorksTime)_time
- (id)initWithTime:(NSTimeInterval)_time
position:(NSPoint)_position
isSaccading:(int)_is_saccading {

Expand Down
2 changes: 1 addition & 1 deletion EyeWindow/MWEyeWindowController.m
Expand Up @@ -115,7 +115,7 @@ - (void)updateEyeVariableNames {
*******************************************************************/
- (void)codecReceived:(MWCocoaEvent *)event {
if(!eyeWindowStarted) {
[NSThread detachNewThreadSelector:@selector(aggregateEvents:)
[NSThread detachNewThreadSelector:@selector(checkForUpdates:)
toTarget:plotView
withObject:nil];
eyeWindowStarted = YES;
Expand Down
13 changes: 7 additions & 6 deletions EyeWindow/MWPlotView.h
Expand Up @@ -31,22 +31,23 @@ Copy right 2006 MIT. All rights reserved.
NSMutableArray *eye_samples;
NSMutableArray *stm_samples;

NSMutableArray *eyeHEvents;
NSMutableArray *eyeVEvents;
MWCocoaEvent *currentEyeH;
MWCocoaEvent *currentEyeV;

mw::MWorksTime last_state_change_time;
MWorksTime last_state_change_time;
int current_state;

mw::MWorksTime timeOfTail;
mw::MWorksTime time_between_updates;
NSTimeInterval timeOfTail;
NSTimeInterval time_between_updates;
BOOL needUpdate;
}

- (void)setWidth:(int)width;
- (void)addEyeHEvent:(MWCocoaEvent *)event;
- (void)addEyeVEvent:(MWCocoaEvent *)event;
- (void)addEyeStateEvent:(MWCocoaEvent *)event;
- (void)acceptStmAnnounce:(mw::Datum *)stm_announce
Time:(mw::MWorksTime)event_time;
Time:(MWorksTime)event_time;
- (void)setTimeOfTail:(NSTimeInterval)_newTimeOfTail;
- (void)setUpdateRate:(float)updates_per_second;
- (void)acceptCalAnnounce:(mw::Datum *)cal_announce;
Expand Down
204 changes: 94 additions & 110 deletions EyeWindow/MWPlotView.m
Expand Up @@ -11,13 +11,21 @@
#define SACCADING 1


@interface MWPlotView(PrivateMethods)
- (void)aggregateEvents:(id)object;
@interface MWPlotView ()

@property(nonatomic, retain) MWCocoaEvent *currentEyeH;
@property(nonatomic, retain) MWCocoaEvent *currentEyeV;

- (void)syncHEvent:(MWCocoaEvent *)eyeH withVEvent:(MWCocoaEvent *)eyeV;
- (void)checkForUpdates:(id)object;
- (void)setNeedsDisplayOnMainThread:(id)arg;

@end

@implementation MWPlotView

@synthesize currentEyeH, currentEyeV;

- (id)initWithFrame:(NSRect)frameRect {
width = 180;
gridStepX = 10;
Expand All @@ -26,16 +34,13 @@ - (id)initWithFrame:(NSRect)frameRect {

eye_samples = [[NSMutableArray alloc] init];
stm_samples = [[NSMutableArray alloc] init];

eyeVEvents = [[NSMutableArray alloc] init];
eyeHEvents = [[NSMutableArray alloc] init];

last_state_change_time = 0;
current_state = FIXATION;

// these correspond to the defaults in the options window.
timeOfTail = 1000000; // 1s
time_between_updates = 100000; // 100ms
timeOfTail = 1.0; // 1s
time_between_updates = 0.1; // 100ms

GLuint attribs[] =
{
Expand Down Expand Up @@ -71,8 +76,8 @@ - (id)initWithFrame:(NSRect)frameRect {
- (void)dealloc {
[eye_samples release];
[stm_samples release];
[eyeVEvents release];
[eyeHEvents release];
[currentEyeH release];
[currentEyeV release];
[super dealloc];
}

Expand Down Expand Up @@ -194,20 +199,70 @@ - (void)setWidth:(int)width_in {

- (void)addEyeHEvent:(MWCocoaEvent *)event {
@synchronized(self) {
[eyeHEvents addObject:event];
if (!self.currentEyeH || ([event time] > [self.currentEyeH time])) {
[self syncHEvent:event withVEvent:self.currentEyeV];
}
}
}

- (void)addEyeVEvent:(MWCocoaEvent *)event {
@synchronized(self) {
[eyeVEvents addObject:event];
if (!self.currentEyeV || ([event time] > [self.currentEyeV time])) {
[self syncHEvent:self.currentEyeH withVEvent:event];
}
}
}

#define EVENT_SYNC_TIME_US 250

- (void)syncHEvent:(MWCocoaEvent *)eyeH withVEvent:(MWCocoaEvent *)eyeV {
MWorksTime eyeHTime;
MWorksTime eyeVTime;
BOOL synced = NO;

if (eyeH && eyeV) {
eyeHTime = [eyeH time];
eyeVTime = [eyeV time];
MWorksTime t_diff = eyeHTime - eyeVTime;
if (abs(t_diff) <= EVENT_SYNC_TIME_US) {
synced = YES;
} else {
if (t_diff > 0) {
eyeV = nil;
} else {
eyeH = nil;
}
}
}

self.currentEyeH = eyeH;
self.currentEyeV = eyeV;

if (synced) {
//
// We have a synced eyeH/eyeV pair, so add a plot element for it
//

int eye_state = (max(eyeHTime, eyeVTime) >= last_state_change_time) ? current_state : !current_state;

MWEyeSamplePlotElement *sample = nil;
sample = [[MWEyeSamplePlotElement alloc] initWithTime:[NSDate timeIntervalSinceReferenceDate]
position:NSMakePoint([self.currentEyeH data]->getFloat(),
[self.currentEyeV data]->getFloat())
isSaccading:eye_state];
[eye_samples addObject:sample];
[sample release];

self.currentEyeH = nil;
self.currentEyeV = nil;
needUpdate = YES;
}
}

- (void)addEyeStateEvent:(MWCocoaEvent *)event {
@synchronized(self) {
if([event data]->getInteger() != current_state) {
mw::MWorksTime time_of_state_change = [event time];
MWorksTime time_of_state_change = [event time];
if(time_of_state_change > last_state_change_time) {
last_state_change_time = time_of_state_change;
current_state = !current_state;
Expand All @@ -218,12 +273,12 @@ - (void)addEyeStateEvent:(MWCocoaEvent *)event {


//==================== stimulus announce is handled here ===============================
- (void)acceptStmAnnounce:(mw::Datum *)stm_announce Time:(mw::MWorksTime)event_time
- (void)acceptStmAnnounce:(mw::Datum *)stm_announce Time:(MWorksTime)event_time
{
@synchronized(self) {
#define MAX_STIM_DRAW_LAG 1000

static mw::MWorksTime last_event_time = 0LL;
static MWorksTime last_event_time = 0LL;


//First check for refresh
Expand Down Expand Up @@ -465,128 +520,57 @@ - (void)clear
@synchronized(self) {
[eye_samples removeAllObjects];
[stm_samples removeAllObjects];
needUpdate = YES;
}
}


- (void)setTimeOfTail:(NSTimeInterval)_newTimeOfTail {
@synchronized(self) {
timeOfTail = _newTimeOfTail*1000000;
timeOfTail = _newTimeOfTail;
}
}

- (void)setUpdateRate:(float)updates_per_second {
@synchronized(self) {
time_between_updates = 1000000/updates_per_second;
time_between_updates = 1.0/updates_per_second;
}
}

/////////////////////////////////////////////////////////////////////////
// Private methods
/////////////////////////////////////////////////////////////////////////

#define EVENT_SYNC_TIME_US 250
#define MAX_SLEEP_INTERVAL 1.0 // 1 second

- (void)aggregateEvents:(id)object {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
float currentEyeH = 0;
float currentEyeV = 0;
mw::MWorksTime currentEventTime = 0;
mw::MWorksTime previous_event_time = 0;



- (void)checkForUpdates:(id)object {
while(1) {
NSAutoreleasePool *loop_pool = [[NSAutoreleasePool alloc] init];
MWEyeSamplePlotElement *sample = nil;
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.000005]];

NSTimeInterval sleepInterval;
@synchronized(self) {
sleepInterval = min(time_between_updates, MAX_SLEEP_INTERVAL);
}

[NSThread sleepForTimeInterval:sleepInterval];

@synchronized(self) {
if([eyeHEvents count] > 0 &&
[eyeVEvents count] > 0) {
MWCocoaEvent *headEyeH = [eyeHEvents objectAtIndex:0];
MWCocoaEvent *headEyeV = [eyeVEvents objectAtIndex:0];

mw::MWorksTime eyeHTime = [headEyeH time];
mw::MWorksTime eyeVTime = [headEyeV time];

currentEyeH = [headEyeH data]->getFloat();
currentEyeV = [headEyeV data]->getFloat();

if(eyeHTime >= eyeVTime) {
// eyeH is the newest on the head

// advance eyeV
while(eyeHTime - eyeVTime > EVENT_SYNC_TIME_US &&
[eyeVEvents count] > 0) {
[eyeVEvents removeObjectAtIndex:0];
if([eyeVEvents count] > 0) {
headEyeV = [eyeVEvents objectAtIndex:0];
currentEyeV = [headEyeV data]->getFloat();
eyeVTime = [headEyeV time];
}
}

currentEventTime = eyeHTime;

} else {
// eyeV is the newest on the head

// advance eyeH
while(eyeVTime - eyeHTime > EVENT_SYNC_TIME_US &&
[eyeHEvents count] > 0) {
[eyeHEvents removeObjectAtIndex:0];
if([eyeHEvents count] > 0) {
headEyeH = [eyeHEvents objectAtIndex:0];
currentEyeH = [headEyeH data]->getFloat();
eyeHTime = [headEyeH time];
}
}

currentEventTime = eyeVTime;
}

// currenly, it can only be 1 or 0
int eye_state = currentEventTime >= last_state_change_time ? current_state : !current_state;



// now all events roughly equal in time
sample = [[MWEyeSamplePlotElement alloc] initWithTime:currentEventTime
position:NSMakePoint(currentEyeH, currentEyeV)
isSaccading:eye_state];

if([eyeHEvents count] > 0) {
[eyeHEvents removeObjectAtIndex:0];
}

if([eyeVEvents count] > 0) {
[eyeVEvents removeObjectAtIndex:0];
}
}
}

if(sample != nil) {
@synchronized(self) {
[eye_samples addObject:sample];
[sample release];

while(currentEventTime - timeOfTail > [[eye_samples objectAtIndex:0] time]) {
[eye_samples removeObjectAtIndex:0];
}
}
NSTimeInterval cutoffTime = [NSDate timeIntervalSinceReferenceDate] - timeOfTail;
while(([eye_samples count] > 0) && ([[eye_samples objectAtIndex:0] time] < cutoffTime)) {
[eye_samples removeObjectAtIndex:0];
needUpdate = YES;
}

if (needUpdate) {
[self performSelectorOnMainThread:@selector(setNeedsDisplayOnMainThread:)
withObject:nil
waitUntilDone:NO];
needUpdate = NO;
}
}

if(currentEventTime - previous_event_time > time_between_updates) {
[self performSelectorOnMainThread:@selector(setNeedsDisplayOnMainThread:)
withObject:nil
waitUntilDone:NO];
previous_event_time = currentEventTime;
}

[loop_pool release];
[loop_pool drain];
}
[pool release];
}

- (void)setNeedsDisplayOnMainThread:(id)arg {
Expand Down
4 changes: 2 additions & 2 deletions EyeWindow/MWorksEyeWindow.xcodeproj/project.pbxproj
Expand Up @@ -128,15 +128,15 @@
children = (
68D2929F0AF8E8AE00E9A885 /* MWEyeWindowOptionController.h */,
68D292A00AF8E8AE00E9A885 /* MWEyeWindowOptionController.m */,
5C10618C09904FE9007A63F8 /* MWPlotViewElement.h */,
B28377190A8A951400358169 /* MWStimulusPlotElement.h */,
B283771A0A8A951400358169 /* MWStimulusPlotElement.m */,
5C8E4A6B098FA6FF00EB44CA /* MWPlotView.h */,
5C8E4A6C098FA6FF00EB44CA /* MWPlotView.m */,
5C8E4A79098FB02400EB44CA /* MWEyeWindowController.h */,
5C8E4A7A098FB02400EB44CA /* MWEyeWindowController.m */,
5CF28589099402F4000C55A3 /* MWEyeSamplePlotElement.m */,
5C10618C09904FE9007A63F8 /* MWPlotViewElement.h */,
5CF28588099402F4000C55A3 /* MWEyeSamplePlotElement.h */,
5CF28589099402F4000C55A3 /* MWEyeSamplePlotElement.m */,
);
name = Classes;
sourceTree = "<group>";
Expand Down

0 comments on commit cf079db

Please sign in to comment.