1 #include "effects/lv2/lv2manifest.h"
2
3 #include "effects/effectmanifestparameter.h"
4 #include "util/fpclassify.h"
5
LV2Manifest(const LilvPlugin * plug,QHash<QString,LilvNode * > & properties)6 LV2Manifest::LV2Manifest(const LilvPlugin* plug,
7 QHash<QString, LilvNode*>& properties)
8 : m_pEffectManifest(new EffectManifest()),
9 m_status(AVAILABLE) {
10
11 m_pLV2plugin = plug;
12
13 // Get and set the ID
14 const LilvNode* id = lilv_plugin_get_uri(m_pLV2plugin);
15 m_pEffectManifest->setId(lilv_node_as_string(id));
16
17 // Get and set the name
18 LilvNode* info = lilv_plugin_get_name(m_pLV2plugin);
19 m_pEffectManifest->setName(lilv_node_as_string(info));
20 lilv_node_free(info);
21
22 // Get and set the author
23 info = lilv_plugin_get_author_name(m_pLV2plugin);
24 m_pEffectManifest->setAuthor(lilv_node_as_string(info));
25 lilv_node_free(info);
26
27 int numPorts = lilv_plugin_get_num_ports(plug);
28 m_minimum = new float[numPorts];
29 m_maximum = new float[numPorts];
30 m_default = new float[numPorts];
31 lilv_plugin_get_port_ranges_float(m_pLV2plugin, m_minimum, m_maximum,
32 m_default);
33
34 // Counters to determine the type of the plug in
35 int inputPorts = 0;
36 int outputPorts = 0;
37
38 for (int i = 0; i < numPorts; i++) {
39 const LilvPort *port = lilv_plugin_get_port_by_index(plug, i);
40
41 if (lilv_port_is_a(m_pLV2plugin, port, properties["audio_port"])) {
42 if (lilv_port_is_a(m_pLV2plugin, port, properties["input_port"])) {
43 audioPortIndices.append(i);
44 inputPorts++;
45 } else if (lilv_port_is_a(m_pLV2plugin, port, properties["output_port"])) {
46 audioPortIndices.append(i);
47 outputPorts++;
48 }
49 }
50
51 if (lilv_port_is_a(m_pLV2plugin, port, properties["control_port"])
52 && !lilv_port_has_property(m_pLV2plugin, port, properties["enumeration_port"])
53 && !lilv_port_has_property(m_pLV2plugin, port, properties["button_port"])) {
54 controlPortIndices.append(i);
55 EffectManifestParameterPointer param = m_pEffectManifest->addParameter();
56
57 // Get and set the parameter name
58 info = lilv_port_get_name(m_pLV2plugin, port);
59 QString paramName = lilv_node_as_string(info);
60 param->setName(paramName);
61 lilv_node_free(info);
62
63 const LilvNode* node = lilv_port_get_symbol(m_pLV2plugin, port);
64 QString symbol = lilv_node_as_string(node);
65 param->setId(symbol);
66 // node must not be freed here, it is owned by port
67
68 param->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
69 param->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
70 param->setDefault(m_default[i]);
71 param->setMinimum(m_minimum[i]);
72 param->setMaximum(m_maximum[i]);
73
74 // Set the appropriate Hints
75 if (lilv_port_has_property(m_pLV2plugin, port, properties["button_port"])) {
76 param->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING);
77 } else if (lilv_port_has_property(m_pLV2plugin, port, properties["enumeration_port"])) {
78 buildEnumerationOptions(port, param);
79 param->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING);
80 } else if (lilv_port_has_property(m_pLV2plugin, port, properties["integer_port"])) {
81 param->setControlHint(EffectManifestParameter::ControlHint::KNOB_STEPPING);
82 } else {
83 param->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR);
84 }
85 }
86 }
87
88 // Hack for putting enum parameters to the end of controlportindices
89 for (int i = 0; i < numPorts; i++) {
90 const LilvPort *port = lilv_plugin_get_port_by_index(plug, i);
91
92 if (lilv_port_is_a(m_pLV2plugin, port, properties["control_port"]) &&
93 (lilv_port_has_property(m_pLV2plugin, port, properties["enumeration_port"]) ||
94 lilv_port_has_property(m_pLV2plugin, port, properties["button_port"]))) {
95 controlPortIndices.append(i);
96 EffectManifestParameterPointer param = m_pEffectManifest->addParameter();
97
98 // Get and set the parameter name
99 info = lilv_port_get_name(m_pLV2plugin, port);
100 QString paramName = lilv_node_as_string(info);
101 param->setName(paramName);
102 lilv_node_free(info);
103
104 const LilvNode* node = lilv_port_get_symbol(m_pLV2plugin, port);
105 QString symbol = lilv_node_as_string(node);
106 param->setId(symbol);
107 // info must not be freed here, it is owned by port
108
109 param->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
110 param->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
111 param->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING);
112 if (lilv_port_has_property(m_pLV2plugin, port, properties["enumeration_port"])) {
113 buildEnumerationOptions(port, param);
114 } else {
115 param->appendStep(qMakePair(QString("Inactive"), 0.0));
116 param->appendStep(qMakePair(QString("Active"), 1.0));
117 }
118
119 // Some plugins don't specify minimum, maximum and default values
120 // In this case set the minimum and default values to 0 and
121 // the maximum to the number of scale points
122 if (util_isnan(m_default[i])) {
123 param->setDefault(0);
124 } else {
125 param->setDefault(m_default[i]);
126 }
127
128 if (util_isnan(m_minimum[i])) {
129 param->setMinimum(0);
130 } else {
131 param->setMinimum(m_minimum[i]);
132 }
133
134 if (util_isnan(m_maximum[i])) {
135 param->setMaximum(param->getSteps().size() - 1);
136 } else {
137 param->setMaximum(m_maximum[i]);
138 }
139 }
140 }
141
142 // We only support the case when the input and output samples are stereo
143 if (inputPorts != 2 || outputPorts != 2) {
144 m_status = IO_NOT_STEREO;
145 }
146
147 // We don't support any features
148 LilvNodes* features = lilv_plugin_get_required_features(m_pLV2plugin);
149 if (lilv_nodes_size(features) > 0) {
150 m_status = HAS_REQUIRED_FEATURES;
151 }
152 lilv_nodes_free(features);
153 }
154
~LV2Manifest()155 LV2Manifest::~LV2Manifest() {
156 delete[] m_minimum;
157 delete[] m_maximum;
158 delete[] m_default;
159 }
160
getEffectManifest() const161 EffectManifestPointer LV2Manifest::getEffectManifest() const {
162 return m_pEffectManifest;
163 }
164
getAudioPortIndices()165 QList<int> LV2Manifest::getAudioPortIndices() {
166 return audioPortIndices;
167 }
168
getControlPortIndices()169 QList<int> LV2Manifest::getControlPortIndices() {
170 return controlPortIndices;
171 }
172
getPlugin()173 const LilvPlugin* LV2Manifest::getPlugin() {
174 return m_pLV2plugin;
175 }
176
getStatus()177 LV2Manifest::Status LV2Manifest::getStatus() {
178 return m_status;
179 }
180
isValid()181 bool LV2Manifest::isValid() {
182 return m_status == AVAILABLE;
183 }
184
buildEnumerationOptions(const LilvPort * port,EffectManifestParameterPointer param)185 void LV2Manifest::buildEnumerationOptions(const LilvPort* port,
186 EffectManifestParameterPointer param) {
187 LilvScalePoints* options = lilv_port_get_scale_points(m_pLV2plugin, port);
188 LILV_FOREACH(scale_points, iterator, options) {
189 const LilvScalePoint* option = lilv_scale_points_get(options, iterator);
190 const LilvNode* description = lilv_scale_point_get_label(option);
191 const LilvNode* value = lilv_scale_point_get_value(option);
192 QString strDescription(lilv_node_as_string(description));
193 param->appendStep(qMakePair(strDescription,
194 static_cast<double>(lilv_node_as_float(value))));
195 }
196
197 if (options != nullptr) {
198 lilv_scale_points_free(options);
199 }
200 }
201