function Y=sonify_disc(S,D,Gen,varargin)
% sonify - Sonify sequences of durations and sound classes
%
% sonify :: 
%    ([[N]] | seq(real))      ~'sequence of pitches in semitones',
%    (natural | seq(real))   ~'sequence of durations',
%    options {
%       bpm :: nonneg  /240     ~'number of time units per minute';
%       fs  :: real    /11025   ~'intended sampling rate';
%       buffer :: noneg /0.125  ~'buffer size in seconds, [] means one per note'
%    }
% -> seq([[1,T]]).

	opts=options('env',[],'bpm',240,'fs',11025,'buffer',0.125, varargin{:});

	sample_rate=opts.fs;
	dm=60*opts.fs/opts.bpm;

	if isscalar(D), D=dd(dm*D);
	else D=map(@(d)dm*d,dd(D)); % D=dm*D with optimisation
	end

	Y=zipwith(@select_gen,D,dd(S));

	% if supplied apply envelope to shape each note
	if ~isempty(opts.env),
		Y=map(opts.env,Y);
	end

	% rebuffer to constant size
	if ~isempty(opts.buffer)
		Y=windowdata(Y,ceil(opts.buffer*opts.fs));
	end

	function y=select_gen(dur,k)
		y=feval(Gen{k},sample_rate,floor(dur));
	end
end

