samer@0
|
1 % audio_bench - put given arrow between audio input and output
|
samer@0
|
2 %
|
samer@0
|
3 % audio_bench ::
|
samer@0
|
4 % N:natural ~'audio frame size',
|
samer@0
|
5 % M:natural ~'audio hop size',
|
samer@0
|
6 % list(string) ~'list of audio file names',
|
samer@0
|
7 % arrow({[[N,W]]}, {[[N,W]]}, S) ~'arrow to process audio buffers',
|
samer@0
|
8 % options {
|
samer@0
|
9 % fs :: nonneg/22050 ~'audio sampling rate';
|
samer@0
|
10 % scope :: natural/0 ~'figure for waveform plot, 0 to disable';
|
samer@0
|
11 % batch :: natural/1 ~'width of buffers';
|
samer@0
|
12 % state :: S/[] ~'initialise with this state';
|
samer@0
|
13 % outbuf :: natural/2 ~'increase audio output buffer by this many frames';
|
samer@0
|
14 % run :: bool/0 ~'if true, run the arrow in arrow_sched';
|
samer@0
|
15 % start :: bool/1 ~'if running and true, start immediately';
|
samer@0
|
16 % period :: nonneg/0.003 ~'if running timer period in seconds';
|
samer@0
|
17 % liveaudio :: bool/0 ~'if true, ignore files and use live audio input';
|
samer@0
|
18 % }
|
samer@0
|
19 % -> arrow( {}, {}, T) ~'arrow describing whole system',
|
samer@0
|
20 % [[1,P]->[2]} ~'path to state S in overall state T',
|
samer@0
|
21 % T, ~'final state if returned from repl'.
|
samer@0
|
22 %
|
samer@0
|
23 % This provides an environment for running an audio processing arrow.
|
samer@0
|
24 % Audio is provided in NxW buffers where N is the frame length and W is determined
|
samer@0
|
25 % by the batch options. Hop size is M. Audio is obtained from the given list of files.
|
samer@0
|
26 %
|
samer@0
|
27 % The processing arrow is initially run as fast as possible, but if the value in the
|
samer@0
|
28 % 'output select' is changed from 1 to 2, output is played on audio output device.
|
samer@0
|
29 % If it is set to 3, the original audio input is played unmodified.
|
samer@0
|
30 %
|
samer@0
|
31 % If the 'liveaudio' option is set, then the list of files is ignored and live audio
|
samer@0
|
32 % input used instead.
|
samer@0
|
33 %
|
samer@0
|
34 % If 'run' is false, the arrow describing the system is returned, but if true, the
|
samer@0
|
35 % system is instantiated using arrow_sched and the user dropped into the 'with_sched>>'
|
samer@0
|
36 % interactive interpreter loop. The loop can be exitted by typing 'return' or 'ret(...)'.
|
samer@0
|
37 % If 'ret(..)' is used, then the value supplied is returned as the second return value
|
samer@0
|
38 % from audio_bench.
|
samer@0
|
39
|
samer@0
|
40 function [o,path,r]=audio_bench(N,M,filelist,a,varargin)
|
samer@37
|
41 opts=options('fs',22050,'period',0.003,'outbuf',3,'run',0,'start',1,'output',1, ...
|
samer@0
|
42 'scope',0,'state',[],'batch',1,'liveaudio',0,'playthru',0,'draw',1,varargin{:});
|
samer@0
|
43
|
samer@0
|
44 if opts.scope>0
|
samer@0
|
45 scope_sink=plotter('fig',opts.scope,'ylim',[-1,1]);
|
samer@0
|
46 if 0
|
samer@0
|
47 if opts.batch>1
|
samer@0
|
48 scope1=obs_with(arr(@(t)t(:,1))*scope_sink);
|
samer@0
|
49 else
|
samer@0
|
50 scope1=obs_with(scope_sink);
|
samer@0
|
51 end
|
samer@0
|
52 else
|
samer@0
|
53 %scope=@(a)a*arr(@(x1,x2)deal(x1,x2,[x1(:,1),x2(1:M,1)]),'nargout',3)*(aid+aid+scope_sink);
|
samer@0
|
54 scope=@(a)a*arr(@scope_join)*(aid+aid+scope_sink);
|
samer@0
|
55 end
|
samer@0
|
56 else
|
samer@0
|
57 scope=@id;
|
samer@0
|
58 end
|
samer@0
|
59
|
samer@0
|
60 fprintf('Creating audio source with %d files.\n',length(filelist));
|
samer@0
|
61 if opts.liveaudio
|
samer@0
|
62 src=linein(1,opts.fs,'bufsize',4*N);
|
samer@0
|
63 else
|
samer@0
|
64 src=resamplex(opts.fs,map(@monofile,filelist),'bs',2^nextpow2(M*opts.batch));
|
samer@0
|
65 end
|
samer@0
|
66 aout=abufsink(lineout(1,opts.fs,'bufsize',(opts.outbuf+opts.batch)*M),1:M);
|
samer@0
|
67
|
samer@0
|
68 o= ( abufsig(src,N,M,opts.batch) ...
|
samer@0
|
69 * dup * scope(a + aid)...
|
samer@0
|
70 * (aid + aid + esender('init',num2str(opts.output),'fig',29,'name','output select')*arr(@selout))...
|
samer@0
|
71 * aswitch(unbox(selout({opts.output}))) ...
|
samer@0
|
72 );
|
samer@0
|
73
|
samer@0
|
74 path=[1,1,2,1]; % path to state of a in state of o
|
samer@0
|
75 if ~isempty(opts.state), o=o^opts.state; disp('Initialising...'); end
|
samer@42
|
76 if opts.run==1,
|
samer@0
|
77 r=arrow_sched(o,opts.period,'start',opts.start);
|
samer@42
|
78 elseif opts.run==2
|
samer@42
|
79 r=with_arrow(o,@run,{});
|
samer@0
|
80 else
|
samer@0
|
81 r=[];
|
samer@0
|
82 end
|
samer@0
|
83
|
samer@42
|
84 function r=run(unit)
|
samer@42
|
85 uiterate(unit,inf,'draw',1,'chunk',100);
|
samer@42
|
86 r=0;
|
samer@42
|
87 end
|
samer@42
|
88
|
samer@0
|
89 function [x1,x2,x3]=scope_join(x1,x2)
|
samer@0
|
90 x3=[x1(1:M,1),x2(1:M,1)];
|
samer@0
|
91 end
|
samer@0
|
92
|
samer@0
|
93 function o=selout(cn)
|
samer@0
|
94 if ~iscell(cn) || isempty(cn), o={};
|
samer@0
|
95 else
|
samer@0
|
96 switch cn{1}
|
samer@0
|
97 case 1, o={anull+anull};
|
samer@0
|
98 case 2, o={aout+anull};
|
samer@0
|
99 case 3, o={anull+aout};
|
samer@0
|
100 otherwise, o={};
|
samer@0
|
101 end
|
samer@0
|
102 end
|
samer@0
|
103 end
|
samer@0
|
104 end
|
samer@0
|
105 function x=unbox(y), x=y{1}; end
|