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.

477 lines
16KB

  1. #!/usr/bin/env python3
  2. # SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
  3. # SPDX-License-Identifier: GPL-2.0-or-later
  4. # ------------------------------------------------------------------------------------------------------------
  5. # Imports (Global)
  6. from os import environ
  7. from sys import argv
  8. # ------------------------------------------------------------------------------------------------------------
  9. # Imports (ctypes)
  10. from ctypes import (
  11. c_bool, c_char_p, c_double, c_int, c_uint, c_uint32, c_void_p,
  12. cdll, Structure,
  13. CFUNCTYPE, POINTER
  14. )
  15. # ------------------------------------------------------------------------------------------------------------
  16. # Imports (Custom)
  17. from carla_backend import (
  18. CARLA_OS_WIN,
  19. PLUGIN_NONE,
  20. PLUGIN_INTERNAL,
  21. PLUGIN_LADSPA,
  22. PLUGIN_DSSI,
  23. PLUGIN_LV2,
  24. PLUGIN_VST2,
  25. PLUGIN_VST3,
  26. PLUGIN_AU,
  27. PLUGIN_DLS,
  28. PLUGIN_GIG,
  29. PLUGIN_SF2,
  30. PLUGIN_SFZ,
  31. PLUGIN_JACK,
  32. PLUGIN_JSFX,
  33. PLUGIN_CLAP,
  34. PLUGIN_CATEGORY_NONE,
  35. PLUGIN_CATEGORY_SYNTH,
  36. PLUGIN_CATEGORY_DELAY,
  37. PLUGIN_CATEGORY_EQ,
  38. PLUGIN_CATEGORY_FILTER,
  39. PLUGIN_CATEGORY_DISTORTION,
  40. PLUGIN_CATEGORY_DYNAMICS,
  41. PLUGIN_CATEGORY_MODULATOR,
  42. PLUGIN_CATEGORY_UTILITY,
  43. PLUGIN_CATEGORY_OTHER,
  44. c_enum, c_uintptr,
  45. charPtrToString,
  46. charPtrPtrToStringList,
  47. structToDict
  48. )
  49. # ------------------------------------------------------------------------------------------------------------
  50. def getPluginTypeAsString(ptype):
  51. if ptype == PLUGIN_NONE:
  52. return "NONE"
  53. if ptype == PLUGIN_INTERNAL:
  54. return "Internal"
  55. if ptype == PLUGIN_LADSPA:
  56. return "LADSPA"
  57. if ptype == PLUGIN_DSSI:
  58. return "DSSI"
  59. if ptype == PLUGIN_LV2:
  60. return "LV2"
  61. if ptype == PLUGIN_VST2:
  62. return "VST2"
  63. if ptype == PLUGIN_VST3:
  64. return "VST3"
  65. if ptype == PLUGIN_AU:
  66. return "AU"
  67. if ptype == PLUGIN_DLS:
  68. return "DLS"
  69. if ptype == PLUGIN_GIG:
  70. return "GIG"
  71. if ptype == PLUGIN_SF2:
  72. return "SF2"
  73. if ptype == PLUGIN_SFZ:
  74. return "SFZ"
  75. if ptype == PLUGIN_JACK:
  76. return "JACK"
  77. if ptype == PLUGIN_JSFX:
  78. return "JSFX"
  79. if ptype == PLUGIN_CLAP:
  80. return "CLAP"
  81. print("getPluginTypeAsString(%i) - invalid type" % ptype)
  82. return "Unknown"
  83. def getPluginTypeFromString(stype):
  84. if not stype:
  85. return PLUGIN_NONE
  86. stype = stype.lower()
  87. if stype == "none":
  88. return PLUGIN_NONE
  89. if stype in ("internal", "native"):
  90. return PLUGIN_INTERNAL
  91. if stype == "ladspa":
  92. return PLUGIN_LADSPA
  93. if stype == "dssi":
  94. return PLUGIN_DSSI
  95. if stype == "lv2":
  96. return PLUGIN_LV2
  97. if stype in ("vst2", "vst"):
  98. return PLUGIN_VST2
  99. if stype == "vst3":
  100. return PLUGIN_VST3
  101. if stype in ("au", "audiounit"):
  102. return PLUGIN_AU
  103. if stype == "dls":
  104. return PLUGIN_DLS
  105. if stype == "gig":
  106. return PLUGIN_GIG
  107. if stype == "sf2":
  108. return PLUGIN_SF2
  109. if stype == "sfz":
  110. return PLUGIN_SFZ
  111. if stype == "jack":
  112. return PLUGIN_JACK
  113. if stype == "jsfx":
  114. return PLUGIN_JSFX
  115. if stype == "clap":
  116. return PLUGIN_CLAP
  117. print("getPluginTypeFromString(\"%s\") - invalid string type" % stype)
  118. return PLUGIN_NONE
  119. def getPluginCategoryAsString(category):
  120. if category == PLUGIN_CATEGORY_NONE:
  121. return "none"
  122. if category == PLUGIN_CATEGORY_SYNTH:
  123. return "synth"
  124. if category == PLUGIN_CATEGORY_DELAY:
  125. return "delay"
  126. if category == PLUGIN_CATEGORY_EQ:
  127. return "eq"
  128. if category == PLUGIN_CATEGORY_FILTER:
  129. return "filter"
  130. if category == PLUGIN_CATEGORY_DISTORTION:
  131. return "distortion"
  132. if category == PLUGIN_CATEGORY_DYNAMICS:
  133. return "dynamics"
  134. if category == PLUGIN_CATEGORY_MODULATOR:
  135. return "modulator"
  136. if category == PLUGIN_CATEGORY_UTILITY:
  137. return "utility"
  138. if category == PLUGIN_CATEGORY_OTHER:
  139. return "other"
  140. print("CarlaBackend::getPluginCategoryAsString(%i) - invalid category" % category)
  141. return "NONE"
  142. # ------------------------------------------------------------------------------------------------------------
  143. # Carla Utils API (C stuff)
  144. CarlaPipeClientHandle = c_void_p
  145. CarlaPipeCallbackFunc = CFUNCTYPE(None, c_void_p, c_char_p)
  146. # Information about an internal Carla plugin.
  147. # @see carla_get_cached_plugin_info()
  148. class CarlaCachedPluginInfo(Structure):
  149. _fields_ = [
  150. # Wherever the data in this struct is valid.
  151. # For performance reasons, plugins are only checked on request,
  152. # and as such, the count vs number of really valid plugins might not match.
  153. # Use this field to skip on plugins which cannot be loaded in Carla.
  154. ("valid", c_bool),
  155. # Plugin category.
  156. ("category", c_enum),
  157. # Plugin hints.
  158. # @see PluginHints
  159. ("hints", c_uint),
  160. # Number of audio inputs.
  161. ("audioIns", c_uint32),
  162. # Number of audio outputs.
  163. ("audioOuts", c_uint32),
  164. # Number of CV inputs.
  165. ("cvIns", c_uint32),
  166. # Number of CV outputs.
  167. ("cvOuts", c_uint32),
  168. # Number of MIDI inputs.
  169. ("midiIns", c_uint32),
  170. # Number of MIDI outputs.
  171. ("midiOuts", c_uint32),
  172. # Number of input parameters.
  173. ("parameterIns", c_uint32),
  174. # Number of output parameters.
  175. ("parameterOuts", c_uint32),
  176. # Plugin name.
  177. ("name", c_char_p),
  178. # Plugin label.
  179. ("label", c_char_p),
  180. # Plugin author/maker.
  181. ("maker", c_char_p),
  182. # Plugin copyright/license.
  183. ("copyright", c_char_p)
  184. ]
  185. # ------------------------------------------------------------------------------------------------------------
  186. # Carla Utils API (Python compatible stuff)
  187. # @see CarlaCachedPluginInfo
  188. PyCarlaCachedPluginInfo = {
  189. 'valid': False,
  190. 'category': PLUGIN_CATEGORY_NONE,
  191. 'hints': 0x0,
  192. 'audioIns': 0,
  193. 'audioOuts': 0,
  194. 'cvIns': 0,
  195. 'cvOuts': 0,
  196. 'midiIns': 0,
  197. 'midiOuts': 0,
  198. 'parameterIns': 0,
  199. 'parameterOuts': 0,
  200. 'name': "",
  201. 'label': "",
  202. 'maker': "",
  203. 'copyright': ""
  204. }
  205. # ------------------------------------------------------------------------------------------------------------
  206. # Carla Utils object using a DLL
  207. class CarlaUtils():
  208. def __init__(self, filename):
  209. self.lib = cdll.LoadLibrary(filename)
  210. #self.lib = CDLL(filename, RTLD_GLOBAL)
  211. self.lib.carla_get_complete_license_text.argtypes = None
  212. self.lib.carla_get_complete_license_text.restype = c_char_p
  213. self.lib.carla_get_supported_file_extensions.argtypes = None
  214. self.lib.carla_get_supported_file_extensions.restype = POINTER(c_char_p)
  215. self.lib.carla_get_supported_features.argtypes = None
  216. self.lib.carla_get_supported_features.restype = POINTER(c_char_p)
  217. self.lib.carla_get_cached_plugin_count.argtypes = [c_enum, c_char_p]
  218. self.lib.carla_get_cached_plugin_count.restype = c_uint
  219. self.lib.carla_get_cached_plugin_info.argtypes = [c_enum, c_uint]
  220. self.lib.carla_get_cached_plugin_info.restype = POINTER(CarlaCachedPluginInfo)
  221. self.lib.carla_fflush.argtypes = [c_bool]
  222. self.lib.carla_fflush.restype = None
  223. self.lib.carla_fputs.argtypes = [c_bool, c_char_p]
  224. self.lib.carla_fputs.restype = None
  225. self.lib.carla_set_process_name.argtypes = [c_char_p]
  226. self.lib.carla_set_process_name.restype = None
  227. self.lib.carla_pipe_client_new.argtypes = [POINTER(c_char_p), CarlaPipeCallbackFunc, c_void_p]
  228. self.lib.carla_pipe_client_new.restype = CarlaPipeClientHandle
  229. self.lib.carla_pipe_client_idle.argtypes = [CarlaPipeClientHandle]
  230. self.lib.carla_pipe_client_idle.restype = None
  231. self.lib.carla_pipe_client_is_running.argtypes = [CarlaPipeClientHandle]
  232. self.lib.carla_pipe_client_is_running.restype = c_bool
  233. self.lib.carla_pipe_client_lock.argtypes = [CarlaPipeClientHandle]
  234. self.lib.carla_pipe_client_lock.restype = None
  235. self.lib.carla_pipe_client_unlock.argtypes = [CarlaPipeClientHandle]
  236. self.lib.carla_pipe_client_unlock.restype = None
  237. self.lib.carla_pipe_client_readlineblock.argtypes = [CarlaPipeClientHandle, c_uint]
  238. self.lib.carla_pipe_client_readlineblock.restype = c_char_p
  239. self.lib.carla_pipe_client_readlineblock_bool.argtypes = [CarlaPipeClientHandle, c_uint]
  240. self.lib.carla_pipe_client_readlineblock_bool.restype = c_bool
  241. self.lib.carla_pipe_client_readlineblock_int.argtypes = [CarlaPipeClientHandle, c_uint]
  242. self.lib.carla_pipe_client_readlineblock_int.restype = c_int
  243. self.lib.carla_pipe_client_readlineblock_float.argtypes = [CarlaPipeClientHandle, c_uint]
  244. self.lib.carla_pipe_client_readlineblock_float.restype = c_double
  245. self.lib.carla_pipe_client_write_msg.argtypes = [CarlaPipeClientHandle, c_char_p]
  246. self.lib.carla_pipe_client_write_msg.restype = c_bool
  247. self.lib.carla_pipe_client_write_and_fix_msg.argtypes = [CarlaPipeClientHandle, c_char_p]
  248. self.lib.carla_pipe_client_write_and_fix_msg.restype = c_bool
  249. self.lib.carla_pipe_client_flush.argtypes = [CarlaPipeClientHandle]
  250. self.lib.carla_pipe_client_flush.restype = c_bool
  251. self.lib.carla_pipe_client_flush_and_unlock.argtypes = [CarlaPipeClientHandle]
  252. self.lib.carla_pipe_client_flush_and_unlock.restype = c_bool
  253. self.lib.carla_pipe_client_destroy.argtypes = [CarlaPipeClientHandle]
  254. self.lib.carla_pipe_client_destroy.restype = None
  255. self.lib.carla_get_desktop_scale_factor.argtypes = None
  256. self.lib.carla_get_desktop_scale_factor.restype = c_double
  257. self.lib.carla_cocoa_get_window.argtypes = [c_uintptr]
  258. self.lib.carla_cocoa_get_window.restype = c_int
  259. self.lib.carla_cocoa_set_transient_window_for.argtypes = [c_uintptr, c_uintptr]
  260. self.lib.carla_cocoa_set_transient_window_for.restype = None
  261. self.lib.carla_x11_reparent_window.argtypes = [c_uintptr, c_uintptr]
  262. self.lib.carla_x11_reparent_window.restype = None
  263. self.lib.carla_x11_move_window.argtypes = [c_uintptr, c_int, c_int]
  264. self.lib.carla_x11_move_window.restype = None
  265. self.lib.carla_x11_get_window_pos.argtypes = [c_uintptr]
  266. self.lib.carla_x11_get_window_pos.restype = POINTER(c_int)
  267. self._pipeClientFunc = None
  268. self._pipeClientCallback = None
  269. # use _putenv on windows
  270. if not CARLA_OS_WIN:
  271. self.msvcrt = None
  272. return
  273. self.msvcrt = cdll.msvcrt
  274. # pylint: disable=protected-access
  275. self.msvcrt._putenv.argtypes = [c_char_p]
  276. self.msvcrt._putenv.restype = None
  277. # pylint: enable=protected-access
  278. # --------------------------------------------------------------------------------------------------------
  279. # set environment variable
  280. def setenv(self, key, value):
  281. environ[key] = value
  282. if CARLA_OS_WIN:
  283. keyvalue = "%s=%s" % (key, value)
  284. # pylint: disable=protected-access
  285. self.msvcrt._putenv(keyvalue.encode("utf-8"))
  286. # pylint: enable=protected-access
  287. # unset environment variable
  288. def unsetenv(self, key):
  289. if environ.get(key) is not None:
  290. environ.pop(key)
  291. if CARLA_OS_WIN:
  292. keyrm = "%s=" % key
  293. # pylint: disable=protected-access
  294. self.msvcrt._putenv(keyrm.encode("utf-8"))
  295. # pylint: enable=protected-access
  296. # --------------------------------------------------------------------------------------------------------
  297. # Get the complete license text of used third-party code and features.
  298. # Returned string is in basic html format.
  299. def get_complete_license_text(self):
  300. return charPtrToString(self.lib.carla_get_complete_license_text())
  301. # Get the list of supported file extensions in carla_load_file().
  302. def get_supported_file_extensions(self):
  303. return charPtrPtrToStringList(self.lib.carla_get_supported_file_extensions())
  304. # Get the list of supported features in the current Carla build.
  305. def get_supported_features(self):
  306. return charPtrPtrToStringList(self.lib.carla_get_supported_features())
  307. # Get how many internal plugins are available.
  308. # Internal and LV2 plugin formats are cached and need to be discovered via this function.
  309. # Do not call this for any other plugin formats.
  310. def get_cached_plugin_count(self, ptype, pluginPath):
  311. return int(self.lib.carla_get_cached_plugin_count(ptype, pluginPath.encode("utf-8")))
  312. # Get information about a cached plugin.
  313. def get_cached_plugin_info(self, ptype, index):
  314. return structToDict(self.lib.carla_get_cached_plugin_info(ptype, index).contents)
  315. def fflush(self, err):
  316. self.lib.carla_fflush(err)
  317. def fputs(self, err, string):
  318. self.lib.carla_fputs(err, string.encode("utf-8"))
  319. def set_process_name(self, name):
  320. self.lib.carla_set_process_name(name.encode("utf-8"))
  321. def pipe_client_new(self, func):
  322. argc = len(argv)
  323. cagrvtype = c_char_p * argc
  324. cargv = cagrvtype()
  325. for i in range(argc):
  326. cargv[i] = c_char_p(argv[i].encode("utf-8"))
  327. self._pipeClientFunc = func
  328. self._pipeClientCallback = CarlaPipeCallbackFunc(func)
  329. return self.lib.carla_pipe_client_new(cargv, self._pipeClientCallback, None)
  330. def pipe_client_idle(self, handle):
  331. try:
  332. self.lib.carla_pipe_client_idle(handle)
  333. except OSError as e:
  334. print("carla_pipe_client_idle", e)
  335. def pipe_client_is_running(self, handle):
  336. return bool(self.lib.carla_pipe_client_is_running(handle))
  337. def pipe_client_lock(self, handle):
  338. self.lib.carla_pipe_client_lock(handle)
  339. def pipe_client_unlock(self, handle):
  340. self.lib.carla_pipe_client_unlock(handle)
  341. def pipe_client_readlineblock(self, handle, timeout):
  342. return charPtrToString(self.lib.carla_pipe_client_readlineblock(handle, timeout))
  343. def pipe_client_readlineblock_bool(self, handle, timeout):
  344. return bool(self.lib.carla_pipe_client_readlineblock_bool(handle, timeout))
  345. def pipe_client_readlineblock_int(self, handle, timeout):
  346. return int(self.lib.carla_pipe_client_readlineblock_int(handle, timeout))
  347. def pipe_client_readlineblock_float(self, handle, timeout):
  348. return float(self.lib.carla_pipe_client_readlineblock_float(handle, timeout))
  349. def pipe_client_write_msg(self, handle, msg):
  350. return bool(self.lib.carla_pipe_client_write_msg(handle, msg.encode("utf-8")))
  351. def pipe_client_write_and_fix_msg(self, handle, msg):
  352. return bool(self.lib.carla_pipe_client_write_and_fix_msg(handle, msg.encode("utf-8")))
  353. def pipe_client_flush(self, handle):
  354. return bool(self.lib.carla_pipe_client_flush(handle))
  355. def pipe_client_flush_and_unlock(self, handle):
  356. return bool(self.lib.carla_pipe_client_flush_and_unlock(handle))
  357. def pipe_client_destroy(self, handle):
  358. self.lib.carla_pipe_client_destroy(handle)
  359. def get_desktop_scale_factor(self):
  360. return float(self.lib.carla_get_desktop_scale_factor())
  361. def cocoa_get_window(self, winId):
  362. return self.lib.carla_cocoa_get_window(winId)
  363. def cocoa_set_transient_window_for(self, childWinId, parentWinId):
  364. self.lib.carla_cocoa_set_transient_window_for(childWinId, parentWinId)
  365. def x11_reparent_window(self, winId1, winId2):
  366. self.lib.carla_x11_reparent_window(winId1, winId2)
  367. def x11_move_window(self, winId, x, y):
  368. self.lib.carla_x11_move_window(winId, x, y)
  369. def x11_get_window_pos(self, winId):
  370. data = self.lib.carla_x11_get_window_pos(winId)
  371. return tuple(int(data[i]) for i in range(4))
  372. # ------------------------------------------------------------------------------------------------------------