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.

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