matthiasm@8: function song = segmentation_auto(song, param, varargin) matthiasm@8: matthiasm@8: matthiasm@8: %% calculating similarity matrix matthiasm@8: % exp of minus the cosine distance matthiasm@8: matthiasm@8: if any(strcmp(fieldnames(song.syncchroma),'wide')) matthiasm@8: v = song.syncchroma.wide; matthiasm@8: else matthiasm@8: v = song.syncchroma.treble + song.syncchroma.bass(:,1:12) * 0.8; matthiasm@8: end matthiasm@8: nBeat = song.nBeat; matthiasm@8: flatPCP = std(v')<.000001; matthiasm@8: v(flatPCP,1) = 1000; % arbitrary matthiasm@8: simmat0 = squareform(pdist(v,'correlation')); matthiasm@8: % simmat0(flatPCP,:) = 2; matthiasm@8: % simmat0(:,flatPCP) = 2; matthiasm@8: % simmat = qnormalise(exp(-simmat0),inf,1); matthiasm@8: % simmat(flatPCP,:) = 0; matthiasm@8: % simmat(:,flatPCP) = 0; matthiasm@8: matthiasm@8: simmat0(flatPCP,:) = 1; matthiasm@8: simmat0(:,flatPCP) = 1; matthiasm@8: simmat = 1-simmat0/2; matthiasm@8: simmat(flatPCP,:) = 0; matthiasm@8: simmat(:,flatPCP) = 0; matthiasm@8: matthiasm@8: %% matthiasm@8: median_simmat = zeros(size(simmat)); matthiasm@8: for i = 1:nBeat matthiasm@8: temp1 = diag(medfilt1(diag(simmat,i-1),param.seg.medfilt_length,[],1),i-1); matthiasm@8: median_simmat = median_simmat + temp1; matthiasm@8: end matthiasm@8: median_simmat = median_simmat + median_simmat' - diag(diag(median_simmat)); matthiasm@8: median_simmat(isnan(median_simmat)) = 0; matthiasm@8: %%median_simmat = (median_simmat - mean(median_simmat(:)))/std(median_simmat(:)); matthiasm@8: %%%%%%%% ATTENTION!!!!!!!! using MEDIAN %%%%%%%%%%%%% matthiasm@8: % median_simmat = (median_simmat - median(median_simmat(:)))/std(median_simmat(:)); matthiasm@8: if param.seg.standardise matthiasm@8: med_median_simmat = repmat(median(median_simmat),nBeat,1); matthiasm@8: std_median_simmat = repmat(std(median_simmat),nBeat,1); matthiasm@8: median_simmat = (median_simmat - med_median_simmat) ./ std_median_simmat; matthiasm@8: end matthiasm@8: %% get bar boundaries!!! matthiasm@8: matthiasm@8: potential_duplicates = triu(median_simmat > param.seg.thresh_beat); matthiasm@8: matthiasm@8: %% matthiasm@8: partlengths = param.seg.minlength:4:param.seg.maxlength; matthiasm@8: nPartlengths = length(partlengths); matthiasm@8: matthiasm@8: % initialise arrays matthiasm@8: simArray = zeros(nBeat,nBeat,nPartlengths); matthiasm@8: decisionArray2 = zeros(nBeat,nBeat,nPartlengths); matthiasm@8: matthiasm@8: matthiasm@8: matthiasm@8: fprintf(1,'\n'); matthiasm@8: fprintf(2,' '); matthiasm@8: for iLength = 1:nPartlengths matthiasm@8: len = partlengths(iLength); matthiasm@8: nUsedBeat = nBeat - len + 1; % number of potential rep beginnings: they can't overlap at the end of the song matthiasm@8: fprintf(1,'\rLength: %1.0d',len) matthiasm@8: fprintf(2,'\b\b\b\b%3.0f%%',iLength/nPartlengths*100); matthiasm@8: for iBeat = 1:nUsedBeat % looping over all columns (arbitrarily chosen columns) matthiasm@8: help2 = find(potential_duplicates(1:nUsedBeat,iBeat)); matthiasm@8: for kBeat = help2' % check only potential duplicates matthiasm@8: % measure how well two length len segments go together matthiasm@8: simArray(iBeat,kBeat,iLength) = ... matthiasm@8: quantile(diag(median_simmat(iBeat+(0:len-1),kBeat+(0:len-1))),param.seg.quantile); matthiasm@8: end matthiasm@8: end matthiasm@8: simArray(1:nUsedBeat,1:nUsedBeat,iLength) = simArray(1:nUsedBeat,1:nUsedBeat,iLength) ... matthiasm@8: + simArray(1:nUsedBeat,1:nUsedBeat,iLength)' ... matthiasm@8: - eye(nUsedBeat) .* simArray(1:nUsedBeat,1:nUsedBeat,iLength); matthiasm@8: matthiasm@8: simArray(:,:,iLength) = conv2(simArray(:,:,iLength),[.01 .98 .01], 'same'); matthiasm@8: % take only over-average bars that do not overlap matthiasm@8: for iBeat = 1:nUsedBeat matthiasm@8: temp = simArray(:,iBeat,iLength) > param.seg.thresh_seg; matthiasm@8: decisionArray2(temp,iBeat,iLength) = ... matthiasm@8: simArray(temp,iBeat,iLength); matthiasm@8: end matthiasm@8: decisionArray2(:,:,iLength) = decisionArray2(:,:,iLength) .* (decisionArray2(:,:,iLength) >= maxfilt1(decisionArray2(:,:,iLength),len-1)); matthiasm@8: decisionArray2(:,:,iLength) = decisionArray2(:,:,iLength) .* decisionArray2(:,:,iLength)'; matthiasm@8: % potential_duplicates = triu(simArray(:,:,iLength) > param.seg.thresh_seg * 0.7); matthiasm@8: potential_duplicates = potential_duplicates .* (simArray(:,:,iLength) > param.seg.thresh_seg); matthiasm@8: end matthiasm@8: %% milk the data matthiasm@8: matthiasm@8: bestvals = []; matthiasm@8: for iLength = 1:nPartlengths matthiasm@8: currLogicSum = sum(decisionArray2(:,:,iLength)>0,2); matthiasm@8: for iBeat = 1:nBeat matthiasm@8: if currLogicSum(iBeat) > 1.0 matthiasm@8: currSum = (mean(decisionArray2(decisionArray2(:,iBeat,iLength)>0,iBeat,iLength)))/2; matthiasm@8: bestvals = [bestvals; (currLogicSum(iBeat)-1) * partlengths(iLength), currSum, iLength, iBeat, currLogicSum(iBeat)]; matthiasm@8: end matthiasm@8: end matthiasm@8: end matthiasm@8: %% matthiasm@8: %% matthiasm@8: % make a table of all valid sets of parts matthiasm@8: partletters = {'A','B','C','D','E','F','G', 'H','I','J','K','L','M','N','O','P','Q','R','S'}; matthiasm@8: valid_sets = ones(1,size(bestvals,1)); matthiasm@8: parts = []; matthiasm@8: if ~isempty(bestvals) matthiasm@8: bestvals(:,2) = bestvals(:,2) / max(bestvals(:,2)*2); matthiasm@8: bestvals(:,1) = bestvals(:,1) + bestvals(:,2); matthiasm@8: bestvals(:,2) = []; matthiasm@8: matthiasm@8: for kSeg = 1:7 matthiasm@8: currbestvals = bestvals(logical(valid_sets),:); matthiasm@8: [m,i] = max(currbestvals(:,1)); matthiasm@8: if isempty(m) matthiasm@8: break matthiasm@8: end matthiasm@8: matthiasm@8: bestLength = partlengths(currbestvals(i,2)); matthiasm@8: bestIndices = decisionArray2(currbestvals(i,3),:,currbestvals(i,2)); matthiasm@8: islands = conv2(1*(bestIndices > 0), [zeros(1,bestLength-1) ones(1,bestLength)], 'same'); matthiasm@8: %% matthiasm@8: if param.seg.newcheck matthiasm@8: iBetter = i; matthiasm@8: bestSubval = 0; matthiasm@8: subm1 = find(currbestvals(:,4) > currbestvals(i,4)); % has to have more part instances matthiasm@8: for kSub = 1:length(subm1) matthiasm@8: iSub = subm1(kSub); matthiasm@8: subIndices = decisionArray2(currbestvals(iSub,3),:,currbestvals(iSub,2)); matthiasm@8: subLength = partlengths(currbestvals(iSub,2)); matthiasm@8: subIslands = conv2(1*(subIndices > 0), [zeros(1,subLength-1) ones(1,subLength)], 'same'); matthiasm@8: if sum(islands.*subIslands) == currbestvals(i,4) * subLength ... matthiasm@8: && currbestvals(iSub,1) > bestSubval matthiasm@8: iBetter = iSub; matthiasm@8: bestSubval = currbestvals(iSub,1); matthiasm@8: end matthiasm@8: end matthiasm@8: i = iBetter; matthiasm@8: bestLength = partlengths(currbestvals(i,2)); matthiasm@8: bestIndices = decisionArray2(currbestvals(i,3),:,currbestvals(i,2)); matthiasm@8: islands = conv2(1*(bestIndices > 0), [zeros(1,bestLength-1) ones(1,bestLength)], 'same'); matthiasm@8: end matthiasm@8: %% matthiasm@8: part.n = bestLength; matthiasm@8: part.indices = find(bestIndices); matthiasm@8: part.letter = partletters{kSeg}; matthiasm@8: part.level = kSeg; matthiasm@8: parts = [parts part]; matthiasm@8: matthiasm@8: for iSet = find(valid_sets) matthiasm@8: currislands = conv2(2*(decisionArray2(bestvals(iSet,3),:,bestvals(iSet,2)) > 0), ... matthiasm@8: [zeros(1,partlengths(bestvals(iSet,2))-1) ones(1,partlengths(bestvals(iSet,2)))], 'same'); matthiasm@8: if any(islands .* currislands > 0) matthiasm@8: valid_sets(iSet) = false; matthiasm@8: else matthiasm@8: % stem(islands+currislands*.5) matthiasm@8: % aaa = 1; matthiasm@8: end matthiasm@8: end matthiasm@8: end matthiasm@8: else matthiasm@8: part.n = nBeat; matthiasm@8: part.indices = 1; matthiasm@8: part.letter = 'A'; matthiasm@8: part.level = 1; matthiasm@8: parts = [parts part]; matthiasm@8: end matthiasm@8: matthiasm@8: parts = [parts, nullpart(parts,1:nBeat)]; matthiasm@8: if param.seg.editor matthiasm@8: [pa, ta] = partarray(parts); matthiasm@8: parts = editorssearch(pa, ta, parts); matthiasm@8: parts = [parts, nullpart(parts,1:nBeat)]; matthiasm@8: end matthiasm@8: parts = mergenulls(parts); matthiasm@8: matthiasm@8: song.parts = parts; matthiasm@8: % song.parts matthiasm@8: matthiasm@8: