3 # This file is part of jack_mixer
5 # Copyright (C) 2006 Nedko Arnaudov <nedko@arnaudov.name>
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.
26 from serialization import serialized_object
34 class channel(gtk.VBox, serialized_object):
35 '''Widget with slider and meter used as base class for more specific channel widgets'''
38 def __init__(self, app, name, stereo):
39 gtk.VBox.__init__(self)
41 self.mixer = app.mixer
42 self.gui_factory = app.gui_factory
43 self._channel_name = name
45 self.meter_scale = self.gui_factory.get_default_meter_scale()
46 self.slider_scale = self.gui_factory.get_default_slider_scale()
47 self.slider_adjustment = slider.adjustment_dBFS(self.slider_scale, 0.0)
48 self.balance_adjustment = gtk.Adjustment(0.0, -1.0, 1.0, 0.02)
49 self.future_volume_midi_cc = None
50 self.future_balance_midi_cc = None
52 def get_channel_name(self):
53 return self._channel_name
57 def set_channel_name(self, name):
58 self._channel_name = name
60 self.label_name.set_text(name)
62 self.channel.name = name
63 channel_name = property(get_channel_name, set_channel_name)
66 #print "Realizing channel \"%s\"" % self.channel_name
68 self.slider_adjustment.connect("volume-changed", self.on_volume_changed)
69 self.balance_adjustment.connect("value-changed", self.on_balance_changed)
70 self.connect('midi-event-received', self.on_midi_event_received)
73 self.create_slider_widget()
76 self.meter = meter.stereo(self.meter_scale)
78 self.meter = meter.mono(self.meter_scale)
79 self.on_vumeter_color_changed(self.gui_factory)
81 self.meter.set_events(gtk.gdk.SCROLL_MASK)
83 self.gui_factory.connect("default-meter-scale-changed", self.on_default_meter_scale_changed)
84 self.gui_factory.connect("default-slider-scale-changed", self.on_default_slider_scale_changed)
85 self.gui_factory.connect('vumeter-color-changed', self.on_vumeter_color_changed)
86 self.gui_factory.connect('vumeter-color-scheme-changed', self.on_vumeter_color_changed)
87 self.gui_factory.connect('use-custom-widgets-changed', self.on_custom_widgets_changed)
89 self.abspeak = abspeak.widget()
90 self.abspeak.connect("reset", self.on_abspeak_reset)
91 self.abspeak.connect("volume-adjust", self.on_abspeak_adjust)
93 self.volume_digits = gtk.Entry()
94 self.volume_digits.connect("key-press-event", self.on_volume_digits_key_pressed)
95 self.volume_digits.connect("focus-out-event", self.on_volume_digits_focus_out)
97 self.connect("key-press-event", self.on_key_pressed)
98 self.connect("scroll-event", self.on_scroll)
101 #print "Unrealizing channel \"%s\"" % self.channel_name
104 def create_balance_widget(self):
105 if self.gui_factory.use_custom_widgets and phat:
106 self.balance = phat.HFanSlider()
107 self.balance.set_default_value(0)
108 self.balance.set_adjustment(self.balance_adjustment)
110 self.balance = gtk.HScale(self.balance_adjustment)
111 self.balance.set_draw_value(False)
112 self.pack_start(self.balance, False)
113 if self.monitor_button:
114 self.reorder_child(self.monitor_button, -1)
117 def create_slider_widget(self):
120 parent = self.slider.get_parent()
121 self.slider.destroy()
122 if self.gui_factory.use_custom_widgets:
123 self.slider = slider.CustomSliderWidget(self.slider_adjustment)
125 self.slider = slider.GtkSlider(self.slider_adjustment)
127 parent.pack_start(self.slider)
128 parent.reorder_child(self.slider, 0)
131 def on_default_meter_scale_changed(self, gui_factory, scale):
132 #print "Default meter scale change detected."
133 self.meter.set_scale(scale)
135 def on_default_slider_scale_changed(self, gui_factory, scale):
136 #print "Default slider scale change detected."
137 self.slider_scale = scale
138 self.slider_adjustment.set_scale(scale)
139 self.channel.set_midi_scale(self.slider_scale.scale)
141 def on_vumeter_color_changed(self, gui_factory, *args):
142 color = gui_factory.get_vumeter_color()
143 color_scheme = gui_factory.get_vumeter_color_scheme()
144 if color_scheme != 'solid':
145 self.meter.set_color(None)
147 self.meter.set_color(gtk.gdk.color_parse(color))
149 def on_custom_widgets_changed(self, gui_factory, value):
150 self.balance.destroy()
151 self.create_balance_widget()
152 self.create_slider_widget()
154 def on_abspeak_adjust(self, abspeak, adjust):
155 #print "abspeak adjust %f" % adjust
156 self.slider_adjustment.set_value_db(self.slider_adjustment.get_value_db() + adjust)
157 self.channel.abspeak = None
158 #self.update_volume(False) # We want to update gui even if actual decibels have not changed (scale wrap for example)
160 def on_abspeak_reset(self, abspeak):
161 #print "abspeak reset"
162 self.channel.abspeak = None
164 def on_volume_digits_key_pressed(self, widget, event):
165 if (event.keyval == gtk.keysyms.Return or event.keyval == gtk.keysyms.KP_Enter):
166 db_text = self.volume_digits.get_text()
169 #print "Volume digits confirmation \"%f dBFS\"" % db
170 except (ValueError), e:
171 #print "Volume digits confirmation ignore, reset to current"
172 self.update_volume(False)
174 self.slider_adjustment.set_value_db(db)
176 #self.update_volume(False) # We want to update gui even if actual decibels have not changed (scale wrap for example)
178 def on_volume_digits_focus_out(self, widget, event):
179 #print "volume digits focus out detected"
180 self.update_volume(False)
182 def read_meter(self):
186 meter_left, meter_right = self.channel.meter
187 self.meter.set_values(meter_left, meter_right)
189 self.meter.set_value(self.channel.meter[0])
191 self.abspeak.set_peak(self.channel.abspeak)
193 def on_scroll(self, widget, event):
194 if event.direction == gtk.gdk.SCROLL_DOWN:
195 self.slider_adjustment.step_down()
196 elif event.direction == gtk.gdk.SCROLL_UP:
197 self.slider_adjustment.step_up()
200 def update_volume(self, update_engine):
201 db = self.slider_adjustment.get_value_db()
203 db_text = "%.2f" % db
204 self.volume_digits.set_text(db_text)
207 #print "Setting engine volume to " + db_text
208 self.channel.volume = db
209 self.app.update_monitor(self)
211 def on_volume_changed(self, adjustment):
212 self.update_volume(True)
214 def on_balance_changed(self, adjustment):
215 balance = self.balance_adjustment.get_value()
216 #print "%s balance: %f" % (self.channel_name, balance)
217 self.channel.balance = balance
218 self.app.update_monitor(self)
220 def on_key_pressed(self, widget, event):
221 if (event.keyval == gtk.keysyms.Up):
222 #print self.channel_name + " Up"
223 self.slider_adjustment.step_up()
225 elif (event.keyval == gtk.keysyms.Down):
226 #print self.channel_name + " Down"
227 self.slider_adjustment.step_down()
232 def serialize(self, object_backend):
233 object_backend.add_property("volume", "%f" % self.slider_adjustment.get_value_db())
234 object_backend.add_property("balance", "%f" % self.balance_adjustment.get_value())
236 if self.channel.volume_midi_cc:
237 object_backend.add_property('volume_midi_cc', str(self.channel.volume_midi_cc))
238 if self.channel.balance_midi_cc:
239 object_backend.add_property('balance_midi_cc', str(self.channel.balance_midi_cc))
241 def unserialize_property(self, name, value):
243 self.slider_adjustment.set_value_db(float(value))
245 if name == "balance":
246 self.balance_adjustment.set_value(float(value))
248 if name == 'volume_midi_cc':
249 self.future_volume_midi_cc = int(value)
251 if name == 'balance_midi_cc':
252 self.future_balance_midi_cc = int(value)
256 def on_midi_event_received(self, *args):
257 self.slider_adjustment.set_value_db(self.channel.volume)
258 self.balance_adjustment.set_value(self.channel.balance)
260 def midi_change_callback(self, *args):
261 # the changes are not applied directly to the widgets as they
262 # absolutely have to be done from the gtk thread.
263 self.emit('midi-event-received')
265 def on_monitor_button_toggled(self, button):
266 if not button.get_active():
267 self.app.main_mix.monitor_button.set_active(True)
269 for channel in self.app.channels + self.app.output_channels + [self.app.main_mix]:
270 if channel.monitor_button.get_active() and channel.monitor_button is not button:
271 channel.monitor_button.handler_block_by_func(
272 channel.on_monitor_button_toggled)
273 channel.monitor_button.set_active(False)
274 channel.monitor_button.handler_unblock_by_func(
275 channel.on_monitor_button_toggled)
276 self.app.set_monitored_channel(self)
278 def set_monitored(self):
280 self.app.set_monitored_channel(self)
281 self.monitor_button.set_active(True)
283 gobject.signal_new('midi-event-received', channel,
284 gobject.SIGNAL_RUN_FIRST | gobject.SIGNAL_ACTION,
285 gobject.TYPE_NONE, ())
287 class input_channel(channel):
288 def __init__(self, app, name, stereo):
289 channel.__init__(self, app, name, stereo)
292 self.channel = self.mixer.add_channel(self.channel_name, self.stereo)
293 if self.channel == None:
294 raise Exception,"Cannot create a channel"
295 channel.realize(self)
296 if self.future_volume_midi_cc:
297 self.channel.volume_midi_cc = self.future_volume_midi_cc
298 if self.future_balance_midi_cc:
299 self.channel.balance_midi_cc = self.future_balance_midi_cc
300 self.channel.midi_scale = self.slider_scale.scale
301 self.channel.midi_change_callback = self.midi_change_callback
303 self.on_volume_changed(self.slider_adjustment)
304 self.on_balance_changed(self.balance_adjustment)
306 # vbox child at upper part
307 self.vbox = gtk.VBox()
308 self.pack_start(self.vbox, False)
309 self.label_name = gtk.Label()
310 self.label_name.set_text(self.channel_name)
311 self.label_name.set_size_request(0, -1)
312 self.label_name_event_box = gtk.EventBox()
313 self.label_name_event_box.connect("button-press-event", self.on_label_mouse)
314 self.label_name_event_box.add(self.label_name)
315 self.vbox.pack_start(self.label_name_event_box, True)
316 # self.label_stereo = gtk.Label()
318 # self.label_stereo.set_text("stereo")
320 # self.label_stereo.set_text("mono")
321 # self.label_stereo.set_size_request(0, -1)
322 # self.vbox.pack_start(self.label_stereo, True)
324 # hbox for mute and solo buttons
325 self.hbox_mutesolo = gtk.HBox()
327 self.mute = gtk.ToggleButton()
328 self.mute.set_label("M")
329 self.mute.set_active(self.channel.mute)
330 self.mute.connect("button-press-event", self.on_mute_button_pressed)
331 self.mute.connect("toggled", self.on_mute_toggled)
332 self.hbox_mutesolo.pack_start(self.mute, True)
334 self.solo = gtk.ToggleButton()
335 self.solo.set_label("S")
336 self.solo.set_active(self.channel.solo)
337 self.solo.connect("button-press-event", self.on_solo_button_pressed)
338 self.solo.connect("toggled", self.on_solo_toggled)
339 self.hbox_mutesolo.pack_start(self.solo, True)
341 self.vbox.pack_start(self.hbox_mutesolo, False)
344 frame.set_shadow_type(gtk.SHADOW_IN)
345 frame.add(self.abspeak);
346 self.pack_start(frame, False)
348 # hbox child at lower part
349 self.hbox = gtk.HBox()
350 self.hbox.pack_start(self.slider, True)
352 frame.set_shadow_type(gtk.SHADOW_IN)
353 frame.add(self.meter);
354 self.hbox.pack_start(frame, True)
356 frame.set_shadow_type(gtk.SHADOW_IN)
357 frame.add(self.hbox);
358 self.pack_start(frame, True)
360 self.volume_digits.set_size_request(0, -1)
361 self.pack_start(self.volume_digits, False)
363 self.create_balance_widget()
365 self.monitor_button = gtk.ToggleButton('MON')
366 self.monitor_button.connect('toggled', self.on_monitor_button_toggled)
367 self.pack_start(self.monitor_button, False, False)
369 def add_control_group(self, channel):
370 control_group = ControlGroup(channel, self)
371 control_group.show_all()
372 self.vbox.pack_start(control_group, False)
375 def update_control_group(self, channel):
376 for control_group in self.vbox.get_children():
377 if isinstance(control_group, ControlGroup):
378 if control_group.output_channel is channel:
379 control_group.update()
381 def get_control_group(self, channel):
382 for control_group in self.vbox.get_children():
383 if isinstance(control_group, ControlGroup):
384 if control_group.output_channel is channel:
389 channel.unrealize(self)
390 self.channel.remove()
393 channel_properties_dialog = None
394 def on_channel_properties(self):
395 if not self.channel_properties_dialog:
396 self.channel_properties_dialog = ChannelPropertiesDialog(self, self.app)
397 self.channel_properties_dialog.show()
398 self.channel_properties_dialog.present()
400 def on_label_mouse(self, widget, event):
401 if event.type == gtk.gdk._2BUTTON_PRESS:
402 if event.button == 1:
403 self.on_channel_properties()
405 def on_mute_toggled(self, button):
406 self.channel.mute = self.mute.get_active()
407 self.app.update_monitor(self.app.main_mix)
409 def on_mute_button_pressed(self, button, event, *args):
410 if event.button == 3:
411 # right click on the mute button, act on all output channels
412 if button.get_active(): # was muted
413 button.set_active(False)
414 if hasattr(button, 'touched_channels'):
415 touched_channels = button.touched_channels
416 for chan in touched_channels:
417 ctlgroup = self.get_control_group(chan)
418 ctlgroup.mute.set_active(False)
419 del button.touched_channels
420 else: # was not muted
421 button.set_active(True)
422 touched_channels = []
423 for chan in self.app.output_channels:
424 ctlgroup = self.get_control_group(chan)
425 if not ctlgroup.mute.get_active():
426 ctlgroup.mute.set_active(True)
427 touched_channels.append(chan)
428 button.touched_channels = touched_channels
432 def on_solo_toggled(self, button):
433 self.channel.solo = self.solo.get_active()
434 self.app.update_monitor(self.app.main_mix)
436 def on_solo_button_pressed(self, button, event, *args):
437 if event.button == 3:
438 # right click on the solo button, act on all output channels
439 if button.get_active(): # was soloed
440 button.set_active(False)
441 if hasattr(button, 'touched_channels'):
442 touched_channels = button.touched_channels
443 for chan in touched_channels:
444 ctlgroup = self.get_control_group(chan)
445 ctlgroup.solo.set_active(False)
446 del button.touched_channels
447 else: # was not soloed
448 button.set_active(True)
449 touched_channels = []
450 for chan in self.app.output_channels:
451 ctlgroup = self.get_control_group(chan)
452 if not ctlgroup.solo.get_active():
453 ctlgroup.solo.set_active(True)
454 touched_channels.append(chan)
455 button.touched_channels = touched_channels
459 def serialization_name(self):
460 return input_channel_serialization_name()
462 def serialize(self, object_backend):
463 object_backend.add_property("name", self.channel_name)
465 object_backend.add_property("type", "stereo")
467 object_backend.add_property("type", "mono")
468 channel.serialize(self, object_backend)
470 def unserialize_property(self, name, value):
472 self.channel_name = str(value)
475 if value == "stereo":
481 return channel.unserialize_property(self, name, value)
483 def input_channel_serialization_name():
484 return "input_channel"
487 available_colours = [
488 ('#ef2929', '#cc0000', '#840000'),
489 ('#729fcf', '#3465a4', '#204a67'),
490 ('#8aa234', '#73d216', '#4e7a06'),
491 ('#fce84f', '#edd400', '#c48000'),
492 ('#fcaf3e', '#f57900', '#ae5c00'),
493 ('#ad7fa8', '#75507b', '#4c3556'),
494 ('#e9b96e', '#c17d11', '#6f4902'),
497 class output_channel(channel):
498 colours = available_colours[:]
499 _display_solo_buttons = False
501 _init_muted_channels = None
502 _init_solo_channels = None
504 def __init__(self, app, name, stereo):
505 channel.__init__(self, app, name, stereo)
507 def get_display_solo_buttons(self):
508 return self._display_solo_buttons
510 def set_display_solo_buttons(self, value):
511 self._display_solo_buttons = value
512 # notifying control groups
513 for inputchannel in self.app.channels:
514 inputchannel.update_control_group(self)
516 display_solo_buttons = property(get_display_solo_buttons, set_display_solo_buttons)
519 channel.realize(self)
520 self.channel = self.mixer.add_output_channel(self.channel_name, self.stereo)
521 if self.channel == None:
522 raise Exception,"Cannot create a channel"
523 channel.realize(self)
525 self.channel.midi_scale = self.slider_scale.scale
526 self.channel.midi_change_callback = self.midi_change_callback
528 self.on_volume_changed(self.slider_adjustment)
529 self.on_balance_changed(self.balance_adjustment)
531 # vbox child at upper part
532 self.vbox = gtk.VBox()
533 self.pack_start(self.vbox, False)
534 self.label_name = gtk.Label()
535 self.label_name.set_text(self.channel_name)
536 self.label_name.set_size_request(0, -1)
537 self.label_name_event_box = gtk.EventBox()
538 self.label_name_event_box.connect('button-press-event', self.on_label_mouse)
539 self.label_name_event_box.add(self.label_name)
541 self.colours = available_colours[:]
542 for color in self.colours:
543 self.color_tuple = [gtk.gdk.color_parse(color[x]) for x in range(3)]
544 self.colours.remove(color)
546 self.label_name_event_box.modify_bg(gtk.STATE_NORMAL, self.color_tuple[1])
547 self.vbox.pack_start(self.label_name_event_box, True)
549 frame.set_shadow_type(gtk.SHADOW_IN)
550 frame.add(self.abspeak);
551 self.vbox.pack_start(frame, False)
553 # hbox child at lower part
554 self.hbox = gtk.HBox()
555 self.hbox.pack_start(self.slider, True)
557 frame.set_shadow_type(gtk.SHADOW_IN)
558 frame.add(self.meter);
559 self.hbox.pack_start(frame, True)
561 frame.set_shadow_type(gtk.SHADOW_IN)
562 frame.add(self.hbox);
563 self.pack_start(frame, True)
565 self.volume_digits.set_size_request(0, -1)
566 self.pack_start(self.volume_digits, False)
568 self.create_balance_widget()
570 self.monitor_button = gtk.ToggleButton('MON')
571 self.monitor_button.connect('toggled', self.on_monitor_button_toggled)
572 self.pack_start(self.monitor_button, False, False)
574 # add control groups to the input channels, and initialize them
576 for input_channel in self.app.channels:
577 ctlgroup = input_channel.add_control_group(self)
578 if self._init_muted_channels and input_channel.channel.name in self._init_muted_channels:
579 ctlgroup.mute.set_active(True)
580 if self._init_solo_channels and input_channel.channel.name in self._init_solo_channels:
581 ctlgroup.solo.set_active(True)
582 self._init_muted_channels = None
583 self._init_solo_channels = None
585 channel_properties_dialog = None
586 def on_channel_properties(self):
587 if not self.channel_properties_dialog:
588 self.channel_properties_dialog = OutputChannelPropertiesDialog(self, self.app)
589 self.channel_properties_dialog.show()
590 self.channel_properties_dialog.present()
592 def on_label_mouse(self, widget, event):
593 if event.type == gtk.gdk._2BUTTON_PRESS:
594 if event.button == 1:
595 self.on_channel_properties()
598 channel.unrealize(self)
601 def serialization_name(self):
602 return output_channel_serialization_name()
604 def serialize(self, object_backend):
605 object_backend.add_property("name", self.channel_name)
607 object_backend.add_property("type", "stereo")
609 object_backend.add_property("type", "mono")
610 if self.display_solo_buttons:
611 object_backend.add_property("solo_buttons", "true")
614 for input_channel in self.app.channels:
615 if self.channel.is_muted(input_channel.channel):
616 muted_channels.append(input_channel)
617 if self.channel.is_solo(input_channel.channel):
618 solo_channels.append(input_channel)
620 object_backend.add_property('muted_channels', '|'.join([x.channel.name for x in muted_channels]))
622 object_backend.add_property('solo_channels', '|'.join([x.channel.name for x in solo_channels]))
623 channel.serialize(self, object_backend)
625 def unserialize_property(self, name, value):
627 self.channel_name = str(value)
630 if value == "stereo":
636 if name == "solo_buttons":
638 self.display_solo_buttons = True
640 if name == 'muted_channels':
641 self._init_muted_channels = value.split('|')
643 if name == 'solo_channels':
644 self._init_solo_channels = value.split('|')
646 return channel.unserialize_property(self, name, value)
648 def output_channel_serialization_name():
649 return "output_channel"
651 class main_mix(channel):
652 _init_muted_channels = None
653 _init_solo_channels = None
655 def __init__(self, app):
656 channel.__init__(self, app, "MAIN", True)
659 channel.realize(self)
660 self.channel = self.mixer.main_mix_channel
661 self.channel.midi_scale = self.slider_scale.scale
662 self.channel.midi_change_callback = self.midi_change_callback
664 self.on_volume_changed(self.slider_adjustment)
665 self.on_balance_changed(self.balance_adjustment)
667 # vbox child at upper part
668 self.vbox = gtk.VBox()
669 self.pack_start(self.vbox, False)
670 self.label_name = gtk.Label()
671 self.label_name.set_text(self.channel_name)
672 self.label_name.set_size_request(0, -1)
673 self.vbox.pack_start(self.label_name, False)
675 frame.set_shadow_type(gtk.SHADOW_IN)
676 frame.add(self.abspeak);
677 self.vbox.pack_start(frame, False)
679 # hbox child at lower part
680 self.hbox = gtk.HBox()
681 self.hbox.pack_start(self.slider, True)
683 frame.set_shadow_type(gtk.SHADOW_IN)
684 frame.add(self.meter);
685 self.hbox.pack_start(frame, True)
687 frame.set_shadow_type(gtk.SHADOW_IN)
688 frame.add(self.hbox);
689 self.pack_start(frame, True)
691 self.volume_digits.set_size_request(0, -1)
692 self.pack_start(self.volume_digits, False)
694 self.create_balance_widget()
696 self.monitor_button = gtk.ToggleButton('MON')
697 self.monitor_button.connect('toggled', self.on_monitor_button_toggled)
698 self.pack_start(self.monitor_button, False, False)
700 for input_channel in self.app.channels:
701 if self._init_muted_channels and input_channel.channel.name in self._init_muted_channels:
702 input_channel.mute.set_active(True)
703 if self._init_solo_channels and input_channel.channel.name in self._init_solo_channels:
704 input_channel.solo.set_active(True)
705 self._init_muted_channels = None
706 self._init_solo_channels = None
709 channel.unrealize(self)
712 def serialization_name(self):
713 return main_mix_serialization_name()
715 def serialize(self, object_backend):
718 for input_channel in self.app.channels:
719 if input_channel.channel.mute:
720 muted_channels.append(input_channel)
721 if input_channel.channel.solo:
722 solo_channels.append(input_channel)
724 object_backend.add_property('muted_channels', '|'.join([x.channel.name for x in muted_channels]))
726 object_backend.add_property('solo_channels', '|'.join([x.channel.name for x in solo_channels]))
727 channel.serialize(self, object_backend)
729 def unserialize_property(self, name, value):
730 if name == 'muted_channels':
731 self._init_muted_channels = value.split('|')
733 if name == 'solo_channels':
734 self._init_solo_channels = value.split('|')
736 return channel.unserialize_property(self, name, value)
738 def main_mix_serialization_name():
739 return "main_mix_channel"
742 class ChannelPropertiesDialog(gtk.Dialog):
745 def __init__(self, parent, app):
746 self.channel = parent
748 self.mixer = self.channel.mixer
749 gtk.Dialog.__init__(self,
750 'Channel "%s" Properties' % self.channel.channel_name,
751 self.channel.gui_factory.topwindow)
753 self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
754 self.ok_button = self.add_button(gtk.STOCK_APPLY, gtk.RESPONSE_APPLY)
759 self.connect('response', self.on_response_cb)
760 self.connect('delete-event', self.on_response_cb)
762 def create_frame(self, label, child):
763 frame = gtk.Frame('')
764 frame.set_border_width(3)
765 #frame.set_shadow_type(gtk.SHADOW_NONE)
766 frame.get_label_widget().set_markup('<b>%s</b>' % label)
768 alignment = gtk.Alignment(0, 0, 1, 1)
769 alignment.set_padding(0, 0, 12, 0)
779 table = gtk.Table(2, 2, False)
780 vbox.pack_start(self.create_frame('Properties', table))
781 table.set_row_spacings(5)
782 table.set_col_spacings(5)
784 table.attach(gtk.Label('Name'), 0, 1, 0, 1)
785 self.entry_name = gtk.Entry()
786 self.entry_name.set_activates_default(True)
787 self.entry_name.connect('changed', self.on_entry_name_changed)
788 table.attach(self.entry_name, 1, 2, 0, 1)
790 table.attach(gtk.Label('Mode'), 0, 1, 1, 2)
791 self.mode_hbox = gtk.HBox()
792 table.attach(self.mode_hbox, 1, 2, 1, 2)
793 self.mono = gtk.RadioButton(label='Mono')
794 self.stereo = gtk.RadioButton(label='Stereo', group=self.mono)
795 self.mode_hbox.pack_start(self.mono)
796 self.mode_hbox.pack_start(self.stereo)
798 table = gtk.Table(2, 3, False)
799 vbox.pack_start(self.create_frame('MIDI Control Channels', table))
800 table.set_row_spacings(5)
801 table.set_col_spacings(5)
803 table.attach(gtk.Label('Volume'), 0, 1, 0, 1)
804 self.entry_volume_cc = gtk.Entry()
805 self.entry_volume_cc.set_activates_default(True)
806 self.entry_volume_cc.set_editable(False)
807 self.entry_volume_cc.set_width_chars(3)
808 table.attach(self.entry_volume_cc, 1, 2, 0, 1)
809 self.button_sense_midi_volume = gtk.Button('Autoset')
810 self.button_sense_midi_volume.connect('clicked',
811 self.on_sense_midi_volume_clicked)
812 table.attach(self.button_sense_midi_volume, 2, 3, 0, 1)
814 table.attach(gtk.Label('Balance'), 0, 1, 1, 2)
815 self.entry_balance_cc = gtk.Entry()
816 self.entry_balance_cc.set_activates_default(True)
817 self.entry_balance_cc.set_width_chars(3)
818 self.entry_balance_cc.set_editable(False)
819 table.attach(self.entry_balance_cc, 1, 2, 1, 2)
820 self.button_sense_midi_balance = gtk.Button('Autoset')
821 self.button_sense_midi_balance.connect('clicked',
822 self.on_sense_midi_balance_clicked)
823 table.attach(self.button_sense_midi_balance, 2, 3, 1, 2)
828 self.entry_name.set_text(self.channel.channel_name)
829 if self.channel.channel.is_stereo:
830 self.stereo.set_active(True)
832 self.mono.set_active(True)
833 self.mode_hbox.set_sensitive(False)
834 self.entry_volume_cc.set_text('%s' % self.channel.channel.volume_midi_cc)
835 self.entry_balance_cc.set_text('%s' % self.channel.channel.balance_midi_cc)
837 def sense_popup_dialog(self, entry):
838 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
839 window.set_destroy_with_parent(True)
840 window.set_transient_for(self)
841 window.set_decorated(False)
842 window.set_modal(True)
843 window.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
844 window.set_border_width(10)
849 vbox.pack_start(gtk.Label('Please move the MIDI control you want to use for this function.'))
850 timeout_label = gtk.Label('This window will close in 5 seconds')
851 vbox.pack_start(timeout_label)
852 def close_sense_timeout(window, entry):
854 timeout_label.set_text('This window will close in %d seconds.' % window.timeout)
855 if window.timeout == 0:
857 entry.set_text('%s' % self.mixer.last_midi_channel)
861 glib.timeout_add_seconds(1, close_sense_timeout, window, entry)
863 def on_sense_midi_volume_clicked(self, *args):
864 self.sense_popup_dialog(self.entry_volume_cc)
866 def on_sense_midi_balance_clicked(self, *args):
867 self.sense_popup_dialog(self.entry_balance_cc)
869 def on_response_cb(self, dlg, response_id, *args):
870 self.channel.channel_properties_dialog = None
872 if response_id == gtk.RESPONSE_APPLY:
873 name = self.entry_name.get_text()
874 self.channel.channel_name = name
875 self.channel.channel.volume_midi_cc = int(self.entry_volume_cc.get_text())
876 self.channel.channel.balance_midi_cc = int(self.entry_balance_cc.get_text())
878 def on_entry_name_changed(self, entry):
880 if len(entry.get_text()):
881 if self.channel and self.channel.channel.name == entry.get_text():
883 elif entry.get_text() not in [x.channel.name for x in self.app.channels] + \
884 [x.channel.name for x in self.app.output_channels] + ['MAIN']:
886 self.ok_button.set_sensitive(sensitive)
889 class NewChannelDialog(ChannelPropertiesDialog):
890 def __init__(self, app):
891 gtk.Dialog.__init__(self, 'New Channel', app.window)
892 self.mixer = app.mixer
896 self.stereo.set_active(True) # default to stereo
898 self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
899 self.ok_button = self.add_button(gtk.STOCK_ADD, gtk.RESPONSE_OK)
900 self.ok_button.set_sensitive(False)
901 self.set_default_response(gtk.RESPONSE_OK);
903 def get_result(self):
904 return {'name': self.entry_name.get_text(),
905 'stereo': self.stereo.get_active(),
906 'volume_cc': self.entry_volume_cc.get_text(),
907 'balance_cc': self.entry_balance_cc.get_text()
910 class OutputChannelPropertiesDialog(ChannelPropertiesDialog):
912 ChannelPropertiesDialog.create_ui(self)
915 self.vbox.pack_start(self.create_frame('Input Channels', vbox))
917 self.display_solo_buttons = gtk.CheckButton('Display solo buttons')
918 vbox.pack_start(self.display_solo_buttons)
923 ChannelPropertiesDialog.fill_ui(self)
924 self.display_solo_buttons.set_active(self.channel.display_solo_buttons)
926 def on_response_cb(self, dlg, response_id, *args):
927 ChannelPropertiesDialog.on_response_cb(self, dlg, response_id, *args)
928 if response_id == gtk.RESPONSE_APPLY:
929 self.channel.display_solo_buttons = self.display_solo_buttons.get_active()
932 class NewOutputChannelDialog(OutputChannelPropertiesDialog):
933 def __init__(self, app):
934 gtk.Dialog.__init__(self, 'New Output Channel', app.window)
935 self.mixer = app.mixer
939 # TODO: disable mode for output channels as mono output channels may
940 # not be correctly handled yet.
941 self.mode_hbox.set_sensitive(False)
942 self.stereo.set_active(True) # default to stereo
944 self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
945 self.ok_button = self.add_button(gtk.STOCK_ADD, gtk.RESPONSE_OK)
946 self.ok_button.set_sensitive(False)
947 self.set_default_response(gtk.RESPONSE_OK);
949 def get_result(self):
950 return {'name': self.entry_name.get_text(),
951 'stereo': self.stereo.get_active(),
952 'volume_cc': self.entry_volume_cc.get_text(),
953 'balance_cc': self.entry_balance_cc.get_text(),
954 'display_solo_buttons': self.display_solo_buttons.get_active(),
958 class ControlGroup(gtk.Alignment):
959 def __init__(self, output_channel, input_channel):
960 gtk.Alignment.__init__(self, 0.5, 0.5, 0, 0)
961 self.output_channel = output_channel
962 self.input_channel = input_channel
963 self.app = input_channel.app
969 mute = gtk.ToggleButton()
972 mute.connect("toggled", self.on_mute_toggled)
973 hbox.pack_start(mute, False)
975 solo = gtk.ToggleButton()
978 solo.connect("toggled", self.on_solo_toggled)
979 if self.output_channel.display_solo_buttons:
980 hbox.pack_start(solo, True)
982 mute.modify_bg(gtk.STATE_PRELIGHT, output_channel.color_tuple[0])
983 mute.modify_bg(gtk.STATE_NORMAL, output_channel.color_tuple[1])
984 mute.modify_bg(gtk.STATE_ACTIVE, output_channel.color_tuple[2])
985 solo.modify_bg(gtk.STATE_PRELIGHT, output_channel.color_tuple[0])
986 solo.modify_bg(gtk.STATE_NORMAL, output_channel.color_tuple[1])
987 solo.modify_bg(gtk.STATE_ACTIVE, output_channel.color_tuple[2])
990 if self.output_channel.display_solo_buttons:
991 if not self.solo in self.hbox.get_children():
992 self.hbox.pack_start(self.solo, True)
995 if self.solo in self.hbox.get_children():
996 self.hbox.remove(self.solo)
998 def on_mute_toggled(self, button):
999 self.output_channel.channel.set_muted(self.input_channel.channel, button.get_active())
1000 self.app.update_monitor(self)
1002 def on_solo_toggled(self, button):
1003 self.output_channel.channel.set_solo(self.input_channel.channel, button.get_active())
1004 self.app.update_monitor(self)