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.7KB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # External UI
  4. # Copyright (C) 2013-2014 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 doc/GPL.txt file.
  17. # ------------------------------------------------------------------------------------------------------------
  18. # Imports (Custom Stuff)
  19. from carla_shared import *
  20. # ------------------------------------------------------------------------------------------------------------
  21. # External UI
  22. class ExternalUI(object):
  23. def __init__(self):
  24. object.__init__(self)
  25. self.fQuitReceived = False
  26. if len(sys.argv) > 1:
  27. self.fSampleRate = float(sys.argv[1])
  28. self.fUiName = sys.argv[2]
  29. self.fPipeClient = gCarla.utils.pipe_client_new(lambda s,msg: self.msgCallback(msg))
  30. else:
  31. self.fSampleRate = 44100.0
  32. self.fUiName = "TestUI"
  33. self.fPipeClient = None
  34. # -------------------------------------------------------------------
  35. # Public methods
  36. def ready(self):
  37. if self.fPipeClient is None:
  38. # testing, show UI only
  39. self.uiShow()
  40. def isRunning(self):
  41. if self.fPipeClient is not None:
  42. return gCarla.utils.pipe_client_is_running(self.fPipeClient)
  43. return False
  44. def idleExternalUI(self):
  45. if self.fPipeClient is not None:
  46. gCarla.utils.pipe_client_idle(self.fPipeClient)
  47. def closeExternalUI(self):
  48. if self.fPipeClient is None:
  49. return
  50. # FIXME
  51. if not self.fQuitReceived:
  52. self.send(["exiting"])
  53. gCarla.utils.pipe_client_destroy(self.fPipeClient)
  54. self.fPipeClient = None
  55. # -------------------------------------------------------------------
  56. # Host DSP State
  57. def getSampleRate(self):
  58. return self.fSampleRate
  59. def sendControl(self, index, value):
  60. self.send(["control", index, value])
  61. def sendProgram(self, channel, bank, program):
  62. self.send(["program", channel, bank, program])
  63. def sendConfigure(self, key, value):
  64. self.send(["configure", key, value])
  65. def sendNote(self, onOff, channel, note, velocity):
  66. self.send(["note", onOff, channel, note, velocity])
  67. # -------------------------------------------------------------------
  68. # DSP Callbacks
  69. def dspParameterChanged(self, index, value):
  70. return
  71. def dspProgramChanged(self, channel, bank, program):
  72. return
  73. def dspStateChanged(self, key, value):
  74. return
  75. def dspNoteReceived(self, onOff, channel, note, velocity):
  76. return
  77. # -------------------------------------------------------------------
  78. # ExternalUI Callbacks
  79. def uiShow(self):
  80. return
  81. def uiFocus(self):
  82. return
  83. def uiHide(self):
  84. return
  85. def uiQuit(self):
  86. self.closeExternalUI()
  87. def uiTitleChanged(self, uiTitle):
  88. return
  89. # -------------------------------------------------------------------
  90. # Callback
  91. def msgCallback(self, msg):
  92. msg = charPtrToString(msg)
  93. #if not msg:
  94. #return
  95. if msg == "control":
  96. index = self.readlineblock_int()
  97. value = self.readlineblock_float()
  98. self.dspParameterChanged(index, value)
  99. elif msg == "program":
  100. channel = self.readlineblock_int()
  101. bank = self.readlineblock_int()
  102. program = self.readlineblock_int()
  103. self.dspProgramChanged(channel, bank, program)
  104. elif msg == "configure":
  105. key = self.readlineblock()
  106. value = self.readlineblock()
  107. self.dspStateChanged(key, value)
  108. elif msg == "note":
  109. onOff = self.readlineblock_bool()
  110. channel = self.readlineblock_int()
  111. note = self.readlineblock_int()
  112. velocity = self.readlineblock_int()
  113. self.dspNoteReceived(onOff, channel, note, velocity)
  114. elif msg == "show":
  115. self.uiShow()
  116. elif msg == "focus":
  117. self.uiFocus()
  118. elif msg == "hide":
  119. self.uiHide()
  120. elif msg == "quit":
  121. self.fQuitReceived = True
  122. self.uiQuit()
  123. elif msg == "uiTitle":
  124. uiTitle = self.readlineblock()
  125. self.uiTitleChanged(uiTitle)
  126. else:
  127. print("unknown message: \"" + msg + "\"")
  128. # -------------------------------------------------------------------
  129. # Internal stuff
  130. def readlineblock(self):
  131. if self.fPipeClient is None:
  132. return ""
  133. return gCarla.utils.pipe_client_readlineblock(self.fPipeClient, 5000)
  134. def readlineblock_bool(self):
  135. if self.fPipeClient is None:
  136. return False
  137. return gCarla.utils.pipe_client_readlineblock_bool(self.fPipeClient, 5000)
  138. def readlineblock_int(self):
  139. if self.fPipeClient is None:
  140. return 0
  141. return gCarla.utils.pipe_client_readlineblock_int(self.fPipeClient, 5000)
  142. def readlineblock_float(self):
  143. if self.fPipeClient is None:
  144. return 0.0
  145. return gCarla.utils.pipe_client_readlineblock_float(self.fPipeClient, 5000)
  146. def send(self, lines):
  147. if self.fPipeClient is None or len(lines) == 0:
  148. return False
  149. hasError = False
  150. gCarla.utils.pipe_client_lock(self.fPipeClient)
  151. try:
  152. for line in lines:
  153. if line is None:
  154. line2 = "(null)"
  155. elif isinstance(line, str):
  156. line2 = line.replace("\n", "\r")
  157. elif isinstance(line, bool):
  158. line2 = "true" if line else "false"
  159. elif isinstance(line, int):
  160. line2 = "%i" % line
  161. elif isinstance(line, float):
  162. line2 = "%.10f" % line
  163. else:
  164. print("unknown data type to send:", type(line))
  165. hasError = True
  166. break
  167. if not gCarla.utils.pipe_client_write_msg(self.fPipeClient, line2 + "\n"):
  168. hasError = True
  169. break
  170. finally:
  171. return gCarla.utils.pipe_client_flush_and_unlock(self.fPipeClient) and not hasError