Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1099 lines
35KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Carla Backend code
  4. # Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com>
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # For a full copy of the GNU General Public License see the COPYING file
  17. # ------------------------------------------------------------------------------------------------------------
  18. # Imports (Global)
  19. import os
  20. from ctypes import *
  21. from subprocess import Popen, PIPE
  22. # ------------------------------------------------------------------------------------------------------------
  23. # Imports (Custom)
  24. from carla_shared import *
  25. try:
  26. import ladspa_rdf
  27. haveLRDF = True
  28. except:
  29. print("LRDF Support not available (LADSPA-RDF will be disabled)")
  30. haveLRDF = False
  31. # ------------------------------------------------------------------------------------------------------------
  32. # Convert a ctypes c_char_p into a python string
  33. def cString(value):
  34. if not value:
  35. return ""
  36. if isinstance(value, str):
  37. return value
  38. return value.decode("utf-8", errors="ignore")
  39. # ------------------------------------------------------------------------------------------------------------
  40. # Convert a ctypes struct into a python dict
  41. def structToDict(struct):
  42. return dict((attr, getattr(struct, attr)) for attr, value in struct._fields_)
  43. # ------------------------------------------------------------------------------------------------------------
  44. # Default Plugin Folders
  45. if WINDOWS:
  46. splitter = ";"
  47. APPDATA = os.getenv("APPDATA")
  48. PROGRAMFILES = os.getenv("PROGRAMFILES")
  49. PROGRAMFILESx86 = os.getenv("PROGRAMFILES(x86)")
  50. COMMONPROGRAMFILES = os.getenv("COMMONPROGRAMFILES")
  51. # Small integrity tests
  52. if not APPDATA:
  53. print("APPDATA variable not set, cannot continue")
  54. sys.exit(1)
  55. if not PROGRAMFILES:
  56. print("PROGRAMFILES variable not set, cannot continue")
  57. sys.exit(1)
  58. if not COMMONPROGRAMFILES:
  59. print("COMMONPROGRAMFILES variable not set, cannot continue")
  60. sys.exit(1)
  61. DEFAULT_LADSPA_PATH = [
  62. os.path.join(APPDATA, "LADSPA"),
  63. os.path.join(PROGRAMFILES, "LADSPA")
  64. ]
  65. DEFAULT_DSSI_PATH = [
  66. os.path.join(APPDATA, "DSSI"),
  67. os.path.join(PROGRAMFILES, "DSSI")
  68. ]
  69. DEFAULT_LV2_PATH = [
  70. os.path.join(APPDATA, "LV2"),
  71. os.path.join(COMMONPROGRAMFILES, "LV2")
  72. ]
  73. DEFAULT_VST_PATH = [
  74. os.path.join(PROGRAMFILES, "VstPlugins"),
  75. os.path.join(PROGRAMFILES, "Steinberg", "VstPlugins")
  76. ]
  77. DEFAULT_GIG_PATH = [
  78. os.path.join(APPDATA, "GIG")
  79. ]
  80. DEFAULT_SF2_PATH = [
  81. os.path.join(APPDATA, "SF2")
  82. ]
  83. DEFAULT_SFZ_PATH = [
  84. os.path.join(APPDATA, "SFZ")
  85. ]
  86. if PROGRAMFILESx86:
  87. DEFAULT_LADSPA_PATH.append(os.path.join(PROGRAMFILESx86, "LADSPA"))
  88. DEFAULT_DSSI_PATH.append(os.path.join(PROGRAMFILESx86, "DSSI"))
  89. DEFAULT_VST_PATH.append(os.path.join(PROGRAMFILESx86, "VstPlugins"))
  90. DEFAULT_VST_PATH.append(os.path.join(PROGRAMFILESx86, "Steinberg", "VstPlugins"))
  91. elif HAIKU:
  92. splitter = ":"
  93. DEFAULT_LADSPA_PATH = [
  94. # TODO
  95. ]
  96. DEFAULT_DSSI_PATH = [
  97. # TODO
  98. ]
  99. DEFAULT_LV2_PATH = [
  100. # TODO
  101. ]
  102. DEFAULT_VST_PATH = [
  103. # TODO
  104. ]
  105. DEFAULT_GIG_PATH = [
  106. # TODO
  107. ]
  108. DEFAULT_SF2_PATH = [
  109. # TODO
  110. ]
  111. DEFAULT_SFZ_PATH = [
  112. # TODO
  113. ]
  114. elif MACOS:
  115. splitter = ":"
  116. DEFAULT_LADSPA_PATH = [
  117. os.path.join(HOME, "Library", "Audio", "Plug-Ins", "LADSPA"),
  118. os.path.join("/", "Library", "Audio", "Plug-Ins", "LADSPA")
  119. ]
  120. DEFAULT_DSSI_PATH = [
  121. os.path.join(HOME, "Library", "Audio", "Plug-Ins", "DSSI"),
  122. os.path.join("/", "Library", "Audio", "Plug-Ins", "DSSI")
  123. ]
  124. DEFAULT_LV2_PATH = [
  125. os.path.join(HOME, "Library", "Audio", "Plug-Ins", "LV2"),
  126. os.path.join("/", "Library", "Audio", "Plug-Ins", "LV2")
  127. ]
  128. DEFAULT_VST_PATH = [
  129. os.path.join(HOME, "Library", "Audio", "Plug-Ins", "VST"),
  130. os.path.join("/", "Library", "Audio", "Plug-Ins", "VST")
  131. ]
  132. DEFAULT_GIG_PATH = [
  133. # TODO
  134. ]
  135. DEFAULT_SF2_PATH = [
  136. # TODO
  137. ]
  138. DEFAULT_SFZ_PATH = [
  139. # TODO
  140. ]
  141. else:
  142. splitter = ":"
  143. DEFAULT_LADSPA_PATH = [
  144. os.path.join(HOME, ".ladspa"),
  145. os.path.join("/", "usr", "lib", "ladspa"),
  146. os.path.join("/", "usr", "local", "lib", "ladspa")
  147. ]
  148. DEFAULT_DSSI_PATH = [
  149. os.path.join(HOME, ".dssi"),
  150. os.path.join("/", "usr", "lib", "dssi"),
  151. os.path.join("/", "usr", "local", "lib", "dssi")
  152. ]
  153. DEFAULT_LV2_PATH = [
  154. os.path.join(HOME, ".lv2"),
  155. os.path.join("/", "usr", "lib", "lv2"),
  156. os.path.join("/", "usr", "local", "lib", "lv2")
  157. ]
  158. DEFAULT_VST_PATH = [
  159. os.path.join(HOME, ".vst"),
  160. os.path.join("/", "usr", "lib", "vst"),
  161. os.path.join("/", "usr", "local", "lib", "vst")
  162. ]
  163. DEFAULT_GIG_PATH = [
  164. os.path.join(HOME, ".sounds"),
  165. os.path.join("/", "usr", "share", "sounds", "gig")
  166. ]
  167. DEFAULT_SF2_PATH = [
  168. os.path.join(HOME, ".sounds"),
  169. os.path.join("/", "usr", "share", "sounds", "sf2")
  170. ]
  171. DEFAULT_SFZ_PATH = [
  172. os.path.join(HOME, ".sounds"),
  173. os.path.join("/", "usr", "share", "sounds", "sfz")
  174. ]
  175. # ------------------------------------------------------------------------------------------------------------
  176. # Default Plugin Folders (set)
  177. global LADSPA_PATH, DSSI_PATH, LV2_PATH, VST_PATH, GIG_PATH, SF2_PATH, SFZ_PATH
  178. LADSPA_PATH_env = os.getenv("LADSPA_PATH")
  179. DSSI_PATH_env = os.getenv("DSSI_PATH")
  180. LV2_PATH_env = os.getenv("LV2_PATH")
  181. VST_PATH_env = os.getenv("VST_PATH")
  182. GIG_PATH_env = os.getenv("GIG_PATH")
  183. SF2_PATH_env = os.getenv("SF2_PATH")
  184. SFZ_PATH_env = os.getenv("SFZ_PATH")
  185. if LADSPA_PATH_env:
  186. LADSPA_PATH = LADSPA_PATH_env.split(splitter)
  187. else:
  188. LADSPA_PATH = DEFAULT_LADSPA_PATH
  189. if DSSI_PATH_env:
  190. DSSI_PATH = DSSI_PATH_env.split(splitter)
  191. else:
  192. DSSI_PATH = DEFAULT_DSSI_PATH
  193. if LV2_PATH_env:
  194. LV2_PATH = LV2_PATH_env.split(splitter)
  195. else:
  196. LV2_PATH = DEFAULT_LV2_PATH
  197. if VST_PATH_env:
  198. VST_PATH = VST_PATH_env.split(splitter)
  199. else:
  200. VST_PATH = DEFAULT_VST_PATH
  201. if GIG_PATH_env:
  202. GIG_PATH = GIG_PATH_env.split(splitter)
  203. else:
  204. GIG_PATH = DEFAULT_GIG_PATH
  205. if SF2_PATH_env:
  206. SF2_PATH = SF2_PATH_env.split(splitter)
  207. else:
  208. SF2_PATH = DEFAULT_SF2_PATH
  209. if SFZ_PATH_env:
  210. SFZ_PATH = SFZ_PATH_env.split(splitter)
  211. else:
  212. SFZ_PATH = DEFAULT_SFZ_PATH
  213. if haveLRDF:
  214. LADSPA_RDF_PATH_env = os.getenv("LADSPA_RDF_PATH")
  215. if LADSPA_RDF_PATH_env:
  216. ladspa_rdf.set_rdf_path(LADSPA_RDF_PATH_env.split(splitter))
  217. del LADSPA_RDF_PATH_env
  218. del LADSPA_PATH_env
  219. del DSSI_PATH_env
  220. del LV2_PATH_env
  221. del VST_PATH_env
  222. del GIG_PATH_env
  223. del SF2_PATH_env
  224. del SFZ_PATH_env
  225. # ------------------------------------------------------------------------------------------------------------
  226. # Search for Carla library and tools
  227. global carla_library_path
  228. carla_library_path = ""
  229. carla_discovery_native = ""
  230. carla_discovery_posix32 = ""
  231. carla_discovery_posix64 = ""
  232. carla_discovery_win32 = ""
  233. carla_discovery_win64 = ""
  234. carla_bridge_native = ""
  235. carla_bridge_posix32 = ""
  236. carla_bridge_posix64 = ""
  237. carla_bridge_win32 = ""
  238. carla_bridge_win64 = ""
  239. carla_bridge_lv2_gtk2 = ""
  240. carla_bridge_lv2_gtk3 = ""
  241. carla_bridge_lv2_qt4 = ""
  242. carla_bridge_lv2_qt5 = ""
  243. carla_bridge_lv2_cocoa = ""
  244. carla_bridge_lv2_windows = ""
  245. carla_bridge_lv2_x11 = ""
  246. carla_bridge_vst_cocoa = ""
  247. carla_bridge_vst_hwnd = ""
  248. carla_bridge_vst_x11 = ""
  249. if WINDOWS:
  250. carla_libname = "carla_backend.dll"
  251. elif MACOS:
  252. carla_libname = "carla_backend.dylib"
  253. else:
  254. carla_libname = "carla_backend.so"
  255. CWD = sys.path[0]
  256. CWDpp = os.path.join(CWD, "..", "c++")
  257. # make it work with cxfreeze
  258. if CWD.endswith("%scarla" % os.sep):
  259. CWD = CWD.rsplit("%scarla" % os.sep, 1)[0]
  260. CWDpp = CWD
  261. # find carla_library_path
  262. if os.path.exists(os.path.join(CWDpp, "carla-backend", carla_libname)):
  263. carla_library_path = os.path.join(CWDpp, "carla-backend", carla_libname)
  264. else:
  265. if WINDOWS:
  266. CARLA_PATH = (os.path.join(PROGRAMFILES, "Cadence", "carla"),)
  267. elif MACOS:
  268. CARLA_PATH = ("/opt/local/lib", "/usr/local/lib/", "/usr/lib")
  269. else:
  270. CARLA_PATH = ("/usr/local/lib/", "/usr/lib")
  271. for path in CARLA_PATH:
  272. if os.path.exists(os.path.join(path, "cadence", carla_libname)):
  273. carla_library_path = os.path.join(path, "cadence", carla_libname)
  274. break
  275. # find any tool
  276. def findTool(tdir, tname):
  277. if os.path.exists(os.path.join(CWDpp, tdir, tname)):
  278. return os.path.join(CWDpp, tdir, tname)
  279. for p in PATH:
  280. if os.path.exists(os.path.join(p, tname)):
  281. return os.path.join(p, tname)
  282. return ""
  283. # find wine/windows tools
  284. carla_discovery_win32 = findTool("carla-discovery", "carla-discovery-win32.exe")
  285. carla_discovery_win64 = findTool("carla-discovery", "carla-discovery-win64.exe")
  286. carla_bridge_win32 = findTool("carla-bridge", "carla-bridge-win32.exe")
  287. carla_bridge_win64 = findTool("carla-bridge", "carla-bridge-win64.exe")
  288. # find native and posix only tools
  289. if not WINDOWS:
  290. carla_discovery_native = findTool("carla-discovery", "carla-discovery-native")
  291. carla_discovery_posix32 = findTool("carla-discovery", "carla-discovery-posix32")
  292. carla_discovery_posix64 = findTool("carla-discovery", "carla-discovery-posix64")
  293. carla_bridge_native = findTool("carla-bridge", "carla-bridge-native")
  294. carla_bridge_posix32 = findTool("carla-bridge", "carla-bridge-posix32")
  295. carla_bridge_posix64 = findTool("carla-bridge", "carla-bridge-posix64")
  296. # find windows only tools
  297. if WINDOWS:
  298. carla_bridge_lv2_windows = findTool("carla-bridge", "carla-bridge-lv2-windows.exe")
  299. carla_bridge_vst_hwnd = findTool("carla-bridge", "carla-bridge-vst-hwnd.exe")
  300. # find mac os only tools
  301. elif MACOS:
  302. carla_bridge_lv2_cocoa = findTool("carla-bridge", "carla-bridge-lv2-cocoa")
  303. carla_bridge_vst_cocoa = findTool("carla-bridge", "carla-bridge-vst-cocoa")
  304. # find generic tools
  305. else:
  306. carla_bridge_lv2_gtk2 = findTool("carla-bridge", "carla-bridge-lv2-gtk2")
  307. carla_bridge_lv2_gtk3 = findTool("carla-bridge", "carla-bridge-lv2-gtk3")
  308. carla_bridge_lv2_qt4 = findTool("carla-bridge", "carla-bridge-lv2-qt4")
  309. carla_bridge_lv2_qt5 = findTool("carla-bridge", "carla-bridge-lv2-qt5")
  310. # find linux only tools
  311. if LINUX:
  312. carla_bridge_lv2_x11 = os.path.join("carla-bridge", "carla-bridge-lv2-x11")
  313. carla_bridge_vst_x11 = os.path.join("carla-bridge", "carla-bridge-vst-x11")
  314. # ------------------------------------------------------------------------------------------------------------
  315. # Plugin Query (helper functions)
  316. def findBinaries(bPATH, OS):
  317. binaries = []
  318. if OS == "WINDOWS":
  319. extensions = (".dll",)
  320. elif OS == "MACOS":
  321. extensions = (".dylib", ".so")
  322. else:
  323. extensions = (".so", ".sO", ".SO", ".So")
  324. for root, dirs, files in os.walk(bPATH):
  325. for name in [name for name in files if name.endswith(extensions)]:
  326. binaries.append(os.path.join(root, name))
  327. return binaries
  328. def findLV2Bundles(bPATH):
  329. bundles = []
  330. extensions = (".lv2", ".lV2", ".LV2", ".Lv2") if not WINDOWS else (".lv2",)
  331. for root, dirs, files in os.walk(bPATH):
  332. for dir_ in [dir_ for dir_ in dirs if dir_.endswith(extensions)]:
  333. bundles.append(os.path.join(root, dir_))
  334. return bundles
  335. def findSoundKits(bPATH, stype):
  336. soundfonts = []
  337. if stype == "gig":
  338. extensions = (".gig", ".giG", ".gIG", ".GIG", ".GIg", ".Gig") if not WINDOWS else (".gig",)
  339. elif stype == "sf2":
  340. extensions = (".sf2", ".sF2", ".SF2", ".Sf2") if not WINDOWS else (".sf2",)
  341. elif stype == "sfz":
  342. extensions = (".sfz", ".sfZ", ".sFZ", ".SFZ", ".SFz", ".Sfz") if not WINDOWS else (".sfz",)
  343. else:
  344. return []
  345. for root, dirs, files in os.walk(bPATH):
  346. for name in [name for name in files if name.endswith(extensions)]:
  347. soundfonts.append(os.path.join(root, name))
  348. return soundfonts
  349. def findDSSIGUI(filename, name, label):
  350. pluginDir = filename.rsplit(".", 1)[0]
  351. shortName = os.path.basename(pluginDir)
  352. guiFilename = ""
  353. checkName = name.replace(" ", "_")
  354. checkLabel = label
  355. checkSName = shortName
  356. if checkName[-1] != "_": checkName += "_"
  357. if checkLabel[-1] != "_": checkLabel += "_"
  358. if checkSName[-1] != "_": checkSName += "_"
  359. for root, dirs, files in os.walk(pluginDir):
  360. guiFiles = files
  361. break
  362. else:
  363. guiFiles = []
  364. for gui in guiFiles:
  365. if gui.startswith(checkName) or gui.startswith(checkLabel) or gui.startswith(checkSName):
  366. guiFilename = os.path.join(pluginDir, gui)
  367. break
  368. return guiFilename
  369. # ------------------------------------------------------------------------------------------------------------
  370. # Plugin Query
  371. PLUGIN_QUERY_API_VERSION = 1
  372. PyPluginInfo = {
  373. 'API': PLUGIN_QUERY_API_VERSION,
  374. 'build': 0, # BINARY_NONE
  375. 'type': 0, # PLUGIN_NONE
  376. 'hints': 0x0,
  377. 'binary': "",
  378. 'name': "",
  379. 'label': "",
  380. 'maker': "",
  381. 'copyright': "",
  382. 'unique_id': 0,
  383. 'audio.ins': 0,
  384. 'audio.outs': 0,
  385. 'audio.totals': 0,
  386. 'midi.ins': 0,
  387. 'midi.outs': 0,
  388. 'midi.totals': 0,
  389. 'parameters.ins': 0,
  390. 'parameters.outs': 0,
  391. 'parameters.total': 0,
  392. 'programs.total': 0
  393. }
  394. def runCarlaDiscovery(itype, stype, filename, tool, isWine=False):
  395. fakeLabel = os.path.basename(filename).rsplit(".", 1)[0]
  396. plugins = []
  397. command = []
  398. if LINUX or MACOS:
  399. command.append("env")
  400. command.append("LANG=C")
  401. if isWine:
  402. command.append("WINEDEBUG=-all")
  403. command.append(tool)
  404. command.append(stype)
  405. command.append(filename)
  406. Ps = Popen(command, stdout=PIPE)
  407. Ps.wait()
  408. output = Ps.stdout.read().decode("utf-8", errors="ignore").split("\n")
  409. pinfo = None
  410. for line in output:
  411. line = line.strip()
  412. if line == "carla-discovery::init::-----------":
  413. pinfo = deepcopy(PyPluginInfo)
  414. pinfo['type'] = itype
  415. pinfo['binary'] = filename
  416. elif line == "carla-discovery::end::------------":
  417. if pinfo != None:
  418. plugins.append(pinfo)
  419. pinfo = None
  420. elif line == "Segmentation fault":
  421. print("carla-discovery::crash::%s crashed during discovery" % filename)
  422. elif line.startswith("err:module:import_dll Library"):
  423. print(line)
  424. elif line.startswith("carla-discovery::error::"):
  425. print("%s - %s" % (line, filename))
  426. elif line.startswith("carla-discovery::"):
  427. if pinfo == None:
  428. continue
  429. prop, value = line.replace("carla-discovery::", "").split("::", 1)
  430. if prop == "name":
  431. pinfo['name'] = value if value else fakeLabel
  432. elif prop == "label":
  433. pinfo['label'] = value if value else fakeLabel
  434. elif prop == "maker":
  435. pinfo['maker'] = value
  436. elif prop == "copyright":
  437. pinfo['copyright'] = value
  438. elif prop == "unique_id":
  439. if value.isdigit(): pinfo['unique_id'] = int(value)
  440. elif prop == "hints":
  441. if value.isdigit(): pinfo['hints'] = int(value)
  442. elif prop == "audio.ins":
  443. if value.isdigit(): pinfo['audio.ins'] = int(value)
  444. elif prop == "audio.outs":
  445. if value.isdigit(): pinfo['audio.outs'] = int(value)
  446. elif prop == "audio.total":
  447. if value.isdigit(): pinfo['audio.total'] = int(value)
  448. elif prop == "midi.ins":
  449. if value.isdigit(): pinfo['midi.ins'] = int(value)
  450. elif prop == "midi.outs":
  451. if value.isdigit(): pinfo['midi.outs'] = int(value)
  452. elif prop == "midi.total":
  453. if value.isdigit(): pinfo['midi.total'] = int(value)
  454. elif prop == "parameters.ins":
  455. if value.isdigit(): pinfo['parameters.ins'] = int(value)
  456. elif prop == "parameters.outs":
  457. if value.isdigit(): pinfo['parameters.outs'] = int(value)
  458. elif prop == "parameters.total":
  459. if value.isdigit(): pinfo['parameters.total'] = int(value)
  460. elif prop == "programs.total":
  461. if value.isdigit(): pinfo['programs.total'] = int(value)
  462. elif prop == "build":
  463. if value.isdigit(): pinfo['build'] = int(value)
  464. # Additional checks
  465. for pinfo in plugins:
  466. if itype == PLUGIN_DSSI:
  467. if findDSSIGUI(pinfo['binary'], pinfo['name'], pinfo['label']):
  468. pinfo['hints'] |= PLUGIN_HAS_GUI
  469. return plugins
  470. def checkPluginInternal(desc):
  471. plugins = []
  472. pinfo = deepcopy(PyPluginInfo)
  473. pinfo['type'] = PLUGIN_INTERNAL
  474. pinfo['name'] = cString(desc['name'])
  475. pinfo['label'] = cString(desc['label'])
  476. pinfo['maker'] = cString(desc['maker'])
  477. pinfo['copyright'] = cString(desc['copyright'])
  478. pinfo['hints'] = int(desc['hints'])
  479. pinfo['build'] = BINARY_NATIVE
  480. plugins.append(pinfo)
  481. return plugins
  482. def checkPluginLADSPA(filename, tool, isWine=False):
  483. return runCarlaDiscovery(PLUGIN_LADSPA, "LADSPA", filename, tool, isWine)
  484. def checkPluginDSSI(filename, tool, isWine=False):
  485. return runCarlaDiscovery(PLUGIN_DSSI, "DSSI", filename, tool, isWine)
  486. def checkPluginLV2(filename, tool, isWine=False):
  487. return runCarlaDiscovery(PLUGIN_LV2, "LV2", filename, tool, isWine)
  488. def checkPluginVST(filename, tool, isWine=False):
  489. return runCarlaDiscovery(PLUGIN_VST, "VST", filename, tool, isWine)
  490. def checkPluginGIG(filename, tool):
  491. return runCarlaDiscovery(PLUGIN_GIG, "GIG", filename, tool)
  492. def checkPluginSF2(filename, tool):
  493. return runCarlaDiscovery(PLUGIN_SF2, "SF2", filename, tool)
  494. def checkPluginSFZ(filename, tool):
  495. return runCarlaDiscovery(PLUGIN_SFZ, "SFZ", filename, tool)
  496. # ------------------------------------------------------------------------------------------------------------
  497. # Backend C++ -> Python variables
  498. c_enum = c_int
  499. c_nullptr = None
  500. if is64bit:
  501. c_uintptr = c_uint64
  502. else:
  503. c_uintptr = c_uint32
  504. class ParameterData(Structure):
  505. _fields_ = [
  506. ("type", c_enum),
  507. ("index", c_int32),
  508. ("rindex", c_int32),
  509. ("hints", c_int32),
  510. ("midiChannel", c_uint8),
  511. ("midiCC", c_int16)
  512. ]
  513. class ParameterRanges(Structure):
  514. _fields_ = [
  515. ("def", c_float),
  516. ("min", c_float),
  517. ("max", c_float),
  518. ("step", c_float),
  519. ("stepSmall", c_float),
  520. ("stepLarge", c_float)
  521. ]
  522. class MidiProgramData(Structure):
  523. _fields_ = [
  524. ("bank", c_uint32),
  525. ("program", c_uint32),
  526. ("label", c_char_p)
  527. ]
  528. class CustomData(Structure):
  529. _fields_ = [
  530. ("type", c_char_p),
  531. ("key", c_char_p),
  532. ("value", c_char_p)
  533. ]
  534. class PluginInfo(Structure):
  535. _fields_ = [
  536. ("type", c_enum),
  537. ("category", c_enum),
  538. ("hints", c_uint),
  539. ("binary", c_char_p),
  540. ("name", c_char_p),
  541. ("label", c_char_p),
  542. ("maker", c_char_p),
  543. ("copyright", c_char_p),
  544. ("uniqueId", c_long)
  545. ]
  546. class PortCountInfo(Structure):
  547. _fields_ = [
  548. ("ins", c_uint32),
  549. ("outs", c_uint32),
  550. ("total", c_uint32)
  551. ]
  552. class ParameterInfo(Structure):
  553. _fields_ = [
  554. ("name", c_char_p),
  555. ("symbol", c_char_p),
  556. ("unit", c_char_p),
  557. ("scalePointCount", c_uint32)
  558. ]
  559. class ScalePointInfo(Structure):
  560. _fields_ = [
  561. ("value", c_double),
  562. ("label", c_char_p)
  563. ]
  564. class GuiInfo(Structure):
  565. _fields_ = [
  566. ("type", c_enum),
  567. ("resizable", c_bool),
  568. ]
  569. CallbackFunc = CFUNCTYPE(None, c_void_p, c_enum, c_ushort, c_int, c_int, c_double, c_char_p)
  570. # ------------------------------------------------------------------------------------------------------------
  571. # Backend C++ -> Python object
  572. class Host(object):
  573. def __init__(self, lib_prefix_arg):
  574. object.__init__(self)
  575. global carla_library_path
  576. if lib_prefix_arg:
  577. carla_library_path = os.path.join(lib_prefix_arg, "lib", "cadence", carla_libname)
  578. if not carla_library_path:
  579. self.lib = None
  580. return
  581. self.lib = cdll.LoadLibrary(carla_library_path)
  582. self.lib.get_extended_license_text.argtypes = None
  583. self.lib.get_extended_license_text.restype = c_char_p
  584. self.lib.get_engine_driver_count.argtypes = None
  585. self.lib.get_engine_driver_count.restype = c_uint
  586. self.lib.get_engine_driver_name.argtypes = [c_uint]
  587. self.lib.get_engine_driver_name.restype = c_char_p
  588. self.lib.get_internal_plugin_count.argtypes = None
  589. self.lib.get_internal_plugin_count.restype = c_uint
  590. self.lib.get_internal_plugin_info.argtypes = [c_uint]
  591. self.lib.get_internal_plugin_info.restype = POINTER(PluginInfo)
  592. self.lib.engine_init.argtypes = [c_char_p, c_char_p]
  593. self.lib.engine_init.restype = c_bool
  594. self.lib.engine_close.argtypes = None
  595. self.lib.engine_close.restype = c_bool
  596. self.lib.is_engine_running.argtypes = None
  597. self.lib.is_engine_running.restype = c_bool
  598. self.lib.add_plugin.argtypes = [c_enum, c_enum, c_char_p, c_char_p, c_char_p, c_void_p]
  599. self.lib.add_plugin.restype = c_short
  600. self.lib.remove_plugin.argtypes = [c_ushort]
  601. self.lib.remove_plugin.restype = c_bool
  602. self.lib.get_plugin_info.argtypes = [c_ushort]
  603. self.lib.get_plugin_info.restype = POINTER(PluginInfo)
  604. self.lib.get_audio_port_count_info.argtypes = [c_ushort]
  605. self.lib.get_audio_port_count_info.restype = POINTER(PortCountInfo)
  606. self.lib.get_midi_port_count_info.argtypes = [c_ushort]
  607. self.lib.get_midi_port_count_info.restype = POINTER(PortCountInfo)
  608. self.lib.get_parameter_count_info.argtypes = [c_ushort]
  609. self.lib.get_parameter_count_info.restype = POINTER(PortCountInfo)
  610. self.lib.get_parameter_info.argtypes = [c_ushort, c_uint32]
  611. self.lib.get_parameter_info.restype = POINTER(ParameterInfo)
  612. self.lib.get_parameter_scalepoint_info.argtypes = [c_ushort, c_uint32, c_uint32]
  613. self.lib.get_parameter_scalepoint_info.restype = POINTER(ScalePointInfo)
  614. self.lib.get_gui_info.argtypes = [c_ushort]
  615. self.lib.get_gui_info.restype = POINTER(GuiInfo)
  616. self.lib.get_parameter_data.argtypes = [c_ushort, c_uint32]
  617. self.lib.get_parameter_data.restype = POINTER(ParameterData)
  618. self.lib.get_parameter_ranges.argtypes = [c_ushort, c_uint32]
  619. self.lib.get_parameter_ranges.restype = POINTER(ParameterRanges)
  620. self.lib.get_midi_program_data.argtypes = [c_ushort, c_uint32]
  621. self.lib.get_midi_program_data.restype = POINTER(MidiProgramData)
  622. self.lib.get_custom_data.argtypes = [c_ushort, c_uint32]
  623. self.lib.get_custom_data.restype = POINTER(CustomData)
  624. self.lib.get_chunk_data.argtypes = [c_ushort]
  625. self.lib.get_chunk_data.restype = c_char_p
  626. self.lib.get_parameter_count.argtypes = [c_ushort]
  627. self.lib.get_parameter_count.restype = c_uint32
  628. self.lib.get_program_count.argtypes = [c_ushort]
  629. self.lib.get_program_count.restype = c_uint32
  630. self.lib.get_midi_program_count.argtypes = [c_ushort]
  631. self.lib.get_midi_program_count.restype = c_uint32
  632. self.lib.get_custom_data_count.argtypes = [c_ushort]
  633. self.lib.get_custom_data_count.restype = c_uint32
  634. self.lib.get_parameter_text.argtypes = [c_ushort, c_uint32]
  635. self.lib.get_parameter_text.restype = c_char_p
  636. self.lib.get_program_name.argtypes = [c_ushort, c_uint32]
  637. self.lib.get_program_name.restype = c_char_p
  638. self.lib.get_midi_program_name.argtypes = [c_ushort, c_uint32]
  639. self.lib.get_midi_program_name.restype = c_char_p
  640. self.lib.get_real_plugin_name.argtypes = [c_ushort]
  641. self.lib.get_real_plugin_name.restype = c_char_p
  642. self.lib.get_current_program_index.argtypes = [c_ushort]
  643. self.lib.get_current_program_index.restype = c_int32
  644. self.lib.get_current_midi_program_index.argtypes = [c_ushort]
  645. self.lib.get_current_midi_program_index.restype = c_int32
  646. self.lib.get_default_parameter_value.argtypes = [c_ushort, c_uint32]
  647. self.lib.get_default_parameter_value.restype = c_double
  648. self.lib.get_current_parameter_value.argtypes = [c_ushort, c_uint32]
  649. self.lib.get_current_parameter_value.restype = c_double
  650. self.lib.get_input_peak_value.argtypes = [c_ushort, c_ushort]
  651. self.lib.get_input_peak_value.restype = c_double
  652. self.lib.get_output_peak_value.argtypes = [c_ushort, c_ushort]
  653. self.lib.get_output_peak_value.restype = c_double
  654. self.lib.set_active.argtypes = [c_ushort, c_bool]
  655. self.lib.set_active.restype = None
  656. self.lib.set_drywet.argtypes = [c_ushort, c_double]
  657. self.lib.set_drywet.restype = None
  658. self.lib.set_volume.argtypes = [c_ushort, c_double]
  659. self.lib.set_volume.restype = None
  660. self.lib.set_balance_left.argtypes = [c_ushort, c_double]
  661. self.lib.set_balance_left.restype = None
  662. self.lib.set_balance_right.argtypes = [c_ushort, c_double]
  663. self.lib.set_balance_right.restype = None
  664. self.lib.set_parameter_value.argtypes = [c_ushort, c_uint32, c_double]
  665. self.lib.set_parameter_value.restype = None
  666. self.lib.set_parameter_midi_cc.argtypes = [c_ushort, c_uint32, c_int16]
  667. self.lib.set_parameter_midi_cc.restype = None
  668. self.lib.set_parameter_midi_channel.argtypes = [c_ushort, c_uint32, c_uint8]
  669. self.lib.set_parameter_midi_channel.restype = None
  670. self.lib.set_program.argtypes = [c_ushort, c_uint32]
  671. self.lib.set_program.restype = None
  672. self.lib.set_midi_program.argtypes = [c_ushort, c_uint32]
  673. self.lib.set_midi_program.restype = None
  674. self.lib.set_custom_data.argtypes = [c_ushort, c_char_p, c_char_p, c_char_p]
  675. self.lib.set_custom_data.restype = None
  676. self.lib.set_chunk_data.argtypes = [c_ushort, c_char_p]
  677. self.lib.set_chunk_data.restype = None
  678. self.lib.set_gui_container.argtypes = [c_ushort, c_uintptr]
  679. self.lib.set_gui_container.restype = None
  680. self.lib.show_gui.argtypes = [c_ushort, c_bool]
  681. self.lib.show_gui.restype = None
  682. self.lib.idle_guis.argtypes = None
  683. self.lib.idle_guis.restype = None
  684. self.lib.send_midi_note.argtypes = [c_ushort, c_uint8, c_uint8, c_uint8]
  685. self.lib.send_midi_note.restype = None
  686. self.lib.prepare_for_save.argtypes = [c_ushort]
  687. self.lib.prepare_for_save.restype = None
  688. self.lib.get_buffer_size.argtypes = None
  689. self.lib.get_buffer_size.restype = c_uint32
  690. self.lib.get_sample_rate.argtypes = None
  691. self.lib.get_sample_rate.restype = c_double
  692. self.lib.get_last_error.argtypes = None
  693. self.lib.get_last_error.restype = c_char_p
  694. self.lib.get_host_osc_url.argtypes = None
  695. self.lib.get_host_osc_url.restype = c_char_p
  696. self.lib.set_callback_function.argtypes = [CallbackFunc]
  697. self.lib.set_callback_function.restype = None
  698. self.lib.set_option.argtypes = [c_enum, c_int, c_char_p]
  699. self.lib.set_option.restype = None
  700. self.lib.nsm_announce.argtypes = [c_char_p, c_int]
  701. self.lib.nsm_announce.restype = None
  702. self.lib.nsm_reply_open.argtypes = None
  703. self.lib.nsm_reply_open.restype = None
  704. self.lib.nsm_reply_save.argtypes = None
  705. self.lib.nsm_reply_save.restype = None
  706. def get_extended_license_text(self):
  707. return self.lib.get_extended_license_text()
  708. def get_engine_driver_count(self):
  709. return self.lib.get_engine_driver_count()
  710. def get_engine_driver_name(self, index):
  711. return self.lib.get_engine_driver_name(index)
  712. def get_internal_plugin_count(self):
  713. return self.lib.get_internal_plugin_count()
  714. def get_internal_plugin_info(self, index):
  715. return structToDict(self.lib.get_internal_plugin_info(index).contents)
  716. def engine_init(self, driverName, clientName):
  717. return self.lib.engine_init(driverName.encode("utf-8"), clientName.encode("utf-8"))
  718. def engine_close(self):
  719. return self.lib.engine_close()
  720. def is_engine_running(self):
  721. return self.lib.is_engine_running()
  722. def add_plugin(self, btype, ptype, filename, name, label, extraStuff):
  723. return self.lib.add_plugin(btype, ptype, filename.encode("utf-8"), name.encode("utf-8") if name else c_nullptr, label.encode("utf-8"), cast(extraStuff, c_void_p))
  724. def remove_plugin(self, pluginId):
  725. return self.lib.remove_plugin(pluginId)
  726. def get_plugin_info(self, pluginId):
  727. return structToDict(self.lib.get_plugin_info(pluginId).contents)
  728. def get_audio_port_count_info(self, pluginId):
  729. return structToDict(self.lib.get_audio_port_count_info(pluginId).contents)
  730. def get_midi_port_count_info(self, pluginId):
  731. return structToDict(self.lib.get_midi_port_count_info(pluginId).contents)
  732. def get_parameter_count_info(self, pluginId):
  733. return structToDict(self.lib.get_parameter_count_info(pluginId).contents)
  734. def get_parameter_info(self, pluginId, parameterId):
  735. return structToDict(self.lib.get_parameter_info(pluginId, parameterId).contents)
  736. def get_parameter_scalepoint_info(self, pluginId, parameterId, scalePointId):
  737. return structToDict(self.lib.get_parameter_scalepoint_info(pluginId, parameterId, scalePointId).contents)
  738. def get_parameter_data(self, pluginId, parameterId):
  739. return structToDict(self.lib.get_parameter_data(pluginId, parameterId).contents)
  740. def get_parameter_ranges(self, pluginId, parameterId):
  741. return structToDict(self.lib.get_parameter_ranges(pluginId, parameterId).contents)
  742. def get_midi_program_data(self, pluginId, midiProgramId):
  743. return structToDict(self.lib.get_midi_program_data(pluginId, midiProgramId).contents)
  744. def get_custom_data(self, pluginId, customDataId):
  745. return structToDict(self.lib.get_custom_data(pluginId, customDataId).contents)
  746. def get_chunk_data(self, pluginId):
  747. return self.lib.get_chunk_data(pluginId)
  748. def get_gui_info(self, pluginId):
  749. return structToDict(self.lib.get_gui_info(pluginId).contents)
  750. def get_parameter_count(self, pluginId):
  751. return self.lib.get_parameter_count(pluginId)
  752. def get_program_count(self, pluginId):
  753. return self.lib.get_program_count(pluginId)
  754. def get_midi_program_count(self, pluginId):
  755. return self.lib.get_midi_program_count(pluginId)
  756. def get_custom_data_count(self, pluginId):
  757. return self.lib.get_custom_data_count(pluginId)
  758. def get_parameter_text(self, pluginId, parameterId):
  759. return self.lib.get_parameter_text(pluginId, parameterId)
  760. def get_program_name(self, pluginId, programId):
  761. return self.lib.get_program_name(pluginId, programId)
  762. def get_midi_program_name(self, pluginId, midiProgramId):
  763. return self.lib.get_midi_program_name(pluginId, midiProgramId)
  764. def get_real_plugin_name(self, pluginId):
  765. return self.lib.get_real_plugin_name(pluginId)
  766. def get_current_program_index(self, pluginId):
  767. return self.lib.get_current_program_index(pluginId)
  768. def get_current_midi_program_index(self, pluginId):
  769. return self.lib.get_current_midi_program_index(pluginId)
  770. def get_default_parameter_value(self, pluginId, parameterId):
  771. return self.lib.get_default_parameter_value(pluginId, parameterId)
  772. def get_current_parameter_value(self, pluginId, parameterId):
  773. return self.lib.get_current_parameter_value(pluginId, parameterId)
  774. def get_input_peak_value(self, pluginId, portId):
  775. return self.lib.get_input_peak_value(pluginId, portId)
  776. def get_output_peak_value(self, pluginId, portId):
  777. return self.lib.get_output_peak_value(pluginId, portId)
  778. def set_active(self, pluginId, onOff):
  779. self.lib.set_active(pluginId, onOff)
  780. def set_drywet(self, pluginId, value):
  781. self.lib.set_drywet(pluginId, value)
  782. def set_volume(self, pluginId, value):
  783. self.lib.set_volume(pluginId, value)
  784. def set_balance_left(self, pluginId, value):
  785. self.lib.set_balance_left(pluginId, value)
  786. def set_balance_right(self, pluginId, value):
  787. self.lib.set_balance_right(pluginId, value)
  788. def set_parameter_value(self, pluginId, parameterId, value):
  789. self.lib.set_parameter_value(pluginId, parameterId, value)
  790. def set_parameter_midi_cc(self, pluginId, parameterId, cc):
  791. self.lib.set_parameter_midi_cc(pluginId, parameterId, cc)
  792. def set_parameter_midi_channel(self, pluginId, parameterId, channel):
  793. self.lib.set_parameter_midi_channel(pluginId, parameterId, channel)
  794. def set_program(self, pluginId, programId):
  795. self.lib.set_program(pluginId, programId)
  796. def set_midi_program(self, pluginId, midiProgramId):
  797. self.lib.set_midi_program(pluginId, midiProgramId)
  798. def set_custom_data(self, pluginId, type_, key, value):
  799. self.lib.set_custom_data(pluginId, type_.encode("utf-8"), key.encode("utf-8"), value.encode("utf-8"))
  800. def set_chunk_data(self, pluginId, chunkData):
  801. self.lib.set_chunk_data(pluginId, chunkData.encode("utf-8"))
  802. def set_gui_container(self, pluginId, guiAddr):
  803. self.lib.set_gui_container(pluginId, guiAddr)
  804. def show_gui(self, pluginId, yesNo):
  805. self.lib.show_gui(pluginId, yesNo)
  806. def idle_guis(self):
  807. self.lib.idle_guis()
  808. def send_midi_note(self, pluginId, channel, note, velocity):
  809. self.lib.send_midi_note(pluginId, channel, note, velocity)
  810. def prepare_for_save(self, pluginId):
  811. self.lib.prepare_for_save(pluginId)
  812. def set_callback_function(self, func):
  813. self.callback = CallbackFunc(func)
  814. self.lib.set_callback_function(self.callback)
  815. def set_option(self, option, value, valueStr):
  816. self.lib.set_option(option, value, valueStr.encode("utf-8"))
  817. def get_last_error(self):
  818. return self.lib.get_last_error()
  819. def get_host_osc_url(self):
  820. return self.lib.get_host_osc_url()
  821. def get_buffer_size(self):
  822. return self.lib.get_buffer_size()
  823. def get_sample_rate(self):
  824. return self.lib.get_sample_rate()
  825. def nsm_announce(self, url, pid):
  826. self.lib.nsm_announce(url.encode("utf-8"), pid)
  827. def nsm_reply_open(self):
  828. self.lib.nsm_reply_open()
  829. def nsm_reply_save(self):
  830. self.lib.nsm_reply_save()