Mercurial > hg > svapp
comparison align/Align.cpp @ 767:dd742e566e60 pitch-align
Make a start on further alignment methods
author | Chris Cannam |
---|---|
date | Thu, 21 May 2020 16:21:57 +0100 |
parents | 6429a164b7e1 |
children | 1b1960009be6 |
comparison
equal
deleted
inserted
replaced
761:6429a164b7e1 | 767:dd742e566e60 |
---|---|
11 License, or (at your option) any later version. See the file | 11 License, or (at your option) any later version. See the file |
12 COPYING included with this distribution for more information. | 12 COPYING included with this distribution for more information. |
13 */ | 13 */ |
14 | 14 |
15 #include "Align.h" | 15 #include "Align.h" |
16 | |
17 #include "LinearAligner.h" | |
16 #include "TransformAligner.h" | 18 #include "TransformAligner.h" |
19 #include "TransformDTWAligner.h" | |
17 #include "ExternalProgramAligner.h" | 20 #include "ExternalProgramAligner.h" |
21 | |
18 #include "framework/Document.h" | 22 #include "framework/Document.h" |
23 | |
24 #include "transform/Transform.h" | |
25 #include "transform/TransformFactory.h" | |
19 | 26 |
20 #include <QSettings> | 27 #include <QSettings> |
21 #include <QTimer> | 28 #include <QTimer> |
29 | |
30 using std::make_shared; | |
31 | |
32 QString | |
33 Align::getAlignmentTypeTag(AlignmentType type) | |
34 { | |
35 switch (type) { | |
36 case NoAlignment: | |
37 default: | |
38 return "no-alignment"; | |
39 case LinearAlignment: | |
40 return "linear-alignment"; | |
41 case TrimmedLinearAlignment: | |
42 return "trimmed-linear-alignment"; | |
43 case MATCHAlignment: | |
44 return "match-alignment"; | |
45 case MATCHAlignmentWithPitchCompare: | |
46 return "match-alignment-with-pitch"; | |
47 case SungPitchContourAlignment: | |
48 return "sung-pitch-alignment"; | |
49 case TransformDrivenDTWAlignment: | |
50 return "transform-driven-alignment"; | |
51 case ExternalProgramAlignment: | |
52 return "external-program-alignment"; | |
53 } | |
54 } | |
55 | |
56 Align::AlignmentType | |
57 Align::getAlignmentTypeForTag(QString tag) | |
58 { | |
59 for (int i = 0; i <= int(LastAlignmentType); ++i) { | |
60 if (tag == getAlignmentTypeTag(AlignmentType(i))) { | |
61 return AlignmentType(i); | |
62 } | |
63 } | |
64 return NoAlignment; | |
65 } | |
22 | 66 |
23 void | 67 void |
24 Align::alignModel(Document *doc, | 68 Align::alignModel(Document *doc, |
25 ModelId reference, | 69 ModelId reference, |
26 ModelId toAlign) | 70 ModelId toAlign) |
27 { | 71 { |
28 addAligner(doc, reference, toAlign); | 72 if (addAligner(doc, reference, toAlign)) { |
29 m_aligners[toAlign]->begin(); | 73 m_aligners[toAlign]->begin(); |
74 } | |
30 } | 75 } |
31 | 76 |
32 void | 77 void |
33 Align::scheduleAlignment(Document *doc, | 78 Align::scheduleAlignment(Document *doc, |
34 ModelId reference, | 79 ModelId reference, |
35 ModelId toAlign) | 80 ModelId toAlign) |
36 { | 81 { |
37 addAligner(doc, reference, toAlign); | 82 int delay = 700 * int(m_aligners.size()); |
38 int delay = 500 + 500 * int(m_aligners.size()); | |
39 if (delay > 3500) { | 83 if (delay > 3500) { |
40 delay = 3500; | 84 delay = 3500; |
41 } | 85 } |
86 if (!addAligner(doc, reference, toAlign)) { | |
87 return; | |
88 } | |
42 SVCERR << "Align::scheduleAlignment: delaying " << delay << "ms" << endl; | 89 SVCERR << "Align::scheduleAlignment: delaying " << delay << "ms" << endl; |
43 QTimer::singleShot(delay, m_aligners[toAlign].get(), SLOT(begin())); | 90 QTimer::singleShot(delay, m_aligners[toAlign].get(), SLOT(begin())); |
44 } | 91 } |
45 | 92 |
46 void | 93 bool |
47 Align::addAligner(Document *doc, | 94 Align::addAligner(Document *doc, |
48 ModelId reference, | 95 ModelId reference, |
49 ModelId toAlign) | 96 ModelId toAlign) |
50 { | 97 { |
51 bool useProgram; | 98 QString additionalData; |
52 QString program; | 99 AlignmentType type = getAlignmentPreference(additionalData); |
53 getAlignerPreference(useProgram, program); | |
54 | 100 |
55 std::shared_ptr<Aligner> aligner; | 101 std::shared_ptr<Aligner> aligner; |
56 | 102 |
57 { | 103 { |
58 // Replace the aligner with a new one. This also stops any | 104 // Replace the aligner with a new one. This also stops any |
59 // previously-running alignment, when the old entry is | 105 // previously-running alignment, when the old entry is |
60 // replaced and its aligner destroyed. | 106 // replaced and its aligner destroyed. |
61 | 107 |
62 QMutexLocker locker(&m_mutex); | 108 QMutexLocker locker(&m_mutex); |
63 | 109 |
64 if (useProgram && (program != "")) { | 110 switch (type) { |
65 m_aligners[toAlign] = | 111 |
66 std::make_shared<ExternalProgramAligner>(doc, | 112 case NoAlignment: |
67 reference, | 113 return false; |
68 toAlign, | 114 |
69 program); | 115 case LinearAlignment: |
70 } else { | 116 case TrimmedLinearAlignment: { |
71 m_aligners[toAlign] = | 117 bool trimmed = (type == TrimmedLinearAlignment); |
72 std::make_shared<TransformAligner>(doc, | 118 aligner = make_shared<LinearAligner>(doc, |
73 reference, | 119 reference, |
74 toAlign); | 120 toAlign, |
75 } | 121 trimmed); |
76 | 122 break; |
77 aligner = m_aligners[toAlign]; | 123 } |
124 | |
125 case MATCHAlignment: | |
126 case MATCHAlignmentWithPitchCompare: { | |
127 | |
128 bool withTuningDifference = | |
129 (type == MATCHAlignmentWithPitchCompare); | |
130 | |
131 aligner = make_shared<TransformAligner>(doc, | |
132 reference, | |
133 toAlign, | |
134 withTuningDifference); | |
135 break; | |
136 } | |
137 | |
138 case SungPitchContourAlignment: | |
139 { | |
140 auto refModel = ModelById::get(reference); | |
141 if (!refModel) return false; | |
142 | |
143 Transform transform = TransformFactory::getInstance()-> | |
144 getDefaultTransformFor("vamp:pyin:pyin:smoothedpitchtrack", | |
145 refModel->getSampleRate()); | |
146 | |
147 transform.setParameter("outputunvoiced", 2.f); | |
148 | |
149 aligner = make_shared<TransformDTWAligner> | |
150 (doc, | |
151 reference, | |
152 toAlign, | |
153 transform, | |
154 TransformDTWAligner::RiseFall); | |
155 break; | |
156 } | |
157 | |
158 case TransformDrivenDTWAlignment: | |
159 throw std::logic_error("Not yet implemented"); //!!! | |
160 | |
161 case ExternalProgramAlignment: { | |
162 aligner = make_shared<ExternalProgramAligner>(doc, | |
163 reference, | |
164 toAlign, | |
165 additionalData); | |
166 } | |
167 } | |
168 | |
169 m_aligners[toAlign] = aligner; | |
78 } | 170 } |
79 | 171 |
80 connect(aligner.get(), SIGNAL(complete(ModelId)), | 172 connect(aligner.get(), SIGNAL(complete(ModelId)), |
81 this, SLOT(alignerComplete(ModelId))); | 173 this, SLOT(alignerComplete(ModelId))); |
82 | 174 |
83 connect(aligner.get(), SIGNAL(failed(ModelId, QString)), | 175 connect(aligner.get(), SIGNAL(failed(ModelId, QString)), |
84 this, SLOT(alignerFailed(ModelId, QString))); | 176 this, SLOT(alignerFailed(ModelId, QString))); |
85 } | 177 |
86 | 178 return true; |
87 void | 179 } |
88 Align::getAlignerPreference(bool &useProgram, QString &program) | 180 |
181 Align::AlignmentType | |
182 Align::getAlignmentPreference(QString &additionalData) | |
89 { | 183 { |
90 QSettings settings; | 184 QSettings settings; |
91 settings.beginGroup("Preferences"); | 185 settings.beginGroup("Alignment"); |
92 useProgram = settings.value("use-external-alignment", false).toBool(); | 186 |
93 program = settings.value("external-alignment-program", "").toString(); | 187 QString tag = settings.value |
188 ("alignment-type", getAlignmentTypeTag(MATCHAlignment)).toString(); | |
189 | |
190 AlignmentType type = getAlignmentTypeForTag(tag); | |
191 | |
192 if (type == TransformDrivenDTWAlignment) { | |
193 additionalData = settings.value("alignment-transform", "").toString(); | |
194 } else if (type == ExternalProgramAlignment) { | |
195 additionalData = settings.value("alignment-program", "").toString(); | |
196 } | |
197 | |
198 settings.endGroup(); | |
199 return type; | |
200 } | |
201 | |
202 void | |
203 Align::setAlignmentPreference(AlignmentType type, QString additionalData) | |
204 { | |
205 QSettings settings; | |
206 settings.beginGroup("Alignment"); | |
207 | |
208 QString tag = getAlignmentTypeTag(type); | |
209 settings.setValue("alignment-type", tag); | |
210 | |
211 if (type == TransformDrivenDTWAlignment) { | |
212 settings.setValue("alignment-transform", additionalData); | |
213 } else if (type == ExternalProgramAlignment) { | |
214 settings.setValue("alignment-program", additionalData); | |
215 } | |
216 | |
94 settings.endGroup(); | 217 settings.endGroup(); |
95 } | 218 } |
96 | 219 |
97 bool | 220 bool |
98 Align::canAlign() | 221 Align::canAlign() |
99 { | 222 { |
100 bool useProgram; | 223 QString additionalData; |
101 QString program; | 224 AlignmentType type = getAlignmentPreference(additionalData); |
102 getAlignerPreference(useProgram, program); | 225 |
103 | 226 if (type == ExternalProgramAlignment) { |
104 if (useProgram) { | 227 return ExternalProgramAligner::isAvailable(additionalData); |
105 return ExternalProgramAligner::isAvailable(program); | |
106 } else { | 228 } else { |
107 return TransformAligner::isAvailable(); | 229 return TransformAligner::isAvailable(); |
108 } | 230 } |
109 } | 231 } |
110 | 232 |