comparison align/TransformDTWAligner.cpp @ 768:1b1960009be6 pitch-align

Provide callback for output preprocessing before DTW, use it for freq-pitch conversion; use direct setting of completion on alignment models instead of creating fake outputs for completion only
author Chris Cannam
date Fri, 22 May 2020 17:17:44 +0100
parents dd742e566e60
children a316cb6fed81
comparison
equal deleted inserted replaced
767:dd742e566e60 768:1b1960009be6
37 Transform transform, 37 Transform transform,
38 DTWType dtwType) : 38 DTWType dtwType) :
39 m_document(doc), 39 m_document(doc),
40 m_reference(reference), 40 m_reference(reference),
41 m_toAlign(toAlign), 41 m_toAlign(toAlign),
42 m_referenceTransformComplete(false),
43 m_toAlignTransformComplete(false),
44 m_transform(transform), 42 m_transform(transform),
45 m_dtwType(dtwType), 43 m_dtwType(dtwType),
46 m_incomplete(true) 44 m_incomplete(true),
45 m_outputPreprocessor([](double x) { return x; })
46 {
47 }
48
49 TransformDTWAligner::TransformDTWAligner(Document *doc,
50 ModelId reference,
51 ModelId toAlign,
52 Transform transform,
53 DTWType dtwType,
54 std::function<double(double)>
55 outputPreprocessor) :
56 m_document(doc),
57 m_reference(reference),
58 m_toAlign(toAlign),
59 m_transform(transform),
60 m_dtwType(dtwType),
61 m_incomplete(true),
62 m_outputPreprocessor(outputPreprocessor)
47 { 63 {
48 } 64 }
49 65
50 TransformDTWAligner::~TransformDTWAligner() 66 TransformDTWAligner::~TransformDTWAligner()
51 { 67 {
55 } 71 }
56 } 72 }
57 73
58 ModelById::release(m_referenceOutputModel); 74 ModelById::release(m_referenceOutputModel);
59 ModelById::release(m_toAlignOutputModel); 75 ModelById::release(m_toAlignOutputModel);
60 ModelById::release(m_alignmentProgressModel);
61 } 76 }
62 77
63 bool 78 bool
64 TransformDTWAligner::isAvailable() 79 TransformDTWAligner::isAvailable()
65 { 80 {
112 127
113 connect(referenceOutputModel.get(), SIGNAL(completionChanged(ModelId)), 128 connect(referenceOutputModel.get(), SIGNAL(completionChanged(ModelId)),
114 this, SLOT(completionChanged(ModelId))); 129 this, SLOT(completionChanged(ModelId)));
115 connect(toAlignOutputModel.get(), SIGNAL(completionChanged(ModelId)), 130 connect(toAlignOutputModel.get(), SIGNAL(completionChanged(ModelId)),
116 this, SLOT(completionChanged(ModelId))); 131 this, SLOT(completionChanged(ModelId)));
117
118 auto alignmentProgressModel = std::make_shared<SparseTimeValueModel>
119 (reference->getSampleRate(), m_transform.getStepSize(), false);
120 alignmentProgressModel->setCompletion(0);
121 m_alignmentProgressModel = ModelById::add(alignmentProgressModel);
122 132
123 auto alignmentModel = std::make_shared<AlignmentModel> 133 auto alignmentModel = std::make_shared<AlignmentModel>
124 (m_reference, m_toAlign, m_alignmentProgressModel); 134 (m_reference, m_toAlign, ModelId());
125 m_alignmentModel = ModelById::add(alignmentModel); 135 m_alignmentModel = ModelById::add(alignmentModel);
126 136
127 toAlign->setAlignment(m_alignmentModel); 137 toAlign->setAlignment(m_alignmentModel);
128 m_document->addNonDerivedModel(m_alignmentModel); 138 m_document->addNonDerivedModel(m_alignmentModel);
129 139
151 SVCERR << "TransformDTWAligner[" << this << "]: completionChanged: " 161 SVCERR << "TransformDTWAligner[" << this << "]: completionChanged: "
152 << "model " << id << endl; 162 << "model " << id << endl;
153 163
154 auto referenceOutputModel = ModelById::get(m_referenceOutputModel); 164 auto referenceOutputModel = ModelById::get(m_referenceOutputModel);
155 auto toAlignOutputModel = ModelById::get(m_toAlignOutputModel); 165 auto toAlignOutputModel = ModelById::get(m_toAlignOutputModel);
156 166 auto alignmentModel = ModelById::getAs<AlignmentModel>(m_alignmentModel);
157 if (!referenceOutputModel || !toAlignOutputModel) { 167
168 if (!referenceOutputModel || !toAlignOutputModel || !alignmentModel) {
158 return; 169 return;
159 } 170 }
160 171
161 int referenceCompletion = 0, toAlignCompletion = 0; 172 int referenceCompletion = 0, toAlignCompletion = 0;
162 bool referenceReady = referenceOutputModel->isReady(&referenceCompletion); 173 bool referenceReady = referenceOutputModel->isReady(&referenceCompletion);
163 bool toAlignReady = toAlignOutputModel->isReady(&toAlignCompletion); 174 bool toAlignReady = toAlignOutputModel->isReady(&toAlignCompletion);
164 175
165 auto alignmentProgressModel =
166 ModelById::getAs<SparseTimeValueModel>(m_alignmentProgressModel);
167
168 if (referenceReady && toAlignReady) { 176 if (referenceReady && toAlignReady) {
169 177
170 SVCERR << "TransformDTWAligner[" << this << "]: completionChanged: " 178 SVCERR << "TransformDTWAligner[" << this << "]: completionChanged: "
171 << "ready, calling performAlignment" << endl; 179 << "ready, calling performAlignment" << endl;
172 180
173 if (alignmentProgressModel) { 181 alignmentModel->setCompletion(95);
174 alignmentProgressModel->setCompletion(95);
175 }
176 182
177 if (performAlignment()) { 183 if (performAlignment()) {
178 emit complete(m_alignmentModel); 184 emit complete(m_alignmentModel);
179 } else { 185 } else {
180 emit failed(m_toAlign, tr("Alignment of transform outputs failed")); 186 emit failed(m_toAlign, tr("Alignment of transform outputs failed"));
184 190
185 SVCERR << "TransformDTWAligner[" << this << "]: completionChanged: " 191 SVCERR << "TransformDTWAligner[" << this << "]: completionChanged: "
186 << "not ready yet: reference completion " << referenceCompletion 192 << "not ready yet: reference completion " << referenceCompletion
187 << ", toAlign completion " << toAlignCompletion << endl; 193 << ", toAlign completion " << toAlignCompletion << endl;
188 194
189 if (alignmentProgressModel) { 195 int completion = std::min(referenceCompletion,
190 int completion = std::min(referenceCompletion, 196 toAlignCompletion);
191 toAlignCompletion); 197 completion = (completion * 94) / 100;
192 completion = (completion * 94) / 100; 198 alignmentModel->setCompletion(completion);
193 alignmentProgressModel->setCompletion(completion);
194 }
195 } 199 }
196 } 200 }
197 201
198 bool 202 bool
199 TransformDTWAligner::performAlignment() 203 TransformDTWAligner::performAlignment()
227 vector<double> s1, s2; 231 vector<double> s1, s2;
228 232
229 { 233 {
230 auto events = referenceOutputSTVM->getAllEvents(); 234 auto events = referenceOutputSTVM->getAllEvents();
231 for (auto e: events) { 235 for (auto e: events) {
232 s1.push_back(e.getValue()); 236 s1.push_back(m_outputPreprocessor(e.getValue()));
233 } 237 }
234 events = toAlignOutputSTVM->getAllEvents(); 238 events = toAlignOutputSTVM->getAllEvents();
235 for (auto e: events) { 239 for (auto e: events) {
236 s2.push_back(e.getValue()); 240 s2.push_back(m_outputPreprocessor(e.getValue()));
237 } 241 }
238 } 242 }
239 243
240 SVCERR << "TransformDTWAligner[" << this << "]: performAlignment: " 244 SVCERR << "TransformDTWAligner[" << this << "]: performAlignment: "
241 << "Have " << s1.size() << " events from reference, " 245 << "Have " << s1.size() << " events from reference, "
258 for (int i = 0; i < alignment.size() && i < 100; ++i) { 262 for (int i = 0; i < alignment.size() && i < 100; ++i) {
259 SVCERR << alignment[i] << " "; 263 SVCERR << alignment[i] << " ";
260 } 264 }
261 SVCERR << endl; 265 SVCERR << endl;
262 266
263 auto alignmentProgressModel = 267 alignmentModel->setCompletion(100);
264 ModelById::getAs<SparseTimeValueModel>(m_alignmentProgressModel);
265 if (alignmentProgressModel) {
266 alignmentProgressModel->setCompletion(100);
267 }
268
269 // clear the alignment progress model
270 alignmentModel->setPathFrom(ModelId());
271 268
272 sv_frame_t resolution = referenceOutputSTVM->getResolution(); 269 sv_frame_t resolution = referenceOutputSTVM->getResolution();
273 sv_frame_t sourceFrame = 0; 270 sv_frame_t sourceFrame = 0;
274 271
275 Path path(referenceOutputSTVM->getSampleRate(), resolution); 272 Path path(referenceOutputSTVM->getSampleRate(), resolution);
304 } 301 }
305 302
306 if (!alignmentModel) { 303 if (!alignmentModel) {
307 return false; 304 return false;
308 } 305 }
309 306
310 vector<RiseFallDTW::Value> s1, s2; 307 auto convertEvents =
311 double prev1 = 0.0, prev2 = 0.0; 308 [this](const EventVector &ee) {
312 309 vector<RiseFallDTW::Value> s;
313 { 310 double prev = 0.0;
314 auto events = referenceOutputSTVM->getAllEvents(); 311 for (auto e: ee) {
315 for (auto e: events) { 312 double v = m_outputPreprocessor(e.getValue());
316 double v = e.getValue(); 313 if (v == prev || s.empty()) {
317 //!!! the original does this using MIDI pitch for the 314 s.push_back({ RiseFallDTW::Direction::None, 0.0 });
318 //!!! pYin transform... rework with a lambda passed in 315 } else if (v > prev) {
319 //!!! for modification maybe? + factor out s1/s2 of course 316 s.push_back({ RiseFallDTW::Direction::Up, v - prev });
320 if (v > prev1) { 317 } else {
321 s1.push_back({ RiseFallDTW::Direction::Up, v - prev1 }); 318 s.push_back({ RiseFallDTW::Direction::Down, prev - v });
322 } else { 319 }
323 s1.push_back({ RiseFallDTW::Direction::Down, prev1 - v });
324 } 320 }
325 prev1 = v; 321 return s;
326 } 322 };
327 events = toAlignOutputSTVM->getAllEvents(); 323
328 for (auto e: events) { 324 vector<RiseFallDTW::Value> s1 =
329 double v = e.getValue(); 325 convertEvents(referenceOutputSTVM->getAllEvents());
330 //!!! as above 326
331 if (v > prev2) { 327 vector<RiseFallDTW::Value> s2 =
332 s2.push_back({ RiseFallDTW::Direction::Up, v - prev2 }); 328 convertEvents(toAlignOutputSTVM->getAllEvents());
333 } else {
334 s2.push_back({ RiseFallDTW::Direction::Down, prev2 - v });
335 }
336 prev2 = v;
337 }
338 }
339 329
340 SVCERR << "TransformDTWAligner[" << this << "]: performAlignment: " 330 SVCERR << "TransformDTWAligner[" << this << "]: performAlignment: "
341 << "Have " << s1.size() << " events from reference, " 331 << "Have " << s1.size() << " events from reference, "
342 << s2.size() << " from toAlign" << endl; 332 << s2.size() << " from toAlign" << endl;
343 333
359 for (int i = 0; i < alignment.size() && i < 100; ++i) { 349 for (int i = 0; i < alignment.size() && i < 100; ++i) {
360 SVCERR << alignment[i] << " "; 350 SVCERR << alignment[i] << " ";
361 } 351 }
362 SVCERR << endl; 352 SVCERR << endl;
363 353
364 auto alignmentProgressModel = 354 alignmentModel->setCompletion(100);
365 ModelById::getAs<SparseTimeValueModel>(m_alignmentProgressModel);
366 if (alignmentProgressModel) {
367 alignmentProgressModel->setCompletion(100);
368 }
369
370 // clear the alignment progress model
371 alignmentModel->setPathFrom(ModelId());
372 355
373 sv_frame_t resolution = referenceOutputSTVM->getResolution(); 356 sv_frame_t resolution = referenceOutputSTVM->getResolution();
374 sv_frame_t sourceFrame = 0; 357 sv_frame_t sourceFrame = 0;
375 358
376 Path path(referenceOutputSTVM->getSampleRate(), resolution); 359 Path path(referenceOutputSTVM->getSampleRate(), resolution);