Mercurial > hg > camir-aes2014
view toolboxes/MIRtoolbox1.3.2/MIRToolbox/@mirchromagram/mirchromagram.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 source
function varargout = mirchromagram(orig,varargin) % c = mirchromagram(x) computes the chromagram, or distribution of energy % along pitches, of the audio signal x. % (x can be the name of an audio file as well, or a spectrum, ...) % Optional argument: % c = mirchromagram(...,'Tuning',t): specifies the central frequency % (in Hz.) associated to chroma C. % Default value, t = 261.6256 Hz % c = mirchromagram(...,'Wrap',w): specifies whether the chromagram is % wrapped or not. % w = 1: groups all the pitches belonging to same pitch classes % (default value) % w = 0: pitches are considered as absolute values. % c = mirchromagram(...,'Frame',l,h) orders a frame decomposition of window % length l (in seconds) and hop factor h, expressed relatively to % the window length. For instance h = 1 indicates no overlap. % Default values: l = .2 seconds and h = .05 % c = mirchromagram(...,'Center'): centers the result. % c = mirchromagram(...,'Normal',n): performs a n-norm of the % resulting chromagram. Toggled off if n = 0 % Default value: n = Inf (corresponding to a normalization by % the maximum value). % c = mirchromagram(...,'Pitch',p): specifies how to label chromas in % the figures. % p = 1: chromas are labeled using pitch names (default) % alternative syntax: chromagram(...,'Pitch') % p = 0: chromas are labeled using MIDI pitch numbers % c = mirchromagram(...,'Triangle'): weight the contribution of each % frequency with respect to the distance with the actual % frequency of the corresponding chroma. % c = mirchromagram(...,'Weight',o): specifies the relative radius of % the weighting window, with respect to the distance between % frequencies of successive chromas. % o = 1: each window begins at the centers of the previous one. % o = .5: each window begins at the end of the previous one. % (default value) % mirchromagram(...,'Min',mi) indicates the lowest frequency taken into % consideration in the spectrum computation, expressed in Hz. % Default value: 100 Hz. (Gomez, 2006) % mirchromagram(...,'Max',ma) indicates the highest frequency taken into % consideration in the spectrum computation, expressed in Hz. % This upper limit is further shifted to a highest value until % the frequency range covers an exact multiple of octaves. % Default value: 5000 Hz. (Gomez, 2006) % mirchromagram(...,'Res',r) indicates the resolution of the % chromagram in number of bins per octave. % Default value, r = 12. % % Gómez, E. (2006). Tonal description of music audio signal. Phd thesis, % Universitat Pompeu Fabra, Barcelona . cen.key = 'Center'; cen.type = 'Boolean'; cen.default = 0; option.cen = cen; nor.key = {'Normal','Norm'}; nor.type = 'Integer'; nor.default = Inf; option.nor = nor; wth.key = 'Weight'; wth.type = 'Integer'; wth.default = .5; option.wth = wth; tri.key = 'Triangle'; tri.type = 'Boolean'; tri.default = 0; option.tri = tri; wrp.key = 'Wrap'; wrp.type = 'Boolean'; wrp.default = 1; option.wrp = wrp; plabel.key = 'Pitch'; plabel.type = 'Boolean'; plabel.default = 1; option.plabel = plabel; thr.key = {'Threshold','dB'}; thr.type = 'Integer'; thr.default = 20; option.thr = thr; min.key = 'Min'; min.type = 'Integer'; min.default = 100; option.min = min; max.key = 'Max'; max.type = 'Integer'; max.default = 5000; option.max = max; res.key = 'Res'; res.type = 'Integer'; res.default = 12; option.res = res; origin.key = 'Tuning'; origin.type = 'Integer'; origin.default = 261.6256; option.origin = origin; specif.option = option; specif.defaultframelength = .2; specif.defaultframehop = .05; varargout = mirfunction(@mirchromagram,orig,varargin,nargout,specif,@init,@main); function [x type] = init(x,option) if isamir(x,'mirtemporal') || isamir(x,'mirspectrum') freqmin = option.min; freqmax = freqmin*2; while freqmax < option.max freqmax = freqmax*2; end %freqres = freqmin*(2.^(1/option.res)-1); % Minimal frequency resolution should correspond to frequency range % between the first two bins of the chromagram x = mirspectrum(x,'dB',option.thr,'Min',freqmin,'Max',freqmax,... 'NormalInput','MinRes',option.res,'OctaveRatio',.85); %freqres*.5,... % 'WarningRes',freqres); end type = 'mirchromagram'; function c = main(orig,option,postoption) if iscell(orig) orig = orig{1}; end if option.res == 12 chromascale = {'C','C#','D','D#','E','F','F#','G','G#','A','A#','B'}; else chromascale = 1:option.res; option.plabel = 0; end if isa(orig,'mirchromagram') c = modif(orig,option,chromascale); else c.plabel = 1; c.wrap = 0; c.chromaclass = {}; c.chromafreq = {}; c.register = {}; c = class(c,'mirchromagram',mirdata(orig)); c = purgedata(c); c = set(c,'Title','Chromagram','Ord','magnitude','Interpolable',0); if option.wrp c = set(c,'Abs','chroma class'); else c = set(c,'Abs','chroma'); end m = get(orig,'Magnitude'); f = get(orig,'Frequency'); %disp('Computing chromagram...') fs = get(orig,'Sampling'); n = cell(1,length(m)); % The final structured list of magnitudes. cc = cell(1,length(m)); % The final structured list of chroma classes. o = cell(1,length(m)); % The final structured list of octave registers. p = cell(1,length(m)); % The final structured list of chromas. cf = cell(1,length(m)); % The final structured list of central frequencies related to chromas. for i = 1:length(m) mi = m{i}; fi = f{i}; if not(iscell(mi)) mi = {mi}; fi = {fi}; end ni = cell(1,length(mi)); % The list of magnitudes. ci = cell(1,length(mi)); % The list of chroma classes. oi = cell(1,length(mi)); % The list of octave registers. pi = cell(1,length(mi)); % The list of absolute chromas. cfi = cell(1,length(mi)); % The central frequency of each chroma. for j = 1:length(mi) mj = mi{j}; fj = fi{j}; % Let's remove the frequencies exceeding the last whole octave. minfj = min(min(min(fj))); maxfj = max(max(max(fj))); maxfj = minfj*2^(floor(log2(maxfj/minfj))); fz = find(fj(:,1,1,1) > maxfj); mj(fz,:,:,:) = []; fj(fz,:,:,:) = []; [s1 s2 s3] = size(mj); cj = freq2chro(fj,option.res,option.origin); if not(ismember(min(cj)+1,cj)) warning('WARNING IN MIRCHROMAGRAM: Frequency resolution of the spectrum is too low.'); display('The conversion of low frequencies into chromas may be incorrect.'); end ccj = min(min(min(cj))):max(max(max(cj))); sc = length(ccj); % The size of range of absolute chromas. mat = zeros(s1,sc); fc = chro2freq(ccj,option.res,option.origin); % The absolute chromas in Hz. fl = chro2freq(ccj-1,option.res,option.origin); % Each previous chromas in Hz. fr = chro2freq(ccj+1,option.res,option.origin); % Each related next chromas in Hz. for k = 1:sc rad = find(and(fj(:,1) > fc(k)-option.wth*(fc(k)-fl(k)),... fj(:,1) < fc(k)-option.wth*(fc(k)-fr(k)))); if option.tri dist = fc(k) - fj(:,1,1,1); rad1 = dist/(fc(k) - fl(k))/option.wth; rad2 = dist/(fc(k) - fr(k))/option.wth; ndist = max(rad1,rad2); mat(:,k) = max(min(1-ndist,1),0)/length(rad); else mat(rad,k) = ones(length(rad),1)/length(rad); end if k ==1 || k == sc mat(:,k) = mat(:,k)/2; end end nj = zeros(sc,s2,s3); for k = 1:s2 for l = 1:s3 nj(:,k,l) = (mj(:,k,l)'*mat)'; end end cj = mod(ccj',option.res); oi{j} = floor(ccj/option.res)+4; if option.plabel pj = strcat(chromascale(cj+1)',num2str(oi{j}')); else pj = ccj'+60; end ci{j} = repmat(cj,[1,s2,s3]); pi{j} = repmat(pj,[1,s2,s3]); ni{j} = nj; cfi{j} = fc; end n{i} = ni; cc{i} = ci; o{i} = oi; p{i} = pi; cf{i} = cfi; end c = set(c,'Magnitude',n,'Chroma',p,'ChromaClass',cc,... 'ChromaFreq',cf,'Register',o); c = modif(c,option,chromascale); c = {c orig}; end function c = modif(c,option,chromascale) if option.plabel c = set(c,'PitchLabel',1); end if option.cen || option.nor || option.wrp n = get(c,'Magnitude'); p = get(c,'Chroma'); cl = get(c,'ChromaClass'); fp = get(c,'FramePos'); n2 = cell(1,length(n)); p2 = cell(1,length(n)); wrp = option.wrp && not(get(c,'Wrap')); for i = 1:length(n) ni = n{i}; pi = p{i}; cli = cl{i}; if not(iscell(ni)) ni = {ni}; pi = {pi}; cli = {cli}; end if wrp c = set(c,'Wrap',option.wrp); end n2i = cell(1,length(ni)); p2i = cell(1,length(ni)); for j = 1:length(ni) nj = ni{j}; pj = pi{j}; clj = cli{j}; if wrp n2j = zeros(option.res,size(nj,2),size(nj,3)); for k = 1:size(pj,1) n2j(clj(k)+1,:,:) = n2j(clj(k)+1,:,:) + nj(k,:,:); % squared sum (parameter) end p2i{j} = chromascale'; else n2j = nj; p2i{j} = pi{j}; end if option.cen n2j = n2j - repmat(mean(n2j),[size(n2j,1),1,1]); end if option.nor n2j = n2j ./ repmat(vectnorm(n2j,option.nor) + ... repmat(1e-6,[1,size(n2j,2),size(n2j,3)] )... ,[size(n2j,1),1,1]); end n2i{j} = n2j; end n2{i} = n2i; p2{i} = p2i; end c = set(c,'Magnitude',n2,'Chroma',p2,'FramePos',fp); end function c = freq2chro(f,res,origin) c = round(res*log2(f/origin)); function f = chro2freq(c,res,origin) f = 2.^(c/res)*origin; function y = vectnorm(x,p) if isinf(p) y = max(x); else y = sum(abs(x).^p).^(1/p); end