annotate audio/playaudio_unfold.m @ 61:eff6bddf82e3 tip

Finally implemented perceptual brightness thing.
author samer
date Sun, 11 Oct 2015 10:20:42 +0100
parents beb8a3f4a345
children
rev   line source
samer@0 1 function [Sched,GetData]=playaudio_unfold(buflen,unfold_fn,S,Snk,varargin)
samer@0 2 % playaudio_async - Play stream of audio data asynchronously
samer@0 3 %
samer@0 4 % playaudio ::
samer@0 5 % N:natural ~'buflen',
samer@0 6 % (S->[[C,N]],S) ~'unfolding function',
samer@36 7 % sink(C,R) ~'sink for C channels',
samer@0 8 % options {
samer@0 9 % maxbuf :: natural/2*max(size(X)) ~'maximum buffer size';
samer@0 10 % hook :: (iterator(S)->iterator(T)) ~'fn to build iterator';
samer@0 11 % onstart :: A -> action ~'called BEFORE timer starts';
samer@0 12 % onstop :: A -> action ~'called AFTER timer stops';
samer@0 13 % onfinish:: A -> action ~'called when end of signal reached';
samer@0 14 % defer :: bool / 0 ~'if 1, don't start the timer'
samer@0 15 % }
samer@0 16 % -> sched(S) ~'scheduler api functions',
samer@0 17 % (S -> [[N]]) ~'function to recover audio from iterator state'.
samer@0 18 %
samer@0 19 % iterator(S) ::= cell {(S->action S)~'state transformer', S~'initial state'}.
samer@0 20 %
samer@0 21 % sched(S) ::= struct {
samer@0 22 % dispose :: unit -> action unit;
samer@0 23 % isrunning :: unit -> action bool;
samer@0 24 % startat :: real -> action unit;
samer@0 25 % start :: unit -> action unit;
samer@0 26 % stop :: unit -> action unit;
samer@0 27 % rewind :: unit -> action unit;
samer@0 28 % getstate :: unit -> action S;
samer@0 29 % setstate :: S -> action unit
samer@0 30 % }.
samer@0 31 %
samer@0 32 % The 'hook' option gives the caller an opportunity to elaborate on the
samer@0 33 % 'iterator' used to drive the audio playback. The 'iterator' is a cell
samer@0 34 % array contain a state transformer function and initial state. The caller
samer@0 35 % can use this to build a more complex iterator the does other things
samer@0 36 % for each buffer of samples.
samer@0 37 %
samer@0 38 % The third return value is a function which can be used in a state
samer@0 39 % transformer function to recover a buffer of audio samples from the
samer@0 40 % current state.
samer@0 41 %
samer@0 42 % NB: all the audio buffers must be the same size for this to work.
samer@0 43 % NB: the rewind function should only be called when the timer is stopped.
samer@0 44
samer@0 45 N=buflen;
samer@37 46 opts=options('onstop',@nop,'onstart',@nop,'onfinish',@nop, ...
samer@0 47 'period_adjust',0.9,'preload',2,'sched',@iterate_timed,varargin{:});
samer@0 48
samer@0 49 it=feval(getparam(opts,'hook',@id),{@playbuf,S});
samer@0 50
samer@0 51 maxbuf=getparam(opts,'maxbuf',2*N);
samer@0 52 sync_delta=getparam(opts,'sync_delta',0.02);
samer@0 53 sync_offset=getparam(opts,'sync_offset',0);
samer@0 54
samer@0 55 L=construct(Snk);
samer@0 56 write=L.writer(maxbuf);
samer@0 57 period=(N/rate(Snk))*opts.period_adjust;
samer@0 58
samer@0 59 Sched=opts.sched(it{1},it{2},period, ...
samer@0 60 'exec_mode','fixedRate', 'busy_mode','drop', opts, ...
samer@0 61 'onstart',@onstart,'onstop',@onstop);
samer@0 62 getstate=Sched.getstate;
samer@0 63 odispose=Sched.dispose;
samer@0 64 Sched.atend=@()isempty(getstate());
samer@0 65 Sched.dispose=@dispose;
samer@0 66 Sched.setGain=L.setGain;
samer@0 67
samer@0 68 GetData=@head;
samer@0 69
samer@0 70 function dispose
samer@0 71 odispose();
samer@0 72 L.dispose();
samer@0 73 end
samer@0 74
samer@0 75 function onstart(S),
samer@0 76 opts.onstart(S);
samer@0 77 L.start();
samer@0 78 for i=1:opts.preload
samer@0 79 write(zeros(maxbuf,1));
samer@0 80 end
samer@0 81 end
samer@0 82
samer@0 83 function onstop(S),
samer@0 84 write(zeros(maxbuf,1));
samer@0 85 L.stop();
samer@0 86 opts.onstop(S);
samer@0 87 end
samer@0 88
samer@0 89 function S=playbuf(S)
samer@0 90 [y,S]=unfold_fn(S);
samer@0 91 n=size(y,2);
samer@0 92 if n>0, write(y); end
samer@0 93 end
samer@0 94 end
samer@0 95