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.

externalui.py 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # DISTRHO Plugin Toolkit (DPT)
  4. # Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
  5. #
  6. # Permission to use, copy, modify, and/or distribute this software for any purpose with
  7. # or without fee is hereby granted, provided that the above copyright notice and this
  8. # permission notice appear in all copies.
  9. #
  10. # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  11. # TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  12. # NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  13. # DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  14. # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  15. # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. # -----------------------------------------------------------------------
  17. # Imports
  18. from os import fdopen, O_NONBLOCK
  19. from fcntl import fcntl, F_GETFL, F_SETFL
  20. from sys import argv
  21. # -----------------------------------------------------------------------
  22. # External UI
  23. class ExternalUI(object):
  24. def __init__(self):
  25. object.__init__(self)
  26. self.fPipeRecv = None
  27. self.fPipeSend = None
  28. self.fQuitReceived = False
  29. if len(argv) > 1:
  30. self.fSampleRate = float(argv[1])
  31. self.fUiName = argv[2]
  32. self.fPipeRecvFd = int(argv[3])
  33. self.fPipeSendFd = int(argv[4])
  34. fcntl(self.fPipeRecvFd, F_SETFL, fcntl(self.fPipeRecvFd, F_GETFL) | O_NONBLOCK)
  35. self.fPipeRecv = fdopen(self.fPipeRecvFd, 'r')
  36. self.fPipeSend = fdopen(self.fPipeSendFd, 'w')
  37. else:
  38. self.fSampleRate = 44100.0
  39. self.fUiName = "TestUI"
  40. self.fPipeRecv = None
  41. self.fPipeSend = None
  42. # send empty line (just newline char)
  43. self.send([""])
  44. def showUiIfTesting(self):
  45. if self.fPipeRecv is None:
  46. self.d_uiShow()
  47. # -------------------------------------------------------------------
  48. # Host DSP State
  49. def d_getSampleRate(self):
  50. return self.fSampleRate
  51. def d_editParameter(self, index, started):
  52. self.send(["editParam", index, started])
  53. def d_setParameterValue(self, index, value):
  54. self.send(["control", index, value])
  55. def d_setState(self, key, value):
  56. self.send(["configure", key, value])
  57. def d_sendNote(self, onOff, channel, note, velocity):
  58. self.send(["note", onOff, channel, note, velocity])
  59. # -------------------------------------------------------------------
  60. # DSP Callbacks
  61. def d_parameterChanged(self, index, value):
  62. return
  63. def d_programChanged(self, index):
  64. return
  65. def d_stateChanged(self, key, value):
  66. return
  67. def d_noteReceived(self, onOff, channel, note, velocity):
  68. return
  69. # -------------------------------------------------------------------
  70. # ExternalUI Callbacks
  71. def d_uiShow(self):
  72. return
  73. def d_uiHide(self):
  74. return
  75. def d_uiQuit(self):
  76. return
  77. def d_uiTitleChanged(self, uiTitle):
  78. return
  79. # -------------------------------------------------------------------
  80. # Public methods
  81. def closeExternalUI(self):
  82. if not self.fQuitReceived:
  83. self.send(["exiting"])
  84. if self.fPipeRecv is not None:
  85. self.fPipeRecv.close()
  86. self.fPipeRecv = None
  87. if self.fPipeSend is not None:
  88. self.fPipeSend.close()
  89. self.fPipeSend = None
  90. def idleExternalUI(self):
  91. while True:
  92. if self.fPipeRecv is None:
  93. return True
  94. try:
  95. msg = self.fPipeRecv.readline().strip()
  96. except IOError:
  97. return False
  98. if not msg:
  99. return True
  100. elif msg == "control":
  101. index = int(self.fPipeRecv.readline())
  102. value = float(self.fPipeRecv.readline())
  103. self.d_parameterChanged(index, value)
  104. elif msg == "program":
  105. index = int(self.fPipeRecv.readline())
  106. self.d_programChanged(index)
  107. elif msg == "configure":
  108. key = self.fPipeRecv.readline().strip().replace("\r", "\n")
  109. value = self.fPipeRecv.readline().strip().replace("\r", "\n")
  110. self.d_stateChanged(key, value)
  111. elif msg == "note":
  112. onOff = bool(self.fPipeRecv.readline().strip() == "true")
  113. channel = int(self.fPipeRecv.readline())
  114. note = int(self.fPipeRecv.readline())
  115. velocity = int(self.fPipeRecv.readline())
  116. self.d_noteReceived(onOff, channel, note, velocity)
  117. elif msg == "show":
  118. self.d_uiShow()
  119. elif msg == "hide":
  120. self.d_uiHide()
  121. elif msg == "quit":
  122. self.fQuitReceived = True
  123. self.d_uiQuit()
  124. elif msg == "uiTitle":
  125. uiTitle = self.fPipeRecv.readline().strip().replace("\r", "\n")
  126. self.d_uiTitleChanged(uiTitle)
  127. else:
  128. print("unknown message: \"" + msg + "\"")
  129. return True
  130. # -------------------------------------------------------------------
  131. # Internal stuff
  132. def send(self, lines):
  133. if self.fPipeSend is None:
  134. return
  135. for line in lines:
  136. if isinstance(line, str):
  137. line2 = line.replace("\n", "\r")
  138. else:
  139. if isinstance(line, bool):
  140. line2 = "true" if line else "false"
  141. elif isinstance(line, int):
  142. line2 = "%i" % line
  143. elif isinstance(line, float):
  144. line2 = "%.10f" % line
  145. else:
  146. return
  147. self.fPipeSend.write(line2 + "\n")
  148. self.fPipeSend.flush()