% audio_sonifier - Create sonifier object
%
% audio_sonifier ::
%    nonneg ~ 'Duration of each note',
%    options {
%       transpose/0    :: int    ~'pitch transposition in semitones';
%       gen    /'sine' :: {'sine','blsquare'};
%       attack /5      :: nonneg ~'attack time in ms';
%       decay  /200    :: nonneg ~'decay time in ms';
%       release/5      :: nonneg ~'release time in ms';
%       cutoff /0.4    :: nonneg ~'low pass cut-off as norm freq';
%       fs     /11025  :: nonneg ~'sample rate'
%    }
% => sonifier.
%
% sonifier ::= 
%   seq(natural) ~'thing to sonify', 
%   (void=>void) ~'action on finish' 
% => player.
%
% player ::= struct {
%    start     :: void => void;    
%    startq    :: (nonneg,nonneg) => void;    
%    stop      :: void => void;
%    isrunning :: void => bool;
%    atend     :: void => bool;
%    rewind    :: void => void;
%    dispose   :: void => void
% }.

function f=audio_sonifier(dur,varargin)
	audio_info = options( ...
				'transpose',0,'gen','sine','fs',11025, 'cutoff',0.4, ...
				'attack',5,'decay',200,'release',5,varargin{:});

	audio_info.lineout = lineout(1,audio_info.fs);
	f=@(seq,onfinish)sonify_audio(audio_info,dur,seq,onfinish);
end

function player=sonify_audio(audio,dur,seq,onfinish)
	%disp('preparing audio signal.');
	sched  = playaudio_async( ...
		sonify(seq,dur,audio_opts(audio)), audio.lineout, ...
		'defer',1,'its',2^31,'onfinish',@(a)onfinish());

	player=cpfields({'stop','isrunning','atend','rewind','dispose'},...
		sched, struct(...
			'start',  @()sched.startat(nows+1), ...
			'startq', @(q,o)sched.startat(o+quant(q,nows))));
%			'wait',   sig.wait));

	%disp('audio playback ready to go.');
end

function opts=audio_opts(A)
	c=@(t)round(A.fs*t/1000);
	opts=options('bpm',60, 'transpose',A.transpose-69, ...
		'env',envadr(c(A.attack),c(A.decay),c(A.release)), ...
		'gen',A.gen,'bl_cutoff',A.cutoff,'fs',A.fs,'buffer',0.125);
end

