% wavsink - file reader implementation using ishara.audio.StreamSink
%
% wavsink ::
%    (unit -> (InputStream, unit -> unit)) ~'function to open stream',
%    (unit -> string) ~'function to create character representation',
%    options {
%       channels :: natural/nan ~'desired number of channels';
%       rate     :: nonneg/nan ~'desired sampling rate';
%       bits     :: natural/16 ~'desired bits per sample';
%    }
% -> signal(C,R).
%
% If channels or rate are not nan, audio format will be converted to match.
% If either of them are nan, the corresponding value from the audio file will
% be left unchanged.

classdef wavsink < sink
	properties (GetAccess=private, SetAccess=immutable)
		streamfn
		stringfn
		format
	end

	methods
		function s=wavsink(ch,rate,streamfn,stringfn,varargin)
			opts=options('bits',16,varargin{:});
			s.streamfn=streamfn;
			s.stringfn=stringfn;
			s.format=audio_format(ch,rate,opts.bits);
		end

		function s=tostring(sig), s=sig.stringfn(); end
		function c=channels(s), c=s.format.getChannels(); end
		function r=rate(s), r=s.format.getSampleRate(); end
		function s=construct(sig)
			import  ishara.audio.*;

			[str,cleanup]=sig.streamfn();
			snk=StreamSink(StreamSink.wavOutputStream(str, sig.format));
			snk.setScale(0.999);
			ref=disposables('reg',snk);
			s.start = @()snk.start();
			s.stop = @()snk.stop();
			s.writer = @writer;
			s.dispose = @dispose;

			function r=writer(n)
				ch=snk.getFormat.getChannels();
				wr=snk.writer(n*ch);
				r=@next;
				function rem=next(x), rem=wr.write(x(:))/ch; end
			end
			function dispose
				disposables('dereg',ref);
				fprintf('Closing WAV output stream.\n');
				snk.dispose();
				cleanup();
			end
		end

	end
end

function str=austream(str)
	if ~str.markSupported, str=java.io.BufferedInputStream(str); end
	str=javax.sound.sampled.AudioSystem.getAudioInputStream(str);
end
