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

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  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
  19. from os import fdopen, O_NONBLOCK
  20. from fcntl import fcntl, F_GETFL, F_SETFL
  21. from sys import argv
  22. # -----------------------------------------------------------------------
  23. # External UI
  24. class ExternalUI(object):
  25. def __init__(self):
  26. object.__init__(self)
  27. self.fPipeRecv = None
  28. self.fPipeSend = None
  29. self.fQuitReceived = False
  30. if len(argv) > 1:
  31. self.fSampleRate = float(argv[1])
  32. self.fUiName = argv[2]
  33. self.fPipeRecvFd = int(argv[3])
  34. self.fPipeSendFd = int(argv[4])
  35. oldFlags = fcntl(self.fPipeRecvFd, F_GETFL)
  36. fcntl(self.fPipeRecvFd, F_SETFL, oldFlags | O_NONBLOCK)
  37. self.fPipeRecv = fdopen(self.fPipeRecvFd, 'r')
  38. self.fPipeSend = fdopen(self.fPipeSendFd, 'w')
  39. else:
  40. self.fSampleRate = 44100.0
  41. self.fUiName = "TestUI"
  42. self.fPipeRecv = None
  43. self.fPipeSend = None
  44. # send empty line (just newline char)
  45. self.send([""])
  46. def showUiIfTesting(self):
  47. if self.fPipeRecv is None:
  48. self.d_uiShow()
  49. # -------------------------------------------------------------------
  50. # Host DSP State
  51. def d_getSampleRate(self):
  52. return self.fSampleRate
  53. def d_editParameter(self, index, started):
  54. self.send(["editParam", index, started])
  55. def d_setParameterValue(self, index, value):
  56. self.send(["control", index, value])
  57. def d_setProgram(self, channel, bank, program):
  58. self.send(["program", channel, bank, program])
  59. def d_setState(self, key, value):
  60. self.send(["configure", key, value])
  61. def d_sendNote(self, onOff, channel, note, velocity):
  62. self.send(["note", onOff, channel, note, velocity])
  63. # -------------------------------------------------------------------
  64. # DSP Callbacks
  65. def d_parameterChanged(self, index, value):
  66. return
  67. def d_programChanged(self, channel, bank, program):
  68. return
  69. def d_stateChanged(self, key, value):
  70. return
  71. def d_noteReceived(self, onOff, channel, note, velocity):
  72. return
  73. # -------------------------------------------------------------------
  74. # ExternalUI Callbacks
  75. def d_uiShow(self):
  76. return
  77. def d_uiHide(self):
  78. return
  79. def d_uiQuit(self):
  80. return
  81. def d_uiTitleChanged(self, uiTitle):
  82. return
  83. # -------------------------------------------------------------------
  84. # Public methods
  85. def closeExternalUI(self):
  86. if not self.fQuitReceived:
  87. self.send(["exiting"])
  88. if self.fPipeRecv is not None:
  89. self.fPipeRecv.close()
  90. self.fPipeRecv = None
  91. if self.fPipeSend is not None:
  92. self.fPipeSend.close()
  93. self.fPipeSend = None
  94. def idleExternalUI(self):
  95. while True:
  96. if self.fPipeRecv is None:
  97. return True
  98. try:
  99. msg = self.fPipeRecv.readline().strip()
  100. except IOError:
  101. return False
  102. if not msg:
  103. return True
  104. elif msg == "control":
  105. index = int(self.fPipeRecv.readline())
  106. value = float(self.fPipeRecv.readline())
  107. self.d_parameterChanged(index, value)
  108. elif msg == "program":
  109. channel = int(self.fPipeRecv.readline())
  110. bank = int(self.fPipeRecv.readline())
  111. program = int(self.fPipeRecv.readline())
  112. self.d_programChanged(channel, bank, program)
  113. elif msg == "configure":
  114. key = self.fPipeRecv.readline().strip().replace("\r", "\n")
  115. value = self.fPipeRecv.readline().strip().replace("\r", "\n")
  116. self.d_stateChanged(key, value)
  117. elif msg == "note":
  118. onOff = bool(self.fPipeRecv.readline().strip() == "true")
  119. channel = int(self.fPipeRecv.readline())
  120. note = int(self.fPipeRecv.readline())
  121. velocity = int(self.fPipeRecv.readline())
  122. self.d_noteReceived(onOff, channel, note, velocity)
  123. elif msg == "show":
  124. self.d_uiShow()
  125. elif msg == "hide":
  126. self.d_uiHide()
  127. elif msg == "quit":
  128. self.fQuitReceived = True
  129. self.d_uiQuit()
  130. elif msg == "uiTitle":
  131. uiTitle = self.fPipeRecv.readline().strip().replace("\r", "\n")
  132. self.d_uiTitleChanged(uiTitle)
  133. else:
  134. print("unknown message: \"" + msg + "\"")
  135. return True
  136. # -------------------------------------------------------------------
  137. # Internal stuff
  138. def send(self, lines):
  139. if self.fPipeSend is None:
  140. return
  141. for line in lines:
  142. if line is None:
  143. line2 = "(null)"
  144. elif isinstance(line, str):
  145. line2 = line.replace("\n", "\r")
  146. else:
  147. if isinstance(line, bool):
  148. line2 = "true" if line else "false"
  149. elif isinstance(line, int):
  150. line2 = "%i" % line
  151. elif isinstance(line, float):
  152. line2 = "%.10f" % line
  153. else:
  154. print("unknown data type to send:", type(line))
  155. return
  156. self.fPipeSend.write(line2 + "\n")
  157. self.fPipeSend.flush()