comparison framework/Align.cpp @ 687:e0b0f3e163ca by-id

Update for removal of (public) getId from Model
author Chris Cannam
date Fri, 05 Jul 2019 15:35:11 +0100
parents 0736beb8b852
children c8ba09756eff
comparison
equal deleted inserted replaced
686:610fa108fbcc 687:e0b0f3e163ca
87 return factory->haveTransform(id) && 87 return factory->haveTransform(id) &&
88 (tdId == "" || factory->haveTransform(tdId)); 88 (tdId == "" || factory->haveTransform(tdId));
89 } 89 }
90 90
91 bool 91 bool
92 Align::alignModelViaTransform(Document *doc, ModelId ref, ModelId other, 92 Align::alignModelViaTransform(Document *doc,
93 ModelId referenceId,
94 ModelId otherId,
93 QString &error) 95 QString &error)
94 { 96 {
95 QMutexLocker locker (&m_mutex); 97 QMutexLocker locker (&m_mutex);
96 98
97 auto reference = ModelById::getAs<RangeSummarisableTimeValueModel>(ref); 99 auto reference =
98 auto rm = ModelById::getAs<RangeSummarisableTimeValueModel>(other); 100 ModelById::getAs<RangeSummarisableTimeValueModel>(referenceId);
99 if (!reference || !rm) return false; 101 auto other =
102 ModelById::getAs<RangeSummarisableTimeValueModel>(otherId);
103
104 if (!reference || !other) return false;
100 105
101 // This involves creating either three or four new models: 106 // This involves creating either three or four new models:
102 // 107 //
103 // 1. an AggregateWaveModel to provide the mixdowns of the main 108 // 1. an AggregateWaveModel to provide the mixdowns of the main
104 // model and the new model in its two channels, as input to the 109 // model and the new model in its two channels, as input to the
133 // this is quite unnecessary from the perspective of simply 138 // this is quite unnecessary from the perspective of simply
134 // producing the results.) 139 // producing the results.)
135 140
136 AggregateWaveModel::ChannelSpecList components; 141 AggregateWaveModel::ChannelSpecList components;
137 142
138 components.push_back(AggregateWaveModel::ModelChannelSpec 143 components.push_back
139 (reference->getId(), -1)); 144 (AggregateWaveModel::ModelChannelSpec(referenceId, -1));
140 145
141 components.push_back(AggregateWaveModel::ModelChannelSpec 146 components.push_back
142 (rm->getId(), -1)); 147 (AggregateWaveModel::ModelChannelSpec(otherId, -1));
143 148
144 auto aggregateModel = std::make_shared<AggregateWaveModel>(components); 149 auto aggregateModel = std::make_shared<AggregateWaveModel>(components);
145 ModelById::add(aggregateModel); 150 auto aggregateModelId = ModelById::add(aggregateModel);
146 doc->addAggregateModel(aggregateModel->getId()); 151 doc->addAggregateModel(aggregateModelId);
147 152
148 auto alignmentModel = std::make_shared<AlignmentModel>(ref, other, 153 auto alignmentModel = std::make_shared<AlignmentModel>
149 ModelId()); 154 (referenceId, otherId, ModelId());
150 ModelById::add(alignmentModel); 155 auto alignmentModelId = ModelById::add(alignmentModel);
151 156
152 TransformId tdId = getTuningDifferenceTransformName(); 157 TransformId tdId = getTuningDifferenceTransformName();
153 158
154 if (tdId == "") { 159 if (tdId == "") {
155 160
156 if (beginTransformDrivenAlignment(aggregateModel->getId(), 161 if (beginTransformDrivenAlignment(aggregateModelId,
157 alignmentModel->getId())) { 162 alignmentModelId)) {
158 rm->setAlignment(alignmentModel->getId()); 163 other->setAlignment(alignmentModelId);
159 } else { 164 } else {
160 error = alignmentModel->getError(); 165 error = alignmentModel->getError();
161 ModelById::release(alignmentModel); 166 ModelById::release(alignmentModel);
162 return false; 167 return false;
163 } 168 }
180 185
181 ModelTransformerFactory *mtf = ModelTransformerFactory::getInstance(); 186 ModelTransformerFactory *mtf = ModelTransformerFactory::getInstance();
182 187
183 QString message; 188 QString message;
184 ModelId transformOutput = mtf->transform(transform, 189 ModelId transformOutput = mtf->transform(transform,
185 aggregateModel->getId(), 190 aggregateModelId,
186 message); 191 message);
187 192
188 auto tdout = ModelById::getAs<SparseTimeValueModel>(transformOutput); 193 auto tdout = ModelById::getAs<SparseTimeValueModel>(transformOutput);
189 if (!tdout) { 194 if (!tdout) {
190 SVCERR << "Align::alignModel: ERROR: Failed to create tuning-difference output model (no Tuning Difference plugin?)" << endl; 195 SVCERR << "Align::alignModel: ERROR: Failed to create tuning-difference output model (no Tuning Difference plugin?)" << endl;
191 error = message; 196 error = message;
192 return false; 197 return false;
193 } 198 }
194 199
195 rm->setAlignment(alignmentModel->getId()); 200 other->setAlignment(alignmentModelId);
196 201
197 connect(tdout.get(), SIGNAL(completionChanged()), 202 connect(tdout.get(), SIGNAL(completionChanged(ModelId)),
198 this, SLOT(tuningDifferenceCompletionChanged())); 203 this, SLOT(tuningDifferenceCompletionChanged(ModelId)));
199 204
200 TuningDiffRec rec; 205 TuningDiffRec rec;
201 rec.input = aggregateModel->getId(); 206 rec.input = aggregateModelId;
202 rec.alignment = alignmentModel->getId(); 207 rec.alignment = alignmentModelId;
203 208
204 // This model exists only so that the AlignmentModel can get a 209 // This model exists only so that the AlignmentModel can get a
205 // completion value from somewhere while the tuning difference 210 // completion value from somewhere while the tuning difference
206 // calculation is going on 211 // calculation is going on
207 auto preparatoryModel = std::make_shared<SparseTimeValueModel> 212 auto preparatoryModel = std::make_shared<SparseTimeValueModel>
208 (aggregateModel->getSampleRate(), 1); 213 (aggregateModel->getSampleRate(), 1);
209 ModelById::add(preparatoryModel); 214 auto preparatoryModelId = ModelById::add(preparatoryModel);
210 preparatoryModel->setCompletion(0); 215 preparatoryModel->setCompletion(0);
211 rec.preparatory = preparatoryModel->getId(); 216 rec.preparatory = preparatoryModelId;
212 alignmentModel->setPathFrom(rec.preparatory); 217 alignmentModel->setPathFrom(rec.preparatory);
213 218
214 m_pendingTuningDiffs[transformOutput] = rec; 219 m_pendingTuningDiffs[transformOutput] = rec;
215 } 220 }
216 221
217 return true; 222 return true;
218 } 223 }
219 224
220 void 225 void
221 Align::tuningDifferenceCompletionChanged() 226 Align::tuningDifferenceCompletionChanged(ModelId tdId)
222 { 227 {
223 QMutexLocker locker (&m_mutex); 228 QMutexLocker locker(&m_mutex);
224
225 ModelId tdId;
226 if (Model *modelPtr = qobject_cast<Model *>(sender())) {
227 tdId = modelPtr->getId();
228 } else {
229 return;
230 }
231 229
232 if (m_pendingTuningDiffs.find(tdId) == m_pendingTuningDiffs.end()) { 230 if (m_pendingTuningDiffs.find(tdId) == m_pendingTuningDiffs.end()) {
233 SVCERR << "ERROR: Align::tuningDifferenceCompletionChanged: Model " 231 SVCERR << "ERROR: Align::tuningDifferenceCompletionChanged: Model "
234 << tdId << " not found in pending tuning diff map!" << endl; 232 << tdId << " not found in pending tuning diff map!" << endl;
235 return; 233 return;
344 } 342 }
345 343
346 path->setCompletion(0); 344 path->setCompletion(0);
347 alignmentModel->setPathFrom(transformOutput); //!!! who releases transformOutput? 345 alignmentModel->setPathFrom(transformOutput); //!!! who releases transformOutput?
348 346
349 connect(alignmentModel.get(), SIGNAL(completionChanged()), 347 connect(alignmentModel.get(), SIGNAL(completionChanged(ModelId)),
350 this, SLOT(alignmentCompletionChanged())); 348 this, SLOT(alignmentCompletionChanged(ModelId)));
351 349
352 return true; 350 return true;
353 } 351 }
354 352
355 void 353 void
356 Align::alignmentCompletionChanged() 354 Align::alignmentCompletionChanged(ModelId modelId)
357 { 355 {
358 QMutexLocker locker (&m_mutex); 356 QMutexLocker locker (&m_mutex);
359 357
360 if (AlignmentModel *amPtr = qobject_cast<AlignmentModel *>(sender())) { 358 auto am = ModelById::getAs<AlignmentModel>(modelId);
361 359 if (am && am->isReady()) {
362 auto am = ModelById::getAs<AlignmentModel>(amPtr->getId()); 360 disconnect(am.get(), SIGNAL(completionChanged(ModelId)),
363 if (am && am->isReady()) { 361 this, SLOT(alignmentCompletionChanged(ModelId)));
364 disconnect(am.get(), SIGNAL(completionChanged()), 362 emit alignmentComplete(modelId);
365 this, SLOT(alignmentCompletionChanged()));
366 emit alignmentComplete(am->getId());
367 }
368 } 363 }
369 } 364 }
370 365
371 bool 366 bool
372 Align::alignModelViaProgram(Document *, ModelId ref, ModelId other, 367 Align::alignModelViaProgram(Document *,
373 QString program, QString &error) 368 ModelId referenceId,
369 ModelId otherId,
370 QString program,
371 QString &error)
374 { 372 {
375 QMutexLocker locker (&m_mutex); 373 QMutexLocker locker (&m_mutex);
376
377 auto reference = ModelById::getAs<RangeSummarisableTimeValueModel>(ref);
378 auto rm = ModelById::getAs<RangeSummarisableTimeValueModel>(other);
379 if (!reference || !rm) return false;
380
381 while (!reference->isReady(nullptr) || !rm->isReady(nullptr)) {
382 qApp->processEvents();
383 }
384 374
385 // Run an external program, passing to it paths to the main 375 // Run an external program, passing to it paths to the main
386 // model's audio file and the new model's audio file. It returns 376 // model's audio file and the new model's audio file. It returns
387 // the path in CSV form through stdout. 377 // the path in CSV form through stdout.
388 378
389 auto roref = ModelById::getAs<ReadOnlyWaveFileModel>(ref); 379 auto reference = ModelById::getAs<ReadOnlyWaveFileModel>(referenceId);
390 auto rorm = ModelById::getAs<ReadOnlyWaveFileModel>(other); 380 auto other = ModelById::getAs<ReadOnlyWaveFileModel>(otherId);
391 if (!roref || !rorm) { 381 if (!reference || !other) {
392 SVCERR << "ERROR: Align::alignModelViaProgram: Can't align non-read-only models via program (no local filename available)" << endl; 382 SVCERR << "ERROR: Align::alignModelViaProgram: Can't align non-read-only models via program (no local filename available)" << endl;
393 return false; 383 return false;
394 } 384 }
395 385
396 QString refPath = roref->getLocalFilename(); 386 while (!reference->isReady(nullptr) || !other->isReady(nullptr)) {
397 QString otherPath = rorm->getLocalFilename(); 387 qApp->processEvents();
388 }
389
390 QString refPath = reference->getLocalFilename();
391 QString otherPath = other->getLocalFilename();
398 392
399 if (refPath == "" || otherPath == "") { 393 if (refPath == "" || otherPath == "") {
400 error = "Failed to find local filepath for wave-file model"; 394 error = "Failed to find local filepath for wave-file model";
401 return false; 395 return false;
402 } 396 }
403 397
404 auto alignmentModel = std::make_shared<AlignmentModel>(ref, other, 398 auto alignmentModel =
405 ModelId()); 399 std::make_shared<AlignmentModel>(referenceId, otherId, ModelId());
406 ModelById::add(alignmentModel); 400 auto alignmentModelId = ModelById::add(alignmentModel);
407 rm->setAlignment(alignmentModel->getId()); 401 other->setAlignment(alignmentModelId);
408 402
409 QProcess *process = new QProcess; 403 QProcess *process = new QProcess;
410 QStringList args; 404 QStringList args;
411 args << refPath << otherPath; 405 args << refPath << otherPath;
412 406
413 connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), 407 connect(process, SIGNAL(finished(int, QProcess::ExitStatus)),
414 this, SLOT(alignmentProgramFinished(int, QProcess::ExitStatus))); 408 this, SLOT(alignmentProgramFinished(int, QProcess::ExitStatus)));
415 409
416 m_pendingProcesses[process] = alignmentModel->getId(); 410 m_pendingProcesses[process] = alignmentModelId;
417 process->start(program, args); 411 process->start(program, args);
418 412
419 bool success = process->waitForStarted(); 413 bool success = process->waitForStarted();
420 414
421 if (!success) { 415 if (!success) {
422 SVCERR << "ERROR: Align::alignModelViaProgram: Program did not start" 416 SVCERR << "ERROR: Align::alignModelViaProgram: Program did not start"
423 << endl; 417 << endl;
424 error = "Alignment program could not be started"; 418 error = "Alignment program could not be started";
425 m_pendingProcesses.erase(process); 419 m_pendingProcesses.erase(process);
426 //!!! who releases alignmentModel? does this? review 420 //!!! who releases alignmentModel? does this? review
427 rm->setAlignment({}); 421 other->setAlignment({});
428 delete process; 422 delete process;
429 } 423 }
430 424
431 return success; 425 return success;
432 } 426 }
480 474
481 //!!! to use ById? 475 //!!! to use ById?
482 476
483 Model *csvOutput = reader.load(); 477 Model *csvOutput = reader.load();
484 478
485 SparseTimeValueModel *path = qobject_cast<SparseTimeValueModel *>(csvOutput); 479 SparseTimeValueModel *path =
480 qobject_cast<SparseTimeValueModel *>(csvOutput);
486 if (!path) { 481 if (!path) {
487 SVCERR << "ERROR: Align::alignmentProgramFinished: Output did not convert to sparse time-value model" 482 SVCERR << "ERROR: Align::alignmentProgramFinished: Output did not convert to sparse time-value model"
488 << endl; 483 << endl;
489 alignmentModel->setError 484 alignmentModel->setError
490 ("Output of program did not produce sparse time-value model"); 485 ("Output of program did not produce sparse time-value model");
502 } 497 }
503 498
504 SVCERR << "Align::alignmentProgramFinished: Setting alignment path (" 499 SVCERR << "Align::alignmentProgramFinished: Setting alignment path ("
505 << path->getEventCount() << " point(s))" << endl; 500 << path->getEventCount() << " point(s))" << endl;
506 501
507 ModelById::add(std::shared_ptr<SparseTimeValueModel>(path)); 502 auto pathId =
508 alignmentModel->setPathFrom(path->getId()); 503 ModelById::add(std::shared_ptr<SparseTimeValueModel>(path));
504 alignmentModel->setPathFrom(pathId);
509 505
510 emit alignmentComplete(alignmentModelId); 506 emit alignmentComplete(alignmentModelId);
507
508 ModelById::release(pathId);
511 509
512 } else { 510 } else {
513 SVCERR << "ERROR: Align::alignmentProgramFinished: Aligner program " 511 SVCERR << "ERROR: Align::alignmentProgramFinished: Aligner program "
514 << "failed: exit code " << exitCode << ", status " << status 512 << "failed: exit code " << exitCode << ", status " << status
515 << endl; 513 << endl;