diff toolboxes/MIRtoolbox1.3.2/MIRToolbox/@miraudio/miraudio.m @ 0:e9a9cd732c1e tip

first hg version after svn
author wolffd
date Tue, 10 Feb 2015 15:05:51 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toolboxes/MIRtoolbox1.3.2/MIRToolbox/@miraudio/miraudio.m	Tue Feb 10 15:05:51 2015 +0000
@@ -0,0 +1,410 @@
+function varargout = miraudio(orig,varargin)
+%   a = miraudio('filename') loads the sound file 'filename' (in WAV or AU
+%       format) into a miraudio object.
+%   a = miraudio('Folder') loads all the sound files in the CURRENT folder
+%       into a miraudio object.
+%   a = miraudio(v,sr), where v is a column vector, translates the vector v
+%       into a miraudio object. The sampling frequency is set to sr Hertz.
+%           Default value for sr: 44100 Hz.
+%   a = miraudio(b, ...), where b is already a miraudio object, performs 
+%       operations on b specified by the optional arguments (see below).
+%
+%   Transformation options:
+%       miraudio(...,'Mono',0) does not perform the default summing of
+%           channels into one single mono track, but instead stores each 
+%           channel of the initial soundfile separately.       
+%       miraudio(...,'Center') centers the signals.
+%       miraudio(...,'Sampling',r) resamples at sampling rate r (in Hz).
+%           (Requires the Signal Processing Toolbox.)
+%       miraudio(...,'Normal') normalizes with respect to RMS energy.
+%   Extraction options:
+%       miraudio(...,'Extract',t1,t2,u,f) extracts the signal between dates
+%           t1 and t2, expressed in the unit u.
+%           Possible values for u:
+%               's' (seconds, by default),
+%               'sp' (sample index, starting from 1).
+%           The additional optional argument f indicates the referential
+%               origin of the temporal positions. Possible values for f:
+%               'Start' (by default)
+%               'Middle' (of the sequence)
+%               'End' of the sequence
+%               When using 'Middle' or 'End', negative values for t1 or t2
+%               indicate values before the middle or the end of the audio
+%               sequence.
+%       miraudio(...,'Trim') trims the pseudo-silence beginning and end off
+%           the audio file. Silent frames are frames with RMS below t times
+%           the medium RMS of the whole audio file.
+%               Default value: t = 0.06
+%           instead of 'Trim':
+%              'TrimStart' only trims the beginning of the audio file,
+%              'TrimEnd' only trims the end.
+%           miraudio(...,'TrimThreshold',t) specifies the trimming threshold t.
+%       miraudio(...,'Channel',c) or miraudio(...,'Channels',c) selects the
+%           channels indicated by the (array of) integer(s) c.
+%   Labeling option:
+%       miraudio(...,'Label',l) labels the audio signal(s) following the 
+%           label(s) l.
+%           If l is a (series of) number(s), the audio signal(s) are
+%           labelled using the substring of their respective file name of 
+%           index l. If l=0, the audio signal(s) are labelled using the
+%           whole file name.
+
+
+if isnumeric(orig)
+    if size(orig,2) > 1 || size(orig,3) > 1
+        mirerror('MIRAUDIO','Only column vectors can be imported into mirtoolbox.');
+    end
+    if nargin == 1
+        f = 44100;
+    else
+        f = varargin{1};
+    end
+    b = 32;
+    if size(orig,1) == 1
+        orig = orig';
+    end
+    tp = (0:size(orig,1)-1)'/f;
+    t = mirtemporal([],'Time',{{tp}},'Data',{{orig}},...
+                    'FramePos',{{tp([1 end])}},'Sampling',{f},...
+                    'Name',{inputname(1)},'Label',{{}},'Clusters',{{}},...
+                    'Channels',[],'Centered',0,'NBits',{b},...
+                    'Title','Audio signal',...
+                    'PeakPos',{{{}}},'PeakVal',{{{}}},'PeakMode',{{{}}});
+    aa.fresh = 1;
+    varargout = {class(aa,'miraudio',t)};
+    return
+end
+
+
+        center.key = 'Center';
+        center.type = 'Boolean';
+        center.default = 0;
+        center.when = 'After';
+    option.center = center;
+        
+        normal.key = 'Normal';
+        normal.type = 'Boolean';
+        normal.default = 0;
+        normal.when = 'After';
+    option.normal = normal;
+    
+        extract.key = {'Extract','Excerpt'};
+        extract.type = 'Integer';
+        extract.number = 2;
+        extract.default = [];
+        extract.unit = {'s','sp'};
+        extract.defaultunit = 's';
+        extract.from = {'Start','Middle','End'};
+        extract.defaultfrom = 'Start';
+    option.extract = extract;
+        
+        trim.type = 'String';
+        trim.choice = {'NoTrim','Trim','TrimBegin','TrimStart','TrimEnd'};
+        trim.default = 'NoTrim';
+        trim.when = 'After';
+    option.trim = trim;
+        
+        trimthreshold.key = 'TrimThreshold';
+        trimthreshold.type = 'Integer';
+        trimthreshold.default = .06;
+        trimthreshold.when = 'After';
+    option.trimthreshold = trimthreshold;
+        
+        label.key = 'Label';
+        label.default = '';
+        label.when = 'After';
+    option.label = label;
+        
+        sampling.key = 'Sampling';
+        sampling.type = 'Integer';
+        sampling.default = 0;
+        sampling.when = 'Both';
+    option.sampling = sampling;
+        
+   %     segment.key = 'Segment';
+   %     segment.type = 'Integer';
+   %     segment.default = [];
+   %     segment.when = 'After';
+   % option.segment = segment;
+
+        reverse.key = 'Reverse';
+        reverse.type = 'Boolean';
+        reverse.default = 0;
+        reverse.when = 'After';
+    option.reverse = reverse;
+
+        mono.key = 'Mono';
+        mono.type = 'Boolean';
+        mono.default = NaN;
+        mono.when = 'After';
+    option.mono = mono;    
+
+        separate.key = 'SeparateChannels';
+        separate.type = 'Boolean';
+        separate.default = 0;
+    option.separate = separate;    
+    
+        Ch.key = {'Channel','Channels'};
+        Ch.type = 'Integer';
+        Ch.default = [];
+        Ch.when = 'After';
+    option.Ch = Ch;
+        
+specif.option = option;
+
+specif.beforechunk = {@beforechunk,'normal'};
+specif.eachchunk = @eachchunk;
+specif.combinechunk = @combinechunk;
+
+if nargin > 1 && ischar(varargin{1}) && strcmp(varargin{1},'Now')
+    if nargin > 2
+        extract = varargin{2};
+    else
+        extract = [];
+    end
+    para = [];
+    varargout = {main(orig,[],para,[],extract)};
+else
+    varargout = mirfunction(@miraudio,orig,varargin,nargout,specif,@init,@main);
+end
+if isempty(varargout)
+    varargout = {{}};
+end
+
+
+function [x type] = init(x,option)
+if isa(x,'mirdesign')
+    if option.sampling
+        x = setresampling(x,option.sampling);
+    end
+end
+type = 'miraudio';
+
+
+function a = main(orig,option,after,index,extract)
+if iscell(orig)
+    orig = orig{1};
+end
+if ischar(orig)
+    if nargin < 5
+        extract = [];
+    end
+    [d{1},tp{1},fp{1},f{1},b{1},n{1},ch{1}] = mirread(extract,orig,1,0);
+    t = mirtemporal([],'Time',tp,'Data',d,'FramePos',fp,'Sampling',f,...
+                       'Name',n,'Label',cell(1,length(d)),...
+                       'Clusters',cell(1,length(d)),...
+                       'Channels',ch,'Centered',0,'NBits',b);
+    t = set(t,'Title','Audio waveform');
+    a.fresh = 1;
+    a = class(a,'miraudio',t);
+else
+    if not(isempty(option)) && not(isempty(option.extract))
+        if not(isstruct(after))
+            after = struct;
+        end
+        after.extract = option.extract;
+    end
+    if isa(orig,'miraudio')
+        a = orig;
+    else
+        a.fresh = 1;
+        a = class(a,'miraudio',orig);
+    end
+end      
+if not(isempty(after))
+    a = post(a,after);
+end    
+
+
+function a = post(a,para)
+if a.fresh && isfield(para,'mono')
+    a.fresh = 0;
+    if isnan(para.mono)
+        para.mono = 1;
+    end
+end
+if isfield(para,'mono') && para.mono == 1
+    a = mirsum(a,'Mean');
+end
+d = get(a,'Data');
+t = get(a,'Time');
+ac = get(a,'AcrossChunks');
+f = get(a,'Sampling');
+cl = get(a,'Clusters');
+for h = 1:length(d)
+    for k = 1:length(d{h})
+        tk = t{h}{k};
+        dk = d{h}{k};
+        if isfield(para,'extract') && not(isempty(para.extract))
+            t1 = para.extract(1);
+            t2 = para.extract(2);
+            if para.extract(4)
+                if para.extract(4) == 1
+                    shift = round(size(tk,1)/2);
+                elseif para.extract(4) == 2
+                    shift = size(tk,1);
+                end
+                if para.extract(3)
+                    shift = tk(shift,1,1);
+                end
+                t1 = t1+shift;
+                t2 = t2+shift;
+            end                
+            if para.extract(3) % in seconds
+                ft = find(tk>=t1 & tk<=t2);
+            else               % in samples
+                if not(t1)
+                    warning('WARNING IN MIRAUDIO: Extract sample positions should be real positive integers.')
+                    display('Positions incremented by one.');
+                    t1 = t1+1;
+                    t2 = t2+1;
+                end
+                ft = t1:t2;
+            end
+            tk = tk(ft,:,:);
+            dk = dk(ft,:,:);
+        end
+        if isfield(para,'Ch') && not(isempty(para.Ch))
+            dk = dk(:,:,para.Ch);
+        end
+        if isfield(para,'center') && para.center
+            dk = center(dk);
+            a = set(a,'Centered',1);
+        end
+        if isfield(para,'normal') && para.normal
+            nl = size(dk,1);
+            nc = size(dk,3);
+            if isempty(ac)
+                ee = 0;
+                for j = 1:nc
+                    ee = ee+sum(dk(:,:,j).^2);
+                end
+                ee = sqrt(ee/nl/nc);
+            else
+                ee = sqrt(sum(ac.sqrsum.^2)/ac.samples);
+            end
+            dk = dk./repmat(ee,[nl,1,nc]);
+        end
+        if isfield(para,'trim') && not(isequal(para.trim,0)) ...
+                && not(strcmpi(para.trim,'NoTrim'))
+            if not(para.trimthreshold)
+                para.trimthreshold = 0.06;
+            end
+            trimframe = 100;
+            trimhop = 10;
+            nframes = floor((length(tk)-trimframe)/trimhop)+1;
+            rms = zeros(1,nframes);
+            for j = 1:nframes
+                st = floor((j-1)*trimhop)+1;
+                for z = 1:size(dk,3)
+                    rms(1,j,z) = norm(dk(st:st+trimframe-1,1,z))/sqrt(trimframe);
+                end
+            end
+            rms = (rms-repmat(min(rms),[1,size(rms,2),1]))...
+                     ./repmat(max(rms)-min(rms),[1,size(rms,2),1]);
+            nosil = find(rms>para.trimthreshold);
+            if strcmpi(para.trim,'Trim') || strcmpi(para.trim,'TrimStart') ...
+                                         || strcmpi(para.trim,'TrimBegin')
+                nosil1 = min(nosil);
+                if nosil1 > 1
+                    nosil1 = nosil1-1;
+                end
+                n1 = floor((nosil1-1)*trimhop)+1;
+            else
+                n1 = 1;
+            end
+            if strcmpi(para.trim,'Trim') || strcmpi(para.trim,'TrimEnd')
+                nosil2 = max(nosil);
+                if nosil2 < length(rms)
+                    nosil2 = nosil2+1;
+                end
+                n2 = floor((nosil2-1)*trimhop)+1;
+            else
+                n2 = length(tk);
+            end
+            wh = ones(n2-n1+1,1);
+            dt = round(.02*f{h});
+            ha = hann(dt*2);
+            wh(1:dt) = ha(1:dt);
+            wh(end-dt+1:end) = ha(dt+1:end);
+            tk = tk(n1:n2);
+            dk = dk(n1:n2,1,:);%.*repmat(wh,[1 1 size(dk,3)]);
+        end
+        if isfield(para,'sampling') && para.sampling
+            if and(f{k}, not(f{k} == para.sampling))
+                for j = 1:size(dk,3)
+                    rk(:,:,j) = resample(dk(:,:,j),para.sampling,f{k});
+                end
+                dk = rk;
+                tk = repmat((0:size(dk,1)-1)',[1 1 size(tk,3)])...
+                            /para.sampling + tk(1,:,:);
+            end
+            f{k} = para.sampling;
+        end
+        d{h}{k} = dk;
+        t{h}{k} = tk;
+        %if isfield(para,'reverse') && para.reverse
+        %    d{h}{k} = flipdim(d{h}{k},1);
+        %end
+    end
+end
+a = set(a,'Data',d,'Time',t,'Sampling',f,'Clusters',cl);
+if isfield(para,'label') 
+    if isnumeric(para.label)
+        n = get(a,'Name');
+        l = cell(1,length(d));
+        for k = 1:length(d)
+            if para.label
+                l{k} = n{k}(para.label);
+            else
+                l{k} = n{k};
+            end
+        end
+        a = set(a,'Label',l);
+    elseif iscell(para.label)
+        idx = mod(get(a,'Index'),length(para.label));
+        if not(idx)
+            idx = length(para.label);
+        end
+        a = set(a,'Label',para.label{idx});
+    elseif ischar(para.label)
+        l = cell(1,length(d));
+        for k = 1:length(d)
+            l{k} = para.label;
+        end
+        a = set(a,'Label',l);
+    end
+end
+
+
+function [new orig] = beforechunk(orig,option,missing)
+option.normal = 0;
+a = miraudio(orig,option);
+d = get(a,'Data');
+old = get(orig,'AcrossChunks');
+if isempty(old)
+    old.sqrsum = 0;
+    old.samples = 0;
+end
+new = mircompute(@crossum,d);
+new = new{1}{1};
+new.sqrsum = old.sqrsum + new.sqrsum;
+new.samples = old.samples + new.samples;
+
+
+function s = crossum(d)
+s.sqrsum = sum(d.^2);
+s.samples = length(d);
+
+
+function [y orig] = eachchunk(orig,option,missing)
+y = miraudio(orig,option);
+
+
+function y = combinechunk(old,new)
+do = get(old,'Data');
+to = get(old,'Time');
+dn = get(new,'Data');
+tn = get(new,'Time');
+y = set(old,'Data',{{[do{1}{1};dn{1}{1}]}},...
+            'Time',{{[to{1}{1};tn{1}{1}]}});
\ No newline at end of file