wolffd@0: function varargout = mironsets(x,varargin) wolffd@0: % o = mironsets(x) shows a temporal curve where peaks relate to the wolffd@0: % position of note onset times, and estimates those note onset wolffd@0: % positions. wolffd@0: % Optional arguments: wolffd@0: % mironsets(...,f) selects the strategy for the computation of the wolffd@0: % onset detection function. wolffd@0: % f = 'Envelope': Envelope of the audio signal. (Default choice). wolffd@0: % With two methods for envelope extraction: wolffd@0: % mironsets(...,'Spectro') (Default): wolffd@0: % mironsets(...,'SpectroFrame',fl,fh) species the frame wolffd@0: % length fl (in s.) and the hop factor fh (as a value wolffd@0: % between 0 and 1) wolffd@0: % Default values: fl = .1 s., fh = .1 wolffd@0: % the frequency reassigment method can be specified: wolffd@0: % 'Freq' (default), 'Mel', 'Bark' or 'Cents' (cf. mirspectrum). wolffd@0: % mironsets(...,'Filter'): wolffd@0: % mironsets(...,'Filterbank',nc) specifies a preliminary wolffd@0: % filterbank decomposition into nc channels. If nc = 0, wolffd@0: % no decomposition is performed. wolffd@0: % Default value: 40. wolffd@0: % mironsets(...,'FilterbankType',ft) specifies the type of wolffd@0: % filterbank (see mirfilterbank). wolffd@0: % Default value: 'Gammatone'; wolffd@0: % Options associated to the mirenvelope function can be wolffd@0: % passed here as well (see help mirenvelope): wolffd@0: % 'FilterType','Tau','PreDecim' wolffd@0: % mironsets(...,'Sum','no') does not sum back the channels at wolffd@0: % the end of the computation. The resulting onset curve wolffd@0: % remains therefore decomposed into several channels. wolffd@0: % Options associated to the mirenvelope function can be wolffd@0: % passed here as well (see help mirenvelope): wolffd@0: % 'HalfwaveCenter','Diff','HalfwaveDiff','Center', wolffd@0: % 'Smooth', 'Sampling','Log','Power','Lambda', wolffd@0: % ,'PostDecim','UpSample' wolffd@0: % f = 'SpectralFlux': Spectral flux of the audio signal. wolffd@0: % Options associated to the mirflux function can be wolffd@0: % passed here as well (see help mirflux): wolffd@0: % 'Inc' (toggled on by default here), wolffd@0: % 'Halfwave' (toggled on by default here), wolffd@0: % 'Complex' (toggled off by default), wolffd@0: % 'Median' (toggled on by default here) wolffd@0: % f = 'Pitch ':computes a frame-decomposed autocorrelation function , wolffd@0: % of same default characteristics than those returned wolffd@0: % by mirpitch, with however a range of frequencies set by wolffd@0: % the following options: wolffd@0: % 'Min' (set by default to 30 Hz), wolffd@0: % 'Max' (set by default to 1000 Hz), wolffd@0: % and subsequently computes the novelty curve of the wolffd@0: % resulting similatrix matrix. wolffd@0: % Option associated to the mirnovelty function can be wolffd@0: % passed here as well (see help mirnovelty): wolffd@0: % 'KernelSize' (set by default to 32 samples) wolffd@0: % mironsets(...,'Detect',d) toggles on or off the onset detection, wolffd@0: % which is based on the onset detection function. wolffd@0: % (By default toggled on.) wolffd@0: % Option associated to the mirpeaks function can be specified as wolffd@0: % well: wolffd@0: % 'Contrast' with default value c = .01 wolffd@0: % 'Threshold' with default value t = 0 wolffd@0: % mironsets(...,'Attack') (or 'Attacks') detects attack phases. wolffd@0: % mironsets(...,'Release') (or 'Releases') detects release phases. wolffd@0: % mironsets(...,'Gauss',o) estimate the attack and/or release wolffd@0: % points using a gaussian envelope smoothing of order o of the wolffd@0: % onset curve. wolffd@0: % mironsets(...,'Frame',...) decomposes into frames, with default frame wolffd@0: % length 3 seconds and hop factor .1 wolffd@0: % Preselected onset detection models: wolffd@0: % mironsets(...,'Scheirer') corresponds to (Scheirer, 1998): wolffd@0: % mironsets(...,'FilterBankType','Scheirer',... wolffd@0: % 'FilterType','HalfHann','Sampling',200,... wolffd@0: % 'HalfWaveDiff','Sum',0,'Detect',0) wolffd@0: % mironsets(...,'Klapuri99') corresponds to most of (Klapuri, 1999). wolffd@0: wolffd@0: %% options related to 'Envelope': wolffd@0: wolffd@0: env.key = 'Envelope'; wolffd@0: env.type = 'Boolean'; wolffd@0: env.default = NaN; wolffd@0: option.env = env; wolffd@0: wolffd@0: envmethod.key = 'Method'; % optional wolffd@0: envmethod.type = 'Boolean'; wolffd@0: option.envmethod = envmethod; wolffd@0: wolffd@0: envmeth.type = 'String'; wolffd@0: envmeth.choice = {'Filter','Spectro'}; wolffd@0: envmeth.default = 'Spectro'; wolffd@0: option.envmeth = envmeth; wolffd@0: wolffd@0: %% options related to 'Filter': wolffd@0: wolffd@0: filter.key = 'FilterType'; wolffd@0: filter.type = 'String'; wolffd@0: filter.choice = {'IIR','HalfHann'}; wolffd@0: filter.default = 'IIR'; wolffd@0: option.filter = filter; wolffd@0: wolffd@0: tau.key = 'Tau'; wolffd@0: tau.type = 'Integer'; wolffd@0: tau.default = .02; wolffd@0: option.tau = tau; wolffd@0: wolffd@0: fb.key = {'Filterbank','NbChannels'}; wolffd@0: fb.type = 'Integer'; wolffd@0: fb.default = 40; wolffd@0: option.fb = fb; wolffd@0: wolffd@0: filtertype.key = 'FilterbankType'; wolffd@0: filtertype.type = 'String'; wolffd@0: %filtertype.choice = {'Gammatone','2Channels','Scheirer','Klapuri'}; wolffd@0: filtertype.default = 'Gammatone'; wolffd@0: option.filtertype = filtertype; wolffd@0: wolffd@0: decim.key = {'Decim','PreDecim'}; wolffd@0: decim.type = 'Integer'; wolffd@0: decim.default = 0; wolffd@0: option.decim = decim; wolffd@0: wolffd@0: %% options related to 'Spectro': wolffd@0: wolffd@0: band.type = 'String'; wolffd@0: band.choice = {'Freq','Mel','Bark','Cents'}; wolffd@0: band.default = 'Freq'; wolffd@0: option.band = band; wolffd@0: wolffd@0: specframe.key = 'SpectroFrame'; wolffd@0: specframe.type = 'Integer'; wolffd@0: specframe.number = 2; wolffd@0: specframe.default = [.1 .1]; wolffd@0: option.specframe = specframe; wolffd@0: wolffd@0: sum.key = 'Sum'; wolffd@0: sum.type = 'Boolean'; wolffd@0: sum.default = 1; wolffd@0: option.sum = sum; wolffd@0: wolffd@0: chwr.key = 'HalfwaveCenter'; wolffd@0: chwr.type = 'Boolean'; wolffd@0: chwr.default = 0; wolffd@0: chwr.when = 'After'; wolffd@0: option.chwr = chwr; wolffd@0: wolffd@0: mu.key = 'Mu'; wolffd@0: mu.type = 'Boolean'; wolffd@0: mu.default = 0; wolffd@0: mu.when = 'After'; wolffd@0: option.mu = mu; wolffd@0: wolffd@0: oplog.key = 'Log'; wolffd@0: oplog.type = 'Boolean'; wolffd@0: oplog.default = 0; wolffd@0: oplog.when = 'After'; wolffd@0: option.log = oplog; wolffd@0: wolffd@0: oppow.key = 'Power'; wolffd@0: oppow.type = 'Boolean'; wolffd@0: oppow.default = 0; wolffd@0: oppow.when = 'After'; wolffd@0: option.power = oppow; wolffd@0: wolffd@0: diffenv.key = 'DiffEnvelope'; % obsolete, replaced by 'Diff' wolffd@0: diffenv.type = 'Boolean'; wolffd@0: diffenv.default = 0; wolffd@0: option.diffenv = diffenv; wolffd@0: wolffd@0: diff.key = 'Diff'; wolffd@0: diff.type = 'Integer'; wolffd@0: diff.default = 0; wolffd@0: diff.keydefault = 1; wolffd@0: diff.when = 'After'; wolffd@0: option.diff = diff; wolffd@0: wolffd@0: diffhwr.key = 'HalfwaveDiff'; wolffd@0: diffhwr.type = 'Integer'; wolffd@0: diffhwr.default = 0; wolffd@0: diffhwr.keydefault = 1; wolffd@0: diffhwr.when = 'After'; wolffd@0: option.diffhwr = diffhwr; wolffd@0: wolffd@0: lambda.key = 'Lambda'; wolffd@0: lambda.type = 'Integer'; wolffd@0: lambda.default = 1; wolffd@0: lambda.when = 'After'; wolffd@0: option.lambda = lambda; wolffd@0: wolffd@0: c.key = 'Center'; wolffd@0: c.type = 'Boolean'; wolffd@0: c.default = 0; wolffd@0: c.when = 'After'; wolffd@0: option.c = c; wolffd@0: wolffd@0: aver.key = 'Smooth'; wolffd@0: aver.type = 'Integer'; wolffd@0: aver.default = 0; wolffd@0: aver.keydefault = 30; wolffd@0: aver.when = 'After'; wolffd@0: option.aver = aver; wolffd@0: wolffd@0: ds.key = {'Down','PostDecim'}; wolffd@0: ds.type = 'Integer'; wolffd@0: if isamir(x,'mirenvelope') wolffd@0: ds.default = 1; wolffd@0: else wolffd@0: ds.default = NaN; wolffd@0: end wolffd@0: ds.when = 'After'; wolffd@0: ds.chunkcombine = 'During'; wolffd@0: option.ds = ds; wolffd@0: wolffd@0: sampling.key = 'Sampling'; wolffd@0: sampling.type = 'Integer'; wolffd@0: sampling.default = 0; wolffd@0: sampling.when = 'After'; wolffd@0: option.sampling = sampling; wolffd@0: wolffd@0: up.key = {'UpSample'}; wolffd@0: up.type = 'Integer'; wolffd@0: up.default = 0; wolffd@0: up.keydefault = 2; wolffd@0: option.up = up; wolffd@0: wolffd@0: %% options related to 'SpectralFlux' wolffd@0: flux.key = 'SpectralFlux'; wolffd@0: flux.type = 'Boolean'; wolffd@0: flux.default = 0; wolffd@0: option.flux = flux; wolffd@0: wolffd@0: complex.key = 'Complex'; wolffd@0: complex.type = 'Boolean'; wolffd@0: complex.when = 'Both'; wolffd@0: complex.default = 0; wolffd@0: option.complex = complex; wolffd@0: wolffd@0: inc.key = 'Inc'; wolffd@0: inc.type = 'Boolean'; wolffd@0: inc.default = 1; wolffd@0: option.inc = inc; wolffd@0: wolffd@0: median.key = 'Median'; wolffd@0: median.type = 'Integer'; wolffd@0: median.number = 2; wolffd@0: median.default = [.2 1.3]; wolffd@0: median.when = 'After'; wolffd@0: option.median = median; wolffd@0: wolffd@0: hw.key = 'Halfwave'; wolffd@0: hw.type = 'Boolean'; wolffd@0: hw.default = 1; wolffd@0: hw.when = 'After'; wolffd@0: option.hw = hw; wolffd@0: wolffd@0: %% options related to 'Pitch': wolffd@0: pitch.key = 'Pitch'; wolffd@0: pitch.type = 'Boolean'; wolffd@0: pitch.default = 0; wolffd@0: option.pitch = pitch; wolffd@0: wolffd@0: min.key = 'Min'; wolffd@0: min.type = 'Integer'; wolffd@0: min.default = 30; wolffd@0: option.min = min; wolffd@0: wolffd@0: max.key = 'Max'; wolffd@0: max.type = 'Integer'; wolffd@0: max.default = 1000; wolffd@0: option.max = max; wolffd@0: wolffd@0: kernelsize.key = 'KernelSize'; wolffd@0: kernelsize.type = 'Integer'; wolffd@0: kernelsize.default = 32; wolffd@0: option.kernelsize = kernelsize; wolffd@0: wolffd@0: %% options related to event detection wolffd@0: detect.key = 'Detect'; wolffd@0: detect.type = 'String'; wolffd@0: detect.choice = {'Peaks','Valleys',0,'no','off'}; wolffd@0: detect.default = 'Peaks'; wolffd@0: detect.keydefault = 'Peaks'; wolffd@0: detect.when = 'After'; wolffd@0: option.detect = detect; wolffd@0: wolffd@0: cthr.key = 'Contrast'; wolffd@0: cthr.type = 'Integer'; wolffd@0: cthr.default = NaN; wolffd@0: cthr.when = 'After'; wolffd@0: option.cthr = cthr; wolffd@0: wolffd@0: thr.key = 'Threshold'; wolffd@0: thr.type = 'Integer'; wolffd@0: thr.default = 0; wolffd@0: thr.when = 'After'; wolffd@0: option.thr = thr; wolffd@0: wolffd@0: attack.key = {'Attack','Attacks'}; wolffd@0: attack.type = 'Boolean'; wolffd@0: attack.default = 0; wolffd@0: attack.when = 'After'; wolffd@0: option.attack = attack; wolffd@0: wolffd@0: release.key = {'Release','Releases'}; wolffd@0: release.type = 'String'; wolffd@0: release.choice = {'Olivier','Valeri',0,'no','off'}; wolffd@0: release.default = 0; wolffd@0: release.keydefault = 'Olivier'; wolffd@0: release.when = 'After'; wolffd@0: option.release = release; wolffd@0: wolffd@0: gauss.key = 'Gauss'; wolffd@0: gauss.type = 'Integer'; wolffd@0: gauss.default = 0; wolffd@0: gauss.when = 'After'; wolffd@0: option.gauss = gauss; wolffd@0: wolffd@0: %% preselection wolffd@0: presel.choice = {'Scheirer','Klapuri99'}; wolffd@0: presel.type = 'String'; wolffd@0: presel.default = 0; wolffd@0: option.presel = presel; wolffd@0: wolffd@0: wolffd@0: %% 'Frame' option wolffd@0: frame.key = 'Frame'; wolffd@0: frame.type = 'Integer'; wolffd@0: frame.when = 'Both'; wolffd@0: frame.number = 2; wolffd@0: frame.default = [0 0]; wolffd@0: frame.keydefault = [3 .1]; wolffd@0: option.frame = frame; wolffd@0: wolffd@0: specif.option = option; wolffd@0: wolffd@0: specif.eachchunk = 'Normal'; wolffd@0: specif.combinechunk = 'Concat'; wolffd@0: specif.extensive = 1; wolffd@0: wolffd@0: specif.title = 'Onset curve'; %used for miroptions wolffd@0: wolffd@0: varargout = mirfunction(@mironsets,x,varargin,nargout,specif,@init,@main); wolffd@0: wolffd@0: wolffd@0: %% INIT wolffd@0: wolffd@0: function [y type] = init(x,option) wolffd@0: if iscell(x) wolffd@0: x = x{1}; wolffd@0: end wolffd@0: if ischar(option.presel) wolffd@0: if strcmpi(option.presel,'Scheirer') wolffd@0: option.filtertype = 'Scheirer'; wolffd@0: option.filter = 'HalfHann'; wolffd@0: option.envmeth = 'Filter'; wolffd@0: elseif strcmpi(option.presel,'Klapuri99') wolffd@0: option.filtertype = 'Klapuri'; wolffd@0: option.filter = 'HalfHann'; wolffd@0: option.envmeth = 'Filter'; wolffd@0: option.decim = 180; wolffd@0: end wolffd@0: end wolffd@0: if option.diffenv wolffd@0: option.env = 1; wolffd@0: end wolffd@0: if isnan(option.env) wolffd@0: if option.flux || option.pitch wolffd@0: option.env = 0; wolffd@0: else wolffd@0: option.env = 1; wolffd@0: end wolffd@0: end wolffd@0: if isamir(x,'miraudio') wolffd@0: if option.env wolffd@0: if strcmpi(option.envmeth,'Filter') && option.fb>1 wolffd@0: fb = mirfilterbank(x,option.filtertype,'NbChannels',option.fb); wolffd@0: else wolffd@0: fb = x; wolffd@0: end wolffd@0: y = mirenvelope(fb,option.envmeth,option.band,... wolffd@0: 'Frame',option.specframe(1),option.specframe(2),... wolffd@0: 'FilterType',option.filter,... wolffd@0: 'Tau',option.tau,'UpSample',option.up,... wolffd@0: 'PreDecim',option.decim,'PostDecim',0); wolffd@0: type = 'mirenvelope'; wolffd@0: elseif option.flux wolffd@0: x = mirframenow(x,option); wolffd@0: y = mirflux(x,'Inc',option.inc,'Complex',option.complex); wolffd@0: type = 'mirscalar'; wolffd@0: elseif option.pitch wolffd@0: [unused ac] = mirpitch(x,'Frame','Min',option.min,'Max',option.max); wolffd@0: y = mirnovelty(ac,'KernelSize',option.kernelsize); wolffd@0: type = 'mirscalar'; wolffd@0: end wolffd@0: elseif (option.pitch && not(isamir(x,'mirscalar'))) ... wolffd@0: || isamir(x,'mirsimatrix') wolffd@0: y = mirnovelty(x,'KernelSize',option.kernelsize); wolffd@0: type = 'mirscalar'; wolffd@0: elseif isamir(x,'mirscalar') || isamir(x,'mirenvelope') wolffd@0: y = x; %mirframenow(x,option); wolffd@0: type = mirtype(x); wolffd@0: else wolffd@0: x = mirframenow(x,option); wolffd@0: y = mirflux(x,'Inc',option.inc,'Complex',option.complex); %Not used... wolffd@0: type = 'mirscalar'; wolffd@0: end wolffd@0: wolffd@0: wolffd@0: %% MAIN wolffd@0: wolffd@0: function o = main(o,option,postoption) wolffd@0: if not(isempty(option)) && ischar(option.presel) wolffd@0: if strcmpi(option.presel,'Scheirer') wolffd@0: postoption.sampling = 200; wolffd@0: postoption.diffhwr = 1; wolffd@0: option.sum = 0; wolffd@0: postoption.detect = 0; wolffd@0: elseif strcmpi(option.presel,'Klapuri99') wolffd@0: postoption.mu = 1; wolffd@0: postoption.diffhwr = 1; wolffd@0: option.sum = 0; wolffd@0: postoption.ds = 0; wolffd@0: o2 = o; wolffd@0: end wolffd@0: end wolffd@0: if iscell(o) wolffd@0: o = o{1}; wolffd@0: end wolffd@0: if not(isempty(option)) && option.diffenv wolffd@0: postoption.diff = 1; wolffd@0: end wolffd@0: if isa(o,'mirenvelope') wolffd@0: if isfield(postoption,'sampling') && postoption.sampling wolffd@0: o = mirenvelope(o,'Sampling',postoption.sampling); wolffd@0: elseif isfield(postoption,'ds') wolffd@0: if isnan(postoption.ds) wolffd@0: if option.decim || strcmpi(option.envmeth,'Spectro') wolffd@0: postoption.ds = 0; wolffd@0: else wolffd@0: postoption.ds = 16; wolffd@0: end wolffd@0: end wolffd@0: if postoption.ds wolffd@0: o = mirenvelope(o,'Down',postoption.ds); wolffd@0: end wolffd@0: end wolffd@0: end wolffd@0: if isfield(postoption,'cthr') wolffd@0: if isa(o,'mirenvelope') wolffd@0: if postoption.mu wolffd@0: o = mirenvelope(o,'Mu'); wolffd@0: end wolffd@0: if postoption.log wolffd@0: o = mirenvelope(o,'Log'); wolffd@0: end wolffd@0: if postoption.power wolffd@0: o = mirenvelope(o,'Power'); wolffd@0: end wolffd@0: if postoption.diff wolffd@0: o = mirenvelope(o,'Diff',postoption.diff,... wolffd@0: 'Lambda',postoption.lambda,... wolffd@0: 'Complex',postoption.complex); wolffd@0: end wolffd@0: if postoption.diffhwr wolffd@0: o = mirenvelope(o,'HalfwaveDiff',postoption.diffhwr,... wolffd@0: 'Lambda',postoption.lambda,... wolffd@0: 'Complex',postoption.complex); wolffd@0: end wolffd@0: if postoption.aver wolffd@0: o = mirenvelope(o,'Smooth',postoption.aver); wolffd@0: end wolffd@0: if postoption.chwr wolffd@0: o = mirenvelope(o,'HalfwaveCenter'); wolffd@0: end wolffd@0: if postoption.c wolffd@0: o = mirenvelope(o,'Center'); wolffd@0: end wolffd@0: elseif isa(o,'mirscalar') && strcmp(get(o,'Title'),'Spectral flux') wolffd@0: if postoption.median wolffd@0: o = mirflux(o,'Median',postoption.median(1),postoption.median(2),... wolffd@0: 'Halfwave',postoption.hw); wolffd@0: else wolffd@0: o = mirflux(o,'Halfwave',postoption.hw); wolffd@0: end wolffd@0: end wolffd@0: end wolffd@0: if isfield(option,'sum') && option.sum wolffd@0: o = mirsum(o,'Adjacent',option.sum); wolffd@0: end wolffd@0: if isfield(option,'presel') && ... wolffd@0: ischar(option.presel) && strcmpi(option.presel,'Klapuri99') wolffd@0: % o, already computed, corresponds to mirenvelope(o,'Mu','HalfwaveDiff'); wolffd@0: % o is the relative distance function W in (Klapuri, 99); wolffd@0: o2 = mirenvelope(o2,'HalfwaveDiff'); wolffd@0: % o2 is the absolute distance function D in (Klapuri, 99); wolffd@0: p = mirpeaks(o,'Contrast',.2,'Chrono'); wolffd@0: p2 = mirpeaks(o2,'ScanForward',p,'Chrono'); wolffd@0: o = combinepeaks(p,p2,.05); wolffd@0: clear o2 p p2 wolffd@0: filtfreq = 44*[2.^ ([ 0:2, ( 9+(0:17) )/3 ]) ];% Center frequencies of bands wolffd@0: o = mirsum(o,'Weights',(filtfreq(1:end-1)+filtfreq(2:end))/2); wolffd@0: o = mirenvelope(o,'Smooth',12); wolffd@0: end wolffd@0: if not(isa(o,'mirscalar')) wolffd@0: o = mirframenow(o,postoption); wolffd@0: end wolffd@0: if isfield(postoption,'detect') && ischar(postoption.detect) wolffd@0: if isnan(postoption.cthr) || not(postoption.cthr) wolffd@0: if ischar(postoption.detect) || postoption.detect wolffd@0: postoption.cthr = .01; wolffd@0: end wolffd@0: elseif postoption.cthr wolffd@0: if not(ischar(postoption.detect) || postoption.detect) wolffd@0: postoption.detect = 'Peaks'; wolffd@0: end wolffd@0: end wolffd@0: if strcmpi(postoption.detect,'Peaks') wolffd@0: o = mirpeaks(o,'Total',Inf,'SelectFirst',... wolffd@0: 'Threshold',postoption.thr,'Contrast',postoption.cthr,... wolffd@0: 'Order','Abscissa','NoBegin','NoEnd'); wolffd@0: elseif strcmpi(postoption.detect,'Valleys') wolffd@0: o = mirpeaks(o,'Total',Inf,'SelectFirst',... wolffd@0: 'Threshold',postoption.thr,'Contrast',postoption.cthr,... wolffd@0: 'Valleys','Order','Abscissa','NoBegin','NoEnd'); wolffd@0: end wolffd@0: nop = cell(size(get(o,'Data'))); wolffd@0: o = set(o,'AttackPos',nop,'ReleasePos',nop); wolffd@0: end wolffd@0: if (isfield(postoption,'attack') && postoption.attack) || ... wolffd@0: (isfield(postoption,'release') && postoption.release) wolffd@0: p = get(o,'PeakPos'); wolffd@0: pm = get(o,'PeakMode'); wolffd@0: d = get(o,'Data'); wolffd@0: if postoption.attack wolffd@0: [st p pm] = mircompute(@startattack,d,p,pm); wolffd@0: end wolffd@0: if ischar(postoption.release) && ~strcmpi(postoption.release,'No') ... wolffd@0: && ~strcmpi(postoption.release,'Off') wolffd@0: [rl p pm st] = mircompute(@endrelease,d,p,pm,st,postoption.release); wolffd@0: o = set(o,'ReleasePos',rl); wolffd@0: end wolffd@0: o = set(o,'AttackPos',st,'PeakPos',p,'PeakMode',pm); wolffd@0: end wolffd@0: title = get(o,'Title'); wolffd@0: if not(length(title)>11 && strcmp(title(1:11),'Onset curve')) wolffd@0: o = set(o,'Title',['Onset curve (',title,')']); wolffd@0: end wolffd@0: wolffd@0: wolffd@0: function st = startattack(d,z,pm) wolffd@0: z = sort(z{1}); wolffd@0: pm = pm{1}; wolffd@0: st = zeros(size(z)); wolffd@0: i = 1; wolffd@0: dd = diff(d,1,1); % d' wolffd@0: ddd = diff(dd,1,1); % d'' wolffd@0: dddd = diff(ddd,1,1); % d''' wolffd@0: while i<=length(z) wolffd@0: % Start attack is identified to previous peak in d''. wolffd@0: p = find(dddd((z(i)-1)-1:-1:1)<0,1); % previous decreasing d'' wolffd@0: if isempty(p) wolffd@0: st(i) = 1; wolffd@0: else wolffd@0: n = find(dddd((z(i)-1)-p-1:-1:1)>0,1); % previous increasing d'' wolffd@0: if isempty(n) wolffd@0: st(i) = 1; wolffd@0: else wolffd@0: st(i) = ((z(i)-1)-p-(n-1))+1; wolffd@0: end wolffd@0: if i>1 && st(i-1)==st(i) wolffd@0: if d(z(i))>d(z(i-1)) wolffd@0: del = i-1; wolffd@0: else wolffd@0: del = i; wolffd@0: end wolffd@0: st(del) = []; wolffd@0: z(del) = []; wolffd@0: pm(del) = []; wolffd@0: i = i-1; wolffd@0: end wolffd@0: end wolffd@0: i = i+1; wolffd@0: end wolffd@0: st = {{st} {z} {pm}}; wolffd@0: wolffd@0: wolffd@0: function rt = endrelease(d,z,pm,st,meth) wolffd@0: z = sort(z{1}); wolffd@0: pm = pm{1}; wolffd@0: if not(isempty(st)) wolffd@0: st = st{1}; wolffd@0: end wolffd@0: rt = zeros(size(z)); wolffd@0: i = 1; wolffd@0: dd = diff(d,1,1); % d' wolffd@0: ddd = diff(dd,1,1); % d'' wolffd@0: dddd = diff(ddd,1,1); % d''' wolffd@0: while i<=length(z) wolffd@0: if strcmpi(meth,'Olivier') wolffd@0: % Release attack is identified to next (sufficiently positive) peak wolffd@0: % in d''. wolffd@0: l = find(ddd((z(i)-1):end)max(ddd)/100,1); % next increasing d'' wolffd@0: if isempty(p) wolffd@0: rt(i) = length(d); wolffd@0: else wolffd@0: n = find(dddd((z(i)-1)+(l-1)+p+1:end)<0,1); % next decreasing d'' wolffd@0: if isempty(n) wolffd@0: rt(i) = length(d); wolffd@0: else wolffd@0: rt(i) = ((z(i)-1)+(l-1)+p+n)+1; wolffd@0: end wolffd@0: end wolffd@0: end wolffd@0: elseif strcmpi(meth,'Valeri') wolffd@0: p = find(dd((z(i)-1)+1:end)>min(dd)/100,1); % find point nearest to min(dd)/100 from current peak. wolffd@0: if isempty(p) wolffd@0: rt(i) = length(d); wolffd@0: elseif p<=3 %that means if p is less than 3 points away from the peak then it can not be considered as the end point of release. wolffd@0: %Assumption is that the whole DSR(decay sustain release) section can not be shorter than 30 ms (sampling rate is 100 Hz), also, no successive note can be nearer than 30ms. wolffd@0: rt(i) = z(i)+3; wolffd@0: else wolffd@0: rt(i) = (z(i)-1)+(p-1); wolffd@0: end wolffd@0: end wolffd@0: if i>1 && rt(i-1)==rt(i) wolffd@0: if d(z(i))>d(z(i-1)) wolffd@0: del = i-1; wolffd@0: else wolffd@0: del = i; wolffd@0: end wolffd@0: rt(del) = []; wolffd@0: z(del) = []; wolffd@0: pm(del) = []; wolffd@0: if not(isempty(st)) wolffd@0: st(del) = []; wolffd@0: end wolffd@0: i = i-1; wolffd@0: end wolffd@0: i = i+1; wolffd@0: end wolffd@0: rt = {{rt} {z} {pm} {st}};