Ignore JACK port connection failures due to connection already existing.
[calfbox.git] / example.py
blob0e190631a31e7e28ef1ed6fe160e18e556060b19
1 import sys
2 sys.argv = []
3 from gi.repository import GObject, Gdk, Gtk
4 import math
6 sys.path = ["./py"] + sys.path
8 import cbox
9 from gui_tools import *
10 import fx_gui
11 import instr_gui
12 import drumkit_editor
13 import drum_pattern_editor
15 class SceneDialog(SelectObjectDialog):
16 title = "Select a scene"
17 def __init__(self, parent):
18 SelectObjectDialog.__init__(self, parent)
19 def update_model(self, model):
20 for s in cbox.Config.sections("scene:"):
21 title = s["title"]
22 model.append((s.name[6:], "Scene", s.name, title))
23 for s in cbox.Config.sections("instrument:"):
24 title = s["title"]
25 model.append((s.name[11:], "Instrument", s.name, title))
26 for s in cbox.Config.sections("layer:"):
27 title = s["title"]
28 model.append((s.name[6:], "Layer", s.name, title))
30 class AddLayerDialog(SelectObjectDialog):
31 title = "Add a layer"
32 def __init__(self, parent):
33 SelectObjectDialog.__init__(self, parent)
34 def update_model(self, model):
35 for s in cbox.Config.sections("instrument:"):
36 title = s["title"]
37 model.append((s.name[11:], "Instrument", s.name, title))
38 for s in cbox.Config.sections("layer:"):
39 title = s["title"]
40 model.append((s.name[6:], "Layer", s.name, title))
42 class PlayPatternDialog(SelectObjectDialog):
43 title = "Play a drum pattern"
44 def __init__(self, parent):
45 SelectObjectDialog.__init__(self, parent)
46 def update_model(self, model):
47 model.append((None, "Stop", "", ""))
48 for s in cbox.Config.sections("drumpattern:"):
49 title = s["title"]
50 model.append((s.name[12:], "Pattern", s.name, title))
51 for s in cbox.Config.sections("drumtrack:"):
52 title = s["title"]
53 model.append((s.name[10:], "Track", s.name, title))
55 in_channels_ls = Gtk.ListStore(GObject.TYPE_INT, GObject.TYPE_STRING)
56 in_channels_ls.append((0, "All"))
57 out_channels_ls = Gtk.ListStore(GObject.TYPE_INT, GObject.TYPE_STRING)
58 out_channels_ls.append((0, "Same"))
59 for i in range(1, 17):
60 in_channels_ls.append((i, str(i)))
61 out_channels_ls.append((i, str(i)))
62 notes_ls = Gtk.ListStore(GObject.TYPE_INT, GObject.TYPE_STRING)
63 opt_notes_ls = Gtk.ListStore(GObject.TYPE_INT, GObject.TYPE_STRING)
64 opt_notes_ls.append((-1, "N/A"))
65 for i in range(0, 128):
66 notes_ls.append((i, note_to_name(i)))
67 opt_notes_ls.append((i, note_to_name(i)))
68 transpose_ls = Gtk.ListStore(GObject.TYPE_INT, GObject.TYPE_STRING)
69 for i in range(-60, 61):
70 transpose_ls.append((i, str(i)))
72 class SceneLayersModel(Gtk.ListStore):
73 def __init__(self):
74 Gtk.ListStore.__init__(self, GObject.TYPE_STRING, GObject.TYPE_BOOLEAN,
75 GObject.TYPE_INT, GObject.TYPE_INT, GObject.TYPE_BOOLEAN,
76 GObject.TYPE_INT, GObject.TYPE_INT, GObject.TYPE_INT, GObject.TYPE_INT, GObject.TYPE_STRING)
77 #def make_row_item(self, opath, tree_path):
78 # return opath % self[(1 + int(tree_path))]
79 def make_row_item(self, opath, tree_path):
80 return cbox.Document.uuid_cmd(self[int(tree_path)][-1], opath)
81 def refresh(self, scene_status):
82 self.clear()
83 for layer in scene_status.layers:
84 ls = layer.status()
85 self.append((ls.instrument_name, ls.enable != 0, ls.in_channel, ls.out_channel, ls.consume != 0, ls.low_note, ls.high_note, ls.fixed_note, ls.transpose, layer.uuid))
87 class SceneLayersView(Gtk.TreeView):
88 def __init__(self, model):
89 Gtk.TreeView.__init__(self, model)
90 self.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, [("text/plain", 0, 1)], Gdk.DragAction.MOVE)
91 self.enable_model_drag_dest([("text/plain", Gtk.TargetFlags.SAME_APP | Gtk.TargetFlags.SAME_WIDGET, 1)], Gdk.DragAction.MOVE)
92 self.connect('drag_data_get', self.drag_data_get)
93 self.connect('drag_data_received', self.drag_data_received)
94 self.insert_column_with_attributes(0, "On?", standard_toggle_renderer(model, "/enable", 1), active=1)
95 self.insert_column_with_attributes(1, "Name", Gtk.CellRendererText(), text=0)
96 self.insert_column_with_data_func(2, "In Ch#", standard_combo_renderer(model, in_channels_ls, "/in_channel", 2), lambda column, cell, model, iter, data: cell.set_property('text', "%s" % model[iter][2] if model[iter][2] != 0 else 'All'), None)
97 self.insert_column_with_data_func(3, "Out Ch#", standard_combo_renderer(model, out_channels_ls, "/out_channel", 3), lambda column, cell, model, iter, data: cell.set_property('text', "%s" % model[iter][3] if model[iter][3] != 0 else 'Same'), None)
98 self.insert_column_with_attributes(4, "Eat?", standard_toggle_renderer(model, "/consume", 4), active=4)
99 self.insert_column_with_data_func(5, "Lo N#", standard_combo_renderer(model, notes_ls, "/low_note", 5), lambda column, cell, model, iter, data: cell.set_property('text', note_to_name(model[iter][5])), None)
100 self.insert_column_with_data_func(6, "Hi N#", standard_combo_renderer(model, notes_ls, "/high_note", 6), lambda column, cell, model, iter, data: cell.set_property('text', note_to_name(model[iter][6])), None)
101 self.insert_column_with_data_func(7, "Fix N#", standard_combo_renderer(model, opt_notes_ls, "/fixed_note", 7), lambda column, cell, model, iter, data: cell.set_property('text', note_to_name(model[iter][7])), None)
102 self.insert_column_with_attributes(8, "Transpose", standard_combo_renderer(model, transpose_ls, "/transpose", 8), text=8)
103 def drag_data_get(self, treeview, context, selection, target_id, etime):
104 cursor = treeview.get_cursor()
105 if cursor is not None:
106 selection.set('text/plain', 8, str(cursor[0][0]))
107 def drag_data_received(self, treeview, context, x, y, selection, info, etime):
108 src_row = int(selection.data)
109 dest_row_info = treeview.get_dest_row_at_pos(x, y)
110 if dest_row_info is not None:
111 dest_row = dest_row_info[0][0]
112 #print src_row, dest_row, dest_row_info[1]
113 scene = cbox.Document.get_scene()
114 scene.move_layer(src_row, dest_row)
115 self.get_model().refresh(scene.status())
117 class SceneAuxBusesModel(Gtk.ListStore):
118 def __init__(self):
119 Gtk.ListStore.__init__(self, GObject.TYPE_STRING, GObject.TYPE_STRING)
120 def refresh(self, scene_status):
121 self.clear()
122 for aux_name, aux_obj in scene_status.auxes.items():
123 # XXXKF make slots more 1st class
124 slot = aux_obj.get_slot_status()
125 self.append((slot.insert_preset, slot.insert_engine))
127 class SceneAuxBusesView(Gtk.TreeView):
128 def __init__(self, model):
129 Gtk.TreeView.__init__(self, model)
130 self.insert_column_with_attributes(0, "Name", Gtk.CellRendererText(), text=0)
131 self.insert_column_with_attributes(1, "Engine", Gtk.CellRendererText(), text=1)
132 def get_current_row(self):
133 if self.get_cursor()[0] is None:
134 return None, None
135 row = self.get_cursor()[0][0]
136 return row + 1, self.get_model()[row]
138 class StatusBar(Gtk.Statusbar):
139 def __init__(self):
140 Gtk.Statusbar.__init__(self)
141 self.sample_rate_label = Gtk.Label("")
142 self.pack_start(self.sample_rate_label, False, False, 2)
143 self.status = self.get_context_id("Status")
144 self.sample_rate = self.get_context_id("Sample rate")
145 self.push(self.status, "")
146 self.push(self.sample_rate, "-")
147 def update(self, status, sample_rate):
148 self.pop(self.status)
149 self.push(self.status, status)
150 self.sample_rate_label.set_text("%s Hz" % sample_rate)
152 class MainWindow(Gtk.Window):
153 def __init__(self):
154 Gtk.Window.__init__(self, Gtk.WindowType.TOPLEVEL)
155 self.vbox = Gtk.VBox(spacing = 5)
156 self.add(self.vbox)
157 self.create()
158 set_timer(self, 30, self.update)
159 self.drum_pattern_editor = None
160 self.drumkit_editor = None
162 def create(self):
163 self.menu_bar = Gtk.MenuBar()
165 self.menu_bar.append(create_menu("_Scene", [
166 ("_Load", self.load_scene),
167 ("_Quit", self.quit),
169 self.menu_bar.append(create_menu("_Layer", [
170 ("_Add", self.layer_add),
171 ("_Remove", self.layer_remove),
173 self.menu_bar.append(create_menu("_AuxBus", [
174 ("_Add", self.aux_bus_add),
175 ("_Edit", self.aux_bus_edit),
176 ("_Remove", self.aux_bus_remove),
178 self.menu_bar.append(create_menu("_Tools", [
179 ("_Drum Kit Editor", self.tools_drumkit_editor),
180 ("_Play Drum Pattern", self.tools_play_drum_pattern),
181 ("_Edit Drum Pattern", self.tools_drum_pattern_editor),
182 ("_Un-zombify", self.tools_unzombify),
183 ("_Object list", self.tools_object_list),
184 ("_Wave bank dump", self.tools_wave_bank_dump),
187 self.vbox.pack_start(self.menu_bar, False, False, 0)
188 rt = cbox.GetThings("/rt/status", ['audio_channels'], [])
189 scene = cbox.Document.get_scene()
190 self.nb = Gtk.Notebook()
191 self.vbox.add(self.nb)
192 self.nb.append_page(self.create_master(scene), Gtk.Label("Master"))
193 self.status_bar = StatusBar()
194 self.vbox.pack_start(self.status_bar, False, False, 0)
195 self.create_instrument_pages(scene.status(), rt)
197 def create_master(self, scene):
198 scene_status = scene.status()
199 self.master_info = left_label("")
200 self.timesig_info = left_label("")
202 t = Gtk.Table(3, 8)
203 t.set_col_spacings(5)
204 t.set_row_spacings(5)
206 t.attach(bold_label("Scene"), 0, 1, 0, 1, Gtk.AttachOptions.SHRINK | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK)
207 self.scene_label = left_label(scene_status.name)
208 t.attach(self.scene_label, 1, 3, 0, 1, Gtk.AttachOptions.SHRINK | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK)
210 self.title_label = left_label(scene_status.title)
211 t.attach(bold_label("Title"), 0, 1, 1, 2, Gtk.AttachOptions.SHRINK | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK)
212 t.attach(self.title_label, 1, 3, 1, 2, Gtk.AttachOptions.SHRINK | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK)
214 t.attach(bold_label("Play pos"), 0, 1, 2, 3, Gtk.AttachOptions.SHRINK | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK)
215 t.attach(self.master_info, 1, 3, 2, 3, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK)
217 t.attach(bold_label("Time sig"), 0, 1, 3, 4, Gtk.AttachOptions.SHRINK | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK)
218 t.attach(self.timesig_info, 1, 2, 3, 4, Gtk.AttachOptions.SHRINK | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK)
219 hb = Gtk.HButtonBox()
220 b = Gtk.Button("Play")
221 b.connect('clicked', lambda w: cbox.Transport.play())
222 hb.pack_start(b, False, False, 5)
223 b = Gtk.Button("Stop")
224 b.connect('clicked', lambda w: cbox.Transport.stop())
225 hb.pack_start(b, False, False, 5)
226 b = Gtk.Button("Rewind")
227 b.connect('clicked', lambda w: cbox.Transport.seek_ppqn(0))
228 hb.pack_start(b, False, False, 5)
229 b = Gtk.Button("Panic")
230 b.connect('clicked', lambda w: cbox.Transport.panic())
231 hb.pack_start(b, False, False, 5)
232 t.attach(hb, 2, 3, 3, 4, Gtk.AttachOptions.EXPAND, Gtk.AttachOptions.SHRINK)
234 t.attach(bold_label("Tempo"), 0, 1, 4, 5, Gtk.AttachOptions.SHRINK | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK)
235 self.tempo_adj = Gtk.Adjustment(40, 40, 300, 1, 5, 0)
236 self.tempo_adj.connect('value_changed', adjustment_changed_float, cbox.VarPath("/master/set_tempo"))
237 t.attach(standard_hslider(self.tempo_adj), 1, 3, 4, 5, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK)
239 t.attach(bold_label("Transpose"), 0, 1, 5, 6, Gtk.AttachOptions.SHRINK | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK)
240 self.transpose_adj = Gtk.Adjustment(scene_status.transpose, -24, 24, 1, 5, 0)
241 self.transpose_adj.connect('value_changed', adjustment_changed_int, cbox.VarPath('/scene/transpose'))
242 t.attach(standard_align(Gtk.SpinButton(adjustment = self.transpose_adj), 0, 0, 0, 0), 1, 3, 5, 6, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK)
244 self.layers_model = SceneLayersModel()
245 self.layers_view = SceneLayersView(self.layers_model)
246 t.attach(standard_vscroll_window(-1, 160, self.layers_view), 0, 3, 6, 7, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK)
248 self.auxes_model = SceneAuxBusesModel()
249 self.auxes_view = SceneAuxBusesView(self.auxes_model)
250 t.attach(standard_vscroll_window(-1, 120, self.auxes_view), 0, 3, 7, 8, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK)
252 self.layers_model.refresh(scene_status)
253 self.auxes_model.refresh(scene_status)
255 return t
257 def quit(self, w):
258 self.destroy()
260 def load_scene(self, w):
261 d = SceneDialog(self)
262 response = d.run()
263 try:
264 if response == Gtk.ResponseType.OK:
265 scene = cbox.Document.get_scene()
266 item_name, item_type, item_key, item_label = d.get_selected_object()
267 if item_type == 'Scene':
268 scene.load(item_name)
269 elif item_type == 'Layer':
270 scene.clear()
271 scene.add_layer(item_name)
272 elif item_type == 'Instrument':
273 scene.clear()
274 scene.add_instrument_layer(item_name)
275 scene_status = scene.status()
276 self.scene_label.set_text(scene_status.name)
277 self.title_label.set_text(scene_status.title)
278 self.refresh_instrument_pages(scene_status)
279 finally:
280 d.destroy()
282 def layer_add(self, w):
283 d = AddLayerDialog(self)
284 response = d.run()
285 try:
286 if response == Gtk.ResponseType.OK:
287 scene = cbox.Document.get_scene()
288 item_name, item_type, item_key, item_label = d.get_selected_object()
289 if item_type == 'Layer':
290 scene.add_layer(item_name)
291 elif item_type == 'Instrument':
292 scene.add_instrument_layer(item_name)
293 self.refresh_instrument_pages()
294 finally:
295 d.destroy()
297 def layer_remove(self, w):
298 if self.layers_view.get_cursor()[0] is not None:
299 pos = self.layers_view.get_cursor()[0][0]
300 cbox.Document.get_scene().delete_layer(pos)
301 self.refresh_instrument_pages()
303 def aux_bus_add(self, w):
304 d = fx_gui.LoadEffectDialog(self)
305 response = d.run()
306 try:
307 cbox.do_cmd("/scene/load_aux", None, [d.get_selected_object()[0]])
308 self.refresh_instrument_pages()
309 finally:
310 d.destroy()
311 def aux_bus_remove(self, w):
312 rowid, row = self.auxes_view.get_current_row()
313 if rowid is None:
314 return
315 cbox.do_cmd("/scene/delete_aux", None, [row[0]])
316 self.refresh_instrument_pages()
318 def aux_bus_edit(self, w):
319 rowid, row = self.auxes_view.get_current_row()
320 if rowid is None:
321 return
322 wclass = fx_gui.effect_window_map[row[1]]
323 popup = wclass("Aux: %s" % row[0], self, "/scene/aux/%d/engine" % rowid)
324 popup.show_all()
325 popup.present()
327 def tools_unzombify(self, w):
328 cbox.do_cmd("/rt/cycle", None, [])
330 def tools_drumkit_editor(self, w):
331 if self.drumkit_editor is None:
332 self.drumkit_editor = drumkit_editor.EditorDialog(self)
333 self.refresh_instrument_pages()
334 self.drumkit_editor.connect('destroy', self.on_drumkit_editor_destroy)
335 self.drumkit_editor.show_all()
336 self.drumkit_editor.present()
338 def on_drumkit_editor_destroy(self, w):
339 self.drumkit_editor = None
341 def tools_object_list(self, w):
342 cbox.Document.dump()
344 def tools_wave_bank_dump(self, w):
345 waves = cbox.GetThings("/waves/list", ["*waveform"], [])
346 for w in waves.waveform:
347 info = cbox.GetThings("/waves/info", ["filename", "name", "bytes", "loop"], [w])
348 print("%s: %d bytes, loop = %s" % (info.filename, info.bytes, info.loop))
350 def tools_play_drum_pattern(self, w):
351 d = PlayPatternDialog(self)
352 response = d.run()
353 try:
354 if response == Gtk.ResponseType.OK:
355 row = d.get_selected_object()
356 if row[1] == 'Pattern':
357 song = cbox.Document().get_song()
358 song.loop_single_pattern(lambda: song.load_drum_pattern(row[0]))
359 elif row[1] == 'Track':
360 song = cbox.Document().get_song()
361 song.loop_single_pattern(lambda: song.load_drum_track(row[0]))
362 elif row[1] == 'Stop':
363 song = cbox.Document().get_song()
364 song.clear()
365 song.update_playback()
366 finally:
367 d.destroy()
369 def tools_drum_pattern_editor(self, w):
370 if self.drum_pattern_editor is None:
371 length = drum_pattern_editor.PPQN * 4
372 pat_data = cbox.Pattern.get_pattern()
373 if pat_data is not None:
374 pat_data, length = pat_data
375 self.drum_pattern_editor = drum_pattern_editor.DrumSeqWindow(length, pat_data)
376 self.drum_pattern_editor.set_title("Drum pattern editor")
377 self.drum_pattern_editor.show_all()
378 self.drum_pattern_editor.connect('destroy', self.on_drum_pattern_editor_destroy)
379 self.drum_pattern_editor.pattern.connect('changed', self.on_drum_pattern_changed)
380 self.drum_pattern_editor.pattern.changed()
381 self.drum_pattern_editor.present()
383 def on_drum_pattern_changed(self, pattern):
384 data = bytearray()
385 for i in pattern.items():
386 ch = i.channel - 1
387 data += cbox.Pattern.serialize_event(int(i.pos), 0x90 + ch, int(i.row), int(i.vel))
388 if i.len > 1:
389 data += cbox.Pattern.serialize_event(int(i.pos + i.len - 1), 0x80 + ch, int(i.row), int(i.vel))
390 else:
391 data += cbox.Pattern.serialize_event(int(i.pos + 1), 0x80 + ch, int(i.row), int(i.vel))
393 length = pattern.get_length()
395 song = cbox.Document().get_song()
396 song.loop_single_pattern(lambda: song.pattern_from_blob(data, length))
398 def on_drum_pattern_editor_destroy(self, w):
399 self.drum_pattern_editor = None
401 def refresh_instrument_pages(self, scene_status = None):
402 self.delete_instrument_pages()
403 rt = cbox.GetThings("/rt/status", ['audio_channels'], [])
404 if scene_status is None:
405 scene_status = cbox.Document.get_scene().status()
406 self.layers_model.refresh(scene_status)
407 self.auxes_model.refresh(scene_status)
408 self.create_instrument_pages(scene_status, rt)
409 self.nb.show_all()
410 self.title_label.set_text(scene_status.title)
412 def create_instrument_pages(self, scene_status, rt):
413 self.path_widgets = {}
414 self.path_popups = {}
415 self.fx_choosers = {}
417 outputs_ls = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_INT)
418 for out in range(0, rt.audio_channels[1]//2):
419 outputs_ls.append(("Out %s/%s" % (out * 2 + 1, out * 2 + 2), out))
421 auxbus_ls = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_STRING)
422 auxbus_ls.append(("", ""))
423 for bus_name in scene_status.auxes.keys():
424 auxbus_ls.append(("Aux: %s" % bus_name, bus_name))
426 for iname, (iengine, iobj) in scene_status.instruments.items():
427 ipath = "/scene/instr/%s" % iname
428 idata = iobj.status()
429 #attribs = cbox.GetThings("/scene/instr_info", ['engine', 'name'], [i])
430 #markup += '<b>Instrument %d:</b> engine %s, name %s\n' % (i, attribs.engine, attribs.name)
431 b = Gtk.VBox(spacing = 5)
432 b.set_border_width(5)
433 b.pack_start(Gtk.Label("Engine: %s" % iengine), False, False, 5)
434 b.pack_start(Gtk.HSeparator(), False, False, 5)
435 t = Gtk.Table(1 + idata.outputs, 7)
436 t.set_col_spacings(5)
437 t.attach(bold_label("Instr. output", 0.5), 0, 1, 0, 1, Gtk.AttachOptions.SHRINK, Gtk.AttachOptions.SHRINK)
438 t.attach(bold_label("Send to", 0.5), 1, 2, 0, 1, Gtk.AttachOptions.SHRINK, Gtk.AttachOptions.SHRINK)
439 t.attach(bold_label("Gain [dB]", 0.5), 2, 3, 0, 1, 0, Gtk.AttachOptions.SHRINK)
440 t.attach(bold_label("Effect", 0.5), 3, 4, 0, 1, 0, Gtk.AttachOptions.SHRINK)
441 t.attach(bold_label("Preset", 0.5), 4, 7, 0, 1, 0, Gtk.AttachOptions.SHRINK)
442 b.pack_start(t, False, False, 5)
444 y = 1
445 for o in range(1, idata.outputs + 1):
446 is_aux = o >= idata.aux_offset
447 if not is_aux:
448 opath = "%s/output/%s" % (ipath, o)
449 output_name = "Out %s" % o
450 else:
451 opath = "%s/aux/%s" % (ipath, o - idata.aux_offset + 1)
452 output_name = "Aux %s" % (o - idata.aux_offset + 1)
453 odata = cbox.GetThings(opath + "/status", ['gain', 'output', 'bus', 'insert_engine', 'insert_preset', 'bypass'], [])
454 engine = odata.insert_engine
455 preset = odata.insert_preset
456 bypass = odata.bypass
458 t.attach(Gtk.Label(output_name), 0, 1, y, y + 1, Gtk.AttachOptions.SHRINK, Gtk.AttachOptions.SHRINK)
460 if not is_aux:
461 cb = standard_combo(outputs_ls, odata.output - 1)
462 cb.connect('changed', combo_value_changed, cbox.VarPath(opath + '/output'), 1)
463 else:
464 cb = standard_combo(auxbus_ls, ls_index(auxbus_ls, odata.bus, 1))
465 cb.connect('changed', combo_value_changed_use_column, cbox.VarPath(opath + '/bus'), 1)
466 t.attach(cb, 1, 2, y, y + 1, Gtk.AttachOptions.SHRINK, Gtk.AttachOptions.SHRINK)
468 adj = Gtk.Adjustment(odata.gain, -96, 24, 1, 6, 0)
469 adj.connect('value_changed', adjustment_changed_float, cbox.VarPath(opath + '/gain'))
470 t.attach(standard_hslider(adj), 2, 3, y, y + 1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK)
472 chooser = fx_gui.InsertEffectChooser(opath, "%s: %s" % (iname, output_name), engine, preset, bypass, self)
473 self.fx_choosers[opath] = chooser
474 t.attach(chooser.fx_engine, 3, 4, y, y + 1, 0, Gtk.AttachOptions.SHRINK)
475 t.attach(chooser.fx_preset, 4, 5, y, y + 1, 0, Gtk.AttachOptions.SHRINK)
476 t.attach(chooser.fx_edit, 5, 6, y, y + 1, 0, Gtk.AttachOptions.SHRINK)
477 t.attach(chooser.fx_bypass, 6, 7, y, y + 1, 0, Gtk.AttachOptions.SHRINK)
478 y += 1
479 if iengine in instr_gui.instrument_window_map:
480 b.pack_start(Gtk.HSeparator(), False, False, 5)
481 b.pack_start(instr_gui.instrument_window_map[iengine](iname, iobj), True, True, 5)
482 self.nb.append_page(b, Gtk.Label(iname))
483 self.update()
485 def delete_instrument_pages(self):
486 while self.nb.get_n_pages() > 1:
487 self.nb.remove_page(self.nb.get_n_pages() - 1)
489 def update(self):
490 cbox.call_on_idle()
491 master = cbox.GetThings("/master/status", ['pos', 'pos_ppqn', 'tempo', 'timesig', 'sample_rate'], [])
492 if master.tempo is not None:
493 self.master_info.set_markup('%s (%s)' % (master.pos, master.pos_ppqn))
494 self.timesig_info.set_markup("%s/%s" % tuple(master.timesig))
495 self.tempo_adj.set_value(master.tempo)
496 state = cbox.GetThings("/rt/status", ['state'], []).state
497 self.status_bar.update(state[1], master.sample_rate)
498 return True
500 def do_quit(window):
501 Gtk.main_quit()
503 w = MainWindow()
504 w.set_title("My UI")
505 w.show_all()
506 w.connect('destroy', do_quit)
508 Gtk.main()