Mercurial > hg > ishara
changeset 43:62e31e7980e6
Various fixes to audio, pipes, character encodings etc.
author | samer |
---|---|
date | Tue, 13 Jan 2015 13:52:18 +0000 |
parents | ae596261e75f |
children | 3cedfd4549ef |
files | audio/filesink.m audio/flacfile.m audio/mp3enc.m audio/mp3file.m audio/oggenc.m audio/oggfile.m audio/pipesink.m audio/private/austream.m audio/private/jfile.m audio/private/pipein.m audio/private/pipeout.m audio/rawpipe.m audio/sndfile.m audio/sndpipe.m audio/sndread.m audio/wavedata.m dsp/specgrm.m signals/@signal/signal.m |
diffstat | 18 files changed, 89 insertions(+), 51 deletions(-) [+] |
line wrap: on
line diff
--- a/audio/filesink.m Tue Dec 02 14:51:13 2014 +0000 +++ b/audio/filesink.m Tue Jan 13 13:52:18 2015 +0000 @@ -1,3 +1,5 @@ +% filesink - sink which writes a signal to a WAV file +% filesink :: C:natural, R:real, path, options {...} -> sink(C,R). function s=filesink(ch,rate,file,varargin) str=sprintf('filesink(''%s'')',file); s=wavsink(ch,rate,@()filestream(file),@()str,varargin{:});
--- a/audio/flacfile.m Tue Dec 02 14:51:13 2014 +0000 +++ b/audio/flacfile.m Tue Jan 13 13:52:18 2015 +0000 @@ -1,4 +1,7 @@ -function s=mp3dec(file,varargin) - s=sndpipe(sprintf('flac --decode -o - "%s"',file),'stringfn',@()sprintf('flacfile(''%s'')',file),varargin{:}); +% flacfile - audio signal from FLAC file +% flacfile :: path, options -> signal(C,R). +% Options are passed to SNDPIPE +function s=flacfile(file,varargin) + s=sndpipe(sprintf('flac --decode -o - %s',bash_arg(file)),'stringfn',@()sprintf('flacfile(''%s'')',file),varargin{:}); end
--- a/audio/mp3enc.m Tue Dec 02 14:51:13 2014 +0000 +++ b/audio/mp3enc.m Tue Jan 13 13:52:18 2015 +0000 @@ -1,3 +1,4 @@ +% mp3enc - sink which writes audio signal to MP3 file using lame function s=mp3enc(ch,rate,file,varargin) opts=options('quality',5,varargin{:}); s=pipesink(ch,rate,sprintf('lame -h -V %d - "%s"',opts.quality,file));
--- a/audio/mp3file.m Tue Dec 02 14:51:13 2014 +0000 +++ b/audio/mp3file.m Tue Jan 13 13:52:18 2015 +0000 @@ -1,9 +1,12 @@ -function s=mp3dec(file,varargin) +% mp3file - audio signal from MP3 file +% mp3file :: path, options(sndpipe) -> signal(C,R). +function s=mp3file(file,varargin) % NB: mpg123 was sometimes putting the wrong sampling rate in the header (expecting to seek % back and fix it after writing) but mpg321 seems to get it right first time. % mpg321 broken in Macports, 17th Nov 2014 % s=sndpipe(sprintf('mpg321 --au - "%s"',file),'stringfn',@()sprintf('mp3file(''%s'')',file),varargin{:}); - s=sndpipe(sprintf('sox -t mp3 "%s" -t au -',file),'stringfn',@()sprintf('mp3file(''%s'')',file),varargin{:}); + % NB: sox already knows how to read URLs, so we only need to properly escape the path/url + s=sndpipe(sprintf('sox -t mp3 %s -t au -',bash_esc(file)),'stringfn',@()sprintf('mp3file(''%s'')',file),varargin{:}); end
--- a/audio/oggenc.m Tue Dec 02 14:51:13 2014 +0000 +++ b/audio/oggenc.m Tue Jan 13 13:52:18 2015 +0000 @@ -1,3 +1,4 @@ +% oggenc - sink which writes audio signal to OGG file using oggenc function s=oggenc(ch,rate,file,varargin) opts=options('quality',5,varargin{:}); s=pipesink(ch,rate,sprintf('oggenc -q %d -o "%s" -',opts.quality,file));
--- a/audio/oggfile.m Tue Dec 02 14:51:13 2014 +0000 +++ b/audio/oggfile.m Tue Jan 13 13:52:18 2015 +0000 @@ -1,2 +1,4 @@ +% oggfile - audio signal from OGG file using ogg123 +% oggfile :: bash_file, options(sndpipe) -> signal(C,R). function s=oggdec(file) - s=sndpipe(sprintf('ogg123 -d au -f - "%s"',file),'stringfn',@()sprintf('oggfile(''%s'')',file)); + s=sndpipe(sprintf('ogg123 -d au -f - %s',bash_arg(file)),'stringfn',@()sprintf('oggfile(''%s'')',file));
--- a/audio/pipesink.m Tue Dec 02 14:51:13 2014 +0000 +++ b/audio/pipesink.m Tue Jan 13 13:52:18 2015 +0000 @@ -1,3 +1,5 @@ +% pipesink - sink which writes audio signal to shell pipeline. +% pipesink :: C:natural, R:nonneg, string, options(wavsink) -> sink(C,R). function s=pipesink(ch,rate,cmd,varargin) str=sprintf('pipesink(''%s'')',cmd); s=wavsink(ch,rate,@()pipeout(cmd),@()str,varargin{:});
--- a/audio/private/austream.m Tue Dec 02 14:51:13 2014 +0000 +++ b/audio/private/austream.m Tue Jan 13 13:52:18 2015 +0000 @@ -1,3 +1,5 @@ +% austream - construct audio stream from ordinary stream +% austream :: java.io.InputStream -> java.sound.sampled.AudioInputStream. function str=austream(str) if ~str.markSupported, str=java.io.BufferedInputStream(str); end str=javax.sound.sampled.AudioSystem.getAudioInputStream(str);
--- a/audio/private/jfile.m Tue Dec 02 14:51:13 2014 +0000 +++ b/audio/private/jfile.m Tue Jan 13 13:52:18 2015 +0000 @@ -1,5 +1,17 @@ +% jfile - construct Java File object from path string +% jfile :: text -> java.io.File. function f=jfile(path) % The problem was that file names with accents in where not being found % when converted to Java file names. % I have no idea what is going on here but it seems to work - f=java.io.File(java.lang.String(unicode2native(path,'latin1'),'UTF8')); + % f=java.io.File(java.lang.String(unicode2native(path,'latin1'),'UTF8')); + + % SA 2014: UPDATE + % Now I have a faint idea about what is going on here. Matlab ignores the + % LANG environment variable, and previously was using LATIN1 as it's + % feature('DefaultCharacterSet'). This meant that the entire Java subsystem + % was starting up with LATIN1 as its chacterset. Now, I have found a way + % to persuade Matlab to use Unicode, and indeed, for the JVM to use unicode + % also. This means that the old version of this function was no good. + % Instead, we should use unicode2native with no 2nd argument. + f=java.io.File(java.lang.String(unicode2native(path),'UTF8'));
--- a/audio/private/pipein.m Tue Dec 02 14:51:13 2014 +0000 +++ b/audio/private/pipein.m Tue Jan 13 13:52:18 2015 +0000 @@ -1,6 +1,12 @@ +% pipein - start shell command and return stream for reading standard output +% pipein :: +% text ~'bash shell command', +% bool ~'quiet operation flag' +% -> java.io.InputStream ~ 'connected to stdout of command', +% (void -> action void) ~'call this to clean up afterwards'. +% +% If quiet flag is not supplied, it defaults to false. function [str,cleanup]=pipein(cmd,q) - import java.io.*; - if nargin<2, q=false; end if ~q, fprintf('Starting sub-process: %s\n',cmd); end @@ -24,7 +30,7 @@ % BETTER: cs=feature('DefaultCharacterSet'), process=java.lang.Runtime.getRuntime().exec('bash'); - writer=OutputStreamWriter(process.getOutputStream(),cs); + writer=java.io.OutputStreamWriter(process.getOutputStream(),cs); writer.write(cmd); writer.close(); str=process.getInputStream();
--- a/audio/private/pipeout.m Tue Dec 02 14:51:13 2014 +0000 +++ b/audio/private/pipeout.m Tue Jan 13 13:52:18 2015 +0000 @@ -1,11 +1,25 @@ -function [str,cleanup]=pipeout(cmd) - fprintf('Starting sub-process: %s\n',cmd); - process=java.lang.Runtime.getRuntime().exec({'bash','-c',cmd}); +% pipeout - start shell command and return stream for writing to its standard input +% pipeout :: +% text ~'bash shell command', +% bool ~'quiet operation flag' +% -> java.io.OutputStream ~ 'connected to stdout of command', +% (void -> action void) ~'call this to clean up afterwards'. +% +% If quiet flag is not supplied, it defaults to false. +function [str,cleanup]=pipeout(cmd,q) + if nargin<2, q=false; end + if ~q, fprintf('Starting sub-process: %s\n',cmd); end + + cs=feature('DefaultCharacterSet'), + process=java.lang.Runtime.getRuntime().exec('bash'); + writer=java.io.OutputStreamWriter(process.getOutputStream(),cs); + writer.write(cmd); writer.close(); + str=process.getOutputStream(); cleanup=@dispose; function dispose - fprintf('Killing subprocess...\n'); + if ~q, fprintf('Killing subprocess...\n'); end process.destroy(); end end
--- a/audio/rawpipe.m Tue Dec 02 14:51:13 2014 +0000 +++ b/audio/rawpipe.m Tue Jan 13 13:52:18 2015 +0000 @@ -1,13 +1,9 @@ -% rawpipe - pipe reader implementation of sndstream (raw audio stream) +% rawpipe - audio signal from raw stream from shell pipe % % rawpipe :: % string ~'shell pipe', % AudioFormat~'stream format', -% options { -% channels :: natural/nan ~'desired number of channels'; -% rate :: nonneg/nan ~'desired sampling rate'; -% bits :: natural/16 ~'desired bits per sample'; -% } +% options(sndstream) % -> signal(C,R). % % If channels or rate are not nan, audio format will be converted to match.
--- a/audio/sndfile.m Tue Dec 02 14:51:13 2014 +0000 +++ b/audio/sndfile.m Tue Jan 13 13:52:18 2015 +0000 @@ -1,40 +1,37 @@ -% sndfile - file reader implementation using samer.audio.alt.FileSource +% sndfile - audio signal from audio file % % sndfile :: -% path ~'file name' +% path | cell { nonneg, nonneg, path } ~'file name or { start, end, path }' % options { +% enc :: {'mp3','aac','flac','ogg'}; % channels :: natural/nan ~'desired number of channels'; % rate :: nonneg/nan ~'desired sampling rate'; % bits :: natural/16 ~'desired bits per sample'; % } % -> signal(C,R). % +% This will use mp3file, aacfile or flacfile for those types of file, but jsndfile +% for anything else, including OGG files. +% % 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. -% -% Javazoom MP3 decoder does not get the length of the signal right. -% Would be better to use mpg123 on a pipe in this case. + function s=sndfile(file,varargin) + opts=options('enc','unknown',varargin{:}); if iscell(file) s=taket(file{2}-file{1},dropt(file{1},sndfile(file{3}))) return end string=sprintf('sndfile(''%s'')',file); - if endswith(file,'mp3') || endswith(file,'MP3') - s=mp3file(file,'stringfn',@()string,varargin{:}); % Java version doesn't remove padding correctly - elseif endswith(file,'m4a') - s=aacfile(file,'stringfn',@()string,varargin{:}); + if strcmp(opts.enc,'mp3') || endswith(file,'mp3') || endswith(file,'MP3') + s=mp3file(file,'stringfn',@()string,opts); % Java version doesn't remove padding correctly + elseif strcmp(opts.enc,'aac') || endswith(file,'m4a') + s=aacfile(file,'stringfn',@()string,opts); + elseif strcmp(opts.enc,'flac') || endswith(file,'flac') + s=flacfile(file,'stringfn',@()string,opts); else - s=sndstream(@filestream,'stringfn',@()string,varargin{:}); - end - - function [str,cleanup]=filestream(q) - jf=jfile(file); - if ~jf.exists(), error(sprintf('File %s does not exist',file)); end - if ~q, fprintf('Opening sound file: %s\n',file); end - str=austream(java.io.FileInputStream(jf)); - cleanup=@nop; + s=jsndfile(file,varargin{:}); end end
--- a/audio/sndpipe.m Tue Dec 02 14:51:13 2014 +0000 +++ b/audio/sndpipe.m Tue Jan 13 13:52:18 2015 +0000 @@ -1,17 +1,8 @@ -% sndpipe - pipe reader implementation of sndstream +% sndpipe - audio signal from shell pipe line. +% sndpipe :: string~'shell command', options(sndstream) -> signal(C,R). % -% sndpipe :: -% string ~'shell pipe' -% 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. +% The shell command must produce a self-describing stream that can be recognised +% by the JavaSound subsystem. Then, function s=sndpipe(cmd,varargin) s=sndstream(@pipestream,'stringfn',@()sprintf('sndpipe(''%s'')',cmd),varargin{:});
--- a/audio/sndread.m Tue Dec 02 14:51:13 2014 +0000 +++ b/audio/sndread.m Tue Jan 13 13:52:18 2015 +0000 @@ -1,3 +1,4 @@ +% sndread - read entire contents of any audo file readable by sndfile function X=sndread(file,FS,varargin) opts=options('bs',1024,varargin{:}); sig=sndfile(file,opts);
--- a/audio/wavedata.m Tue Dec 02 14:51:13 2014 +0000 +++ b/audio/wavedata.m Tue Jan 13 13:52:18 2015 +0000 @@ -1,1 +1,2 @@ +% wavedata - alternative name for WAVREAD function y=wavedata(varargin), y=wavdata(varargin{:}); end
--- a/dsp/specgrm.m Tue Dec 02 14:51:13 2014 +0000 +++ b/dsp/specgrm.m Tue Jan 13 13:52:18 2015 +0000 @@ -29,7 +29,7 @@ if nargout==0 opts=options('fs',1,'range',13.5,varargin{:}); - tfdimage(y,n,m,opts.fs,opts.range); + tfdimage(y,n,m,opts.fs,opts.range,opts); clear y; end
--- a/signals/@signal/signal.m Tue Dec 02 14:51:13 2014 +0000 +++ b/signals/@signal/signal.m Tue Jan 13 13:52:18 2015 +0000 @@ -68,5 +68,9 @@ if rate(s1)==f2, s2=s1; else, s2=sigresample(f2,s1,varargin{:}); end end + + function varargout=specgrm(x,varargin) + [varargout{1:nargout}]=specgrm(gather(x),varargin{:},'fs',rate(x)); + end end end