samer@0: % sndstream - file reader implementation using samer.audio.alt.FileSource samer@0: % samer@0: % sndstream :: samer@0: % (unit -> (AudioInputStream, unit -> unit)) ~'function to open stream', samer@0: % (unit -> string) ~'function to create character representation', samer@0: % options { samer@0: % channels :: natural/nan ~'desired number of channels'; samer@0: % rate :: nonneg/nan ~'desired sampling rate'; samer@0: % bits :: natural/16 ~'desired bits per sample'; samer@0: % } samer@0: % -> signal(C,R). samer@0: % samer@0: % If channels or rate are not nan, audio format will be converted to match. samer@0: % If either of them are nan, the corresponding value from the audio file will samer@0: % be left unchanged. samer@0: samer@0: classdef sndstream < signal samer@0: properties (GetAccess=private, SetAccess=immutable) samer@0: streamfn samer@0: stringfn samer@0: format samer@0: end samer@0: methods samer@0: function s=sndstream(streamfn,varargin) samer@0: opts=prefs('channels',nan,'rate',nan,'bits',16, ... samer@0: 'stringfn',@()sprintf('sndstream(%s)',tostring(streamfn)), ... samer@0: varargin{:}); samer@0: samer@0: if any(isnan([opts.channels,opts.rate,opts.bits])) samer@0: fmt=peek(streamfn); samer@0: if isnan(opts.channels), opts.channels=fmt.getChannels(); end samer@0: if isnan(opts.rate), opts.rate=fmt.getSampleRate(); end samer@0: if isnan(opts.bits), opts.bits=fmt.getSampleSizeInBits(); end samer@0: end samer@0: if opts.bits<0 samer@0: error('Cannot determine bits per sample'); samer@0: end samer@0: samer@0: s.streamfn=streamfn; samer@0: s.stringfn=opts.stringfn; samer@0: s.format=audio_format(opts.channels,opts.rate,opts.bits); samer@0: end samer@0: samer@0: function s=tostring(sig), s=sig.stringfn(); end samer@0: function c=channels(s), c=s.format.getChannels(); end samer@0: function r=rate(s), r=s.format.getSampleRate(); end samer@0: samer@0: function s=construct(sig) samer@0: [str,cleanup]=sig.streamfn(false); samer@0: src=samer.audio.alt.StreamSource(str,sig.format); samer@0: ref=disposables('reg',src); samer@0: s.start = @()src.start(); samer@0: s.stop = @()src.stop(); samer@0: s.reader = @reader; samer@0: s.dispose = @dispose; samer@0: samer@0: function r=reader(n) samer@0: ch=src.getFormat.getChannels(); samer@0: rdr=src.reader(n*ch); samer@0: r=@next; samer@0: function [x,rem]=next samer@0: x=reshape(rdr.next(),ch,n); samer@0: rem=rdr.unread()/ch; samer@0: end samer@0: end samer@0: function dispose samer@0: disposables('dereg',ref); samer@0: src.dispose(); samer@0: cleanup(); samer@0: end samer@0: end samer@0: end samer@0: end samer@0: samer@0: function fmt=peek(streamfn) samer@0: [str,cleanup]=streamfn(true); samer@0: f1=str.getFormat(); samer@0: str.close(); cleanup(); samer@0: ss=f1.getSampleSizeInBits(); samer@0: if ss<0, ss=16; end samer@0: fmt=audio_format(f1.getChannels(),f1.getSampleRate(),ss); samer@0: end