Chris@420: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@420: Chris@420: /* Chris@420: Sonic Visualiser Chris@420: An audio file viewer and annotation editor. Chris@420: Centre for Digital Music, Queen Mary, University of London. Chris@420: Chris@420: This program is free software; you can redistribute it and/or Chris@420: modify it under the terms of the GNU General Public License as Chris@420: published by the Free Software Foundation; either version 2 of the Chris@420: License, or (at your option) any later version. See the file Chris@420: COPYING included with this distribution for more information. Chris@420: */ Chris@420: Chris@754: #ifndef SV_ALIGN_H Chris@754: #define SV_ALIGN_H Chris@420: Chris@420: #include Chris@423: #include Chris@423: #include Chris@670: #include Chris@423: #include Chris@420: Chris@753: #include "Aligner.h" Chris@683: Chris@776: #include "transform/Transform.h" Chris@776: Chris@423: class AlignmentModel; Chris@664: class Document; Chris@420: Chris@423: class Align : public QObject Chris@420: { Chris@423: Q_OBJECT Chris@423: Chris@420: public: Chris@670: Align() { } Chris@420: Chris@767: enum AlignmentType { Chris@767: NoAlignment, Chris@767: LinearAlignment, Chris@767: TrimmedLinearAlignment, Chris@767: MATCHAlignment, Chris@767: MATCHAlignmentWithPitchCompare, Chris@771: SungNoteContourAlignment, Chris@767: TransformDrivenDTWAlignment, Chris@767: ExternalProgramAlignment, Chris@767: Chris@767: LastAlignmentType = ExternalProgramAlignment Chris@767: }; Chris@767: Chris@776: /** Chris@776: * Convert an alignment type to a stable machine-readable string. Chris@776: */ Chris@767: static QString getAlignmentTypeTag(AlignmentType type); Chris@776: Chris@776: /** Chris@776: * Convert an alignment type back from a stable machine-readable Chris@776: * string. Chris@776: */ Chris@767: static AlignmentType getAlignmentTypeForTag(QString tag); Chris@767: Chris@776: /** Chris@776: * Get the currently set alignment preference from the global Chris@776: * application settings. If the returned preference is Chris@776: * TransformDrivenDTWAlignment or ExternalProgramAlignment, then Chris@776: * it will also be necessary to query Chris@776: * getPreferredAlignmentTransform() or Chris@776: * getPreferredAlignmentProgram() respectively in order to get the Chris@776: * information needed to perform an alignment. Chris@776: */ Chris@776: static AlignmentType getAlignmentPreference(); Chris@776: Chris@776: /** Chris@776: * Set the alignment preference to the global application Chris@776: * settings. If the preference is TransformDrivenDTWAlignment or Chris@776: * ExternalProgramAlignment, you may also wish to call Chris@776: * setPreferredAlignmentTransform() or Chris@776: * setPreferredAlignmentProgram() respectively. Chris@776: */ Chris@776: static void setAlignmentPreference(AlignmentType type); Chris@776: Chris@776: /** Chris@776: * Get the external program associated with the Chris@776: * ExternalProgramAlignment type, if any is set (an empty string Chris@776: * otherwise). Note that this will return a value if any has ever Chris@776: * been set, regardless of whether ExternalProgramAlignment is the Chris@776: * currently chosen alignment type or not. Chris@776: */ Chris@776: static QString getPreferredAlignmentProgram(); Chris@776: Chris@776: /** Chris@776: * Set the external program associated with the Chris@776: * ExternalProgramAlignment type. It is not necessary for the Chris@776: * current preferred alignment type actually to be Chris@776: * ExternalProgramAlignment in order to change this setting. No Chris@776: * validation is carried out on the argument - we don't verify Chris@776: * that it actually is the path of a program, or anything else. Chris@776: */ Chris@776: static void setPreferredAlignmentProgram(QString program); Chris@776: Chris@776: /** Chris@776: * Get the transform associated with the Chris@776: * TransformDrivenDTWAlignment type, if any is set (a default Chris@776: * constructed Transform otherwise). Note that this will return a Chris@776: * value if any has ever been set, regardless of whether Chris@776: * TransformDrivenDTWAlignment is the currently chosen alignment Chris@776: * type or not. Chris@776: */ Chris@776: static Transform getPreferredAlignmentTransform(); Chris@776: Chris@776: /** Chris@776: * Set the transform associated with the Chris@776: * TransformDrivenDTWAlignment type. It is not necessary for the Chris@776: * current preferred alignment type actually to be Chris@776: * TransformDrivenDTWAlignment in order to change this setting. Chris@776: */ Chris@776: static void setPreferredAlignmentTransform(Transform transform); Chris@781: Chris@781: /** Chris@781: * Return true if subsequence alignment is preferred. In this case Chris@781: * the toAlign model is aligned to the best-matching subsequence Chris@781: * of the reference model rather than to the whole reference. This Chris@781: * is only possible for the true built-in alignment types - it's Chris@781: * meaningless for linear or trimmed linear alignment, and for Chris@781: * external program alignment. The default is false. Chris@781: */ Chris@781: static bool getUseSubsequenceAlignment(); Chris@781: Chris@781: /** Chris@781: * Set whether subsequence alignment is to be preferred. Chris@781: */ Chris@781: static void setUseSubsequenceAlignment(bool subsequence); Chris@767: Chris@423: /** Chris@423: * Align the "other" model to the reference, attaching an Chris@423: * AlignmentModel to it. Alignment is carried out by the method Chris@776: * configured in the user preferences (see Chris@776: * getAlignmentPreference() etc) and is done asynchronously. Chris@423: * Chris@761: * Any errors are reported by firing the alignmentFailed Chris@761: * signal. Note that the signal may be fired during the call to Chris@761: * this function, if the aligner fails to start at all. Chris@761: * Chris@761: * If alignment starts successfully, then an AlignmentModel has Chris@670: * been constructed and attached to the toAlign model, and you can Chris@670: * query that model to discover the alignment progress, eventual Chris@761: * outcome, and also (separately from the alignmentFailed signal Chris@761: * here) any error message generated during alignment. Chris@670: * Chris@423: * A single Align object may carry out many simultanous alignment Chris@423: * calls -- you do not need to create a new Align object each Chris@423: * time, nor to wait for an alignment to be complete before Chris@423: * starting a new one. Chris@423: * Chris@423: * The Align object must survive after this call, for at least as Chris@428: * long as the alignment takes. The usual expectation is that the Chris@428: * Align object will simply share the process or document Chris@428: * lifespan. Chris@423: */ Chris@761: void alignModel(Document *doc, Chris@683: ModelId reference, Chris@761: ModelId toAlign); Chris@420: Chris@428: /** Chris@761: * As alignModel, except that the alignment does not begin Chris@761: * immediately, but is instead placed behind an event callback Chris@761: * with a small delay. Useful to avoid an unresponsive GUI when Chris@761: * firing off alignments while doing something else as well. Any Chris@761: * error is reported by firing the alignmentFailed signal. Chris@761: * Chris@761: * Scheduled alignments are not queued or serialised - many could Chris@761: * happen at once. They are just delayed a little for UI Chris@761: * responsiveness. Chris@761: */ Chris@761: void scheduleAlignment(Document *doc, Chris@761: ModelId reference, Chris@761: ModelId toAlign); Chris@761: Chris@761: /** Chris@776: * Return true if the preferred alignment facility is available Chris@776: * (relevant plugin installed, etc). Chris@428: */ Chris@428: static bool canAlign(); Chris@428: Chris@428: signals: Chris@428: /** Chris@428: * Emitted when an alignment is successfully completed. The Chris@428: * reference and other models can be queried from the alignment Chris@428: * model. Chris@428: */ Chris@683: void alignmentComplete(ModelId alignmentModel); // an AlignmentModel Chris@428: Chris@761: /** Chris@761: * Emitted when an alignment fails. The model is the toAlign model Chris@761: * that was passed to the call to alignModel or scheduleAlignment. Chris@761: */ Chris@761: void alignmentFailed(ModelId toAlign, QString errorText); Chris@761: Chris@423: private slots: Chris@753: void alignerComplete(ModelId alignmentModel); // an AlignmentModel Chris@761: void alignerFailed(ModelId toAlign, QString errorText); Chris@423: Chris@420: private: Chris@670: QMutex m_mutex; Chris@671: Chris@753: // maps toAlign -> aligner for ongoing alignment - note that Chris@753: // although we can calculate alignments with different references, Chris@753: // we can only have one alignment on any given toAlign model, so Chris@753: // we don't key this on the whole (reference, toAlign) pair Chris@753: std::map> m_aligners; Chris@671: Chris@767: bool addAligner(Document *doc, ModelId reference, ModelId toAlign); Chris@761: void removeAligner(QObject *); Chris@420: }; Chris@420: Chris@420: #endif Chris@420: