Mercurial > hg > svcore
view data/model/AlignmentModel.cpp @ 998:e25dc8d57565
Add descriptions for writers; add housekeeping options to Sonic Annotator to list writers and formats
author | Chris Cannam |
---|---|
date | Mon, 13 Oct 2014 14:44:51 +0100 |
parents | cd42620e3f40 |
children | 13f53ecc8bb5 |
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ /* Sonic Visualiser An audio file viewer and annotation editor. Centre for Digital Music, Queen Mary, University of London. This file copyright 2007 QMUL. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See the file COPYING included with this distribution for more information. */ #include "AlignmentModel.h" #include "SparseTimeValueModel.h" //#define DEBUG_ALIGNMENT_MODEL 1 AlignmentModel::AlignmentModel(Model *reference, Model *aligned, Model *inputModel, SparseTimeValueModel *path) : m_reference(reference), m_aligned(aligned), m_inputModel(inputModel), m_rawPath(path), m_path(0), m_reversePath(0), m_pathBegun(false), m_pathComplete(false) { if (m_rawPath) { connect(m_rawPath, SIGNAL(modelChanged()), this, SLOT(pathChanged())); connect(m_rawPath, SIGNAL(modelChangedWithin(int, int)), this, SLOT(pathChangedWithin(int, int))); connect(m_rawPath, SIGNAL(completionChanged()), this, SLOT(pathCompletionChanged())); constructPath(); constructReversePath(); } if (m_rawPath && m_rawPath->isReady()) { pathCompletionChanged(); } } AlignmentModel::~AlignmentModel() { if (m_inputModel) m_inputModel->aboutToDelete(); delete m_inputModel; if (m_rawPath) m_rawPath->aboutToDelete(); delete m_rawPath; if (m_path) m_path->aboutToDelete(); delete m_path; if (m_reversePath) m_reversePath->aboutToDelete(); delete m_reversePath; } bool AlignmentModel::isOK() const { if (m_rawPath) return m_rawPath->isOK(); else return true; } int AlignmentModel::getStartFrame() const { int a = m_reference->getStartFrame(); int b = m_aligned->getStartFrame(); return std::min(a, b); } int AlignmentModel::getEndFrame() const { int a = m_reference->getEndFrame(); int b = m_aligned->getEndFrame(); return std::max(a, b); } int AlignmentModel::getSampleRate() const { return m_reference->getSampleRate(); } Model * AlignmentModel::clone() const { return new AlignmentModel (m_reference, m_aligned, m_inputModel ? m_inputModel->clone() : 0, m_rawPath ? static_cast<SparseTimeValueModel *>(m_rawPath->clone()) : 0); } bool AlignmentModel::isReady(int *completion) const { if (!m_pathBegun && m_rawPath) { if (completion) *completion = 0; return false; } if (m_pathComplete || !m_rawPath) { if (completion) *completion = 100; return true; } return m_rawPath->isReady(completion); } const ZoomConstraint * AlignmentModel::getZoomConstraint() const { return 0; } const Model * AlignmentModel::getReferenceModel() const { return m_reference; } const Model * AlignmentModel::getAlignedModel() const { return m_aligned; } int AlignmentModel::toReference(int frame) const { #ifdef DEBUG_ALIGNMENT_MODEL SVDEBUG << "AlignmentModel::toReference(" << frame << ")" << endl; #endif if (!m_path) { if (!m_rawPath) return frame; constructPath(); } return align(m_path, frame); } int AlignmentModel::fromReference(int frame) const { #ifdef DEBUG_ALIGNMENT_MODEL SVDEBUG << "AlignmentModel::fromReference(" << frame << ")" << endl; #endif if (!m_reversePath) { if (!m_rawPath) return frame; constructReversePath(); } return align(m_reversePath, frame); } void AlignmentModel::pathChanged() { if (m_pathComplete) { cerr << "AlignmentModel: deleting raw path model" << endl; if (m_rawPath) m_rawPath->aboutToDelete(); delete m_rawPath; m_rawPath = 0; } } void AlignmentModel::pathChangedWithin(int, int) { if (!m_pathComplete) return; constructPath(); constructReversePath(); } void AlignmentModel::pathCompletionChanged() { if (!m_rawPath) return; m_pathBegun = true; if (!m_pathComplete) { int completion = 0; m_rawPath->isReady(&completion); #ifdef DEBUG_ALIGNMENT_MODEL SVDEBUG << "AlignmentModel::pathCompletionChanged: completion = " << completion << endl; #endif m_pathComplete = (completion == 100); if (m_pathComplete) { constructPath(); constructReversePath(); if (m_inputModel) m_inputModel->aboutToDelete(); delete m_inputModel; m_inputModel = 0; } } emit completionChanged(); } void AlignmentModel::constructPath() const { if (!m_path) { if (!m_rawPath) { cerr << "ERROR: AlignmentModel::constructPath: " << "No raw path available" << endl; return; } m_path = new PathModel (m_rawPath->getSampleRate(), m_rawPath->getResolution(), false); } else { if (!m_rawPath) return; } m_path->clear(); SparseTimeValueModel::PointList points = m_rawPath->getPoints(); for (SparseTimeValueModel::PointList::const_iterator i = points.begin(); i != points.end(); ++i) { long frame = i->frame; float value = i->value; long rframe = lrintf(value * m_aligned->getSampleRate()); m_path->addPoint(PathPoint(frame, rframe)); } #ifdef DEBUG_ALIGNMENT_MODEL SVDEBUG << "AlignmentModel::constructPath: " << m_path->getPointCount() << " points, at least " << (2 * m_path->getPointCount() * (3 * sizeof(void *) + sizeof(int) + sizeof(PathPoint))) << " bytes" << endl; #endif } void AlignmentModel::constructReversePath() const { if (!m_reversePath) { if (!m_path) { cerr << "ERROR: AlignmentModel::constructReversePath: " << "No forward path available" << endl; return; } m_reversePath = new PathModel (m_path->getSampleRate(), m_path->getResolution(), false); } else { if (!m_path) return; } m_reversePath->clear(); PathModel::PointList points = m_path->getPoints(); for (PathModel::PointList::const_iterator i = points.begin(); i != points.end(); ++i) { long frame = i->frame; long rframe = i->mapframe; m_reversePath->addPoint(PathPoint(rframe, frame)); } #ifdef DEBUG_ALIGNMENT_MODEL SVDEBUG << "AlignmentModel::constructReversePath: " << m_reversePath->getPointCount() << " points, at least " << (2 * m_reversePath->getPointCount() * (3 * sizeof(void *) + sizeof(int) + sizeof(PathPoint))) << " bytes" << endl; #endif } int AlignmentModel::align(PathModel *path, int frame) const { if (!path) return frame; // The path consists of a series of points, each with frame equal // to the frame on the source model and mapframe equal to the // frame on the target model. Both should be monotonically // increasing. const PathModel::PointList &points = path->getPoints(); if (points.empty()) { #ifdef DEBUG_ALIGNMENT_MODEL SVDEBUG << "AlignmentModel::align: No points" << endl; #endif return frame; } #ifdef DEBUG_ALIGNMENT_MODEL SVDEBUG << "AlignmentModel::align: frame " << frame << " requested" << endl; #endif PathModel::Point point(frame); PathModel::PointList::const_iterator i = points.lower_bound(point); if (i == points.end()) { #ifdef DEBUG_ALIGNMENT_MODEL cerr << "Note: i == points.end()" << endl; #endif --i; } while (i != points.begin() && i->frame > long(frame)) --i; long foundFrame = i->frame; long foundMapFrame = i->mapframe; long followingFrame = foundFrame; long followingMapFrame = foundMapFrame; if (++i != points.end()) { #ifdef DEBUG_ALIGNMENT_MODEL cerr << "another point available" << endl; #endif followingFrame = i->frame; followingMapFrame = i->mapframe; } else { #ifdef DEBUG_ALIGNMENT_MODEL cerr << "no other point available" << endl; #endif } if (foundMapFrame < 0) return 0; int resultFrame = foundMapFrame; if (followingFrame != foundFrame && long(frame) > foundFrame) { float interp = float(frame - foundFrame) / float(followingFrame - foundFrame); resultFrame += lrintf((followingMapFrame - foundMapFrame) * interp); } #ifdef DEBUG_ALIGNMENT_MODEL SVDEBUG << "AlignmentModel::align: resultFrame = " << resultFrame << endl; #endif return resultFrame; } void AlignmentModel::setPath(PathModel *path) { if (m_path) m_path->aboutToDelete(); delete m_path; m_path = path; #ifdef DEBUG_ALIGNMENT_MODEL SVDEBUG << "AlignmentModel::setPath: path = " << m_path << endl; #endif constructReversePath(); #ifdef DEBUG_ALIGNMENT_MODEL SVDEBUG << "AlignmentModel::setPath: after construction path = " << m_path << ", rpath = " << m_reversePath << endl; #endif } void AlignmentModel::toXml(QTextStream &stream, QString indent, QString extraAttributes) const { if (!m_path) { SVDEBUG << "AlignmentModel::toXml: no path" << endl; return; } m_path->toXml(stream, indent, ""); Model::toXml(stream, indent, QString("type=\"alignment\" reference=\"%1\" aligned=\"%2\" path=\"%3\" %4") .arg(getObjectExportId(m_reference)) .arg(getObjectExportId(m_aligned)) .arg(getObjectExportId(m_path)) .arg(extraAttributes)); }