changeset 1:289445d368a7

import.
author samer
date Wed, 19 Dec 2012 22:46:05 +0000
parents 672052bd81f8
children 7357e1dc2ad6
files signals/@sigarray/sigarray.m signals/@sigbase/sigbase.m signals/@sigbinop/sigbinop.m signals/@sigcat/sigcat.m signals/@sigconst/sigconst.m signals/@sigdrop/sigdrop.m signals/@sigempty/sigempty.m signals/@sigfun/sigfun.m signals/@siglzcat/construct.m signals/@siglzcat/siglzcat.m signals/@sigmap/sigmap.m signals/@signal/gather.m signals/@signal/gathern.m signals/@signal/length.m signals/@signal/signal.m signals/@sigreclock/sigreclock.m signals/@sigresample/construct.m signals/@sigresample/design.m signals/@sigresample/sigresample.m signals/@sigtake/construct.m signals/@sigtake/sigtake.m signals/TODO signals/mixdown.m signals/private/unify.m signals/resamplex.m signals/sconst.m signals/sigcatx.m signals/sigpar.m signals/sigreadn.m signals/sigrep.m signals/sigsel.m signals/snull.m signals/sones.m signals/szeros.m signals/transfer.m signals/unify_channels.m signals/unify_rates.m
diffstat 37 files changed, 858 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@sigarray/sigarray.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,46 @@
+classdef sigarray < signal
+	properties (GetAccess=private, SetAccess=immutable)
+		fs
+		array
+	end
+	methods
+		function s=sigarray(array,rate)
+			if nargin<2, rate=nan; end
+			s.array=array;
+			s.fs=rate;
+		end
+
+		function s=tostring(sig)
+			s=sprintf('sigarray(<%dx%d>)',size(sig.array,1),size(sig.array,2));
+		end
+
+		function c=channels(s), c=size(s.array,1); end
+		function c=rate(s), c=s.fs; end
+		function s=construct(sig)
+			array=sig.array;
+			ch=size(array,1);
+			length=size(array,2);
+			pos=0;
+
+			s.start   = @nop;
+			s.stop    = @nop;
+			s.dispose = @nop;
+			s.reader = @reader;
+
+			function r=reader(n)
+				r = @next;
+				CHUNK = 1:uint32(n);
+				function [x,rem]=next
+					if pos+n<=length
+						x=array(:,pos+CHUNK); rem=0; 
+						pos=pos+n;
+					else
+						rem=n-(length-pos);
+						x=[array(:,pos+1:end),zeros(ch,rem)];
+						pos=length;
+					end
+				end
+			end
+		end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@sigbase/sigbase.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,17 @@
+classdef sigbase < signal
+	properties (GetAccess=protected, SetAccess=immutable)
+		chans
+		fs
+	end
+	methods
+		function s=sigbase(channels,rate)
+			if nargin<2, rate=nan; end
+			if nargin<1, channels=nan; end
+			s.chans=channels;
+			s.fs=rate;
+		end
+
+		function c=channels(s), c=s.chans; end
+		function c=rate(s), c=s.fs; end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@sigbinop/sigbinop.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,54 @@
+classdef sigbinop < signal
+	properties (GetAccess=private, SetAccess=immutable)
+		op
+		sig1
+		sig2
+		chans
+	end
+	methods
+		function s=sigbinop(f,sig1,sig2,chf)
+			if isinf(unify_rates(rate(sig1),rate(sig2))),
+				error('Sample rate mismatch');
+			end
+			if nargin<4, 
+				chf=@(c1,c2)size(f(zeros(c1,1),zeros(c2,1)),1);
+			end
+			s.op=f;
+			s.sig1=sig1;
+			s.sig2=sig2;
+			s.chans=chf(channels(sig1),channels(sig2)); 
+		end
+
+		function c=channels(s), c=s.chans; end
+		function r=rate(s), r=rate(s.sig1); end
+		function s=construct(sig)
+
+			s1=construct(sig.sig1);
+			s2=construct(sig.sig2);
+			op=sig.op;
+
+			s.start   = @start;
+			s.stop    = @stop;
+			s.dispose = @dispose;
+			s.reader = @reader;
+
+			function start, s1.start(); s2.start(); end
+			function stop, s1.stop(); s2.stop(); end
+			function dispose, s1.dispose(); s2.dispose(); end 
+			function r=reader(n)
+				r1=s1.reader(n);
+				r2=s2.reader(n);
+				r =@next;
+				function [x,rem]=next
+					[x1,rem1]=r1();
+					[x2,rem2]=r2();
+					x=op(x1,x2);
+					rem=max(rem1,rem2);
+				end
+			end
+		end
+		function s=tostring(sig)
+			s=sprintf('(%s <%s> %s)',tostring(sig.sig1),tostring(sig.op),tostring(sig.sig2));
+		end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@sigcat/sigcat.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,52 @@
+classdef sigcat < sigbase
+	properties (GetAccess=private, SetAccess=immutable)
+		signals
+	end
+	methods
+		function s=sigcat(varargin)
+			fs=foldl(@unify_rates,nan,map(@rate,varargin));
+			if isinf(fs), error('sampling rate mismatch'); end
+			ch=foldl(@unify_channels,nan,map(@channels,varargin));
+			if isinf(ch), error('channel count mismatch'); end
+			s=s@sigbase(ch,fs);
+			s.signals=varargin;
+		end
+
+		function s=tostring(sig)
+			n=length(sig.signals);
+			strx=map(@tostring,sig.signals);
+			if n==1, s=strx{1};
+			elseif n==2, s=sprintf('%s & %s',strx{1},strx{2});
+			else s=sprintf('sigcat(%s,...)',strx{1});
+			end
+		end
+
+		function s=construct(sig)
+			sc=construct(sig.signals{1});
+			sx=sig.signals(2:end);
+
+			s.start   = @start;
+			s.stop    = @stop;
+			s.dispose = @dispose;
+			s.reader  = @reader;
+
+			function start, sc.start(); end
+			function stop, sc.stop(); end
+			function dispose, sc.dispose(); end 
+
+			function r=reader(n)
+				rc=sc.reader(n);
+				r = @next;
+				function [x,rem]=next
+					[x,rem]=rc();
+					while rem>0 && ~isempty(sx) % current signal exhausted, try next
+						sc.dispose();
+						sc=construct(sx{1}); sx=sx(2:end);
+						[x(:,end-rem+1:end),rem]=sigreadn(sc,rem);
+						rc=sc.reader(n);
+					end
+				end
+			end
+		end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@sigconst/sigconst.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,29 @@
+classdef sigconst < signal
+	properties (GetAccess=private, SetAccess=immutable)
+		val
+		fs
+	end
+	methods
+		function s=sigconst(val,rate)
+			if nargin<2, rate=nan; end
+			s.val=reshape(val,size(val,1),1);
+			s.fs=rate;
+		end
+
+		function s=tostring(sig), s=sprintf('sigconst(%s)',mat2str(sig.val)); end
+		function c=channels(s), c=size(s.val,1); end
+		function c=rate(s), c=s.fs; end
+		function s=construct(sig)
+			s.start   = @nop;
+			s.stop    = @nop;
+			s.dispose = @nop;
+			s.reader = @reader;
+
+			function r=reader(n)
+				r = @next;
+				buf=repmat(sig.val,1,double(n));
+				function [x,rem]=next, x=buf; rem=0; end
+			end
+		end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@sigdrop/sigdrop.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,25 @@
+classdef sigdrop < signal
+	properties (GetAccess=private, SetAccess=immutable)
+		todrop % natural
+		sig    % signal(C,R)
+	end
+	methods
+		function s=sigdrop(n,sig)
+			s.todrop=n;
+			s.sig=sig;
+		end
+
+		function s=tostring(sig)
+			s=sprintf('drop(%d,%s)',sig.todrop,tostring(sig.sig));
+		end
+
+		function c=rate(s), c=rate(s.sig); end
+		function c=channels(s), c=channels(s.sig); end
+		function s=construct(sig)
+			s=construct(sig.sig);
+			s.start();
+			sigreadn(s,sig.todrop);
+			s.stop();
+		end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@sigempty/sigempty.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,22 @@
+classdef sigempty < sigbase
+	methods
+		function s=sigempty(channels,rate)
+			if nargin<2, rate=nan; end
+			s=s@sigbase(channels,rate);
+		end
+
+		function s=tostring(sig), s='sigempty'; end
+		function s=construct(sig)
+			s.start   = @nop;
+			s.stop    = @nop;
+			s.dispose = @nop;
+			s.reader = @reader;
+
+			function r=reader(n)
+				r = @next;
+				buf=zeros(sig.channels,double(n));
+				function [x,rem]=next, x=buf; rem=n; end
+			end
+		end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@sigfun/sigfun.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,36 @@
+classdef sigfun < signal
+	properties (GetAccess=private, SetAccess=immutable)
+		fun
+		fs
+	end
+	methods
+		function s=sigfun(fun,rate)
+			s.fun=fun;
+			s.fs=rate;
+		end
+
+		function s=tostring(sig), s=sprintf('sigfun(%s)',tostring(sig.fun)); end
+		function c=channels(s), c=size(s.fun(0),1); end
+		function c=rate(s), c=s.fs; end
+
+		function s=construct(sig)
+			fun=sig.fun;
+			t=0;
+
+			s.start   = @nop;
+			s.stop    = @nop;
+			s.dispose = @nop;
+			s.reader = @reader;
+
+			function r=reader(n)
+				r = @next;
+				T=(0:n-1)/sig.fs;
+				dt=n/sig.fs;
+				function [x,rem]=next, 
+					x=fun(t+T); rem=0; 
+					t=t+dt;
+				end
+			end
+		end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@siglzcat/construct.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,35 @@
+function s=construct(sig)
+	fs=rate(sig.head);
+	ch=channels(sig.head);
+	sc=construct(sig.head);
+	sx=sig.tail;
+
+	s.start   = @start;
+	s.stop    = @stop;
+	s.dispose = @dispose;
+	s.reader  = @reader;
+
+	function start, sc.start(); end
+	function stop, sc.stop(); end
+	function dispose, sc.dispose(); end 
+	function r=reader(n)
+		rc=sc.reader(n);
+		r = @next;
+		function [x,rem]=next
+			[x,rem]=rc();
+			while rem>0 && ~isempty(sx) % current signal exhausted, try next
+				sc.dispose();
+				[sig2,sx]=sx();
+
+				fs=unify_rates(fs,rate(sig2));
+				if isinf(fs), error('sigcat:Signal sampling rate mismatch'); end
+				ch=unify_channels(ch,channels(sig2));
+				if isinf(ch), error('sigcat:Signal channels count mismatch'); end
+				sc=construct(sig2); 
+
+				[x(:,end-rem+1:end),rem]=sigreadn(sc,rem);
+				rc=sc.reader(n);
+			end
+		end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@siglzcat/siglzcat.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,20 @@
+classdef siglzcat < signal
+	properties (GetAccess=private, SetAccess=immutable)
+		head
+		tail
+	end
+	methods
+		function s=siglzcat(head,tail)
+			if isnan(channels(head)), error('First signal to siglzcat must have determinate channels'); end
+			s.head=head;
+			s.tail=tail;
+		end
+
+		function s=tostring(sig)
+			s=sprintf('%s > %s',tostring(sig.head),tostring(sig.tail));
+		end
+
+		function c=rate(s), c=rate(s.head); end
+		function c=channels(s), c=channels(s.head); end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@sigmap/sigmap.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,40 @@
+classdef sigmap < signal
+	properties (GetAccess=private, SetAccess=immutable)
+		fun
+		sig
+		chans
+	end
+	methods
+		function s=sigmap(f,sig,chf)
+			if nargin<3, chf=@(c1)size(f(zeros(c1,1)),1); end
+			s.fun=f;
+			s.sig=sig;
+			s.chans=chf(channels(sig));
+		end
+
+		function s=tostring(sig)
+			s=sprintf('map(%s,%s)',tostring(sig.fun),tostring(sig.sig));
+		end
+
+		function c=rate(s), c=rate(s.sig); end
+		function c=channels(s), c=s.chans; end
+
+		function s=construct(sig)
+			f=sig.fun;
+			s1=construct(sig.sig);
+			s.start   = s1.start;
+			s.stop    = s1.stop;
+			s.dispose = s1.dispose;
+			s.reader  = @reader;
+
+			function r=reader(n)
+				r1=s1.reader(n);
+				r =@next;
+				function [x,rem]=next
+					[x1,rem]=r1();
+					x=f(x1);
+				end
+			end
+		end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@signal/gather.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,33 @@
+% gather - collect all samples from a finite signal
+% gather   :: signal(C,R), options -> [[C,N]].
+function x=gather(sig,varargin)
+	opts=prefs('chunk',256,'init',512,'grow',2,'max',1e9,varargin{:});
+
+	s=construct(sig);
+	try % to make sure we dispose of s once opened
+		chunk=uint32(opts.chunk);
+		n=uint32(0); CHUNK=1:chunk; 
+		cap=opts.init; % initial capacity of buffer
+		x=zeros(channels(sig),cap); % buffer
+		r=s.reader(opts.chunk);
+		rem=0; 
+		s.start();
+		while rem==0
+			if n+chunk>cap % need more room
+				if n>opts.max, error('maximum capacity exceeded'); end
+				cap=opts.grow*cap; 
+				x=repmat(x,1,opts.grow); 
+			end
+			[x(:,n+CHUNK),rem]=r();
+			n=n+chunk;
+		end
+		n=n-rem; % remove rem samples from end
+	catch ex
+		s.dispose();
+		rethrow(ex);
+	end
+	s.stop();
+	s.dispose();
+	x=x(:,1:n); % grab only valid samples
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@signal/gathern.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,31 @@
+% gathern - Collect exactly n samples from a signal
+%
+% gathern  :: N:natural, signal(C,R), options -> [[C,N]], natural.
+function [x,rem]=gathern(m,sig,varargin)
+	opts=prefs('chunk',256,varargin{:});
+
+	s=construct(sig);
+	try % to make sure we dispose of s once opened
+		chunk=uint32(opts.chunk);
+		n=uint32(0); CHUNK=1:chunk; 
+		x=zeros(channels(sig),m); 
+		r=s.reader(opts.chunk);
+		rem=0; 
+		while rem==0 && n+chunk<=m
+			[x(:,n+CHUNK),rem]=r();
+			n=n+chunk;
+		end
+		if n<m && rem==0 % need more and not run out
+			[y,rem]=r();
+			x(:,n+1:m)=y(:,1:m-n);
+			rem=(m-n)-(chunk-rem);
+		end
+	catch ex
+		s.dispose();
+		rethrow(ex);
+	end
+	s.dispose();
+end
+
+
+	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@signal/length.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,24 @@
+% length - length of finite signal
+function n=length(sig,varargin)
+	opts=prefs('chunk',1024,'init',2,'grow',2,'max',1e12,varargin{:});
+
+	s=construct(sig);
+	try % to make sure we dispose of s once opened
+		chunk=uint64(opts.chunk);
+		n=uint64(0); CHUNK=1:chunk; 
+		r=s.reader(opts.chunk);
+		dummy=[];
+		rem=0; 
+		while rem==0
+			[dummy,rem]=r();
+			n=n+chunk;
+			if n>opts.max, error('maximum length exceeded'); end
+		end
+		n=n-uint64(rem); % remove rem samples from end
+	catch ex
+		s.dispose();
+		rethrow(ex);
+	end
+	s.dispose();
+	n=double(n);
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@signal/signal.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,71 @@
+% signal - Base class for signal
+%
+% signal :: signal(C:natural,R:nonneg).
+%
+% The signal(C,R) type denotes the type of a signal with C
+% channels and a sampling rate of R. 
+%
+% The base signal class cannot be used without subclassing since
+% any attempt to instantiate the live signal generator will throw
+% an exception.
+%
+% METHODS
+%    channels :: signal(C,R) -> natural.
+%    rate     :: signal(C,R) -> nonneg. 
+%    construct:: signal(C,R) -> livesig(C).
+%    length   :: signal(C,R) -> natural.
+%    gather   :: signal(C,R), options -> [[C,N]].
+%    gathern  :: N:natural, signal(C,R), options -> [[C,N]], natural.
+%
+% livesig(C) :== struct {
+%    start   :: void->void;
+%    stop    :: void->void;
+%    dispose :: void->void;
+%    reader  :: N:natural -> (void->[[C,N]]);
+% }
+
+classdef signal
+	properties (GetAccess=private, SetAccess=immutable)
+	end
+	methods
+		function s=signal, end
+
+		function s=and(s1,s2), s=sigcat(s1,s2); end
+		function y=cache(x), y=reclock(rate(x),sigarray(gather(x))); end
+		function c=channels(s), error('number of channels undefined'); end
+		function s=construct(sig), error('Cannot construct base signal class'); end
+		function display(a)
+			disp(sprintf('    %s :: signal(%s,%s)',tostring(a),fmt(channels(a)),fmt(rate(a))));
+			function s=fmt(x), if isnan(x), s='_'; else s=num2str(x); end; end
+		end
+
+		function y=map(f,x), y=sigmap(f,x); end
+		function s=mpower(a,b), s=resample(b,a); end
+		function s=or(s1,s2), s=sigbinop(@vertcat,s1,s2,@plus); end
+		function r=rate(s), error('sampling rate undefined'); end
+		function s2=reclock(r,s1), s2=sigreclock(r,s1); end
+		function y=drop(n,x), y=sigdrop(n,x); end
+		function y=take(n,x), y=sigtake(n,x); end
+
+		function y=dropt(t,x), 
+			if isnan(rate(x)), error('Cannot dropt without definite sampling rate'); end
+			y=sigdrop(round(t*rate(x)),x);
+		end
+			
+		function y=taket(t,x), 
+			if isnan(rate(x)), error('Cannot taket without definite sampling rate'); end
+			y=sigtake(round(t*rate(x)),x);
+		end
+			
+		function y=cycle(x), 
+			y=siglzcat(x,@cyclef);
+			function [s1,sx]=cyclef, s1=x; sx=@cyclef; end
+		end
+
+		function s2=resample(f2,s1,varargin)
+			if isnan(rate(s1)), error('no sample rate set'); end
+			if rate(s1)==f2, s2=s1;
+			else, s2=sigresample(f2,s1,varargin{:}); end
+		end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@sigreclock/sigreclock.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,17 @@
+classdef sigreclock < signal
+	properties (GetAccess=private, SetAccess=immutable)
+		fs
+		sig
+	end
+	methods
+		function s=sigreclock(rate,sig)
+			s.fs=rate;
+			s.sig=sig;
+		end
+
+		function s=tostring(sig), s=sprintf('reclock(%g,%s)',sig.rate,tostring(sig.sig)); end
+		function s=construct(sig), s=construct(sig.sig); end
+		function c=channels(s), c=channels(s.sig); end
+		function c=rate(s), c=s.fs; end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@sigresample/construct.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,88 @@
+function s2=construct(sig)
+
+	fprintf('\nResampling %s to %g Hz...\n',tostring(sig.source),sig.rate);
+	f1=rate(sig.source);
+	f2=sig.rate;
+	c=channels(sig);
+
+	[p,q]=rat(f2/f1,1e-12);
+	sysobj=design(sig,p,q);
+
+
+	delay=(length(sysobj.Numerator)-1)/2; 
+	outdelay = ceil(delay/q);
+	indelay  = ceil(delay/p);
+	m=max(1,floor(sig.opts.bs/q)); % try to approximate requested input block size
+	fprintf('Input/output delays are %d and %d.\n',indelay,outdelay);
+	fprintf('Read block size is %d.\n\n',m*q);
+
+	s1=construct(sig.source & sigarray(zeros(channels(sig.source),indelay)));
+	r1=s1.reader(m*q); % one and only input reader
+	chunk=uint32(m*p); % filter output block size
+	CHUNK=1:chunk;
+	queue=[];
+
+	s2.start   = s1.start;
+	s2.stop    = s1.stop;
+	s2.dispose = @dispose;
+	s2.reader  = @reader;
+
+	% drop some samples to account for filter delay
+	s2.start();
+	sigreadn(s2,outdelay);
+	s2.stop();
+
+	function dispose, s1.dispose(); release(sysobj); end 
+	function r2=reader(n)
+		outbuf=zeros(c,n);
+		r2=@next;
+
+		function [x,rem]=next 
+			% transfer up to n queued samples to outbuf
+			pos=uint32(size(queue,2));
+			if pos>=n % enough samples already waiting
+				outbuf=queue(:,1:n);
+				queue=queue(:,n+1:end);
+				rem=0;
+			else
+				if pos==0, toread=n;
+				else % use up queue
+					outbuf(:,1:pos)=queue; queue=[];
+					toread=n-pos;
+				end
+
+				% transfer complete chunks
+				while toread>=chunk
+					[outbuf(:,pos+CHUNK),rem]=filter_next;
+					toread=toread-chunk;
+					pos=pos+chunk;
+					if rem>0 % we ran out of samples
+						rem=rem+toread; % account for rest of missing samples (not just this chunk) 
+						toread=0; % causes immediate exit after this
+					end
+				end
+
+				% transfer partial chunk if necessary
+				if toread>0
+					[y,rem]=filter_next;
+					outbuf(:,pos+1:n)=y(:,1:toread);
+					queue=y(:,toread+1:chunk-rem);
+					rem=max(0,toread-(chunk-rem));
+				end
+			end
+			x=outbuf;
+		end
+
+		% returns the next block of m*p output samples 
+		function [x,rem]=filter_next
+			[y,rem1]=r1();
+			if rem1>0,
+				y(:,end-rem1+1:end)=zeros(c,rem1); % pad with zeros
+				rem=uint32(ceil(rem1*p/q)); % round down the number of valid samples
+			else
+				rem=rem1;
+			end
+			x=step(sysobj,y')';
+		end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@sigresample/design.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,26 @@
+function so=design(sig,p,q)
+	f1=rate(sig.source);
+	f2=rate(sig);
+	if isfield(sig.opts,'passband')
+		relpass=2*sig.opts.passband/min(f1,f2);
+	elseif isfield(sig.opts,'relpass')
+		relpass=sig.opts.relpass;
+	elseif isfield(sig.opts,'reltrans')
+		relpass=(1-sig.opts.reltrans);
+	else
+		relpass=nan;
+	end
+
+	if isnan(relpass) && ~isfield(sig.opts,'order')
+		so=dsp.FIRRateConverter(p,q,mfilt.firsrc(p,q).Numerator);
+	else
+		tw = max(0.01,1-relpass)*min(f1,f2)/2;
+		if isfield(sig.opts,'astop')
+			fsrc=fdesign.rsrc(p,q,'Nyquist',max(p,q),'TW,Ast',tw,sig.opts.astop,p*f1);
+		else
+			if isfield(sig.opts,'order'), order = sig.opts.order;  else order = 12; end
+			fsrc=fdesign.rsrc(p,q,'Nyquist',max(p,q),'N,TW',2*order*max(p,q),tw,p*f1);
+		end
+		so=design(fsrc,'kaiserwin','SystemObject',true);
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@sigresample/sigresample.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,25 @@
+classdef sigresample < signal
+	properties (GetAccess=private, SetAccess=immutable)
+		fs
+		source
+		opts
+	end
+	methods
+		function s=sigresample(fs,sig1,varargin)
+			if fs==rate(sig1), sig2=sig1;
+			else
+				opts=prefs('bs',1024,varargin{:});
+				s.source=sig1;
+				s.fs=fs;
+				s.opts=opts;
+			end
+		end
+
+		function s=tostring(sig)
+			s=sprintf('resample(%g,%s)',sig.rate,tostring(sig.source));
+		end
+
+		function c=channels(s), c=channels(s.source); end
+		function r=rate(s), r=s.fs; end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@sigtake/construct.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,28 @@
+
+function s=construct(sig)
+	sc=construct(sig.sig);
+	length=uint32(sig.len);
+
+	s.start   = sc.start;
+	s.stop    = sc.stop;
+	s.dispose = sc.dispose;
+	s.reader = @reader;
+
+	function r=reader(n)
+		rc=sc.reader(n);
+		r = @next;
+		n=uint32(n);
+		function [x,rem]=next
+			[x,rem]=rc();
+			if length>n
+				length=length-n;
+			elseif length>0
+				rem=max(rem,n-length);
+				length=0;
+				last=x(:,end);
+			else
+				rem=n;
+			end
+		end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/@sigtake/sigtake.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,16 @@
+classdef sigtake < signal
+	properties (GetAccess=private, SetAccess=immutable)
+		len
+		sig
+	end
+	methods
+		function s=sigtake(n,sig)
+			s.len=n;
+			s.sig=sig;
+		end
+
+		function s=tostring(sig), s=sprintf('take(%d,%s)',sig.len,tostring(sig.sig)); end
+		function c=channels(s), c=channels(s.sig); end
+		function c=rate(s), c=rate(s.sig); end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/TODO	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,10 @@
+stateful generators:
+	unfold    S -> (X,S)                 loop(0 -> 1)
+	scan      (Y,X) -> X                 states(loop(1 -> 0))
+	mapaccum  (Y,S) -> (X,S)             loop(1 -> 1)
+	zipaccum  (Y1,...,S) -> (X,S)        loop(N -> 1)
+	iterate   X -> X                     states(loop(0 -> 0))
+
+
+signal length?
+sndfile from shell pipe
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/mixdown.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,5 @@
+function y=mixdown(x), 
+	cin=channels(x);
+	y=sigmap(@mix,x,@(c)1);
+	function z=mix(w), z=sum(w,1)/cin; end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/private/unify.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,9 @@
+% this is weird but it works
+% nan means variable, so max(nan,x)=x
+% inf means failure so max(inf,x)=inf
+function z=unify(x,y)
+	if ~isfinite(x) || ~isfinite(y), z=max(x,y);
+	elseif x==y, z=x; 
+	else z=inf; 
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/resamplex.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,37 @@
+function s=resamplex(fs,sigs,varargin)
+	opts=prefs(varargin{:});
+	[s1,sx]=feval(rsx1(sigs{1},sigs(2:end)));
+	s=siglzcat(s1,sx);
+
+	function f=rsx1(h,t), f=@()rsx3({h},rate(h),t); end
+	function [s1,sx]=rsx3(heads,fh,tails)
+		if ~isempty(tails) && rate(tails{1})==fh
+			[s1,sx]=rsx3([heads,tails(1)],fh,tails(2:end));
+		else 
+			s1=resample(fs,sigcat(heads{:}),opts);
+			if isempty(tails), sx=[];
+			else sx=rsx1(tails{1},tails(2:end));
+			end
+		end
+	end
+end
+
+function s=resamplex1(fs,signals)
+	s=rsx1(signals);
+
+	function s=rsx1(signals)
+		s=rsx3(signals(1),rate(signals{1}),signals(2:end));
+	end
+
+	function s=rsx3(heads,fh,tails)
+		if ~isempty(tails) && rate(tails{1})==fh
+			s=rsx3([heads,tails(1)],fh,tails(2:end));
+		else 
+			headsig=resample(fs,sigcat(heads{:}),opts);
+			if isempty(tails), s=headsig;
+			else s=siglzcat(headsig, @()deal(rsx1(tails),[]));
+			end
+		end
+	end
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/sconst.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,1 @@
+function s=sconst(x), s=sigconst(x(:)); end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/sigcatx.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,1 @@
+function s=sigcatx(signals), s=sigcat(signals{:});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/sigpar.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,1 @@
+function y=sigpar(x1,x2), y=sigbinop(@vertcat,x1,x2,@plus);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/sigreadn.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,3 @@
+function [x,rem]=sigread1(src,n)
+	r=src.reader(n);
+	[x,rem]=r();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/sigrep.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,3 @@
+function s=sigrep(n,x)
+	%s=sigarray(repmat(x,1,n));
+	s=take(n,sigconst(x));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/sigsel.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,2 @@
+function y=sigsel(chans,x)
+	y=sigmap(@(t)t(chans,:),x,@(c)length(chans));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/snull.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,1 @@
+function s=snull, s=sigconst([]); 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/sones.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,1 @@
+function s=sones(n,m), s=sigarray(ones(n,m));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/szeros.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,1 @@
+function s=szeros(n,m), s=sigarray(zeros(n,m));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/transfer.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,41 @@
+% transfer - Transfer samples from a signal to a sink
+%
+% transfer :: signal(C,R), sink(C,R) -> action natural.
+% 
+% Returns the number of samples transfered.
+function n=transfer(sig,sink,varargin)
+	opts=prefs('chunk',512,varargin{:});
+	chunk=uint32(opts.chunk);
+
+	u=construct(sink);
+	try
+		write=u.writer(chunk);
+		s=construct(sig);
+		try % to make sure we dispose of s once opened
+			n=uint32(0); CHUNK=1:chunk; 
+			x=zeros(channels(sig),chunk); % buffer
+			r=s.reader(opts.chunk);
+			rem=0; 
+			s.start();
+			u.start(); 
+			while rem==0 
+				[x,rem]=r();
+				if rem==0, rem=write(x); 
+				else rem=rem+write(x(:,1:end-rem));
+				end
+				n=n+(chunk-rem);
+			end
+			u.stop();
+			s.stop();
+		catch ex
+			s.dispose();
+			rethrow(ex);
+		end
+	catch ex
+		u.dispose();
+		rethrow(ex);
+	end
+
+	s.dispose();
+	u.dispose();
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/unify_channels.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,2 @@
+function z=unify_channels(x,y), z=unify(x,y); end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/signals/unify_rates.m	Wed Dec 19 22:46:05 2012 +0000
@@ -0,0 +1,5 @@
+% this is weird but it works
+% nan means variable, so max(nan,x)=x
+% inf means failure so max(inf,x)=inf
+function z=unify_rate(x,y), z=unify(x,y); end
+