gregoirelafay@17
|
1 function [sceneSchedule] = generateScene (sceneSchedule,sceneObjects,score,inputPath,outputPath,outputFileName,figuresOption,timeMode,endCut,norm,sr,channelOption)
|
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
|
gregoire@16
|
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
|
mathieu@14
|
24 % All instances of one sample will appear on a given track, before
|
mathieu@14
|
25 % everything is mixed together, making it possible to apply track-specific
|
mathieu@14
|
26 % effects or generate nice colorful representations
|
gregoire@16
|
27
|
mathieu@14
|
28
|
mathieu@14
|
29 % We also generate a "bg" track with all background samples, against which
|
mathieu@14
|
30 % the snr of fg sounds will be evaluated
|
gregoire@16
|
31
|
gregoire@16
|
32 %% Init tab
|
gregoire@16
|
33
|
gregoire@16
|
34 trackLength = sr*score.sceneDuration;
|
gregoire@16
|
35
|
gregoire@16
|
36 tracks = zeros(length(sceneObjects), trackLength);
|
mathieu@14
|
37 bg = zeros(trackLength, 1);
|
mathieu@14
|
38
|
mathieu@14
|
39 dominantTrack = zeros(1,trackLength) + 1;
|
mathieu@14
|
40 dominantObject = zeros(1,trackLength) + 1;
|
mathieu@14
|
41 dominantEnergy = zeros(1,trackLength);
|
mathieu@14
|
42 simulatedEBR = zeros(length(sceneSchedule),2);
|
mathieu@14
|
43 objNum = 1;
|
mathieu@14
|
44
|
mathieu@14
|
45 %% Create sceneSchedule
|
mathieu@14
|
46 id2remove=[];
|
mathieu@14
|
47 for i=1:length(sceneSchedule)
|
mathieu@14
|
48 id = sceneSchedule(i).classId;
|
mathieu@14
|
49 if (sceneSchedule(i).isBackground)
|
gregoire@24
|
50 if strcmp(sceneObjects(i).classLabel,'noise')
|
gregoire@24
|
51 waves=score.backgrounds{1}{2}';
|
gregoire@24
|
52 else
|
gregoire@24
|
53 waves = audioread([inputPath 'background/' sceneObjects(id).names{1}]);
|
gregoire@24
|
54 [MinSizeWaves,indMinSizeWaves]=min(size(waves));
|
gregoire@24
|
55 if MinSizeWaves==2
|
gregoire@24
|
56 waves=mean(waves,indMinSizeWaves);
|
gregoire@24
|
57 end
|
gregoire@23
|
58 end
|
mathieu@14
|
59 scale = 1;
|
mathieu@14
|
60 if (i>1)
|
gregoire@16
|
61 scale = adjustScaleForEBR(waves, bg, 1, sceneSchedule(i).ebr, 1, 0.01);
|
mathieu@14
|
62 end
|
gregoire@16
|
63 if (length(waves) < trackLength)
|
mathieu@14
|
64 % need to loop the sample to fill the bg. Linear crossfade
|
gregoire@19
|
65 fadeLen = sr;
|
mathieu@14
|
66 fadeIn = transpose(0:1/fadeLen:1);
|
mathieu@14
|
67 fadeOut = transpose(1:-1/fadeLen:0);
|
gregoire@19
|
68 loop = waves;
|
mathieu@14
|
69 loop(1:fadeLen) = loop(1:fadeLen) .* fadeIn(1:fadeLen);
|
mathieu@14
|
70 loop(length(loop)-fadeLen+1:length(loop)) = loop(length(loop)+1-fadeLen:length(loop)) .* fadeOut(1:fadeLen);
|
gregoire@19
|
71 loop = scale * loop';
|
gregoire@19
|
72 startLoop=waves;
|
gregoire@19
|
73 startLoop(length(startLoop)-fadeLen+1:length(startLoop)) = startLoop(length(startLoop)+1-fadeLen:length(startLoop)) .* fadeOut(1:fadeLen);
|
gregoire@19
|
74 startLoop = scale * startLoop';
|
mathieu@14
|
75 for l=0:floor(trackLength/(length(loop)-fadeLen))
|
mathieu@14
|
76 t1 = 1+l*(length(loop)-fadeLen);
|
mathieu@14
|
77 t2 = min(length(bg), t1+length(loop)-1);
|
gregoire@19
|
78 if l
|
gregoire@19
|
79 tracks(id,t1:t2) = tracks(id,t1:t2) + loop(1:t2-t1+1);
|
gregoire@19
|
80 else
|
gregoire@19
|
81 tracks(id,t1:t2) = tracks(id,t1:t2) + startLoop(1:t2-t1+1);
|
gregoire@19
|
82 end
|
mathieu@14
|
83 end
|
mathieu@14
|
84 else
|
gregoire@16
|
85 dim = min(trackLength, length(waves));
|
gregoire@19
|
86 tracks(id,1:dim) = tracks(id,1:dim) + scale*waves(1:dim)';
|
mathieu@14
|
87 end
|
mathieu@14
|
88 if (i==1)
|
mathieu@14
|
89 bg = tracks(id,:);
|
mathieu@14
|
90 else
|
mathieu@14
|
91 bg = bg+tracks(id,:);
|
mathieu@14
|
92 end
|
mathieu@14
|
93 else
|
mathieu@14
|
94 objNum = objNum+1;
|
mathieu@14
|
95 inst = sceneSchedule(i).instance;
|
gregoire@16
|
96 waves = audioread([inputPath 'event/' sceneObjects(id).names{inst}]);
|
gregoire@23
|
97 [MinSizeWaves,indMinSizeWaves]=min(size(waves));
|
gregoire@23
|
98 if MinSizeWaves==2
|
gregoire@23
|
99 waves=mean(waves,indMinSizeWaves);
|
gregoire@23
|
100 end
|
mathieu@14
|
101 pos = max(1,floor(sr*sceneSchedule(i).position));
|
mathieu@14
|
102
|
mathieu@14
|
103 switch timeMode
|
mathieu@14
|
104 case {'replicate'}
|
gregoire@16
|
105 if(length(waves)/sr - sceneSchedule(i).duration > 0.5)
|
mathieu@14
|
106 endTime = round(sceneSchedule(i).duration*sr);
|
mathieu@14
|
107 else
|
gregoire@16
|
108 endTime = length(waves);
|
mathieu@14
|
109 end
|
mathieu@14
|
110 case {'abstract'}
|
mathieu@14
|
111 endTime = round(sceneSchedule(i).duration*sr);
|
mathieu@14
|
112 otherwise
|
gregoire@16
|
113 endTime = length(waves);
|
mathieu@14
|
114 end
|
gregoire@16
|
115
|
mathieu@14
|
116 if endCut
|
gregoire@16
|
117 pos2Test=pos;
|
mathieu@14
|
118 else
|
mathieu@14
|
119
|
gregoire@16
|
120 pos2Test=pos+endTime-1;
|
mathieu@14
|
121 end
|
mathieu@14
|
122
|
mathieu@14
|
123 if(pos2Test<round(sceneObjects(sceneSchedule(i).classId).trackLength*sr))
|
mathieu@14
|
124 t2 = min(pos+endTime-1, round(sceneObjects(sceneSchedule(i).classId).trackLength*sr));
|
gregoire@16
|
125 wav2use=waves(1:t2-pos+1);
|
mathieu@14
|
126 sceneSchedule(i).duration=length(wav2use)/sr;
|
mathieu@14
|
127 scale = adjustScaleForEBR(wav2use, bg, pos, sceneSchedule(i).ebr, 1, 0.01);
|
mathieu@14
|
128
|
mathieu@14
|
129 [~,bgEnergy] = powspec(bg(pos:t2));
|
mathieu@14
|
130 [~,evEnergy] = powspec(scale*wav2use.');
|
mathieu@14
|
131 labelStart = min(find(bgEnergy<evEnergy));
|
mathieu@14
|
132 labelEnd = max(find(bgEnergy<evEnergy));
|
mathieu@14
|
133 for t=labelStart:labelEnd
|
mathieu@14
|
134 if evEnergy(t)>dominantEnergy(pos+t)
|
mathieu@14
|
135 dominantObject(pos+round(t*(t2-pos)/length(bgEnergy))) = objNum;
|
mathieu@14
|
136 dominantEnergy(pos+round(t*(t2-pos)/length(bgEnergy))) = evEnergy(t);
|
mathieu@14
|
137 end
|
mathieu@14
|
138 end
|
mathieu@14
|
139 dominantObject(min(find(dominantObject==objNum)):max(find(dominantObject==objNum))) = objNum;
|
mathieu@14
|
140 dominantTrack(dominantObject==objNum) = id;
|
mathieu@14
|
141
|
mathieu@14
|
142 tracks(id, pos:t2) = tracks(id, pos:t2) + scale*wav2use.';
|
mathieu@14
|
143 %% Store EBR and event locations
|
mathieu@14
|
144 simulatedEBR(i,1) = ebr(tracks(id, pos:t2),tracks(1, pos:t2));
|
mathieu@14
|
145 simulatedEBR(i,2)=pos;
|
mathieu@14
|
146 else
|
mathieu@14
|
147 id2remove=[id2remove i];
|
mathieu@14
|
148 end
|
mathieu@14
|
149 end
|
mathieu@14
|
150 end
|
mathieu@14
|
151
|
mathieu@14
|
152 sceneSchedule(id2remove)=[];
|
mathieu@14
|
153 % checkClassPresence(sceneSchedule,sceneObjects);
|
mathieu@14
|
154
|
mathieu@31
|
155
|
mathieu@14
|
156 save ([outputPath 'annotation/' outputFileName '.mat'],'score', 'sceneObjects', 'sceneSchedule','dominantTrack', 'dominantObject','simulatedEBR');
|
mathieu@14
|
157 saveAnnotationTxt(sceneSchedule,outputPath,outputFileName);
|
mathieu@14
|
158
|
gregoire@19
|
159 w = sum(tracks,1);
|
gregoire@19
|
160 if norm %Normalize to [-norm,norm]
|
gregoire@19
|
161 w = w*norm/max(abs(w));
|
gregoire@19
|
162 end
|
gregoire@19
|
163
|
gregoirelafay@26
|
164 audiowrite([outputPath 'sound/' outputFileName '.wav'],w,sr);
|
gregoire@19
|
165
|
gregoirelafay@17
|
166 switch channelOption
|
gregoire@19
|
167 case 1
|
gregoirelafay@17
|
168 if norm %Normalize to [-norm,norm]
|
gregoire@19
|
169 tracks = tracks*norm/max(abs(sum(tracks,1)));
|
gregoirelafay@17
|
170 end
|
gregoire@19
|
171 audiowrite([outputPath 'sound/' outputFileName '_channel_split' '.wav'],tracks',sr);
|
gregoirelafay@17
|
172 case 2
|
gregoire@19
|
173 if norm %Normalize to [-norm,norm]
|
mathieu@34
|
174 tracks = tracks*norm/(1.05*max(abs(sum(tracks,1))));
|
gregoirelafay@17
|
175 end
|
gregoirelafay@17
|
176 for jj=1:size(tracks,1)
|
gregoire@19
|
177 audiowrite([outputPath 'sound/' outputFileName '_channel_' num2str(jj) '_class_' sceneObjects(jj).classLabel '.wav'],tracks(jj,:),sr);
|
gregoirelafay@17
|
178 end
|
gregoire@16
|
179 end
|
gregoire@19
|
180
|
gregoire@16
|
181
|
gregoire@16
|
182 if figuresOption
|
mathieu@34
|
183 settingFigure.cmap = pleasantnessColormap(sceneObjects);
|
mathieu@34
|
184 if any(~sum(settingFigure.cmap, 2))
|
mathieu@34
|
185 fprintf(2, 'Unable to get some of the pleasantness tags, revert to randomized colors');
|
mathieu@34
|
186 settingFigure.cmap = randomColormap(sceneObjects);
|
mathieu@34
|
187 end
|
gregoire@16
|
188 settingFigure.width=29.7; % cm
|
gregoire@16
|
189 settingFigure.height=21; % cm
|
gregoire@16
|
190 settingFigure.FontSize=16;
|
gregoire@16
|
191 settingFigure.sr=sr;
|
gregoire@16
|
192 settingFigure.sceneDuration=score.sceneDuration;
|
mathieu@14
|
193
|
mathieu@34
|
194 nbBg = 0;
|
mathieu@34
|
195 for k=1:length(sceneObjects)
|
mathieu@34
|
196 if sceneObjects(k).isBackground
|
mathieu@34
|
197 nbBg = nbBg+1;
|
mathieu@34
|
198 bgo(nbBg, :) = resample(abs(tracks(k, :)), 1, 44100);
|
mathieu@34
|
199 end
|
mathieu@34
|
200 end
|
mathieu@34
|
201
|
mathieu@34
|
202
|
mathieu@34
|
203
|
mathieu@34
|
204 [~, bgOrder] = sort(mean(bgo, 2)./median(bgo, 2));
|
mathieu@34
|
205 [~, eventOrder] = sort(sum(tracks(nbBg+1:end,:)==0, 2));
|
mathieu@34
|
206 trackOrder = [bgOrder; eventOrder+nbBg];
|
mathieu@34
|
207 tracks = tracks(trackOrder, :);
|
mathieu@34
|
208 sceneObjects = sceneObjects(trackOrder);
|
mathieu@34
|
209 settingFigure.cmap = settingFigure.cmap(trackOrder, :);
|
mathieu@34
|
210
|
gregoire@16
|
211 coloredSpectrumVisualization(tracks,1,settingFigure,figuresOption,[outputPath 'annotation/' outputFileName,'-spectrum.png']);
|
gregoire@16
|
212 timeDomainVisualization(tracks,2,settingFigure,figuresOption,[outputPath 'annotation/' outputFileName,'-timeDomain.png']);
|
gregoire@16
|
213 pianoRollVisualization(sceneObjects,sceneSchedule,score,3,settingFigure,figuresOption,[outputPath 'annotation/' outputFileName,'-pianoRoll.png'])
|
mathieu@14
|
214 end
|