Chris@205
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@205
|
2
|
Chris@205
|
3 /*
|
Chris@205
|
4 Sonic Visualiser
|
Chris@205
|
5 An audio file viewer and annotation editor.
|
Chris@205
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@205
|
7
|
Chris@205
|
8 This program is free software; you can redistribute it and/or
|
Chris@205
|
9 modify it under the terms of the GNU General Public License as
|
Chris@205
|
10 published by the Free Software Foundation; either version 2 of the
|
Chris@205
|
11 License, or (at your option) any later version. See the file
|
Chris@205
|
12 COPYING included with this distribution for more information.
|
Chris@205
|
13 */
|
Chris@205
|
14
|
Chris@205
|
15 #include "TransformUserConfigurator.h"
|
Chris@205
|
16
|
Chris@205
|
17 #include "transform/TransformFactory.h"
|
Chris@205
|
18
|
Chris@205
|
19 #include "widgets/PluginParameterDialog.h"
|
Chris@205
|
20
|
Chris@205
|
21 #include "plugin/FeatureExtractionPluginFactory.h"
|
Chris@205
|
22 #include "plugin/RealTimePluginFactory.h"
|
Chris@205
|
23 #include "plugin/RealTimePluginInstance.h"
|
Chris@205
|
24
|
Chris@205
|
25 #include "data/model/DenseTimeValueModel.h"
|
Chris@205
|
26
|
Chris@205
|
27 #include <vamp-hostsdk/Plugin.h>
|
Chris@205
|
28
|
Chris@205
|
29 #include <QStringList>
|
Chris@205
|
30
|
Chris@205
|
31 #include <typeinfo>
|
Chris@205
|
32
|
Chris@636
|
33 static QWidget *parentWidget = nullptr;
|
Chris@395
|
34
|
Chris@395
|
35 void
|
Chris@395
|
36 TransformUserConfigurator::setParentWidget(QWidget *w)
|
Chris@395
|
37 {
|
Chris@395
|
38 parentWidget = w;
|
Chris@395
|
39 }
|
Chris@395
|
40
|
Chris@205
|
41 bool
|
Chris@205
|
42 TransformUserConfigurator::getChannelRange(TransformId identifier,
|
Chris@740
|
43 std::shared_ptr<Vamp::PluginBase> plugin,
|
Chris@595
|
44 int &minChannels, int &maxChannels)
|
Chris@205
|
45 {
|
Chris@205
|
46 if (plugin && plugin->getType() == "Feature Extraction Plugin") {
|
Chris@740
|
47 auto vp = std::dynamic_pointer_cast<Vamp::Plugin>(plugin);
|
Chris@740
|
48 if (vp) {
|
Chris@740
|
49 SVDEBUG << "TransformUserConfigurator::getChannelRange: is a Vamp plugin" << endl;
|
Chris@740
|
50 minChannels = int(vp->getMinChannelCount());
|
Chris@740
|
51 maxChannels = int(vp->getMaxChannelCount());
|
Chris@740
|
52 return true;
|
Chris@740
|
53 } else {
|
Chris@740
|
54 SVCERR << "TransformUserConfigurator::getChannelRange: inconsistent plugin identity!" << endl;
|
Chris@740
|
55 return false;
|
Chris@740
|
56 }
|
Chris@205
|
57 } else {
|
Chris@595
|
58 SVDEBUG << "TransformUserConfigurator::getChannelRange: is not a Vamp plugin" << endl;
|
Chris@205
|
59 return TransformFactory::getInstance()->
|
Chris@205
|
60 getTransformChannelRange(identifier, minChannels, maxChannels);
|
Chris@205
|
61 }
|
Chris@205
|
62 }
|
Chris@205
|
63
|
Chris@205
|
64 bool
|
Chris@205
|
65 TransformUserConfigurator::configure(ModelTransformer::Input &input,
|
Chris@595
|
66 Transform &transform,
|
Chris@740
|
67 std::shared_ptr<Vamp::PluginBase> plugin,
|
Chris@685
|
68 ModelId &inputModel,
|
Chris@595
|
69 AudioPlaySource *source,
|
Chris@595
|
70 sv_frame_t startFrame,
|
Chris@595
|
71 sv_frame_t duration,
|
Chris@685
|
72 const QMap<QString, ModelId> &modelMap,
|
Chris@595
|
73 QStringList candidateModelNames,
|
Chris@595
|
74 QString defaultModelName)
|
Chris@205
|
75 {
|
Chris@205
|
76 bool ok = false;
|
Chris@205
|
77 QString id = transform.getPluginIdentifier();
|
Chris@205
|
78 QString output = transform.getOutput();
|
Chris@205
|
79 QString outputLabel = "";
|
Chris@205
|
80 QString outputDescription = "";
|
Chris@205
|
81
|
Chris@205
|
82 bool frequency = false;
|
Chris@205
|
83 bool effect = false;
|
Chris@205
|
84 bool generator = false;
|
Chris@205
|
85
|
Chris@205
|
86 if (!plugin) return false;
|
Chris@205
|
87
|
Chris@536
|
88 SVDEBUG << "TransformUserConfigurator::configure: identifier " << id << endl;
|
Chris@536
|
89
|
Chris@529
|
90 if (RealTimePluginFactory::instanceFor(id)) {
|
Chris@205
|
91
|
Chris@205
|
92 RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
|
Chris@740
|
93 RealTimePluginDescriptor desc = factory->getPluginDescriptor(id);
|
Chris@205
|
94
|
Chris@740
|
95 if (desc.audioInputPortCount > 0 &&
|
Chris@740
|
96 desc.audioOutputPortCount > 0 &&
|
Chris@740
|
97 !desc.isSynth) {
|
Chris@205
|
98 effect = true;
|
Chris@205
|
99 }
|
Chris@205
|
100
|
Chris@740
|
101 if (desc.audioInputPortCount == 0) {
|
Chris@205
|
102 generator = true;
|
Chris@205
|
103 }
|
Chris@205
|
104
|
Chris@205
|
105 if (output != "A") {
|
Chris@205
|
106 int outputNo = output.toInt();
|
Chris@740
|
107 if (outputNo >= 0 && outputNo < int(desc.controlOutputPortCount)) {
|
Chris@740
|
108 outputLabel = desc.controlOutputPortNames[outputNo].c_str();
|
Chris@205
|
109 }
|
Chris@205
|
110 }
|
Chris@205
|
111
|
Chris@740
|
112 auto auditionable = std::dynamic_pointer_cast<Auditionable>(plugin);
|
Chris@740
|
113
|
Chris@740
|
114 if (effect && source && auditionable) {
|
Chris@595
|
115 SVDEBUG << "Setting auditioning effect" << endl;
|
Chris@739
|
116 source->setAuditioningEffect(auditionable);
|
Chris@205
|
117 }
|
Chris@529
|
118
|
Chris@529
|
119 } else {
|
Chris@529
|
120
|
Chris@740
|
121 auto vp = std::dynamic_pointer_cast<Vamp::Plugin>(plugin);
|
Chris@529
|
122
|
Chris@595
|
123 frequency = (vp->getInputDomain() == Vamp::Plugin::FrequencyDomain);
|
Chris@529
|
124
|
Chris@595
|
125 std::vector<Vamp::Plugin::OutputDescriptor> od =
|
Chris@595
|
126 vp->getOutputDescriptors();
|
Chris@529
|
127
|
Chris@595
|
128 if (od.size() > 1) {
|
Chris@595
|
129 for (size_t i = 0; i < od.size(); ++i) {
|
Chris@595
|
130 if (od[i].identifier == output.toStdString()) {
|
Chris@595
|
131 outputLabel = od[i].name.c_str();
|
Chris@595
|
132 outputDescription = od[i].description.c_str();
|
Chris@595
|
133 break;
|
Chris@595
|
134 }
|
Chris@595
|
135 }
|
Chris@529
|
136 }
|
Chris@205
|
137 }
|
Chris@529
|
138
|
Chris@205
|
139 int sourceChannels = 1;
|
Chris@685
|
140
|
Chris@685
|
141 if (auto dtvm = ModelById::getAs<DenseTimeValueModel>(inputModel)) {
|
Chris@685
|
142 sourceChannels = dtvm->getChannelCount();
|
Chris@205
|
143 }
|
Chris@205
|
144
|
Chris@205
|
145 int minChannels = 1, maxChannels = sourceChannels;
|
Chris@205
|
146 getChannelRange(transform.getIdentifier(), plugin,
|
Chris@595
|
147 minChannels, maxChannels);
|
Chris@205
|
148
|
Chris@205
|
149 int targetChannels = sourceChannels;
|
Chris@205
|
150 if (!effect) {
|
Chris@595
|
151 if (sourceChannels < minChannels) targetChannels = minChannels;
|
Chris@595
|
152 if (sourceChannels > maxChannels) targetChannels = maxChannels;
|
Chris@205
|
153 }
|
Chris@205
|
154
|
Chris@205
|
155 int defaultChannel = -1; //!!! no longer saved! [was context.channel]
|
Chris@205
|
156
|
Chris@395
|
157 PluginParameterDialog *dialog = new PluginParameterDialog
|
Chris@395
|
158 (plugin, parentWidget);
|
Chris@205
|
159
|
Chris@205
|
160 dialog->setMoreInfoUrl(TransformFactory::getInstance()->
|
Chris@747
|
161 getTransformProvider(transform.getIdentifier())
|
Chris@747
|
162 .infoUrl);
|
Chris@205
|
163
|
Chris@205
|
164 if (candidateModelNames.size() > 1 && !generator) {
|
Chris@595
|
165 dialog->setCandidateInputModels(candidateModelNames,
|
Chris@595
|
166 defaultModelName);
|
Chris@205
|
167 }
|
Chris@205
|
168
|
Chris@205
|
169 if (startFrame != 0 || duration != 0) {
|
Chris@595
|
170 dialog->setShowSelectionOnlyOption(true);
|
Chris@205
|
171 }
|
Chris@205
|
172
|
Chris@205
|
173 if (targetChannels > 0) {
|
Chris@595
|
174 dialog->setChannelArrangement(sourceChannels, targetChannels,
|
Chris@595
|
175 defaultChannel);
|
Chris@205
|
176 }
|
Chris@205
|
177
|
Chris@205
|
178 dialog->setOutputLabel(outputLabel, outputDescription);
|
Chris@205
|
179
|
Chris@205
|
180 dialog->setShowProcessingOptions(true, frequency);
|
Chris@205
|
181
|
Chris@205
|
182 if (dialog->exec() == QDialog::Accepted) {
|
Chris@595
|
183 ok = true;
|
Chris@205
|
184 }
|
Chris@205
|
185
|
Chris@205
|
186 QString selectedInput = dialog->getInputModel();
|
Chris@205
|
187 if (selectedInput != "") {
|
Chris@595
|
188 if (modelMap.contains(selectedInput)) {
|
Chris@595
|
189 inputModel = modelMap.value(selectedInput);
|
Chris@595
|
190 SVDEBUG << "Found selected input \"" << selectedInput << "\" in model map, result is " << inputModel << endl;
|
Chris@595
|
191 } else {
|
Chris@595
|
192 SVDEBUG << "Failed to find selected input \"" << selectedInput << "\" in model map" << endl;
|
Chris@595
|
193 }
|
Chris@205
|
194 } else {
|
Chris@595
|
195 SVDEBUG << "Selected input empty: \"" << selectedInput << "\"" << endl;
|
Chris@205
|
196 }
|
Chris@205
|
197
|
Chris@205
|
198 // Write parameters back to transform object
|
Chris@205
|
199 TransformFactory::getInstance()->
|
Chris@595
|
200 setParametersFromPlugin(transform, plugin);
|
Chris@205
|
201
|
Chris@205
|
202 input.setChannel(dialog->getChannel());
|
Chris@205
|
203
|
Chris@205
|
204 //!!! The dialog ought to be taking & returning transform
|
Chris@205
|
205 //objects and input objects and stuff rather than passing
|
Chris@205
|
206 //around all this misc stuff, but that's for tomorrow
|
Chris@205
|
207 //(whenever that may be)
|
Chris@205
|
208
|
Chris@685
|
209 sv_samplerate_t sampleRate = 0;
|
Chris@685
|
210 if (auto m = ModelById::get(inputModel)) {
|
Chris@685
|
211 sampleRate = m->getSampleRate();
|
Chris@685
|
212 }
|
Chris@685
|
213
|
Chris@205
|
214 if (startFrame != 0 || duration != 0) {
|
Chris@685
|
215 if (dialog->getSelectionOnly() && sampleRate != 0) {
|
Chris@685
|
216 transform.setStartTime
|
Chris@685
|
217 (RealTime::frame2RealTime(startFrame, sampleRate));
|
Chris@685
|
218 transform.setDuration
|
Chris@685
|
219 (RealTime::frame2RealTime(duration, sampleRate));
|
Chris@595
|
220 }
|
Chris@205
|
221 }
|
Chris@205
|
222
|
Chris@366
|
223 int stepSize = 0, blockSize = 0;
|
Chris@205
|
224 WindowType windowType = HanningWindow;
|
Chris@205
|
225
|
Chris@205
|
226 dialog->getProcessingParameters(stepSize,
|
Chris@595
|
227 blockSize,
|
Chris@595
|
228 windowType);
|
Chris@205
|
229
|
Chris@205
|
230 transform.setStepSize(stepSize);
|
Chris@205
|
231 transform.setBlockSize(blockSize);
|
Chris@205
|
232 transform.setWindowType(windowType);
|
Chris@205
|
233
|
Chris@205
|
234 delete dialog;
|
Chris@205
|
235
|
Chris@205
|
236 if (effect && source) {
|
Chris@739
|
237 source->setAuditioningEffect({});
|
Chris@205
|
238 }
|
Chris@205
|
239
|
Chris@205
|
240 return ok;
|
Chris@205
|
241 }
|
Chris@205
|
242
|