mathieu@14
|
1 function [w,sceneSchedule] = generateScene (sceneSchedule,sceneObjects,score,inputPath,outputPath,outputFileName,displayFigures,timeMode,endCut)
|
mathieu@14
|
2 % function [w,sceneSchedule] = generateScene (sceneSchedule,sceneObjects,score,inputPath,outputPath,outputFileName,displayFigures,timeMode,endCut)
|
mathieu@14
|
3 % This function does the actual job of loading, scaling, positioning and
|
mathieu@14
|
4 % mixing the various samples to generate a scene, based on the
|
mathieu@14
|
5 % specifications given by its parameters.
|
mathieu@14
|
6
|
mathieu@14
|
7 % This program was written by Mathias Rossignol & Grégoire Lafay
|
mathieu@14
|
8 % is Copyright (C) 2015 IRCAM <http://www.ircam.fr>
|
mathieu@14
|
9 %
|
mathieu@14
|
10 % This program is free software: you can redistribute it and/or modify it
|
mathieu@14
|
11 % under the terms of the GNU General Public License as published by the Free
|
mathieu@14
|
12 % Software Foundation, either version 3 of the License, or (at your option)
|
mathieu@14
|
13 % any later version.
|
mathieu@14
|
14 %
|
mathieu@14
|
15 % This program is distributed in the hope that it will be useful, but
|
mathieu@14
|
16 % WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
mathieu@14
|
17 % or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
mathieu@14
|
18 % for more details.
|
mathieu@14
|
19 %
|
mathieu@14
|
20 % You should have received a copy of the GNU General Public License along
|
mathieu@14
|
21 % with this program. If not, see <http://www.gnu.org/licenses/>.
|
mathieu@14
|
22
|
mathieu@14
|
23 sr = 44100;
|
mathieu@14
|
24 trackLength = sr*score.sceneDuration;
|
mathieu@14
|
25 nbTracks = length(sceneObjects);
|
mathieu@14
|
26
|
mathieu@14
|
27 % All instances of one sample will appear on a given track, before
|
mathieu@14
|
28 % everything is mixed together, making it possible to apply track-specific
|
mathieu@14
|
29 % effects or generate nice colorful representations
|
mathieu@14
|
30 tracks = zeros(length(sceneObjects), trackLength);
|
mathieu@14
|
31
|
mathieu@14
|
32 % We also generate a "bg" track with all background samples, against which
|
mathieu@14
|
33 % the snr of fg sounds will be evaluated
|
mathieu@14
|
34 bg = zeros(trackLength, 1);
|
mathieu@14
|
35
|
mathieu@14
|
36 %% Preloading all wav samples into memory
|
mathieu@14
|
37 waves = {};
|
mathieu@14
|
38 for i=1:nbTracks
|
mathieu@14
|
39 if(sceneObjects(i).isBackground)
|
mathieu@14
|
40 path = [inputPath,'background/'];
|
mathieu@14
|
41 else
|
mathieu@14
|
42 path = [inputPath,'event/'];
|
mathieu@14
|
43 end
|
mathieu@14
|
44 sample = dir([path '*wav']);
|
mathieu@14
|
45 sampleId = find(cellfun('isempty',regexpi({sample.name},sceneObjects(i).query,'match'))==0);
|
mathieu@14
|
46 for j=1:length(sampleId)
|
mathieu@14
|
47 % this test is necessary because mp3 conversion does not
|
mathieu@14
|
48 % always maintain exact length, and wavread will crash if asked to
|
mathieu@14
|
49 % read too many samples.
|
mathieu@14
|
50 waves{i}{j}= wavread([path sample(sampleId(j)).name]);
|
mathieu@14
|
51 if(size(waves{i}{j},2)==2)
|
mathieu@14
|
52 waves{i}{j}= mean(waves{i}{j},2);
|
mathieu@14
|
53 end
|
mathieu@14
|
54 waves{i}{j} = waves{i}{j}(:);
|
mathieu@14
|
55 end
|
mathieu@14
|
56 end
|
mathieu@14
|
57
|
mathieu@14
|
58 dominantTrack = zeros(1,trackLength) + 1;
|
mathieu@14
|
59 dominantObject = zeros(1,trackLength) + 1;
|
mathieu@14
|
60 dominantEnergy = zeros(1,trackLength);
|
mathieu@14
|
61 simulatedEBR = zeros(length(sceneSchedule),2);
|
mathieu@14
|
62 objNum = 1;
|
mathieu@14
|
63
|
mathieu@14
|
64 %% Create sceneSchedule
|
mathieu@14
|
65 id2remove=[];
|
mathieu@14
|
66 for i=1:length(sceneSchedule)
|
mathieu@14
|
67 id = sceneSchedule(i).classId;
|
mathieu@14
|
68 if (sceneSchedule(i).isBackground)
|
mathieu@14
|
69 scale = 1;
|
mathieu@14
|
70 if (i>1)
|
mathieu@14
|
71 scale = adjustScaleForEBR(waves{id}{1}, bg, 1, sceneSchedule(i).ebr, 1, 0.01);
|
mathieu@14
|
72 end
|
mathieu@14
|
73 if (length(waves{id}{1}) < trackLength)
|
mathieu@14
|
74 % need to loop the sample to fill the bg. Linear crossfade
|
mathieu@14
|
75 loop = waves{id}{1};
|
mathieu@14
|
76 fadeLen = 20000;
|
mathieu@14
|
77 fadeIn = transpose(0:1/fadeLen:1);
|
mathieu@14
|
78 fadeOut = transpose(1:-1/fadeLen:0);
|
mathieu@14
|
79 loop(1:fadeLen) = loop(1:fadeLen) .* fadeIn(1:fadeLen);
|
mathieu@14
|
80 loop(length(loop)-fadeLen+1:length(loop)) = loop(length(loop)+1-fadeLen:length(loop)) .* fadeOut(1:fadeLen);
|
mathieu@14
|
81 loop = scale * loop.';
|
mathieu@14
|
82 for l=0:floor(trackLength/(length(loop)-fadeLen))
|
mathieu@14
|
83 t1 = 1+l*(length(loop)-fadeLen);
|
mathieu@14
|
84 t2 = min(length(bg), t1+length(loop)-1);
|
mathieu@14
|
85 tracks(id,t1:t2) = tracks(id,t1:t2) + loop(1:t2-t1+1);
|
mathieu@14
|
86 end
|
mathieu@14
|
87 else
|
mathieu@14
|
88 dim = min(trackLength, length(waves{id}{1}));
|
mathieu@14
|
89 tracks(id,1:dim) = tracks(id,1:dim) + scale*(waves{id}{1}(1:dim).');
|
mathieu@14
|
90 end
|
mathieu@14
|
91 if (i==1)
|
mathieu@14
|
92 bg = tracks(id,:);
|
mathieu@14
|
93 else
|
mathieu@14
|
94 bg = bg+tracks(id,:);
|
mathieu@14
|
95 end
|
mathieu@14
|
96 else
|
mathieu@14
|
97 objNum = objNum+1;
|
mathieu@14
|
98 inst = sceneSchedule(i).instance;
|
mathieu@14
|
99 pos = max(1,floor(sr*sceneSchedule(i).position));
|
mathieu@14
|
100
|
mathieu@14
|
101 switch timeMode
|
mathieu@14
|
102 case {'replicate'}
|
mathieu@14
|
103 if(length(waves{id}{inst})/sr - sceneSchedule(i).duration > 0.5)
|
mathieu@14
|
104 endTime = round(sceneSchedule(i).duration*sr);
|
mathieu@14
|
105 else
|
mathieu@14
|
106 endTime = length(waves{id}{inst});
|
mathieu@14
|
107 end
|
mathieu@14
|
108 case {'abstract'}
|
mathieu@14
|
109 endTime = round(sceneSchedule(i).duration*sr);
|
mathieu@14
|
110 otherwise
|
mathieu@14
|
111 endTime = length(waves{id}{inst});
|
mathieu@14
|
112 end
|
mathieu@14
|
113
|
mathieu@14
|
114 if endCut
|
mathieu@14
|
115 pos2Test=pos;
|
mathieu@14
|
116 else
|
mathieu@14
|
117
|
mathieu@14
|
118 pos2Test=pos+endTime-1;
|
mathieu@14
|
119 end
|
mathieu@14
|
120
|
mathieu@14
|
121 if(pos2Test<round(sceneObjects(sceneSchedule(i).classId).trackLength*sr))
|
mathieu@14
|
122 t2 = min(pos+endTime-1, round(sceneObjects(sceneSchedule(i).classId).trackLength*sr));
|
mathieu@14
|
123 wav2use=waves{id}{inst}(1:t2-pos+1);
|
mathieu@14
|
124 sceneSchedule(i).duration=length(wav2use)/sr;
|
mathieu@14
|
125 scale = adjustScaleForEBR(wav2use, bg, pos, sceneSchedule(i).ebr, 1, 0.01);
|
mathieu@14
|
126
|
mathieu@14
|
127 [~,bgEnergy] = powspec(bg(pos:t2));
|
mathieu@14
|
128 [~,evEnergy] = powspec(scale*wav2use.');
|
mathieu@14
|
129 labelStart = min(find(bgEnergy<evEnergy));
|
mathieu@14
|
130 labelEnd = max(find(bgEnergy<evEnergy));
|
mathieu@14
|
131 for t=labelStart:labelEnd
|
mathieu@14
|
132 if evEnergy(t)>dominantEnergy(pos+t)
|
mathieu@14
|
133 dominantObject(pos+round(t*(t2-pos)/length(bgEnergy))) = objNum;
|
mathieu@14
|
134 dominantEnergy(pos+round(t*(t2-pos)/length(bgEnergy))) = evEnergy(t);
|
mathieu@14
|
135 end
|
mathieu@14
|
136 end
|
mathieu@14
|
137 dominantObject(min(find(dominantObject==objNum)):max(find(dominantObject==objNum))) = objNum;
|
mathieu@14
|
138 dominantTrack(dominantObject==objNum) = id;
|
mathieu@14
|
139
|
mathieu@14
|
140 tracks(id, pos:t2) = tracks(id, pos:t2) + scale*wav2use.';
|
mathieu@14
|
141 %% Store EBR and event locations
|
mathieu@14
|
142 simulatedEBR(i,1) = ebr(tracks(id, pos:t2),tracks(1, pos:t2));
|
mathieu@14
|
143 simulatedEBR(i,2)=pos;
|
mathieu@14
|
144 else
|
mathieu@14
|
145 id2remove=[id2remove i];
|
mathieu@14
|
146 end
|
mathieu@14
|
147 end
|
mathieu@14
|
148 end
|
mathieu@14
|
149
|
mathieu@14
|
150 sceneSchedule(id2remove)=[];
|
mathieu@14
|
151 % checkClassPresence(sceneSchedule,sceneObjects);
|
mathieu@14
|
152
|
mathieu@14
|
153 save ([outputPath 'annotation/' outputFileName '.mat'],'score', 'sceneObjects', 'sceneSchedule','dominantTrack', 'dominantObject','simulatedEBR');
|
mathieu@14
|
154 saveAnnotationTxt(sceneSchedule,outputPath,outputFileName);
|
mathieu@14
|
155
|
mathieu@14
|
156 w = sum(tracks);
|
mathieu@14
|
157 w = w/(max(abs(w))+0.001); %Normalize to [-1,1]
|
mathieu@14
|
158
|
mathieu@14
|
159 if displayFigures
|
mathieu@14
|
160 cmap = generateColormap(sceneObjects);
|
mathieu@14
|
161
|
mathieu@14
|
162 timeDomainVisualization(tracks, cmap, 1, 10000, 1, [outputPath 'annotation/' outputFileName,'-timeDomain.png']);
|
mathieu@14
|
163
|
mathieu@14
|
164 % Producing a colored spectrum visualization
|
mathieu@14
|
165 for i=1:nbTracks
|
mathieu@14
|
166 spec = log(1+abs(spectrogram(tracks(i,:), hanning(2048), 1024, 2048)));
|
mathieu@14
|
167 spec = min(1, spec ./ max(spec(:)));
|
mathieu@14
|
168 spec = spec(1:400,:);
|
mathieu@14
|
169 spec = flipud(spec);
|
mathieu@14
|
170 for colorComp=1:3
|
mathieu@14
|
171 if (i==1)
|
mathieu@14
|
172 img(:,:,colorComp) = cmap(i,colorComp)*spec;
|
mathieu@14
|
173 else
|
mathieu@14
|
174 img(:,:,colorComp) = img(:,:,colorComp)+cmap(i,colorComp)*spec;
|
mathieu@14
|
175 end
|
mathieu@14
|
176 end
|
mathieu@14
|
177 end
|
mathieu@14
|
178 img = img/max(img(:));
|
mathieu@14
|
179 f = figure(2);
|
mathieu@14
|
180 clf;
|
mathieu@14
|
181 set(gca,'YTick', []);
|
mathieu@14
|
182 set(f, 'Position', [0, 0, 2*size(img,1), 600]);
|
mathieu@14
|
183 imagesc(img);
|
mathieu@14
|
184 imwrite(img, [outputPath 'annotation/' outputFileName,'-spectrum.png'], 'png');
|
mathieu@14
|
185
|
mathieu@14
|
186
|
mathieu@14
|
187 %% Producing a "piano roll" visualization
|
mathieu@14
|
188 f = figure(3);
|
mathieu@14
|
189 clf;
|
mathieu@14
|
190 set(gca,'YTick', []);
|
mathieu@14
|
191 grid on;
|
mathieu@14
|
192 set(f, 'Position', [0, 0, trackLength/512, 300]);
|
mathieu@14
|
193 for i=1:length(sceneObjects)
|
mathieu@14
|
194 text(0, i+.4, [num2str(sceneObjects(i).classLabel), ' '], 'HorizontalAlignment', 'right');
|
mathieu@14
|
195 end
|
mathieu@14
|
196
|
mathieu@14
|
197 for i=1:length(sceneSchedule)
|
mathieu@14
|
198 id = sceneSchedule(i).classId;
|
mathieu@14
|
199 if (sceneSchedule(i).isBackground)
|
mathieu@14
|
200 rectangle('Position', [0, id+.2, score.sceneDuration, .6], 'FaceColor', cmap(id,:));
|
mathieu@14
|
201 else
|
mathieu@14
|
202 t1 = sceneSchedule(i).position;
|
mathieu@14
|
203 rectangle('Position', [t1, id+.1, sceneSchedule(i).duration, .8], 'FaceColor', cmap(id,:));
|
mathieu@14
|
204 end
|
mathieu@14
|
205 end
|
mathieu@14
|
206 set(f, 'PaperPositionMode', 'auto');
|
mathieu@14
|
207 print ('-dpng', '-r150', [outputPath 'annotation/' outputFileName,'-piano_roll.png']);
|
mathieu@14
|
208 end
|
mathieu@14
|
209 end
|