1#!/usr/local/bin/python3.8
2# -*- coding: utf-8 -*-
3
4# LADSPA RDF python support
5# Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com>
6#
7# This program is free software; you can redistribute it and/or
8# modify it under the terms of the GNU General Public License as
9# published by the Free Software Foundation; either version 2 of
10# the License, or any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# For a full copy of the GNU General Public License see the doc/GPL.txt file.
18
19# ------------------------------------------------------------------------------------------------------------
20#  C types
21
22# Imports (Global)
23from ctypes import *
24from copy import deepcopy
25
26# Null type
27c_nullptr = None
28
29# Base Types
30LADSPA_Data = c_float
31LADSPA_Property = c_int
32LADSPA_PluginType = c_ulonglong
33
34# Unit Types
35LADSPA_UNIT_DB                = 0x01
36LADSPA_UNIT_COEF              = 0x02
37LADSPA_UNIT_HZ                = 0x04
38LADSPA_UNIT_S                 = 0x08
39LADSPA_UNIT_MS                = 0x10
40LADSPA_UNIT_MIN               = 0x20
41
42LADSPA_UNIT_CLASS_AMPLITUDE   = LADSPA_UNIT_DB|LADSPA_UNIT_COEF
43LADSPA_UNIT_CLASS_FREQUENCY   = LADSPA_UNIT_HZ
44LADSPA_UNIT_CLASS_TIME        = LADSPA_UNIT_S|LADSPA_UNIT_MS|LADSPA_UNIT_MIN
45
46# Port Types (Official API)
47LADSPA_PORT_INPUT             = 0x1
48LADSPA_PORT_OUTPUT            = 0x2
49LADSPA_PORT_CONTROL           = 0x4
50LADSPA_PORT_AUDIO             = 0x8
51
52# Port Hints
53LADSPA_PORT_UNIT              = 0x1
54LADSPA_PORT_DEFAULT           = 0x2
55LADSPA_PORT_LABEL             = 0x4
56
57# Plugin Types
58LADSPA_PLUGIN_UTILITY         = 0x000000001
59LADSPA_PLUGIN_GENERATOR       = 0x000000002
60LADSPA_PLUGIN_SIMULATOR       = 0x000000004
61LADSPA_PLUGIN_OSCILLATOR      = 0x000000008
62LADSPA_PLUGIN_TIME            = 0x000000010
63LADSPA_PLUGIN_DELAY           = 0x000000020
64LADSPA_PLUGIN_PHASER          = 0x000000040
65LADSPA_PLUGIN_FLANGER         = 0x000000080
66LADSPA_PLUGIN_CHORUS          = 0x000000100
67LADSPA_PLUGIN_REVERB          = 0x000000200
68LADSPA_PLUGIN_FREQUENCY       = 0x000000400
69LADSPA_PLUGIN_FREQUENCY_METER = 0x000000800
70LADSPA_PLUGIN_FILTER          = 0x000001000
71LADSPA_PLUGIN_LOWPASS         = 0x000002000
72LADSPA_PLUGIN_HIGHPASS        = 0x000004000
73LADSPA_PLUGIN_BANDPASS        = 0x000008000
74LADSPA_PLUGIN_COMB            = 0x000010000
75LADSPA_PLUGIN_ALLPASS         = 0x000020000
76LADSPA_PLUGIN_EQ              = 0x000040000
77LADSPA_PLUGIN_PARAEQ          = 0x000080000
78LADSPA_PLUGIN_MULTIEQ         = 0x000100000
79LADSPA_PLUGIN_AMPLITUDE       = 0x000200000
80LADSPA_PLUGIN_PITCH           = 0x000400000
81LADSPA_PLUGIN_AMPLIFIER       = 0x000800000
82LADSPA_PLUGIN_WAVESHAPER      = 0x001000000
83LADSPA_PLUGIN_MODULATOR       = 0x002000000
84LADSPA_PLUGIN_DISTORTION      = 0x004000000
85LADSPA_PLUGIN_DYNAMICS        = 0x008000000
86LADSPA_PLUGIN_COMPRESSOR      = 0x010000000
87LADSPA_PLUGIN_EXPANDER        = 0x020000000
88LADSPA_PLUGIN_LIMITER         = 0x040000000
89LADSPA_PLUGIN_GATE            = 0x080000000
90LADSPA_PLUGIN_SPECTRAL        = 0x100000000
91LADSPA_PLUGIN_NOTCH           = 0x200000000
92
93LADSPA_GROUP_DYNAMICS         = LADSPA_PLUGIN_DYNAMICS | LADSPA_PLUGIN_COMPRESSOR | LADSPA_PLUGIN_EXPANDER | LADSPA_PLUGIN_LIMITER | LADSPA_PLUGIN_GATE
94LADSPA_GROUP_AMPLITUDE        = LADSPA_PLUGIN_AMPLITUDE | LADSPA_PLUGIN_AMPLIFIER | LADSPA_PLUGIN_WAVESHAPER | LADSPA_PLUGIN_MODULATOR | LADSPA_PLUGIN_DISTORTION | LADSPA_GROUP_DYNAMICS
95LADSPA_GROUP_EQ               = LADSPA_PLUGIN_EQ | LADSPA_PLUGIN_PARAEQ | LADSPA_PLUGIN_MULTIEQ
96LADSPA_GROUP_FILTER           = LADSPA_PLUGIN_FILTER | LADSPA_PLUGIN_LOWPASS | LADSPA_PLUGIN_HIGHPASS | LADSPA_PLUGIN_BANDPASS | LADSPA_PLUGIN_COMB | LADSPA_PLUGIN_ALLPASS | LADSPA_PLUGIN_NOTCH
97LADSPA_GROUP_FREQUENCY        = LADSPA_PLUGIN_FREQUENCY | LADSPA_PLUGIN_FREQUENCY_METER | LADSPA_GROUP_FILTER | LADSPA_GROUP_EQ | LADSPA_PLUGIN_PITCH
98LADSPA_GROUP_SIMULATOR        = LADSPA_PLUGIN_SIMULATOR | LADSPA_PLUGIN_REVERB
99LADSPA_GROUP_TIME             = LADSPA_PLUGIN_TIME | LADSPA_PLUGIN_DELAY | LADSPA_PLUGIN_PHASER | LADSPA_PLUGIN_FLANGER | LADSPA_PLUGIN_CHORUS | LADSPA_PLUGIN_REVERB
100LADSPA_GROUP_GENERATOR        = LADSPA_PLUGIN_GENERATOR | LADSPA_PLUGIN_OSCILLATOR
101
102# Scale Point
103class LADSPA_RDF_ScalePoint(Structure):
104    _fields_ = [
105        ("Value", LADSPA_Data),
106        ("Label", c_char_p)
107    ]
108
109# Port
110class LADSPA_RDF_Port(Structure):
111    _fields_ = [
112        ("Type", LADSPA_Property),
113        ("Hints", LADSPA_Property),
114        ("Label", c_char_p),
115        ("Default", LADSPA_Data),
116        ("Unit", LADSPA_Property),
117
118        ("ScalePointCount", c_ulong),
119        ("ScalePoints", POINTER(LADSPA_RDF_ScalePoint))
120    ]
121
122# Plugin
123class LADSPA_RDF_Descriptor(Structure):
124    _fields_ = [
125        ("Type", LADSPA_PluginType),
126        ("UniqueID", c_ulong),
127        ("Title", c_char_p),
128        ("Creator", c_char_p),
129
130        ("PortCount", c_ulong),
131        ("Ports", POINTER(LADSPA_RDF_Port))
132    ]
133
134# ------------------------------------------------------------------------------------------------------------
135#  Python compatible C types
136
137PyLADSPA_RDF_ScalePoint = {
138    'Value': 0.0,
139    'Label': ""
140}
141
142PyLADSPA_RDF_Port = {
143    'Type': 0x0,
144    'Hints': 0x0,
145    'Label': "",
146    'Default': 0.0,
147    'Unit': 0x0,
148
149    'ScalePointCount': 0,
150    'ScalePoints': [],
151
152    # Only here to help, NOT in the API:
153    'index': 0
154}
155
156PyLADSPA_RDF_Descriptor = {
157    'Type': 0x0,
158    'UniqueID': 0,
159    'Title': "",
160    'Creator': "",
161
162    'PortCount': 0,
163    'Ports': []
164}
165
166# ------------------------------------------------------------------------------------------------------------
167#  RDF data and conversions
168
169# Namespaces
170NS_dc     = "http://purl.org/dc/elements/1.1/"
171NS_rdf    = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
172NS_rdfs   = "http://www.w3.org/2000/01/rdf-schema#"
173NS_ladspa = "http://ladspa.org/ontology#"
174NS_caps   = "http://quitte.de/dsp/caps.html#"
175
176# Prefixes (sorted alphabetically and by type)
177rdf_prefix = {
178    # Base types
179    'dc:creator': NS_dc + "creator",
180    'dc:rights':  NS_dc + "rights",
181    'dc:title':   NS_dc + "title",
182    'rdf:value':  NS_rdf + "value",
183    'rdf:type':   NS_rdf + "type",
184
185    # LADSPA Stuff
186    'ladspa:forPort':      NS_ladspa + "forPort",
187    'ladspa:hasLabel':     NS_ladspa + "hasLabel",
188    'ladspa:hasPoint':     NS_ladspa + "hasPoint",
189    'ladspa:hasPort':      NS_ladspa + "hasPort",
190    'ladspa:hasPortValue': NS_ladspa + "hasPortValue",
191    'ladspa:hasScale':     NS_ladspa + "hasScale",
192    'ladspa:hasSetting':   NS_ladspa + "hasSetting",
193    'ladspa:hasUnit':      NS_ladspa + "hasUnit",
194
195    # LADSPA Extensions
196    'ladspa:NotchPlugin':    NS_ladspa + "NotchPlugin",
197    'ladspa:SpectralPlugin': NS_ladspa + "SpectralPlugin"
198}
199
200def get_c_plugin_type(value):
201    valueStr = value.replace(NS_ladspa, "")
202    ret = 0x0
203
204    if valueStr == "Plugin":
205        pass
206    elif valueStr == "UtilityPlugin":
207        ret = LADSPA_PLUGIN_UTILITY
208    elif valueStr == "GeneratorPlugin":
209        ret = LADSPA_PLUGIN_GENERATOR
210    elif valueStr == "SimulatorPlugin":
211        ret = LADSPA_PLUGIN_SIMULATOR
212    elif valueStr == "OscillatorPlugin":
213        ret = LADSPA_PLUGIN_OSCILLATOR
214    elif valueStr == "TimePlugin":
215        ret = LADSPA_PLUGIN_TIME
216    elif valueStr == "DelayPlugin":
217        ret = LADSPA_PLUGIN_DELAY
218    elif valueStr == "PhaserPlugin":
219        ret = LADSPA_PLUGIN_PHASER
220    elif valueStr == "FlangerPlugin":
221        ret = LADSPA_PLUGIN_FLANGER
222    elif valueStr == "ChorusPlugin":
223        ret = LADSPA_PLUGIN_CHORUS
224    elif valueStr == "ReverbPlugin":
225        ret = LADSPA_PLUGIN_REVERB
226    elif valueStr == "FrequencyPlugin":
227        ret = LADSPA_PLUGIN_FREQUENCY
228    elif valueStr == "FrequencyMeterPlugin":
229        ret = LADSPA_PLUGIN_FREQUENCY_METER
230    elif valueStr == "FilterPlugin":
231        ret = LADSPA_PLUGIN_FILTER
232    elif valueStr == "LowpassPlugin":
233        ret = LADSPA_PLUGIN_LOWPASS
234    elif valueStr == "HighpassPlugin":
235        ret = LADSPA_PLUGIN_HIGHPASS
236    elif valueStr == "BandpassPlugin":
237        ret = LADSPA_PLUGIN_BANDPASS
238    elif valueStr == "CombPlugin":
239        ret = LADSPA_PLUGIN_COMB
240    elif valueStr == "AllpassPlugin":
241        ret = LADSPA_PLUGIN_ALLPASS
242    elif valueStr == "EQPlugin":
243        ret = LADSPA_PLUGIN_EQ
244    elif valueStr == "ParaEQPlugin":
245        ret = LADSPA_PLUGIN_PARAEQ
246    elif valueStr == "MultiEQPlugin":
247        ret = LADSPA_PLUGIN_MULTIEQ
248    elif valueStr == "AmplitudePlugin":
249        ret = LADSPA_PLUGIN_AMPLITUDE
250    elif valueStr == "PitchPlugin":
251        ret = LADSPA_PLUGIN_PITCH
252    elif valueStr == "AmplifierPlugin":
253        ret = LADSPA_PLUGIN_AMPLIFIER
254    elif valueStr == "WaveshaperPlugin":
255        ret = LADSPA_PLUGIN_WAVESHAPER
256    elif valueStr == "ModulatorPlugin":
257        ret = LADSPA_PLUGIN_MODULATOR
258    elif valueStr == "DistortionPlugin":
259        ret = LADSPA_PLUGIN_DISTORTION
260    elif valueStr == "DynamicsPlugin":
261        ret = LADSPA_PLUGIN_DYNAMICS
262    elif valueStr == "CompressorPlugin":
263        ret = LADSPA_PLUGIN_COMPRESSOR
264    elif valueStr == "ExpanderPlugin":
265        ret = LADSPA_PLUGIN_EXPANDER
266    elif valueStr == "LimiterPlugin":
267        ret = LADSPA_PLUGIN_LIMITER
268    elif valueStr == "GatePlugin":
269        ret = LADSPA_PLUGIN_GATE
270    elif valueStr == "SpectralPlugin":
271        ret = LADSPA_PLUGIN_SPECTRAL
272    elif valueStr == "NotchPlugin":
273        ret = LADSPA_PLUGIN_NOTCH
274    elif valueStr == "MixerPlugin":
275        ret = LADSPA_PLUGIN_EQ
276    else:
277        print("LADSPA_RDF - Got an unknown plugin type '%s'" % valueStr)
278
279    return ret
280
281def get_c_port_type(value):
282    valueStr = value.replace(NS_ladspa, "")
283    ret = 0x0
284
285    if valueStr == "Port":
286        pass
287    elif valueStr == "ControlPort":
288        ret = LADSPA_PORT_CONTROL
289    elif valueStr == "AudioPort":
290        ret = LADSPA_PORT_AUDIO
291    elif valueStr == "InputPort":
292        ret = LADSPA_PORT_INPUT
293    elif valueStr == "OutputPort":
294        ret = LADSPA_PORT_OUTPUT
295    elif valueStr in ("ControlInputPort", "InputControlPort"):
296        ret = LADSPA_PORT_CONTROL|LADSPA_PORT_INPUT
297    elif valueStr in ("ControlOutputPort", "OutputControlPort"):
298        ret = LADSPA_PORT_CONTROL|LADSPA_PORT_OUTPUT
299    elif valueStr in ("AudioInputPort", "InputAudioPort"):
300        ret = LADSPA_PORT_AUDIO|LADSPA_PORT_INPUT
301    elif valueStr in ("AudioOutputPort", "OutputAudioPort"):
302        ret = LADSPA_PORT_AUDIO|LADSPA_PORT_OUTPUT
303    else:
304        print("LADSPA_RDF - Got an unknown port type '%s'" % valueStr)
305
306    return ret
307
308def get_c_unit_type(value):
309    valueStr = value.replace(NS_ladspa, "")
310    ret = 0x0
311
312    if valueStr in ("Unit", "Units", "AmplitudeUnits", "FrequencyUnits", "TimeUnits"):
313        pass
314    elif valueStr == "dB":
315        ret = LADSPA_UNIT_DB
316    elif valueStr == "coef":
317        ret = LADSPA_UNIT_COEF
318    elif valueStr == "Hz":
319        ret = LADSPA_UNIT_HZ
320    elif valueStr == "seconds":
321        ret = LADSPA_UNIT_S
322    elif valueStr == "milliseconds":
323        ret = LADSPA_UNIT_MS
324    elif valueStr == "minutes":
325        ret = LADSPA_UNIT_MIN
326    else:
327        print("LADSPA_RDF - Got an unknown unit type '%s'" % valueStr)
328
329    return ret
330
331# ------------------------------------------------------------------------------------------------------------
332#  Global objects
333
334LADSPA_RDF_PATH = ("/usr/share/ladspa/rdf", "/usr/local/share/ladspa/rdf")
335LADSPA_Plugins  = []
336
337# Set LADSPA_RDF_PATH variable
338def set_rdf_path(PATH):
339    global LADSPA_RDF_PATH
340    LADSPA_RDF_PATH = PATH
341
342# ------------------------------------------------------------------------------------------------------------
343#  Helper methods
344
345LADSPA_RDF_TYPE_PLUGIN = 1
346LADSPA_RDF_TYPE_PORT = 2
347
348# Check RDF Type
349def rdf_is_type(subject, compare):
350    if isinstance(subject, URIRef) and NS_ladspa in subject:
351        if compare == LADSPA_RDF_TYPE_PLUGIN:
352            return bool(to_plugin_number(subject).isdigit())
353        elif compare == LADSPA_RDF_TYPE_PORT:
354            return bool("." in to_plugin_number(subject))
355    else:
356        return False
357
358def to_float(rdfItem):
359    return float(str(rdfItem).replace("f", ""))
360
361# Convert RDF LADSPA subject into a number
362def to_plugin_number(subject):
363    return str(subject).replace(NS_ladspa, "")
364
365# Convert RDF LADSPA subject into a plugin and port number
366def to_plugin_and_port_number(subject):
367    numbers = str(subject).replace(NS_ladspa, "").split(".")
368    return (numbers[0], numbers[1])
369
370# Convert RDF LADSPA subject into a port number
371def to_plugin_port(subject):
372    return to_plugin_and_port_number(subject)[1]
373
374# ------------------------------------------------------------------------------------------------------------
375#  RDF store/retrieve data methods
376
377def check_and_add_plugin(pluginId):
378    global LADSPA_Plugins
379    for i in range(len(LADSPA_Plugins)):
380        if LADSPA_Plugins[i]['UniqueID'] == pluginId:
381            return i
382    else:
383        plugin = deepcopy(PyLADSPA_RDF_Descriptor)
384        plugin['UniqueID'] = pluginId
385        LADSPA_Plugins.append(plugin)
386        return len(LADSPA_Plugins) - 1
387
388def set_plugin_value(pluginId, key, value):
389    global LADSPA_Plugins
390    index = check_and_add_plugin(pluginId)
391    LADSPA_Plugins[index][key] = value
392
393def add_plugin_value(pluginId, key, value):
394    global LADSPA_Plugins
395    index = check_and_add_plugin(pluginId)
396    LADSPA_Plugins[index][key] += value
397
398def or_plugin_value(pluginId, key, value):
399    global LADSPA_Plugins
400    index = check_and_add_plugin(pluginId)
401    LADSPA_Plugins[index][key] |= value
402
403def append_plugin_value(pluginId, key, value):
404    global LADSPA_Plugins
405    index = check_and_add_plugin(pluginId)
406    LADSPA_Plugins[index][key].append(value)
407
408def check_and_add_port(pluginId, portId):
409    global LADSPA_Plugins
410    index = check_and_add_plugin(pluginId)
411    ports = LADSPA_Plugins[index]['Ports']
412    for i in range(len(ports)):
413        if ports[i]['index'] == portId:
414            return (index, i)
415    else:
416        portCount = LADSPA_Plugins[index]['PortCount']
417        port = deepcopy(PyLADSPA_RDF_Port)
418        port['index'] = portId
419        ports.append(port)
420        LADSPA_Plugins[index]['PortCount'] += 1
421        return (index, portCount)
422
423def set_port_value(pluginId, portId, key, value):
424    global LADSPA_Plugins
425    i, j = check_and_add_port(pluginId, portId)
426    LADSPA_Plugins[i]['Ports'][j][key] = value
427
428def add_port_value(pluginId, portId, key, value):
429    global LADSPA_Plugins
430    i, j = check_and_add_port(pluginId, portId)
431    LADSPA_Plugins[i]['Ports'][j][key] += value
432
433def or_port_value(pluginId, portId, key, value):
434    global LADSPA_Plugins
435    i, j = check_and_add_port(pluginId, portId)
436    LADSPA_Plugins[i]['Ports'][j][key] |= value
437
438def append_port_value(pluginId, portId, key, value):
439    global LADSPA_Plugins
440    i, j = check_and_add_port(pluginId, portId)
441    LADSPA_Plugins[i]['Ports'][j][key].append(value)
442
443def add_scalepoint(pluginId, portId, value, label):
444    global LADSPA_Plugins
445    i, j = check_and_add_port(pluginId, portId)
446    port = LADSPA_Plugins[i]['Ports'][j]
447    scalePoint = deepcopy(PyLADSPA_RDF_ScalePoint)
448    scalePoint['Value'] = value
449    scalePoint['Label'] = label
450    port['ScalePoints'].append(scalePoint)
451    port['ScalePointCount'] += 1
452
453def set_port_default(pluginId, portId, value):
454    global LADSPA_Plugins
455    i, j = check_and_add_port(pluginId, portId)
456    port = LADSPA_Plugins[i]['Ports'][j]
457    port['Default'] = value
458    port['Hints'] |= LADSPA_PORT_DEFAULT
459
460def get_node_objects(valueNodes, nSubject):
461    retNodes = []
462    for subject, predicate, object_ in valueNodes:
463        if subject == nSubject:
464            retNodes.append((predicate, object_))
465    return retNodes
466
467def append_and_sort(value, vlist):
468    if len(vlist) == 0:
469        vlist.append(value)
470    elif value < vlist[0]:
471        vlist.insert(0, value)
472    elif value > vlist[len(vlist) - 1]:
473        vlist.append(value)
474    else:
475        for i in range(len(vlist)):
476            if value < vlist[i]:
477                vlist.insert(i, value)
478                break
479        else:
480            print("LADSPA_RDF - CRITICAL ERROR #001")
481
482    return vlist
483
484def get_value_index(value, vlist):
485    for i in range(len(vlist)):
486        if vlist[i] == value:
487            return i
488    else:
489        print("LADSPA_RDF - CRITICAL ERROR #002")
490        return 0
491
492# ------------------------------------------------------------------------------------------------------------
493#  RDF sort data methods
494
495# Sort the plugin's port's ScalePoints by value
496def SORT_PyLADSPA_RDF_ScalePoints(oldDictList):
497    newDictList = []
498    indexesList = []
499
500    for i in range(len(oldDictList)):
501        newDictList.append(deepcopy(PyLADSPA_RDF_ScalePoint))
502        append_and_sort(oldDictList[i]['Value'], indexesList)
503
504    for i in range(len(oldDictList)):
505        index = get_value_index(oldDictList[i]['Value'], indexesList)
506        newDictList[index]['Value'] = oldDictList[i]['Value']
507        newDictList[index]['Label'] = oldDictList[i]['Label']
508
509    return newDictList
510
511# Sort the plugin's port by index
512def SORT_PyLADSPA_RDF_Ports(oldDictList):
513    newDictList = []
514    maxIndex = -1
515
516    for i in range(len(oldDictList)):
517        if oldDictList[i]['index'] > maxIndex:
518            maxIndex = oldDictList[i]['index']
519
520    for i in range(maxIndex + 1):
521        newDictList.append(deepcopy(PyLADSPA_RDF_Port))
522
523    for i in range(len(oldDictList)):
524        index = oldDictList[i]['index']
525        newDictList[index]['index']   = oldDictList[i]['index']
526        newDictList[index]['Type']    = oldDictList[i]['Type']
527        newDictList[index]['Hints']   = oldDictList[i]['Hints']
528        newDictList[index]['Unit']    = oldDictList[i]['Unit']
529        newDictList[index]['Default'] = oldDictList[i]['Default']
530        newDictList[index]['Label']   = oldDictList[i]['Label']
531        newDictList[index]['ScalePointCount'] = oldDictList[i]['ScalePointCount']
532        newDictList[index]['ScalePoints'] = SORT_PyLADSPA_RDF_ScalePoints(oldDictList[i]['ScalePoints'])
533
534    return newDictList
535
536# ------------------------------------------------------------------------------------------------------------
537#  RDF data parsing
538
539from rdflib import ConjunctiveGraph, URIRef, BNode
540
541# Fully parse rdf file
542def parse_rdf_file(filename):
543    primer = ConjunctiveGraph()
544
545    try:
546        primer.parse(filename, format='xml')
547        rdfList = [(x, y, z) for x, y, z in primer]
548    except:
549        rdfList = []
550
551    # For BNodes
552    indexNodes = [] # Subject (index), Predicate, Plugin, Port
553    valueNodes = [] # Subject (index), Predicate, Object
554
555    # Parse RDF list
556    for subject, predicate, object_ in rdfList:
557        # Fix broken or old plugins
558        if predicate == URIRef("http://ladspa.org/ontology#hasUnits"):
559            predicate = URIRef(rdf_prefix['ladspa:hasUnit'])
560
561        # Plugin information
562        if rdf_is_type(subject, LADSPA_RDF_TYPE_PLUGIN):
563            pluginId = int(to_plugin_number(subject))
564
565            if predicate == URIRef(rdf_prefix['dc:creator']):
566                set_plugin_value(pluginId, 'Creator', str(object_))
567
568            elif predicate == URIRef(rdf_prefix['dc:rights']):
569                # No useful information here
570                pass
571
572            elif predicate == URIRef(rdf_prefix['dc:title']):
573                set_plugin_value(pluginId, 'Title', str(object_))
574
575            elif predicate == URIRef(rdf_prefix['rdf:type']):
576                c_type = get_c_plugin_type(str(object_))
577                or_plugin_value(pluginId, 'Type', c_type)
578
579            elif predicate == URIRef(rdf_prefix['ladspa:hasPort']):
580                # No useful information here
581                pass
582
583            elif predicate == URIRef(rdf_prefix['ladspa:hasSetting']):
584                indexNodes.append((object_, predicate, pluginId, None))
585
586            else:
587                print("LADSPA_RDF - Plugin predicate '%s' not handled" % predicate)
588
589        # Port information
590        elif rdf_is_type(subject, LADSPA_RDF_TYPE_PORT):
591            portInfo = to_plugin_and_port_number(subject)
592            pluginId = int(portInfo[0])
593            portId   = int(portInfo[1])
594
595            if predicate == URIRef(rdf_prefix['rdf:type']):
596                c_class = get_c_port_type(str(object_))
597                or_port_value(pluginId, portId, 'Type', c_class)
598
599            elif predicate == URIRef(rdf_prefix['ladspa:hasLabel']):
600                set_port_value(pluginId, portId, 'Label', str(object_))
601                or_port_value(pluginId, portId, 'Hints', LADSPA_PORT_LABEL)
602
603            elif predicate == URIRef(rdf_prefix['ladspa:hasScale']):
604                indexNodes.append((object_, predicate, pluginId, portId))
605
606            elif predicate == URIRef(rdf_prefix['ladspa:hasUnit']):
607                c_unit = get_c_unit_type(str(object_))
608                set_port_value(pluginId, portId, 'Unit', c_unit)
609                or_port_value(pluginId, portId, 'Hints', LADSPA_PORT_UNIT)
610
611            else:
612                print("LADSPA_RDF - Port predicate '%s' not handled" % predicate)
613
614        # These "extensions" are already implemented. caps stuff is skipped
615        elif subject in (URIRef(rdf_prefix['ladspa:NotchPlugin']), URIRef(rdf_prefix['ladspa:SpectralPlugin'])) or NS_caps in subject:
616            pass
617
618        elif type(subject) == BNode:
619            valueNodes.append((subject, predicate, object_))
620
621        else:
622            print("LADSPA_RDF - Unknown subject type '%s'" % subject)
623
624    # Parse BNodes, indexes
625    bnodesDataDump = []
626
627    for nSubject, nPredicate, pluginId, portId in indexNodes:
628        nObjects = get_node_objects(valueNodes, nSubject)
629
630        for subPredicate, subSubject in nObjects:
631            subObjects = get_node_objects(valueNodes, subSubject)
632
633            for realPredicate, realObject in subObjects:
634                if nPredicate == URIRef(rdf_prefix['ladspa:hasScale']) and subPredicate == URIRef(rdf_prefix['ladspa:hasPoint']):
635                    bnodesDataDump.append(("scalepoint", subSubject, pluginId, portId, realPredicate, realObject))
636                elif nPredicate == URIRef(rdf_prefix['ladspa:hasSetting']) and subPredicate == URIRef(rdf_prefix['ladspa:hasPortValue']):
637                    bnodesDataDump.append(("port_default", subSubject, pluginId, portId, realPredicate, realObject))
638                else:
639                    print("LADSPA_RDF - Unknown BNode combo - '%s' + '%s'" % (nPredicate, subPredicate))
640
641    # Process BNodes, values
642    scalePoints  = [] # subject, plugin, port, value, label
643    portDefaults = [] # subject, plugin, port, def-value
644
645    for nType, nSubject, nPlugin, nPort, nPredicate, nObject in bnodesDataDump:
646        if nType == "scalepoint":
647            for i in range(len(scalePoints)):
648                if scalePoints[i][0] == nSubject:
649                    index = i
650                    break
651            else:
652                scalePoints.append([nSubject, nPlugin, nPort, None, None])
653                index = len(scalePoints) - 1
654
655            if nPredicate == URIRef(rdf_prefix['rdf:value']):
656                scalePoints[index][3] = to_float(nObject)
657            elif nPredicate == URIRef(rdf_prefix['ladspa:hasLabel']):
658                scalePoints[index][4] = str(nObject)
659
660        elif nType == "port_default":
661            for i in range(len(portDefaults)):
662                if portDefaults[i][0] == nSubject:
663                    index = i
664                    break
665            else:
666                portDefaults.append([nSubject, nPlugin, None, None])
667                index = len(portDefaults) - 1
668
669            if nPredicate == URIRef(rdf_prefix['ladspa:forPort']):
670                portDefaults[index][2] = int(to_plugin_port(nObject))
671            elif nPredicate == URIRef(rdf_prefix['rdf:value']):
672                portDefaults[index][3] = to_float(nObject)
673
674    # Now add the last information
675    for scalePoint in scalePoints:
676        index, pluginId, portId, value, label = scalePoint
677        add_scalepoint(pluginId, portId, value, label)
678
679    for portDefault in portDefaults:
680        index, pluginId, portId, value = portDefault
681        set_port_default(pluginId, portId, value)
682
683# ------------------------------------------------------------------------------------------------------------
684#  LADSPA_RDF main methods
685
686import os
687
688# Main function - check all rdfs for information about ladspa plugins
689def recheck_all_plugins(qobject, startValue, percentValue, curValue):
690    global LADSPA_RDF_PATH, LADSPA_Plugins
691
692    LADSPA_Plugins = []
693    rdfFiles       = []
694    rdfExtensions  = (".rdf",)
695
696    # Get all RDF files
697    for PATH in LADSPA_RDF_PATH:
698        for root, dirs, files in os.walk(PATH):
699            for filename in tuple(filename for filename in files if filename.lower().endswith(rdfExtensions)):
700                rdfFiles.append(os.path.join(root, filename))
701
702    # Parse all RDF files
703    for i in range(len(rdfFiles)):
704        rdfFile = rdfFiles[i]
705
706        # Tell GUI we're parsing this bundle
707        if qobject:
708            percent = (float(i) / len(rdfFiles) ) * percentValue
709            qobject._pluginLook(startValue + (percent * curValue), rdfFile)
710
711        # Parse RDF
712        parse_rdf_file(rdfFile)
713
714    return LADSPA_Plugins
715
716# Convert PyLADSPA_Plugins into ctype structs
717def get_c_ladspa_rdfs(pyPluginList):
718    C_LADSPA_Plugins  = []
719    c_unicodeErrorStr = "(unicode error)".encode("utf-8")
720
721    for plugin in pyPluginList:
722        # Sort the ports by index
723        pyLadspaPorts = SORT_PyLADSPA_RDF_Ports(plugin['Ports'])
724
725        # Initial data
726        desc = LADSPA_RDF_Descriptor()
727        desc.Type = plugin['Type']
728        desc.UniqueID = plugin['UniqueID']
729
730        try:
731            if plugin['Title']:
732                desc.Title = plugin['Title'].encode("utf-8")
733            else:
734                desc.Title = c_nullptr
735        except:
736            desc.Title = c_unicodeErrorStr
737
738        try:
739            if plugin['Creator']:
740                desc.Creator = plugin['Creator'].encode("utf-8")
741            else:
742                desc.Creator = c_nullptr
743        except:
744            desc.Creator = c_unicodeErrorStr
745
746        desc.PortCount = plugin['PortCount']
747
748        # Ports
749        _PortType  = LADSPA_RDF_Port * desc.PortCount
750        desc.Ports = _PortType()
751
752        for i in range(desc.PortCount):
753            port   = LADSPA_RDF_Port()
754            pyPort = pyLadspaPorts[i]
755
756            port.Type  = pyPort['Type']
757            port.Hints = pyPort['Hints']
758
759            try:
760                if pyPort['Label']:
761                    port.Label = pyPort['Label'].encode("utf-8")
762                else:
763                    port.Label = c_nullptr
764            except:
765                port.Label = c_unicodeErrorStr
766
767            port.Default = pyPort['Default']
768            port.Unit    = pyPort['Unit']
769
770            # ScalePoints
771            port.ScalePointCount = pyPort['ScalePointCount']
772
773            _ScalePointType  = LADSPA_RDF_ScalePoint * port.ScalePointCount
774            port.ScalePoints = _ScalePointType()
775
776            for j in range(port.ScalePointCount):
777                scalePoint   = LADSPA_RDF_ScalePoint()
778                pyScalePoint = pyPort['ScalePoints'][j]
779
780                try:
781                    if pyScalePoint['Label']:
782                        scalePoint.Label = pyScalePoint['Label'].encode("utf-8")
783                    else:
784                        scalePoint.Label = c_nullptr
785                except:
786                    scalePoint.Label = c_unicodeErrorStr
787
788                scalePoint.Value = pyScalePoint['Value']
789
790                port.ScalePoints[j] = scalePoint
791
792            desc.Ports[i] = port
793
794        C_LADSPA_Plugins.append(desc)
795
796    return C_LADSPA_Plugins
797
798# ------------------------------------------------------------------------------------------------------------
799