Sampler in ChucK
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.

369 lines
12KB

  1. import wx
  2. def sendOSCSafe(channel, data):
  3. try:
  4. sendOSCMsg(channel, data)
  5. except OSCClientError:
  6. print "OSC comms error"
  7. class OSCSlider(wx.Panel):
  8. """ A GUI slider """
  9. def __init__(self, parent, label, min_value=0, max_value=1, default_value=0, align=True, rescale=100.):
  10. """ Constructor """
  11. self.rescale = rescale
  12. wx.Panel.__init__(self, parent)
  13. sizer = wx.BoxSizer(wx.HORIZONTAL)
  14. label = wx.StaticText(self, label=label,
  15. size=(100, 15) if align else None)
  16. sizer.Add(label, 0, wx.RIGHT, 10)
  17. self.slider = wx.Slider(self, value=default_value * self.rescale,
  18. minValue=min_value * self.rescale, maxValue=max_value * self.rescale)
  19. sizer.Add(self.slider, 1, wx.EXPAND)
  20. self.SetSizerAndFit(sizer)
  21. self.Bind = self.slider.Bind
  22. def GetValue(self):
  23. """ Make sure that we rescale """
  24. return self.slider.GetValue() / self.rescale
  25. class CommsPanel(wx.Panel):
  26. """ OSC comms """
  27. def __init__(self, parent):
  28. wx.Panel.__init__(self, parent)
  29. sizer = wx.BoxSizer(wx.HORIZONTAL)
  30. label = wx.StaticText(self, label="Sync:")
  31. font = label.GetFont()
  32. font.SetWeight(wx.BOLD)
  33. label.SetFont(font)
  34. sizer.Add(label, 0, wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND, 5)
  35. choices = ["Master", "Minion"]
  36. self.master = wx.ComboBox(self, choices=choices, style=wx.CB_READONLY, size=(25, 25))
  37. sizer.Add(self.master, 1, wx.ALL, 3)
  38. self.master.SetValue(choices[0])
  39. self.ip = wx.TextCtrl(self, value="127.0.0.1")
  40. sizer.Add(self.ip, 0, wx.ALL, 3)
  41. self.port = wx.TextCtrl(self, value="9000")
  42. sizer.Add(self.port, 0, wx.ALL, 3)
  43. self.SetSizerAndFit(sizer)
  44. class InputPanel(wx.Panel):
  45. """ Handle the ADC input settings """
  46. def __init__(self, parent):
  47. """ Constructor """
  48. wx.Panel.__init__(self, parent)
  49. sizer = wx.BoxSizer(wx.HORIZONTAL)
  50. label = wx.StaticText(self, label="Input:")
  51. font = label.GetFont()
  52. font.SetWeight(wx.BOLD)
  53. label.SetFont(font)
  54. sizer.Add(label, 0, wx.TOP | wx.BOTTOM | wx.RIGHT, 5)
  55. self.gain = OSCSlider(self, "Gain", default_value=.5, align=False)
  56. sizer.Add(self.gain, 1, wx.ALL, 5)
  57. self.thru = OSCSlider(self, "Thru", default_value=.5, align=False)
  58. sizer.Add(self.thru, 1, wx.ALL, 5)
  59. self.mute = wx.ToggleButton(self, 0, "Mute")
  60. # self.mute.SetValue(1)
  61. sizer.Add(self.mute, 0)
  62. self.SetSizerAndFit(sizer)
  63. self.gain.Bind(wx.EVT_SCROLL, self.update)
  64. self.thru.Bind(wx.EVT_SCROLL, self.update)
  65. self.mute.Bind(wx.EVT_TOGGLEBUTTON, self.update)
  66. self.update()
  67. def update(self, evt=None):
  68. """ Send OSC messages """
  69. gain = self.gain.slider.GetValue()
  70. thru = self.thru.slider.GetValue()
  71. if self.mute.GetValue():
  72. gain, thru = 0., 0.
  73. sendOSCSafe("/input", [gain, thru])
  74. class DelayPanel(wx.Panel):
  75. """ Handle the ADC input settings """
  76. def __init__(self, parent):
  77. """ Constructor """
  78. wx.Panel.__init__(self, parent)
  79. sizer = wx.BoxSizer(wx.HORIZONTAL)
  80. label = wx.StaticText(self, label="Loop:")
  81. font = label.GetFont()
  82. font.SetWeight(wx.BOLD)
  83. label.SetFont(font)
  84. sizer.Add(label, 0, wx.TOP | wx.BOTTOM | wx.RIGHT, 5)
  85. self.delayTime = OSCSlider(self, "Time", default_value=1, max_value=10, align=False)
  86. sizer.Add(self.delayTime, 1, wx.ALL, 5)
  87. self.feedback = OSCSlider(self, "Hold", default_value=.99, align=False)
  88. sizer.Add(self.feedback, 1, wx.ALL, 5)
  89. self.metronome = wx.ToggleButton(self, 0, "Metronome")
  90. sizer.Add(self.metronome, 0)
  91. self.SetSizerAndFit(sizer)
  92. self.delayTime.Bind(wx.EVT_SCROLL, self.update)
  93. self.feedback.Bind(wx.EVT_SCROLL, self.update)
  94. self.metronome.Bind(wx.EVT_TOGGLEBUTTON, self.switchMetronome)
  95. self.update(None)
  96. def update(self, evt):
  97. """ Send OSC messages """
  98. a = self.delayTime.slider.GetValue()
  99. b = self.feedback.slider.GetValue()
  100. sendOSCSafe("/delay", [a, b])
  101. def switchMetronome(self, evt):
  102. """ Send OSC messages """
  103. sendOSCSafe("/metronome", [int(self.metronome.GetValue())])
  104. class ButtonArray(wx.Panel):
  105. """ Handle the ADC input settings """
  106. def __init__(self, parent, index):
  107. wx.Panel.__init__(self, parent)
  108. w = 40
  109. sizer = wx.BoxSizer(wx.HORIZONTAL)
  110. self.record = wx.ToggleButton(self, 0, "Arm", size=(w, 25))
  111. sizer.Add(self.record, 1, wx.ALL, 0)
  112. self.mute = wx.ToggleButton(self, 0, "Mute", size=(w, 25))
  113. sizer.Add(self.mute, 1, wx.ALL, 0)
  114. self.clear = wx.Button(self, 0, "Clear", size=(w, 25))
  115. sizer.Add(self.clear, 1, wx.ALL, 0)
  116. self.buttons = (self.record, self.mute, self.clear)
  117. self.SetSizerAndFit(sizer)
  118. class Channel(wx.Panel):
  119. """ A single channel """
  120. def __init__(self, parent, index):
  121. self.index = index
  122. wx.Panel.__init__(self, parent)
  123. sizer = wx.BoxSizer(wx.VERTICAL)
  124. # label = wx.StaticText(self, label="CH%d" % self.index)
  125. # font = label.GetFont(); font.SetWeight(wx.BOLD); label.SetFont(font)
  126. # sizer.Add(label, 0, wx.TOP|wx.BOTTOM|wx.RIGHT, 5)
  127. self.gain = OSCSlider(self, "Gain", default_value=1, max_value=1.3, align=False)
  128. sizer.Add(self.gain, 0, wx.ALL | wx.EXPAND, 3)
  129. self.pan = OSCSlider(self, "Pan", default_value=0, min_value=-1, max_value=1, align=False)
  130. sizer.Add(self.pan, 0, wx.ALL | wx.EXPAND, 3)
  131. self.fxsend = OSCSlider(self, "Dry/Wet", default_value=0, min_value=0, max_value=1, align=False)
  132. sizer.Add(self.fxsend, 0, wx.ALL | wx.EXPAND, 3)
  133. self.buttons = ButtonArray(self, index)
  134. self.record, self.mute, self.clear = self.buttons.buttons
  135. sizer.Add(self.buttons, 0, wx.ALL | wx.EXPAND, 3)
  136. choices = ["1 bar", "2 bars", "4 bars", "Dephase", "1/2 rate"]
  137. self.speed = wx.ComboBox(self, choices=choices, style=wx.CB_READONLY, size=(25, 25))
  138. self.speed.SetValue("1 bar")
  139. sizer.Add(self.speed, 0, wx.ALL | wx.EXPAND, 3)
  140. self.SetSizerAndFit(sizer)
  141. self.gain.Bind(wx.EVT_SCROLL, self.update)
  142. self.pan.Bind(wx.EVT_SCROLL, self.update)
  143. self.fxsend.Bind(wx.EVT_SCROLL, self.update)
  144. self.mute.Bind(wx.EVT_TOGGLEBUTTON, self.update)
  145. self.update()
  146. def update(self, evt=None):
  147. gain = self.gain.GetValue()
  148. pan = self.pan.GetValue()
  149. fxsend = self.fxsend.GetValue()
  150. if self.mute.GetValue():
  151. gain = 0.0
  152. sendOSCSafe("/channel", [self.index, gain, pan, fxsend])
  153. class Mixer(wx.Panel):
  154. """ All the channels """
  155. def __init__(self, parent):
  156. """ Constructor """
  157. wx.Panel.__init__(self, parent)
  158. sizer = wx.BoxSizer(wx.HORIZONTAL)
  159. self.channels = []
  160. for i in range(4):
  161. c = Channel(self, index=i)
  162. c.record.Bind(wx.EVT_TOGGLEBUTTON, self.switch_record)
  163. c.record.index = i
  164. c.clear.Bind(wx.EVT_BUTTON, self.clear_channel)
  165. c.clear.index = i
  166. self.channels.append(c)
  167. sizer.Add(c, 1, wx.EXPAND)
  168. self.SetSizerAndFit(sizer)
  169. def switch_record(self, evt):
  170. """ Send OSC message to switch recording channel """
  171. index = evt.GetEventObject().index
  172. value = evt.GetEventObject().GetValue()
  173. for i, c in enumerate(self.channels):
  174. c.record.SetValue(0)
  175. self.channels[index].record.SetValue(value)
  176. sendOSCSafe("/arm", [index if value else -1])
  177. def clear_channel(self, evt):
  178. """ Send OSC message to clear a channel """
  179. index = evt.GetEventObject().index
  180. sendOSCSafe("/clear", [index])
  181. class FXPanel(wx.Panel):
  182. """ Effects chain """
  183. def __init__(self, parent):
  184. """ Constructor """
  185. wx.Panel.__init__(self, parent)
  186. sizer = wx.BoxSizer(wx.HORIZONTAL)
  187. label = wx.StaticText(self, label="FX:")
  188. font = label.GetFont()
  189. font.SetWeight(wx.BOLD)
  190. label.SetFont(font)
  191. sizer.Add(label, 0, wx.EXPAND | wx.TOP | wx.BOTTOM | wx.RIGHT, 5)
  192. # choices=["Low pass filter", "High pass filter", "Reverb"]
  193. # self.fxtype= wx.ComboBox(self, choices=choices, style=wx.CB_READONLY, size=(25,25))
  194. # sizer.Add(self.fxtype, 1, wx.ALL|wx.EXPAND, 5)
  195. # self.fxtype.SetValue(choices[0])
  196. self.lpf = OSCSlider(self, "Lo-pass", default_value=.5, align=False)
  197. sizer.Add(self.lpf, 2, wx.EXPAND | wx.ALL, 5)
  198. self.lpf.Bind(wx.EVT_SCROLL, self.update)
  199. self.hpf = OSCSlider(self, "Hi-pass", min_value=0.1, default_value=.5, align=False)
  200. sizer.Add(self.hpf, 2, wx.EXPAND | wx.ALL, 5)
  201. self.hpf.Bind(wx.EVT_SCROLL, self.update)
  202. self.reverb = OSCSlider(self, "Reverb", default_value=.5, align=False)
  203. sizer.Add(self.reverb, 2, wx.EXPAND | wx.ALL, 5)
  204. self.reverb.Bind(wx.EVT_SCROLL, self.update)
  205. self.SetSizerAndFit(sizer)
  206. self.update(None)
  207. def update(self, evt):
  208. a = self.lpf.slider.GetValue()
  209. a2 = self.hpf.slider.GetValue()
  210. b = self.reverb.slider.GetValue()
  211. sendOSCSafe("/fx", [a, a2, b])
  212. class OutputPanel(wx.Panel):
  213. """ Handle the ADC input settings """
  214. def __init__(self, parent):
  215. """ Constructor """
  216. wx.Panel.__init__(self, parent)
  217. sizer = wx.BoxSizer(wx.HORIZONTAL)
  218. label = wx.StaticText(self, label="Output:")
  219. font = label.GetFont()
  220. font.SetWeight(wx.BOLD)
  221. label.SetFont(font)
  222. sizer.Add(label, 0, wx.TOP | wx.BOTTOM | wx.RIGHT, 5)
  223. self.level = OSCSlider(self, "Level", default_value=.8, align=False)
  224. sizer.Add(self.level, 2, wx.EXPAND | wx.ALL, 5)
  225. self.level.Bind(wx.EVT_SCROLL, self.update)
  226. # self.gauge = wx.Gauge(self, size=(40,10))
  227. # sizer.Add(self.gauge, 1, wx.EXPAND|wx.ALL, 5)
  228. self.SetSizerAndFit(sizer)
  229. def update(self, evt):
  230. a = self.level.slider.GetValue()
  231. #choices=["Low pass filter", "High pass filter", "Reverb"]
  232. #self.fxtype= wx.ComboBox(self, choices=choices, style=wx.CB_READONLY, size=(25,25))
  233. #sizer.Add(self.fxtype, 1, wx.ALL|wx.EXPAND, 5)
  234. #self.fxtype.SetValue(choices[0])
  235. sendOSCSafe("/master", [a])
  236. class MainGUI(wx.Frame):
  237. """ A simple GUI to talk to Chuck """
  238. def __init__(self):
  239. """ Constructor """
  240. # Build the interface
  241. self.app = wx.App(False)
  242. self.build()
  243. def run(self):
  244. self.app.MainLoop()
  245. def build(self):
  246. """ Builds the various pieces of the GUI """
  247. wx.Frame.__init__(self, None, title="DELAY LORD")
  248. self.Bind(wx.EVT_CLOSE, self.quit)
  249. # The main sizer
  250. self.mainsizer = wx.BoxSizer(wx.VERTICAL)
  251. self.components = []
  252. components = (CommsPanel, InputPanel, DelayPanel, Mixer, FXPanel, OutputPanel)
  253. for index, ctype in enumerate(components):
  254. if index>0: self.mainsizer.Add(wx.StaticLine(self), 0, wx.EXPAND | wx.ALL, 1)
  255. c = ctype(self)
  256. self.components.append(c)
  257. self.mainsizer.Add(self.c, 0, wx.EXPAND | wx.ALL, 5)
  258. self.SetSizerAndFit(self.mainsizer)
  259. self.Show()
  260. def populate_left_panel(self):
  261. """ Populate the left panel """
  262. # Status boxes
  263. def quit(self, *args):
  264. """ Close down gracefully, and then destroy the window """
  265. self.Destroy()
  266. if __name__ == "__main__":
  267. initOSCClient(ip="127.0.0.1", port=9000)
  268. g = MainGUI()
  269. # initOSCServer(ip="127.0.0.1", port=6649, mode=0)
  270. # setOSCHandler("/vu", g.update_vu)
  271. g.run()
  272. closeOSC()