To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / _segmentation / segmentation_auto.m
History | View | Annotate | Download (6.58 KB)
| 1 |
function song = segmentation_auto(song, param, varargin) |
|---|---|
| 2 |
|
| 3 |
|
| 4 |
%% calculating similarity matrix |
| 5 |
% exp of minus the cosine distance |
| 6 |
|
| 7 |
if any(strcmp(fieldnames(song.syncchroma),'wide')) |
| 8 |
v = song.syncchroma.wide; |
| 9 |
else |
| 10 |
v = song.syncchroma.treble + song.syncchroma.bass(:,1:12) * 0.8; |
| 11 |
end |
| 12 |
nBeat = song.nBeat; |
| 13 |
flatPCP = std(v')<.000001; |
| 14 |
v(flatPCP,1) = 1000; % arbitrary |
| 15 |
simmat0 = squareform(pdist(v,'correlation')); |
| 16 |
% simmat0(flatPCP,:) = 2; |
| 17 |
% simmat0(:,flatPCP) = 2; |
| 18 |
% simmat = qnormalise(exp(-simmat0),inf,1); |
| 19 |
% simmat(flatPCP,:) = 0; |
| 20 |
% simmat(:,flatPCP) = 0; |
| 21 |
|
| 22 |
simmat0(flatPCP,:) = 1; |
| 23 |
simmat0(:,flatPCP) = 1; |
| 24 |
simmat = 1-simmat0/2; |
| 25 |
simmat(flatPCP,:) = 0; |
| 26 |
simmat(:,flatPCP) = 0; |
| 27 |
|
| 28 |
%% |
| 29 |
median_simmat = zeros(size(simmat)); |
| 30 |
for i = 1:nBeat |
| 31 |
temp1 = diag(medfilt1(diag(simmat,i-1),param.seg.medfilt_length,[],1),i-1); |
| 32 |
median_simmat = median_simmat + temp1; |
| 33 |
end |
| 34 |
median_simmat = median_simmat + median_simmat' - diag(diag(median_simmat)); |
| 35 |
median_simmat(isnan(median_simmat)) = 0; |
| 36 |
%%median_simmat = (median_simmat - mean(median_simmat(:)))/std(median_simmat(:)); |
| 37 |
%%%%%%%% ATTENTION!!!!!!!! using MEDIAN %%%%%%%%%%%%% |
| 38 |
% median_simmat = (median_simmat - median(median_simmat(:)))/std(median_simmat(:)); |
| 39 |
if param.seg.standardise |
| 40 |
med_median_simmat = repmat(median(median_simmat),nBeat,1); |
| 41 |
std_median_simmat = repmat(std(median_simmat),nBeat,1); |
| 42 |
median_simmat = (median_simmat - med_median_simmat) ./ std_median_simmat; |
| 43 |
end |
| 44 |
%% get bar boundaries!!! |
| 45 |
|
| 46 |
potential_duplicates = triu(median_simmat > param.seg.thresh_beat); |
| 47 |
|
| 48 |
%% |
| 49 |
partlengths = param.seg.minlength:4:param.seg.maxlength; |
| 50 |
nPartlengths = length(partlengths); |
| 51 |
|
| 52 |
% initialise arrays |
| 53 |
simArray = zeros(nBeat,nBeat,nPartlengths); |
| 54 |
decisionArray2 = zeros(nBeat,nBeat,nPartlengths); |
| 55 |
|
| 56 |
|
| 57 |
|
| 58 |
fprintf(1,'\n'); |
| 59 |
fprintf(2,' '); |
| 60 |
for iLength = 1:nPartlengths |
| 61 |
len = partlengths(iLength); |
| 62 |
nUsedBeat = nBeat - len + 1; % number of potential rep beginnings: they can't overlap at the end of the song |
| 63 |
fprintf(1,'\rLength: %1.0d',len) |
| 64 |
fprintf(2,'\b\b\b\b%3.0f%%',iLength/nPartlengths*100); |
| 65 |
for iBeat = 1:nUsedBeat % looping over all columns (arbitrarily chosen columns) |
| 66 |
help2 = find(potential_duplicates(1:nUsedBeat,iBeat)); |
| 67 |
for kBeat = help2' % check only potential duplicates |
| 68 |
% measure how well two length len segments go together |
| 69 |
simArray(iBeat,kBeat,iLength) = ... |
| 70 |
quantile(diag(median_simmat(iBeat+(0:len-1),kBeat+(0:len-1))),param.seg.quantile); |
| 71 |
end |
| 72 |
end |
| 73 |
simArray(1:nUsedBeat,1:nUsedBeat,iLength) = simArray(1:nUsedBeat,1:nUsedBeat,iLength) ... |
| 74 |
+ simArray(1:nUsedBeat,1:nUsedBeat,iLength)' ... |
| 75 |
- eye(nUsedBeat) .* simArray(1:nUsedBeat,1:nUsedBeat,iLength); |
| 76 |
|
| 77 |
simArray(:,:,iLength) = conv2(simArray(:,:,iLength),[.01 .98 .01], 'same'); |
| 78 |
% take only over-average bars that do not overlap |
| 79 |
for iBeat = 1:nUsedBeat |
| 80 |
temp = simArray(:,iBeat,iLength) > param.seg.thresh_seg; |
| 81 |
decisionArray2(temp,iBeat,iLength) = ... |
| 82 |
simArray(temp,iBeat,iLength); |
| 83 |
end |
| 84 |
decisionArray2(:,:,iLength) = decisionArray2(:,:,iLength) .* (decisionArray2(:,:,iLength) >= maxfilt1(decisionArray2(:,:,iLength),len-1)); |
| 85 |
decisionArray2(:,:,iLength) = decisionArray2(:,:,iLength) .* decisionArray2(:,:,iLength)'; |
| 86 |
% potential_duplicates = triu(simArray(:,:,iLength) > param.seg.thresh_seg * 0.7); |
| 87 |
potential_duplicates = potential_duplicates .* (simArray(:,:,iLength) > param.seg.thresh_seg); |
| 88 |
end |
| 89 |
%% milk the data |
| 90 |
|
| 91 |
bestvals = []; |
| 92 |
for iLength = 1:nPartlengths |
| 93 |
currLogicSum = sum(decisionArray2(:,:,iLength)>0,2); |
| 94 |
for iBeat = 1:nBeat |
| 95 |
if currLogicSum(iBeat) > 1.0 |
| 96 |
currSum = (mean(decisionArray2(decisionArray2(:,iBeat,iLength)>0,iBeat,iLength)))/2; |
| 97 |
bestvals = [bestvals; (currLogicSum(iBeat)-1) * partlengths(iLength), currSum, iLength, iBeat, currLogicSum(iBeat)]; |
| 98 |
end |
| 99 |
end |
| 100 |
end |
| 101 |
%% |
| 102 |
%% |
| 103 |
% make a table of all valid sets of parts |
| 104 |
partletters = {'A','B','C','D','E','F','G', 'H','I','J','K','L','M','N','O','P','Q','R','S'};
|
| 105 |
valid_sets = ones(1,size(bestvals,1)); |
| 106 |
parts = []; |
| 107 |
if ~isempty(bestvals) |
| 108 |
bestvals(:,2) = bestvals(:,2) / max(bestvals(:,2)*2); |
| 109 |
bestvals(:,1) = bestvals(:,1) + bestvals(:,2); |
| 110 |
bestvals(:,2) = []; |
| 111 |
|
| 112 |
for kSeg = 1:7 |
| 113 |
currbestvals = bestvals(logical(valid_sets),:); |
| 114 |
[m,i] = max(currbestvals(:,1)); |
| 115 |
if isempty(m) |
| 116 |
break |
| 117 |
end |
| 118 |
|
| 119 |
bestLength = partlengths(currbestvals(i,2)); |
| 120 |
bestIndices = decisionArray2(currbestvals(i,3),:,currbestvals(i,2)); |
| 121 |
islands = conv2(1*(bestIndices > 0), [zeros(1,bestLength-1) ones(1,bestLength)], 'same'); |
| 122 |
%% |
| 123 |
if param.seg.newcheck |
| 124 |
iBetter = i; |
| 125 |
bestSubval = 0; |
| 126 |
subm1 = find(currbestvals(:,4) > currbestvals(i,4)); % has to have more part instances |
| 127 |
for kSub = 1:length(subm1) |
| 128 |
iSub = subm1(kSub); |
| 129 |
subIndices = decisionArray2(currbestvals(iSub,3),:,currbestvals(iSub,2)); |
| 130 |
subLength = partlengths(currbestvals(iSub,2)); |
| 131 |
subIslands = conv2(1*(subIndices > 0), [zeros(1,subLength-1) ones(1,subLength)], 'same'); |
| 132 |
if sum(islands.*subIslands) == currbestvals(i,4) * subLength ... |
| 133 |
&& currbestvals(iSub,1) > bestSubval |
| 134 |
iBetter = iSub; |
| 135 |
bestSubval = currbestvals(iSub,1); |
| 136 |
end |
| 137 |
end |
| 138 |
i = iBetter; |
| 139 |
bestLength = partlengths(currbestvals(i,2)); |
| 140 |
bestIndices = decisionArray2(currbestvals(i,3),:,currbestvals(i,2)); |
| 141 |
islands = conv2(1*(bestIndices > 0), [zeros(1,bestLength-1) ones(1,bestLength)], 'same'); |
| 142 |
end |
| 143 |
%% |
| 144 |
part.n = bestLength; |
| 145 |
part.indices = find(bestIndices); |
| 146 |
part.letter = partletters{kSeg};
|
| 147 |
part.level = kSeg; |
| 148 |
parts = [parts part]; |
| 149 |
|
| 150 |
for iSet = find(valid_sets) |
| 151 |
currislands = conv2(2*(decisionArray2(bestvals(iSet,3),:,bestvals(iSet,2)) > 0), ... |
| 152 |
[zeros(1,partlengths(bestvals(iSet,2))-1) ones(1,partlengths(bestvals(iSet,2)))], 'same'); |
| 153 |
if any(islands .* currislands > 0) |
| 154 |
valid_sets(iSet) = false; |
| 155 |
else |
| 156 |
% stem(islands+currislands*.5) |
| 157 |
% aaa = 1; |
| 158 |
end |
| 159 |
end |
| 160 |
end |
| 161 |
else |
| 162 |
part.n = nBeat; |
| 163 |
part.indices = 1; |
| 164 |
part.letter = 'A'; |
| 165 |
part.level = 1; |
| 166 |
parts = [parts part]; |
| 167 |
end |
| 168 |
|
| 169 |
parts = [parts, nullpart(parts,1:nBeat)]; |
| 170 |
if param.seg.editor |
| 171 |
[pa, ta] = partarray(parts); |
| 172 |
parts = editorssearch(pa, ta, parts); |
| 173 |
parts = [parts, nullpart(parts,1:nBeat)]; |
| 174 |
end |
| 175 |
parts = mergenulls(parts); |
| 176 |
|
| 177 |
song.parts = parts; |
| 178 |
% song.parts |
| 179 |
|
| 180 |
|