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.

349 lines
12KB

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