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