function Timer=msched(e0)
% msched - Schedule events where each event returns the next event.
%
% msched ::
%    cell {
%       double ~'time of event',
%       event  ~'first event action'
%    }
% -> action timer ~'timer being used'.
%
% event ::= 
%    (  double ~'scheduled time',
%       double ~'actual time'
%    -> action (
%          event  ~'the next event action', 
%          double ~'time for next action',
%          double ~'execution time of current event'
%       )
%    ).

% this is most like a Routine or Task in Supercollider, except
% that instead of coroutining via yield, each action explicitly
% returns the continuation action.

	persistent ERROR

	ERROR=[];
	warning('off','MATLAB:TIMER:STARTDELAYPRECISION');

	[t0,a0]=cdeal(e0);

	Timer=timer;
	set(Timer,'TimerFcn',@(o,e)timercb(o,e,t0,a0),'StopFcn',@chain);
	set(Timer,'StartDelay',max(0,t0-nows)); % there will be some small error here..
	start(Timer);

	function timercb(o,e,t,a)
		[a1,t1,tt]=a(t,e.Data.time);
		set(o,'UserData',{a1,t1});
		ERROR=vertcat(ERROR,tt-t);
	end

	function chain(o,e)
		[a1,t1]=cdeal(get(o,'UserData'));
		correction=mean(ERROR);
		while ~isempty(t1)
			tnow=nows;
			delay=t1-correction-tnow;
			if delay>=0, 
				set(o,'TimerFcn',@(oo,ee)timercb(oo,ee,t1,a1));
				set(o,'StartDelay',delay); 
				start(o);
				return; 
			end
			[a1,t1,tt]=a1(t1,tnow);
		end
			
		fprintf('\n| stopping\n');
		set(o,'UserData',ERROR);
		timer_release(o);
	end
end
