static GParamSpec * gst_lv2_class_get_param_spec (GstLV2Class * klass, gint portnum) { SLV2Plugin lv2plugin = klass->plugin; SLV2Port port = slv2_plugin_get_port_by_index (lv2plugin, portnum); SLV2Value lv2def, lv2min, lv2max; GParamSpec *ret; gchar *name; gint perms; gfloat lower = 0.0f, upper = 1.0f, def = 0.0f; name = gst_lv2_class_get_param_name (klass, portnum); perms = G_PARAM_READABLE; if (slv2_port_is_a (lv2plugin, port, input_class)) perms |= G_PARAM_WRITABLE | G_PARAM_CONSTRUCT; if (slv2_port_is_a (lv2plugin, port, control_class)) perms |= GST_PARAM_CONTROLLABLE; if (slv2_port_has_property (lv2plugin, port, toggled_prop)) { ret = g_param_spec_boolean (name, name, name, FALSE, perms); g_free (name); return ret; } slv2_port_get_range (lv2plugin, port, &lv2def, &lv2min, &lv2max); if (lv2def) def = slv2_value_as_float (lv2def); if (lv2min) lower = slv2_value_as_float (lv2min); if (lv2max) upper = slv2_value_as_float (lv2max); if (def < lower) { GST_WARNING ("%s has lower bound %f > default %f\n", slv2_value_as_string (slv2_plugin_get_uri (lv2plugin)), lower, def); lower = def; } if (def > upper) { GST_WARNING ("%s has upper bound %f < default %f\n", slv2_value_as_string (slv2_plugin_get_uri (lv2plugin)), upper, def); upper = def; } if (slv2_port_has_property (lv2plugin, port, integer_prop)) ret = g_param_spec_int (name, name, name, lower, upper, def, perms); else ret = g_param_spec_float (name, name, name, lower, upper, def, perms); g_free (name); return ret; }
static gchar * gst_lv2_class_get_param_name (GstLV2Class * klass, gint portnum) { SLV2Plugin lv2plugin = klass->plugin; SLV2Port port = slv2_plugin_get_port_by_index (lv2plugin, portnum); return g_strdup (slv2_value_as_string (slv2_port_get_symbol (lv2plugin, port))); }
void slv2_port_get_range(SLV2Plugin p, SLV2Port port, SLV2Value* def, SLV2Value* min, SLV2Value* max) { if (def) *def = NULL; if (min) *min = NULL; if (max) *max = NULL; char* query = slv2_strjoin( "SELECT DISTINCT ?def ?min ?max WHERE {\n" "<", slv2_value_as_uri(p->plugin_uri), "> lv2:port ?port .\n" "?port lv2:symbol \"", slv2_value_as_string(port->symbol), "\".\n", "OPTIONAL { ?port lv2:default ?def }\n", "OPTIONAL { ?port lv2:minimum ?min }\n", "OPTIONAL { ?port lv2:maximum ?max }\n", "\n}", NULL); librdf_query_results* results = slv2_plugin_query(p, query); while (!librdf_query_results_finished(results)) { librdf_node* def_node = librdf_query_results_get_binding_value(results, 0); librdf_node* min_node = librdf_query_results_get_binding_value(results, 1); librdf_node* max_node = librdf_query_results_get_binding_value(results, 2); if (def && def_node && !*def) *def = slv2_value_new_librdf_node(p->world, def_node); if (min && min_node && !*min) *min = slv2_value_new_librdf_node(p->world, min_node); if (max && max_node && !*max) *max = slv2_value_new_librdf_node(p->world, max_node); if ((!def || *def) && (!min || *min) && (!max || *max)) break; librdf_query_results_next(results); } librdf_free_query_results(results); free(query); }
SLV2Values slv2_port_get_value_by_qname(SLV2Plugin p, SLV2Port port, const char* property) { assert(property); SLV2Values results = NULL; char* query = slv2_strjoin( "SELECT DISTINCT ?value WHERE {\n" "<", slv2_value_as_uri(p->plugin_uri), "> lv2:port ?port .\n" "?port lv2:symbol \"", slv2_value_as_string(port->symbol), "\";\n\t", property, " ?value .\n" "FILTER(lang(?value) = \"\") }", NULL); results = slv2_plugin_query_variable(p, query, 0); free(query); return results; }
SLV2ScalePoints slv2_port_get_scale_points(SLV2Plugin p, SLV2Port port) { char* query = slv2_strjoin( "SELECT DISTINCT ?value ?label WHERE {\n" "<", slv2_value_as_uri(p->plugin_uri), "> lv2:port ?port .\n" "?port lv2:symbol \"", slv2_value_as_string(port->symbol), "\" ;\n", " lv2:scalePoint ?point .\n" "?point rdf:value ?value ;\n" " rdfs:label ?label .\n" "\n} ORDER BY ?value", NULL); librdf_query_results* results = slv2_plugin_query(p, query); SLV2ScalePoints ret = NULL; if (!librdf_query_results_finished(results)) ret = slv2_scale_points_new(); while (!librdf_query_results_finished(results)) { librdf_node* value_node = librdf_query_results_get_binding_value(results, 0); librdf_node* label_node = librdf_query_results_get_binding_value(results, 1); SLV2Value value = slv2_value_new_librdf_node(p->world, value_node); SLV2Value label = slv2_value_new_librdf_node(p->world, label_node); raptor_sequence_push(ret, slv2_scale_point_new(value, label)); librdf_query_results_next(results); } librdf_free_query_results(results); free(query); assert(!ret || slv2_values_size(ret) > 0); return ret; }
const ScalePointMap& LV2Effect::GetScalePoints() { if (!mScalePointsRetrieved) { char scalePointQuery[] = "PREFIX : <http://lv2plug.in/ns/lv2core#>\n" "SELECT ?index, ?value, ?label WHERE {\n" "<> :port ?port.\n" "?port a :ControlPort.\n" "?port a :InputPort.\n" "?port :index ?index.\n" "?port :scalePoint ?point.\n" "?point rdf:value ?value.\n" "?point rdfs:label ?label.\n" "}"; SLV2Values portIndices = slv2_plugin_query_variable(mData, scalePointQuery, 0); SLV2Values pointValues = slv2_plugin_query_variable(mData, scalePointQuery, 1); SLV2Values pointLabels = slv2_plugin_query_variable(mData, scalePointQuery, 2); size_t nScalePoints = slv2_values_size(portIndices); for (size_t i = 0; i < nScalePoints; ++i) { uint32_t idx = slv2_value_as_int(slv2_values_get_at(portIndices, i)); float value = slv2_value_as_float(slv2_values_get_at(pointValues, i)); wxString label = wxString::FromUTF8(slv2_value_as_string(slv2_values_get_at(pointLabels, i))); mScalePoints[idx][value] = label; } slv2_values_free(portIndices); slv2_values_free(pointValues); slv2_values_free(pointLabels); mScalePointsRetrieved = true; } return mScalePoints; }
bool slv2_port_supports_event(SLV2Plugin p, SLV2Port port, SLV2Value event) { assert(event); char* query = slv2_strjoin( "ASK WHERE {\n" "<", slv2_value_as_uri(p->plugin_uri), "> lv2:port ?port ." "?port lv2:symbol \"", slv2_value_as_string(port->symbol), "\";\n", " lv2ev:supportsEvent <", event, "> .\n" "}", NULL); librdf_query_results* results = slv2_plugin_query(p, query); assert(librdf_query_results_is_boolean(results)); const bool ret = librdf_query_results_get_boolean(results); free(query); librdf_free_query_results(results); return ret; }
bool slv2_port_has_property(SLV2Plugin p, SLV2Port port, SLV2Value property) { assert(property); SLV2Values results = NULL; char* query = slv2_strjoin( "SELECT DISTINCT ?port WHERE {\n" "<", slv2_value_as_uri(p->plugin_uri), "> lv2:port ?port ." "?port lv2:symbol \"", slv2_value_as_string(port->symbol), "\";\n", " lv2:portProperty <", slv2_value_as_uri(property), "> .\n}", NULL); results = slv2_plugin_query_variable(p, query, 0); const bool ret = (slv2_values_size(results) > 0); free(query); free(results); return ret; }
QString Lv2Plugin::copyright () const { return m_copyright ? slv2_value_as_string( m_copyright ) : NULL; }
QString Lv2Plugin::authorHomepage () const { return m_authorHomepage ? slv2_value_as_string( m_authorHomepage ) : NULL; }
QString Lv2Plugin::authorEmail () const { return m_authorEmail ? slv2_value_as_string( m_authorEmail ) : NULL; }
QString Lv2Plugin::authorName () const { return m_authorName ? slv2_value_as_string( m_authorName ) : "Unknown"; }
LV2EffectDialog::LV2EffectDialog(LV2Effect *eff, wxWindow * parent, SLV2Plugin data, int sampleRate, double length, double noteLength, unsigned char noteVelocity, unsigned char noteKey) :wxDialog(parent, -1, LAT1CTOWX(slv2_value_as_string(slv2_plugin_get_name(data))), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), effect(eff), mControls(eff->GetControls()) { mLength = length; this->mData = data; this->sampleRate = sampleRate; #ifdef __WXMSW__ // On Windows, for some reason, wxWindows calls OnTextCtrl during creation // of the text control, and LV2EffectDialog::OnTextCtrl calls HandleText, // which assumes all the fields have been initialized. // This can give us a bad pointer crash, so manipulate inSlider to // no-op HandleText during creation. inSlider = true; #else inSlider = false; #endif inText = false; // Allocate memory for the user parameter controls toggles = new wxCheckBox*[mControls.size()]; sliders = new wxSlider*[mControls.size()]; fields = new wxTextCtrl*[mControls.size()]; labels = new wxStaticText*[mControls.size()]; wxControl *item; wxBoxSizer *vSizer = new wxBoxSizer(wxVERTICAL); // Add information about the plugin SLV2Value tmpValue = slv2_plugin_get_author_name(data); if (tmpValue) { const char* author = slv2_value_as_string(tmpValue); item = new wxStaticText(this, 0, wxString(_("Author: "))+LAT1CTOWX(author)); vSizer->Add(item, 0, wxALL, 5); slv2_value_free(tmpValue); } wxScrolledWindow *w = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL | wxTAB_TRAVERSAL); // Try to give the window a sensible default/minimum size w->SetMinSize(wxSize( wxMax(600, parent->GetSize().GetWidth() * 2/3), parent->GetSize().GetHeight() / 2)); w->SetScrollRate(0, 20); vSizer->Add(w, 1, wxEXPAND|wxALL, 5); // Preview, OK, & Cancel buttons vSizer->Add(CreateStdButtonSizer(this, ePreviewButton|eCancelButton|eOkButton), 0, wxEXPAND); SetSizer(vSizer); wxSizer *paramSizer = new wxStaticBoxSizer(wxVERTICAL, w, _("Effect Settings")); wxFlexGridSizer *gridSizer = new wxFlexGridSizer(5, 0, 0); gridSizer->AddGrowableCol(3); const LV2PortGroup& rootGroup = eff->GetPortGroups(); const ScalePointMap& scalePoints = eff->GetScalePoints(); // Now add the length control if (effect->GetEffectFlags() & INSERT_EFFECT) { item = new wxStaticText(w, 0, _("Length (seconds)")); gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); mSeconds = new wxTextCtrl(w, LADSPA_SECONDS_ID, Internat::ToDisplayString(length)); mSeconds->SetName(_("Length (seconds)")); gridSizer->Add(mSeconds, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); gridSizer->Add(1, 1, 0); gridSizer->Add(1, 1, 0); gridSizer->Add(1, 1, 0); ConnectFocus(mSeconds); } // The note controls if the plugin is a synth if (effect->IsSynth()) { // Note length control item = new wxStaticText(w, 0, _("Note length (seconds)")); gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); mNoteSeconds = new wxTextCtrl(w, LADSPA_SECONDS_ID, Internat::ToDisplayString(length / 2)); mNoteSeconds->SetName(_("Note length (seconds)")); gridSizer->Add(mNoteSeconds, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); gridSizer->Add(1, 1, 0); gridSizer->Add(1, 1, 0); gridSizer->Add(1, 1, 0); ConnectFocus(mNoteSeconds); // Note velocity control item = new wxStaticText(w, 0, _("Note velocity")); gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); mNoteVelocity = new wxTextCtrl(w, LADSPA_SECONDS_ID, Internat::ToDisplayString(64)); mNoteVelocity->SetName(_("Note velocity")); gridSizer->Add(mNoteVelocity, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); gridSizer->Add(1, 1, 0); gridSizer->Add(1, 1, 0); gridSizer->Add(1, 1, 0); ConnectFocus(mNoteVelocity); // Note key control item = new wxStaticText(w, 0, _("Note key")); gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); mNoteKey = new wxTextCtrl(w, LADSPA_SECONDS_ID, Internat::ToDisplayString(64)); mNoteKey->SetName(_("Note key")); gridSizer->Add(mNoteKey, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); gridSizer->Add(1, 1, 0); gridSizer->Add(1, 1, 0); gridSizer->Add(1, 1, 0); ConnectFocus(mNoteKey); } paramSizer->Add(gridSizer, 1, wxEXPAND | wxALL, 5); // Create user parameter controls std::queue<const LV2PortGroup*> groups; groups.push(&rootGroup); while (!groups.empty()) { const LV2PortGroup* pg = groups.front(); groups.pop(); if (pg->GetName() != wxT("")) { wxSizer *groupSizer = new wxStaticBoxSizer(wxVERTICAL, w, pg->GetName()); paramSizer->Add(groupSizer, 0, wxEXPAND | wxALL, 5); gridSizer = new wxFlexGridSizer(5, 0, 0); gridSizer->AddGrowableCol(3); groupSizer->Add(gridSizer, 1, wxEXPAND | wxALL, 5); } std::vector<LV2PortGroup>::const_iterator iter; for (iter = pg->GetSubGroups().begin(); iter != pg->GetSubGroups().end(); ++iter) { groups.push(&*iter); } const std::vector<uint32_t>& params = pg->GetParameters(); for (uint32_t k = 0; k < params.size(); ++k) { uint32_t p = params[k]; wxString labelText = mControls[p].mName; item = new wxStaticText(w, 0, labelText + wxT(":")); gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); wxString fieldText; if (mControls[p].mToggle) { toggles[p] = new wxCheckBox(w, p, wxT("")); toggles[p]->SetName(labelText); toggles[p]->SetValue(mControls[p].mControlBuffer > 0); gridSizer->Add(toggles[p], 0, wxALL, 5); ConnectFocus(toggles[p]); gridSizer->Add(1, 1, 0); gridSizer->Add(1, 1, 0); gridSizer->Add(1, 1, 0); } else { if (mControls[p].mInteger) fieldText.Printf(wxT("%d"), (int)(mControls[p].mControlBuffer + 0.5)); else fieldText = Internat::ToDisplayString(mControls[p].mControlBuffer); fields[p] = new wxTextCtrl(w, p, fieldText); fields[p]->SetName(labelText); gridSizer->Add(fields[p], 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); ConnectFocus(fields[p]); wxString bound; double lower = 0.0; double upper = 0.0; bool haslo = false; bool hashi = false; bool forceint = false; wxString loLabel; wxString hiLabel; ScalePointMap::const_iterator iter = scalePoints.find(mControls[p].mIndex); if (!std::isnan(mControls[p].mMin)) { lower = mControls[p].mMin; haslo = true; if (iter != scalePoints.end()) { std::map<float, wxString>::const_iterator iter2 = iter->second.find(lower); if (iter2 != iter->second.end()) { loLabel = iter2->second; } } } if (!std::isnan(mControls[p].mMax)) { upper = mControls[p].mMax; hashi = true; if (iter != scalePoints.end()) { std::map<float, wxString>::const_iterator iter2 = iter->second.find(upper); if (iter2 != iter->second.end()) hiLabel = iter2->second; } } if (mControls[p].mSampleRate) { lower *= sampleRate * 1000; upper *= sampleRate; forceint = true; } wxString str; if (haslo) { str = loLabel; if (str.IsEmpty()) { if (mControls[p].mInteger || forceint) str.Printf(wxT("%d"), (int)(lower + 0.5)); else str = Internat::ToDisplayString(lower); } item = new wxStaticText(w, 0, str); gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); } else { gridSizer->Add(1, 1, 0); } sliders[p] = new wxSlider(w, p, 0, 0, 1000, wxDefaultPosition, wxSize(200, -1)); sliders[p]->SetName(labelText); gridSizer->Add(sliders[p], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, 5); ConnectFocus(sliders[p]); if (hashi) { str = hiLabel; if (str.IsEmpty()) { if (mControls[p].mInteger || forceint) str.Printf(wxT("%d"), (int)(upper + 0.5)); else str = Internat::ToDisplayString(upper); } item = new wxStaticText(w, 0, str); gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, 5); } else { gridSizer->Add(1, 1, 0); } } } } // Set all of the sliders based on the value in the // text fields inSlider = false; // Now we're ready for HandleText to actually do something. HandleText(); w->SetSizer(paramSizer); Layout(); Fit(); SetSizeHints(GetSize()); }
LV2Effect::LV2Effect(SLV2Plugin data, const std::set<wxString>& categories) : mValid(true), mCategories(categories), mMidiInput(0), mScalePointsRetrieved(false), mPortGroupsRetrieved(false) { // We don't support any features at all, so if the plugin requires // any we skip it. SLV2Values req = slv2_plugin_get_required_features(data); size_t nFeatures = slv2_values_size(req); slv2_values_free(req); if (nFeatures > 0) { mValid = false; return; } mData = data; pluginName = wxString::FromUTF8(slv2_value_as_string(slv2_plugin_get_name(mData))); fInBuffer = NULL; fOutBuffer = NULL; mLength = 0; uint32_t p; // Allocate buffers for the port indices and the default control values uint32_t numPorts = slv2_plugin_get_num_ports(mData); float* minimumValues = new float [numPorts]; float* maximumValues = new float [numPorts]; float* defaultValues = new float [numPorts]; // Retrieve the port ranges for all ports (some values may be NaN) slv2_plugin_get_port_ranges_float(mData, minimumValues, maximumValues, defaultValues); // Get info about all ports for(p = 0; p < numPorts; p++) { SLV2Port port = slv2_plugin_get_port_by_index(mData, p); LV2Port internalPort; internalPort.mIndex = p; // Get the port name SLV2Value tmpName = slv2_port_get_name(data, port); internalPort.mName = LAT1CTOWX(slv2_value_as_string(tmpName)); slv2_value_free(tmpName); // Get the port type if (slv2_port_is_a(mData, port, gAudioPortClass)) { if (slv2_port_is_a(mData, port, gInputPortClass)) mAudioInputs.push_back(internalPort); else if (slv2_port_is_a(mData, port, gOutputPortClass)) mAudioOutputs.push_back(internalPort); } else if (slv2_port_is_a(mData, port, gControlPortClass) && slv2_port_is_a(mData, port, gInputPortClass)) { internalPort.mControlBuffer = float(1.0); internalPort.mMin = minimumValues[p]; internalPort.mMax = maximumValues[p]; internalPort.mDefault = defaultValues[p]; if (std::isfinite(defaultValues[p])) internalPort.mControlBuffer = defaultValues[p]; else if (std::isfinite(minimumValues[p])) internalPort.mControlBuffer = minimumValues[p]; else if (std::isfinite(maximumValues[p])) internalPort.mControlBuffer = maximumValues[p]; if (slv2_port_has_property(data, port, gPortToggled)) internalPort.mToggle = true; if (slv2_port_has_property(data, port, gPortIsInteger)) internalPort.mInteger = true; if (slv2_port_has_property(data, port, gPortIsSampleRate)) internalPort.mSampleRate = true; mControlInputs.push_back(internalPort); } else if (slv2_port_is_a(mData, port, gMidiPortClass) && slv2_port_is_a(mData, port, gInputPortClass)) { // If there are more than one MIDI input ports, the plugin is invalid if (mMidiInput) { mValid = false; continue; } mMidiInput = new LV2Port(internalPort); } else { // Unknown port type, we set the invalid flag mValid = false; } } delete [] minimumValues; delete [] maximumValues; delete [] defaultValues; // MIDI synths may not have any audio inputs. if (mMidiInput && mAudioInputs.size() > 0) mValid = false; // Determine whether the plugin is a generator, effect or analyser // depending on the number of ports of each type (not completely accurate, // but works most of the time) flags = PLUGIN_EFFECT; if (mAudioInputs.size() == 0) flags |= INSERT_EFFECT; else if (mAudioOutputs.size() == 0) flags |= ANALYZE_EFFECT; else flags |= PROCESS_EFFECT; }
const LV2PortGroup& LV2Effect::GetPortGroups() { if (!mPortGroupsRetrieved) { // Find all port groups with ports in them. char portGroupQuery[] = "PREFIX : <http://lv2plug.in/ns/lv2core#>\n" "PREFIX pg: <http://ll-plugins.nongnu.org/lv2/ext/portgroups#>\n" "SELECT ?index, ?uri, ?label WHERE {\n" "<> :port ?port.\n" "?port :index ?index.\n" "?port pg:membership ?ms.\n" "?ms pg:group ?uri.\n" "?uri rdfs:label ?label.\n" "}"; SLV2Values portIndices = slv2_plugin_query_variable(mData, portGroupQuery, 0); SLV2Values groupUris = slv2_plugin_query_variable(mData, portGroupQuery, 1); SLV2Values groupLabels = slv2_plugin_query_variable(mData, portGroupQuery, 2); std::map<wxString, LV2PortGroup> portGroups; std::vector<bool> inGroup(mControlInputs.size(), false); size_t nMemberships = slv2_values_size(portIndices); for (size_t i = 0; i < nMemberships; ++i) { uint32_t idx = slv2_value_as_int(slv2_values_get_at(portIndices, i)); uint32_t p; for (p = 0; p < mControlInputs.size(); ++p) { if (mControlInputs[p].mIndex == idx) break; } if (p == mControlInputs.size()) continue; wxString uri = wxString::FromUTF8(slv2_value_as_string(slv2_values_get_at(groupUris, i))); wxString label = wxString::FromUTF8(slv2_value_as_string(slv2_values_get_at(groupLabels, i))); std::map<wxString, LV2PortGroup>::iterator iter = portGroups.find(uri); if (iter == portGroups.end()) portGroups[uri] = LV2PortGroup(label); portGroups[uri].AddParameter(p); inGroup[p] = true; } slv2_values_free(portIndices); slv2_values_free(groupUris); slv2_values_free(groupLabels); // Add all ports that aren't in any port groups to the root group. for (uint32_t p = 0; p < mControlInputs.size(); ++p) { if (!inGroup[p]) mRootGroup.AddParameter(p); } // Find all subgroup relationships. char subGroupQuery[] = "PREFIX : <http://lv2plug.in/ns/lv2core#>\n" "PREFIX pg: <http://ll-plugins.nongnu.org/lv2/ext/portgroups#>\n" "SELECT ?sub, ?parent WHERE {\n" "?sub pg:subgroupOf ?parent.\n" "}"; SLV2Values subs = slv2_plugin_query_variable(mData, subGroupQuery, 0); SLV2Values parents = slv2_plugin_query_variable(mData, subGroupQuery, 1); size_t nSubgroups = slv2_values_size(subs); for (size_t i = 0; i < nSubgroups; ++i) { wxString parent = wxString::FromUTF8(slv2_value_as_uri(slv2_values_get_at(parents, i))); wxString sub = wxString::FromUTF8(slv2_value_as_uri(slv2_values_get_at(subs, i))); std::map<wxString, LV2PortGroup>::iterator iter = portGroups.find(parent); std::map<wxString, LV2PortGroup>::iterator iter2 = portGroups.find(sub); if (iter != portGroups.end() && iter2 != portGroups.end()) { iter->second.AddSubGroup(iter2->second); } } slv2_values_free(subs); slv2_values_free(parents); // Make all groups subgroups of the root group. std::map<wxString, LV2PortGroup>::iterator iter; for (iter = portGroups.begin(); iter != portGroups.end(); ++iter) mRootGroup.AddSubGroup(iter->second); mPortGroupsRetrieved = true; } std::queue<const LV2PortGroup*> groups; groups.push(&mRootGroup); while (!groups.empty()) { const LV2PortGroup* g = groups.front(); groups.pop(); const std::vector<LV2PortGroup>& subs = g->GetSubGroups(); for (std::vector<LV2PortGroup>::const_iterator iter = subs.begin(); iter != subs.end(); ++iter) groups.push(&*iter); } return mRootGroup; }
static void gst_lv2_base_init (gpointer g_class) { GstLV2Class *klass = (GstLV2Class *) g_class; GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); GstSignalProcessorClass *gsp_class = GST_SIGNAL_PROCESSOR_CLASS (g_class); GstElementDetails *details; SLV2Plugin lv2plugin; SLV2Value val; guint j, audio_in_count, audio_out_count, control_in_count, control_out_count; gchar *klass_tags; GST_DEBUG ("base_init %p", g_class); lv2plugin = (SLV2Plugin) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass), GST_SLV2_PLUGIN_QDATA); g_assert (lv2plugin); /* pad templates */ gsp_class->num_audio_in = 0; gsp_class->num_audio_out = 0; /* properties */ gsp_class->num_control_in = 0; gsp_class->num_control_out = 0; for (j = 0; j < slv2_plugin_get_num_ports (lv2plugin); j++) { SLV2Port port = slv2_plugin_get_port_by_index (lv2plugin, j); if (slv2_port_is_a (lv2plugin, port, audio_class)) { gchar *name = g_strdup (slv2_value_as_string (slv2_port_get_symbol (lv2plugin, port))); GST_DEBUG ("LV2 port name: \"%s\"", name); if (slv2_port_is_a (lv2plugin, port, input_class)) gst_signal_processor_class_add_pad_template (gsp_class, name, GST_PAD_SINK, gsp_class->num_audio_in++); else if (slv2_port_is_a (lv2plugin, port, output_class)) gst_signal_processor_class_add_pad_template (gsp_class, name, GST_PAD_SRC, gsp_class->num_audio_out++); /* TODO: else ignore plugin */ g_free (name); } else if (slv2_port_is_a (lv2plugin, port, control_class)) { if (slv2_port_is_a (lv2plugin, port, input_class)) gsp_class->num_control_in++; else if (slv2_port_is_a (lv2plugin, port, output_class)) gsp_class->num_control_out++; /* TODO: else ignore plugin */ } /* TODO: else ignore plugin */ } /* construct the element details struct */ details = g_new0 (GstElementDetails, 1); val = slv2_plugin_get_name (lv2plugin); if (val) { details->longname = g_strdup (slv2_value_as_string (val)); slv2_value_free (val); } else { details->longname = g_strdup ("no description available"); } details->description = details->longname; val = slv2_plugin_get_author_name (lv2plugin); if (val) { details->author = g_strdup (slv2_value_as_string (val)); slv2_value_free (val); } else { details->author = g_strdup ("no author available"); } if (gsp_class->num_audio_in == 0) klass_tags = "Source/Audio/LV2"; else if (gsp_class->num_audio_out == 0) { if (gsp_class->num_control_out == 0) klass_tags = "Sink/Audio/LV2"; else klass_tags = "Sink/Analyzer/Audio/LV2"; } else klass_tags = "Filter/Effect/Audio/LV2"; details->klass = klass_tags; GST_INFO ("tags : %s", details->klass); gst_element_class_set_details (element_class, details); g_free (details->longname); g_free (details->author); g_free (details); klass->audio_in_portnums = g_new0 (gint, gsp_class->num_audio_in); klass->audio_out_portnums = g_new0 (gint, gsp_class->num_audio_out); klass->control_in_portnums = g_new0 (gint, gsp_class->num_control_in); klass->control_out_portnums = g_new0 (gint, gsp_class->num_control_out); audio_in_count = audio_out_count = control_in_count = control_out_count = 0; for (j = 0; j < slv2_plugin_get_num_ports (lv2plugin); j++) { SLV2Port port = slv2_plugin_get_port_by_index (lv2plugin, j); gboolean is_input = slv2_port_is_a (lv2plugin, port, input_class); if (slv2_port_is_a (lv2plugin, port, audio_class)) { if (is_input) klass->audio_in_portnums[audio_in_count++] = j; else klass->audio_out_portnums[audio_out_count++] = j; } else if (slv2_port_is_a (lv2plugin, port, control_class)) { if (is_input) klass->control_in_portnums[control_in_count++] = j; else klass->control_out_portnums[control_out_count++] = j; } } g_assert (audio_in_count == gsp_class->num_audio_in); g_assert (audio_out_count == gsp_class->num_audio_out); g_assert (control_in_count == gsp_class->num_control_in); g_assert (control_out_count == gsp_class->num_control_out); /*if (!LV2_IS_INPLACE_BROKEN (desc->Properties)) GST_SIGNAL_PROCESSOR_CLASS_SET_CAN_PROCESS_IN_PLACE (klass); */ klass->plugin = lv2plugin; }
SLV2UIInstance slv2_ui_instantiate(SLV2Plugin plugin, SLV2UI ui, LV2UI_Write_Function write_function, LV2UI_Controller controller, const LV2_Feature* const* features) { struct _SLV2UIInstance* result = NULL; bool local_features = (features == NULL); if (local_features) { features = malloc(sizeof(LV2_Feature)); ((LV2_Feature**)features)[0] = NULL; } const char* const lib_uri = slv2_value_as_string(slv2_ui_get_binary_uri(ui)); const char* const lib_path = slv2_uri_to_path(lib_uri); if (!lib_path) return NULL; dlerror(); void* lib = dlopen(lib_path, RTLD_NOW); if (!lib) { fprintf(stderr, "Unable to open UI library %s (%s)\n", lib_path, dlerror()); return NULL; } LV2UI_DescriptorFunction df = dlsym(lib, "lv2ui_descriptor"); if (!df) { fprintf(stderr, "Could not find symbol 'lv2ui_descriptor', " "%s is not a LV2 plugin UI.\n", lib_path); dlclose(lib); return NULL; } else { const char* bundle_path = slv2_uri_to_path(slv2_value_as_uri(slv2_ui_get_bundle_uri(ui))); for (uint32_t i=0; 1; ++i) { const LV2UI_Descriptor* ld = df(i); if (!ld) { fprintf(stderr, "Did not find UI %s in %s\n", slv2_value_as_uri(slv2_ui_get_uri(ui)), lib_path); dlclose(lib); break; // return NULL } else if (!strcmp(ld->URI, slv2_value_as_uri(slv2_ui_get_uri(ui)))) { assert(plugin->plugin_uri); printf("Found UI %s at index %u in:\n\t%s\n\n", slv2_value_as_uri(plugin->plugin_uri), i, lib_path); assert(ld->instantiate); // Create SLV2UIInstance to return result = malloc(sizeof(struct _SLV2UIInstance)); struct _SLV2UIInstanceImpl* impl = malloc(sizeof(struct _SLV2UIInstanceImpl)); impl->lv2ui_descriptor = ld; impl->lv2ui_handle = ld->instantiate(ld, slv2_value_as_uri(slv2_plugin_get_uri(plugin)), (char*)bundle_path, write_function, controller, &impl->widget, features); impl->lib_handle = lib; result->pimpl = impl; break; } } } // Failed to instantiate if (result == NULL || result->pimpl->lv2ui_handle == NULL) { //printf("Failed to instantiate %s\n", plugin->plugin_uri); free(result); return NULL; } // Failed to create a widget, but still got a handle - this means that // the plugin is buggy if (result->pimpl->widget == NULL) { slv2_ui_instance_free(result); return NULL; } if (local_features) free((LV2_Feature**)features); return result; }