Pass height/width to cairo.Surface.create_similar as integers
[jack_mixer.git] / channel.py
blob7895e9cc55c132e4695384dcb554283fd708be9f
1 #!/usr/bin/env python
3 # This file is part of jack_mixer
5 # Copyright (C) 2006 Nedko Arnaudov <nedko@arnaudov.name>
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; version 2 of the License
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.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 import gtk
21 import gobject
22 import glib
23 import scale
24 import slider
25 import meter
26 import abspeak
27 import math
28 import random
29 from serialization import serialized_object
31 try:
32 import phat
33 except:
34 print "PHAT audio widgets not found, some features will not be available"
35 phat = None
37 import fpconst
39 class channel(gtk.VBox, serialized_object):
40 '''Widget with slider and meter used as base class for more specific channel widgets'''
41 def __init__(self, app, name, stereo):
42 gtk.VBox.__init__(self)
43 self.app = app
44 self.mixer = app.mixer
45 self.gui_factory = app.gui_factory
46 self._channel_name = name
47 self.stereo = stereo
48 self.meter_scale = self.gui_factory.get_default_meter_scale()
49 self.slider_scale = self.gui_factory.get_default_slider_scale()
50 self.slider_adjustment = slider.adjustment_dBFS(self.slider_scale, 0.0)
51 self.balance_adjustment = gtk.Adjustment(0.0, -1.0, 1.0, 0.02)
52 self.future_volume_midi_cc = None
53 self.future_balance_midi_cc = None
55 def get_channel_name(self):
56 return self._channel_name
58 label_name = None
59 channel = None
60 def set_channel_name(self, name):
61 self._channel_name = name
62 if self.label_name:
63 self.label_name.set_text(name)
64 if self.channel:
65 self.channel.name = name
66 channel_name = property(get_channel_name, set_channel_name)
68 def realize(self):
69 #print "Realizing channel \"%s\"" % self.channel_name
71 self.slider_adjustment.connect("volume-changed", self.on_volume_changed)
72 self.balance_adjustment.connect("value-changed", self.on_balance_changed)
73 self.connect('midi-event-received', self.on_midi_event_received)
75 self.slider = None
76 self.create_slider_widget()
78 if self.stereo:
79 self.meter = meter.stereo(self.meter_scale)
80 else:
81 self.meter = meter.mono(self.meter_scale)
82 self.on_vumeter_color_changed(self.gui_factory)
84 self.meter.set_events(gtk.gdk.SCROLL_MASK)
86 self.gui_factory.connect("default-meter-scale-changed", self.on_default_meter_scale_changed)
87 self.gui_factory.connect("default-slider-scale-changed", self.on_default_slider_scale_changed)
88 self.gui_factory.connect('vumeter-color-changed', self.on_vumeter_color_changed)
89 self.gui_factory.connect('vumeter-color-scheme-changed', self.on_vumeter_color_changed)
90 self.gui_factory.connect('use-custom-widgets-changed', self.on_custom_widgets_changed)
92 self.abspeak = abspeak.widget()
93 self.abspeak.connect("reset", self.on_abspeak_reset)
94 self.abspeak.connect("volume-adjust", self.on_abspeak_adjust)
96 self.volume_digits = gtk.Entry()
97 self.volume_digits.connect("key-press-event", self.on_volume_digits_key_pressed)
98 self.volume_digits.connect("focus-out-event", self.on_volume_digits_focus_out)
100 self.connect("key-press-event", self.on_key_pressed)
101 self.connect("scroll-event", self.on_scroll)
103 def unrealize(self):
104 #print "Unrealizing channel \"%s\"" % self.channel_name
105 pass
107 def create_balance_widget(self):
108 if self.gui_factory.use_custom_widgets and phat:
109 self.balance = phat.HFanSlider()
110 self.balance.set_default_value(0)
111 self.balance.set_adjustment(self.balance_adjustment)
112 else:
113 self.balance = gtk.HScale(self.balance_adjustment)
114 self.balance.set_draw_value(False)
115 self.pack_start(self.balance, False)
116 self.balance.show()
118 def create_slider_widget(self):
119 parent = None
120 if self.slider:
121 parent = self.slider.get_parent()
122 self.slider.destroy()
123 if self.gui_factory.use_custom_widgets:
124 self.slider = slider.CustomSliderWidget(self.slider_adjustment)
125 else:
126 self.slider = slider.GtkSlider(self.slider_adjustment)
127 if parent:
128 parent.pack_start(self.slider)
129 parent.reorder_child(self.slider, 0)
130 self.slider.show()
132 def on_default_meter_scale_changed(self, gui_factory, scale):
133 #print "Default meter scale change detected."
134 self.meter.set_scale(scale)
136 def on_default_slider_scale_changed(self, gui_factory, scale):
137 #print "Default slider scale change detected."
138 self.slider_scale = scale
139 self.slider_adjustment.set_scale(scale)
140 self.channel.set_midi_scale(self.slider_scale.scale)
142 def on_vumeter_color_changed(self, gui_factory, *args):
143 color = gui_factory.get_vumeter_color()
144 color_scheme = gui_factory.get_vumeter_color_scheme()
145 if color_scheme != 'solid':
146 self.meter.set_color(None)
147 else:
148 self.meter.set_color(gtk.gdk.color_parse(color))
150 def on_custom_widgets_changed(self, gui_factory, value):
151 self.balance.destroy()
152 self.create_balance_widget()
153 self.create_slider_widget()
155 def on_abspeak_adjust(self, abspeak, adjust):
156 #print "abspeak adjust %f" % adjust
157 self.slider_adjustment.set_value_db(self.slider_adjustment.get_value_db() + adjust)
158 self.channel.abspeak = None
159 #self.update_volume(False) # We want to update gui even if actual decibels have not changed (scale wrap for example)
161 def on_abspeak_reset(self, abspeak):
162 #print "abspeak reset"
163 self.channel.abspeak = None
165 def on_volume_digits_key_pressed(self, widget, event):
166 if (event.keyval == gtk.keysyms.Return or event.keyval == gtk.keysyms.KP_Enter):
167 db_text = self.volume_digits.get_text()
168 try:
169 db = float(db_text)
170 #print "Volume digits confirmation \"%f dBFS\"" % db
171 except (ValueError), e:
172 #print "Volume digits confirmation ignore, reset to current"
173 self.update_volume(False)
174 return
175 self.slider_adjustment.set_value_db(db)
176 #self.grab_focus()
177 #self.update_volume(False) # We want to update gui even if actual decibels have not changed (scale wrap for example)
179 def on_volume_digits_focus_out(self, widget, event):
180 #print "volume digits focus out detected"
181 self.update_volume(False)
183 def read_meter(self):
184 if self.stereo:
185 meter_left, meter_right = self.channel.meter
186 self.meter.set_values(meter_left, meter_right)
187 else:
188 self.meter.set_value(self.channel.meter[0])
190 self.abspeak.set_peak(self.channel.abspeak)
192 def on_scroll(self, widget, event):
193 if event.direction == gtk.gdk.SCROLL_DOWN:
194 self.slider_adjustment.step_down()
195 elif event.direction == gtk.gdk.SCROLL_UP:
196 self.slider_adjustment.step_up()
197 return True
199 def update_volume(self, update_engine):
200 db = self.slider_adjustment.get_value_db()
202 db_text = "%.2f" % db
203 self.volume_digits.set_text(db_text)
205 if update_engine:
206 #print "Setting engine volume to " + db_text
207 self.channel.volume = db
209 def on_volume_changed(self, adjustment):
210 self.update_volume(True)
212 def on_balance_changed(self, adjustment):
213 balance = self.balance_adjustment.get_value()
214 #print "%s balance: %f" % (self.channel_name, balance)
215 self.channel.balance = balance
217 def on_key_pressed(self, widget, event):
218 if (event.keyval == gtk.keysyms.Up):
219 #print self.channel_name + " Up"
220 self.slider_adjustment.step_up()
221 return True
222 elif (event.keyval == gtk.keysyms.Down):
223 #print self.channel_name + " Down"
224 self.slider_adjustment.step_down()
225 return True
227 return False
229 def serialize(self, object_backend):
230 object_backend.add_property("volume", "%f" % self.slider_adjustment.get_value_db())
231 object_backend.add_property("balance", "%f" % self.balance_adjustment.get_value())
233 if self.channel.volume_midi_cc:
234 object_backend.add_property('volume_midi_cc', str(self.channel.volume_midi_cc))
235 if self.channel.balance_midi_cc:
236 object_backend.add_property('balance_midi_cc', str(self.channel.balance_midi_cc))
238 def unserialize_property(self, name, value):
239 if name == "volume":
240 self.slider_adjustment.set_value_db(float(value))
241 return True
242 if name == "balance":
243 self.balance_adjustment.set_value(float(value))
244 return True
245 if name == 'volume_midi_cc':
246 self.future_volume_midi_cc = int(value)
247 return True
248 if name == 'balance_midi_cc':
249 self.future_balance_midi_cc = int(value)
250 return True
251 return False
253 def on_midi_event_received(self, *args):
254 self.slider_adjustment.set_value_db(self.channel.volume)
255 self.balance_adjustment.set_value(self.channel.balance)
257 def midi_change_callback(self, *args):
258 # the changes are not applied directly to the widgets as they
259 # absolutely have to be done from the gtk thread.
260 self.emit('midi-event-received')
262 gobject.signal_new('midi-event-received', channel,
263 gobject.SIGNAL_RUN_FIRST | gobject.SIGNAL_ACTION,
264 gobject.TYPE_NONE, ())
266 class input_channel(channel):
267 def __init__(self, app, name, stereo):
268 channel.__init__(self, app, name, stereo)
270 def realize(self):
271 self.channel = self.mixer.add_channel(self.channel_name, self.stereo)
272 if self.channel == None:
273 raise Exception,"Cannot create a channel"
274 channel.realize(self)
275 if self.future_volume_midi_cc:
276 self.channel.volume_midi_cc = self.future_volume_midi_cc
277 if self.future_balance_midi_cc:
278 self.channel.balance_midi_cc = self.future_balance_midi_cc
279 self.channel.midi_scale = self.slider_scale.scale
280 self.channel.midi_change_callback = self.midi_change_callback
282 self.on_volume_changed(self.slider_adjustment)
283 self.on_balance_changed(self.balance_adjustment)
285 # vbox child at upper part
286 self.vbox = gtk.VBox()
287 self.pack_start(self.vbox, False)
288 self.label_name = gtk.Label()
289 self.label_name.set_text(self.channel_name)
290 self.label_name.set_size_request(0, -1)
291 self.label_name_event_box = gtk.EventBox()
292 self.label_name_event_box.connect("button-press-event", self.on_label_mouse)
293 self.label_name_event_box.add(self.label_name)
294 self.vbox.pack_start(self.label_name_event_box, True)
295 # self.label_stereo = gtk.Label()
296 # if self.stereo:
297 # self.label_stereo.set_text("stereo")
298 # else:
299 # self.label_stereo.set_text("mono")
300 # self.label_stereo.set_size_request(0, -1)
301 # self.vbox.pack_start(self.label_stereo, True)
303 # hbox for mute and solo buttons
304 self.hbox_mutesolo = gtk.HBox()
306 self.mute = gtk.ToggleButton()
307 self.mute.set_label("M")
308 self.mute.set_active(self.channel.mute)
309 self.mute.connect("toggled", self.on_mute_toggled)
310 self.hbox_mutesolo.pack_start(self.mute, True)
312 self.solo = gtk.ToggleButton()
313 self.solo.set_label("S")
314 self.solo.set_active(self.channel.solo)
315 self.solo.connect("toggled", self.on_solo_toggled)
316 self.hbox_mutesolo.pack_start(self.solo, True)
318 self.vbox.pack_start(self.hbox_mutesolo, False)
320 frame = gtk.Frame()
321 frame.set_shadow_type(gtk.SHADOW_IN)
322 frame.add(self.abspeak);
323 self.pack_start(frame, False)
325 # hbox child at lower part
326 self.hbox = gtk.HBox()
327 self.hbox.pack_start(self.slider, True)
328 frame = gtk.Frame()
329 frame.set_shadow_type(gtk.SHADOW_IN)
330 frame.add(self.meter);
331 self.hbox.pack_start(frame, True)
332 frame = gtk.Frame()
333 frame.set_shadow_type(gtk.SHADOW_IN)
334 frame.add(self.hbox);
335 self.pack_start(frame, True)
337 self.volume_digits.set_size_request(0, -1)
338 self.pack_start(self.volume_digits, False)
340 self.create_balance_widget()
342 def add_control_group(self, channel):
343 control_group = ControlGroup(channel, self)
344 control_group.show_all()
345 self.vbox.pack_start(control_group, False)
347 def update_control_group(self, channel):
348 for control_group in self.vbox.get_children():
349 if isinstance(control_group, ControlGroup):
350 if control_group.output_channel is channel:
351 control_group.update()
353 def unrealize(self):
354 channel.unrealize(self)
355 self.channel.remove()
356 self.channel = False
358 channel_properties_dialog = None
359 def on_channel_properties(self):
360 if not self.channel_properties_dialog:
361 self.channel_properties_dialog = ChannelPropertiesDialog(self)
362 self.channel_properties_dialog.show()
363 self.channel_properties_dialog.present()
365 def on_label_mouse(self, widget, event):
366 if event.type == gtk.gdk._2BUTTON_PRESS:
367 if event.button == 1:
368 self.on_channel_properties()
370 def on_mute_toggled(self, button):
371 self.channel.mute = self.mute.get_active()
373 def on_solo_toggled(self, button):
374 self.channel.solo = self.solo.get_active()
376 def serialization_name(self):
377 return input_channel_serialization_name()
379 def serialize(self, object_backend):
380 object_backend.add_property("name", self.channel_name)
381 if self.stereo:
382 object_backend.add_property("type", "stereo")
383 else:
384 object_backend.add_property("type", "mono")
385 channel.serialize(self, object_backend)
387 def unserialize_property(self, name, value):
388 if name == "name":
389 self.channel_name = str(value)
390 return True
391 if name == "type":
392 if value == "stereo":
393 self.stereo = True
394 return True
395 if value == "mono":
396 self.stereo = False
397 return True
398 return channel.unserialize_property(self, name, value)
400 def input_channel_serialization_name():
401 return "input_channel"
404 available_colours = [
405 ('#ef2929', '#cc0000', '#a40000'),
406 ('#729fcf', '#3465a4', '#204a87'),
407 ('#8aa234', '#73d216', '#4e9a06'),
408 ('#fce84f', '#edd400', '#c4a000'),
409 ('#fcaf3e', '#f57900', '#ce5c00'),
410 ('#e9b96e', '#c17d11', '#8f5902'),
411 ('#ad7fa8', '#75507b', '#5c3566'),
414 class output_channel(channel):
415 colours = available_colours[:]
416 _display_solo_buttons = False
418 def __init__(self, app, name, stereo):
419 channel.__init__(self, app, name, stereo)
421 def get_display_solo_buttons(self):
422 return self._display_solo_buttons
424 def set_display_solo_buttons(self, value):
425 self._display_solo_buttons = value
426 # notifying control groups
427 for inputchannel in self.app.channels:
428 inputchannel.update_control_group(self)
430 display_solo_buttons = property(get_display_solo_buttons, set_display_solo_buttons)
432 def realize(self):
433 channel.realize(self)
434 self.channel = self.mixer.add_output_channel(self.channel_name, self.stereo)
435 if self.channel == None:
436 raise Exception,"Cannot create a channel"
437 channel.realize(self)
439 self.channel.midi_scale = self.slider_scale.scale
440 self.channel.midi_change_callback = self.midi_change_callback
442 self.on_volume_changed(self.slider_adjustment)
443 self.on_balance_changed(self.balance_adjustment)
445 # vbox child at upper part
446 self.vbox = gtk.VBox()
447 self.pack_start(self.vbox, False)
448 self.label_name = gtk.Label()
449 self.label_name.set_text(self.channel_name)
450 self.label_name.set_size_request(0, -1)
451 self.label_name_event_box = gtk.EventBox()
452 self.label_name_event_box.connect('button-press-event', self.on_label_mouse)
453 self.label_name_event_box.add(self.label_name)
454 if not self.colours:
455 self.colours = available_colours[:]
456 for color in self.colours:
457 self.color_tuple = [gtk.gdk.color_parse(color[x]) for x in range(3)]
458 self.colours.remove(color)
459 break
460 self.label_name_event_box.modify_bg(gtk.STATE_NORMAL, self.color_tuple[1])
461 self.vbox.pack_start(self.label_name_event_box, True)
462 frame = gtk.Frame()
463 frame.set_shadow_type(gtk.SHADOW_IN)
464 frame.add(self.abspeak);
465 self.vbox.pack_start(frame, False)
467 # hbox child at lower part
468 self.hbox = gtk.HBox()
469 self.hbox.pack_start(self.slider, True)
470 frame = gtk.Frame()
471 frame.set_shadow_type(gtk.SHADOW_IN)
472 frame.add(self.meter);
473 self.hbox.pack_start(frame, True)
474 frame = gtk.Frame()
475 frame.set_shadow_type(gtk.SHADOW_IN)
476 frame.add(self.hbox);
477 self.pack_start(frame, True)
479 self.volume_digits.set_size_request(0, -1)
480 self.pack_start(self.volume_digits, False)
482 self.create_balance_widget()
484 channel_properties_dialog = None
485 def on_channel_properties(self):
486 if not self.channel_properties_dialog:
487 self.channel_properties_dialog = OutputChannelPropertiesDialog(self)
488 self.channel_properties_dialog.show()
489 self.channel_properties_dialog.present()
491 def on_label_mouse(self, widget, event):
492 if event.type == gtk.gdk._2BUTTON_PRESS:
493 if event.button == 1:
494 self.on_channel_properties()
496 def unrealize(self):
497 channel.unrealize(self)
498 self.channel = False
500 def serialization_name(self):
501 return output_channel_serialization_name()
503 def serialize(self, object_backend):
504 object_backend.add_property("name", self.channel_name)
505 if self.stereo:
506 object_backend.add_property("type", "stereo")
507 else:
508 object_backend.add_property("type", "mono")
509 if self.display_solo_buttons:
510 object_backend.add_property("solo_buttons", "true")
511 channel.serialize(self, object_backend)
513 def unserialize_property(self, name, value):
514 if name == "name":
515 self.channel_name = str(value)
516 return True
517 if name == "type":
518 if value == "stereo":
519 self.stereo = True
520 return True
521 if value == "mono":
522 self.stereo = False
523 return True
524 if name == "solo_buttons":
525 if value == "true":
526 self.display_solo_buttons = True
527 return channel.unserialize_property(self, name, value)
529 def output_channel_serialization_name():
530 return "output_channel"
532 class main_mix(channel):
533 def __init__(self, app):
534 channel.__init__(self, app, "MAIN", True)
536 def realize(self):
537 channel.realize(self)
538 self.channel = self.mixer.main_mix_channel
539 self.channel.midi_scale = self.slider_scale.scale
540 self.channel.midi_change_callback = self.midi_change_callback
542 self.on_volume_changed(self.slider_adjustment)
543 self.on_balance_changed(self.balance_adjustment)
545 # vbox child at upper part
546 self.vbox = gtk.VBox()
547 self.pack_start(self.vbox, False)
548 self.label_name = gtk.Label()
549 self.label_name.set_text(self.channel_name)
550 self.label_name.set_size_request(0, -1)
551 self.vbox.pack_start(self.label_name, False)
552 frame = gtk.Frame()
553 frame.set_shadow_type(gtk.SHADOW_IN)
554 frame.add(self.abspeak);
555 self.vbox.pack_start(frame, False)
557 # hbox child at lower part
558 self.hbox = gtk.HBox()
559 self.hbox.pack_start(self.slider, True)
560 frame = gtk.Frame()
561 frame.set_shadow_type(gtk.SHADOW_IN)
562 frame.add(self.meter);
563 self.hbox.pack_start(frame, True)
564 frame = gtk.Frame()
565 frame.set_shadow_type(gtk.SHADOW_IN)
566 frame.add(self.hbox);
567 self.pack_start(frame, True)
569 self.volume_digits.set_size_request(0, -1)
570 self.pack_start(self.volume_digits, False)
572 self.create_balance_widget()
574 def unrealize(self):
575 channel.unrealize(self)
576 self.channel = False
578 def serialization_name(self):
579 return main_mix_serialization_name()
581 def main_mix_serialization_name():
582 return "main_mix_channel"
585 class ChannelPropertiesDialog(gtk.Dialog):
586 def __init__(self, parent):
587 self.channel = parent
588 self.mixer = self.channel.mixer
589 gtk.Dialog.__init__(self,
590 'Channel "%s" Properties' % self.channel.channel_name,
591 self.channel.gui_factory.topwindow)
593 self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
594 self.ok_button = self.add_button(gtk.STOCK_APPLY, gtk.RESPONSE_APPLY)
596 self.create_ui()
597 self.fill_ui()
599 self.connect('response', self.on_response_cb)
600 self.connect('delete-event', self.on_response_cb)
602 def create_frame(self, label, child):
603 frame = gtk.Frame('')
604 frame.set_border_width(3)
605 #frame.set_shadow_type(gtk.SHADOW_NONE)
606 frame.get_label_widget().set_markup('<b>%s</b>' % label)
608 alignment = gtk.Alignment(0, 0, 1, 1)
609 alignment.set_padding(0, 0, 12, 0)
610 frame.add(alignment)
611 alignment.add(child)
613 return frame
615 def create_ui(self):
616 vbox = gtk.VBox()
617 self.vbox.add(vbox)
619 table = gtk.Table(2, 2, False)
620 vbox.pack_start(self.create_frame('Properties', table))
621 table.set_row_spacings(5)
622 table.set_col_spacings(5)
624 table.attach(gtk.Label('Name'), 0, 1, 0, 1)
625 self.entry_name = gtk.Entry()
626 self.entry_name.set_activates_default(True)
627 self.entry_name.connect('changed', self.on_entry_name_changed)
628 table.attach(self.entry_name, 1, 2, 0, 1)
630 table.attach(gtk.Label('Mode'), 0, 1, 1, 2)
631 self.mode_hbox = gtk.HBox()
632 table.attach(self.mode_hbox, 1, 2, 1, 2)
633 self.mono = gtk.RadioButton(label='Mono')
634 self.stereo = gtk.RadioButton(label='Stereo', group=self.mono)
635 self.mode_hbox.pack_start(self.mono)
636 self.mode_hbox.pack_start(self.stereo)
638 table = gtk.Table(2, 3, False)
639 vbox.pack_start(self.create_frame('MIDI Control Channels', table))
640 table.set_row_spacings(5)
641 table.set_col_spacings(5)
643 table.attach(gtk.Label('Volume'), 0, 1, 0, 1)
644 self.entry_volume_cc = gtk.Entry()
645 self.entry_volume_cc.set_activates_default(True)
646 self.entry_volume_cc.set_editable(False)
647 self.entry_volume_cc.set_width_chars(3)
648 table.attach(self.entry_volume_cc, 1, 2, 0, 1)
649 self.button_sense_midi_volume = gtk.Button('Autoset')
650 self.button_sense_midi_volume.connect('clicked',
651 self.on_sense_midi_volume_clicked)
652 table.attach(self.button_sense_midi_volume, 2, 3, 0, 1)
654 table.attach(gtk.Label('Balance'), 0, 1, 1, 2)
655 self.entry_balance_cc = gtk.Entry()
656 self.entry_balance_cc.set_activates_default(True)
657 self.entry_balance_cc.set_width_chars(3)
658 self.entry_balance_cc.set_editable(False)
659 table.attach(self.entry_balance_cc, 1, 2, 1, 2)
660 self.button_sense_midi_balance = gtk.Button('Autoset')
661 self.button_sense_midi_balance.connect('clicked',
662 self.on_sense_midi_balance_clicked)
663 table.attach(self.button_sense_midi_balance, 2, 3, 1, 2)
665 self.vbox.show_all()
667 def fill_ui(self):
668 self.entry_name.set_text(self.channel.channel_name)
669 if self.channel.channel.is_stereo:
670 self.stereo.set_active(True)
671 else:
672 self.mono.set_active(True)
673 self.mode_hbox.set_sensitive(False)
674 self.entry_volume_cc.set_text('%s' % self.channel.channel.volume_midi_cc)
675 self.entry_balance_cc.set_text('%s' % self.channel.channel.balance_midi_cc)
677 def sense_popup_dialog(self, entry):
678 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
679 window.set_destroy_with_parent(True)
680 window.set_transient_for(self)
681 window.set_decorated(False)
682 window.set_modal(True)
683 window.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
684 window.set_border_width(10)
686 vbox = gtk.VBox(10)
687 window.add(vbox)
688 window.timeout = 5
689 vbox.pack_start(gtk.Label('Please move the MIDI control you want to use for this function.'))
690 timeout_label = gtk.Label('This window will close in 5 seconds')
691 vbox.pack_start(timeout_label)
692 def close_sense_timeout(window, entry):
693 window.timeout -= 1
694 timeout_label.set_text('This window will close in %d seconds.' % window.timeout)
695 if window.timeout == 0:
696 window.destroy()
697 entry.set_text('%s' % self.mixer.last_midi_channel)
698 return False
699 return True
700 window.show_all()
701 glib.timeout_add_seconds(1, close_sense_timeout, window, entry)
703 def on_sense_midi_volume_clicked(self, *args):
704 self.sense_popup_dialog(self.entry_volume_cc)
706 def on_sense_midi_balance_clicked(self, *args):
707 self.sense_popup_dialog(self.entry_balance_cc)
709 def on_response_cb(self, dlg, response_id, *args):
710 self.channel.channel_properties_dialog = None
711 self.destroy()
712 if response_id == gtk.RESPONSE_APPLY:
713 name = self.entry_name.get_text()
714 self.channel.channel_name = name
715 self.channel.channel.volume_midi_cc = int(self.entry_volume_cc.get_text())
716 self.channel.channel.balance_midi_cc = int(self.entry_balance_cc.get_text())
718 def on_entry_name_changed(self, entry):
719 self.ok_button.set_sensitive(len(entry.get_text()))
721 class NewChannelDialog(ChannelPropertiesDialog):
722 def __init__(self, parent, mixer):
723 gtk.Dialog.__init__(self, 'New Channel', parent)
724 self.mixer = mixer
725 self.create_ui()
727 self.stereo.set_active(True) # default to stereo
729 self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
730 self.ok_button = self.add_button(gtk.STOCK_ADD, gtk.RESPONSE_OK)
731 self.ok_button.set_sensitive(False)
732 self.set_default_response(gtk.RESPONSE_OK);
734 def get_result(self):
735 return {'name': self.entry_name.get_text(),
736 'stereo': self.stereo.get_active(),
737 'volume_cc': self.entry_volume_cc.get_text(),
738 'balance_cc': self.entry_balance_cc.get_text()
741 class OutputChannelPropertiesDialog(ChannelPropertiesDialog):
742 def create_ui(self):
743 ChannelPropertiesDialog.create_ui(self)
745 vbox = gtk.VBox()
746 self.vbox.pack_start(self.create_frame('Input Channels', vbox))
748 self.display_solo_buttons = gtk.CheckButton('Display solo buttons')
749 vbox.pack_start(self.display_solo_buttons)
751 self.vbox.show_all()
753 def fill_ui(self):
754 ChannelPropertiesDialog.fill_ui(self)
755 self.display_solo_buttons.set_active(self.channel.display_solo_buttons)
757 def on_response_cb(self, dlg, response_id, *args):
758 ChannelPropertiesDialog.on_response_cb(self, dlg, response_id, *args)
759 if response_id == gtk.RESPONSE_APPLY:
760 self.channel.display_solo_buttons = self.display_solo_buttons.get_active()
763 class NewOutputChannelDialog(OutputChannelPropertiesDialog):
764 def __init__(self, parent, mixer):
765 gtk.Dialog.__init__(self, 'New Output Channel', parent)
766 self.mixer = mixer
767 self.create_ui()
769 # TODO: disable mode for output channels as mono output channels may
770 # not be correctly handled yet.
771 self.mode_hbox.set_sensitive(False)
772 self.stereo.set_active(True) # default to stereo
774 self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
775 self.ok_button = self.add_button(gtk.STOCK_ADD, gtk.RESPONSE_OK)
776 self.ok_button.set_sensitive(False)
777 self.set_default_response(gtk.RESPONSE_OK);
779 def get_result(self):
780 return {'name': self.entry_name.get_text(),
781 'stereo': self.stereo.get_active(),
782 'volume_cc': self.entry_volume_cc.get_text(),
783 'balance_cc': self.entry_balance_cc.get_text(),
784 'display_solo_buttons': self.display_solo_buttons.get_active(),
788 class ControlGroup(gtk.Alignment):
789 def __init__(self, output_channel, input_channel):
790 gtk.Alignment.__init__(self, 0.5, 0.5, 0, 0)
791 self.output_channel = output_channel
792 self.input_channel = input_channel
794 hbox = gtk.HBox()
795 self.hbox = hbox
796 self.add(hbox)
798 mute = gtk.ToggleButton()
799 mute.set_label("M")
800 #mute.set_active(self.channel.mute)
801 mute.connect("toggled", self.on_mute_toggled)
802 hbox.pack_start(mute, False)
804 solo = gtk.ToggleButton()
805 self.solo = solo
806 solo.set_label("S")
807 #solo.set_active(self.channel.solo)
808 solo.connect("toggled", self.on_solo_toggled)
809 if self.output_channel.display_solo_buttons:
810 hbox.pack_start(solo, True)
812 mute.modify_bg(gtk.STATE_PRELIGHT, output_channel.color_tuple[0])
813 mute.modify_bg(gtk.STATE_NORMAL, output_channel.color_tuple[1])
814 mute.modify_bg(gtk.STATE_ACTIVE, output_channel.color_tuple[2])
815 solo.modify_bg(gtk.STATE_PRELIGHT, output_channel.color_tuple[0])
816 solo.modify_bg(gtk.STATE_NORMAL, output_channel.color_tuple[1])
817 solo.modify_bg(gtk.STATE_ACTIVE, output_channel.color_tuple[2])
819 def update(self):
820 if self.output_channel.display_solo_buttons:
821 if not self.solo in self.hbox.get_children():
822 self.hbox.pack_start(self.solo, True)
823 self.solo.show()
824 else:
825 if self.solo in self.hbox.get_children():
826 self.hbox.remove(self.solo)
828 def on_mute_toggled(self, button):
829 self.output_channel.channel.set_muted(self.input_channel.channel, button.get_active())
831 def on_solo_toggled(self, button):
832 self.output_channel.channel.set_solo(self.input_channel.channel, button.get_active())