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.

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