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