1 # This file is part of jack_mixer
3 # Copyright (C) 2006 Nedko Arnaudov <nedko@arnaudov.name>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; version 2 of the License
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23 from serialization import SerializedObject
31 class Channel(gtk.VBox, SerializedObject):
32 '''Widget with slider and meter used as base class for more specific
36 def __init__(self, app, name, stereo):
37 gtk.VBox.__init__(self)
39 self.mixer = app.mixer
40 self.gui_factory = app.gui_factory
41 self._channel_name = name
43 self.meter_scale = self.gui_factory.get_default_meter_scale()
44 self.slider_scale = self.gui_factory.get_default_slider_scale()
45 self.slider_adjustment = slider.AdjustmentdBFS(self.slider_scale, 0.0)
46 self.balance_adjustment = gtk.Adjustment(0.0, -1.0, 1.0, 0.02)
47 self.future_out_mute = None
48 self.future_volume_midi_cc = None
49 self.future_balance_midi_cc = None
50 self.future_mute_midi_cc = None
51 self.future_solo_midi_cc = None
53 def get_channel_name(self):
54 return self._channel_name
58 post_fader_output_channel = None
59 def set_channel_name(self, name):
60 self.app.on_channel_rename(self._channel_name, name);
61 self._channel_name = name
63 self.label_name.set_text(name)
65 self.channel.name = name
66 if self.post_fader_output_channel:
67 self.post_fader_output_channel.name = "%s Out" % name;
68 channel_name = property(get_channel_name, set_channel_name)
71 #print "Realizing channel \"%s\"" % self.channel_name
72 if self.future_out_mute != None:
73 self.channel.out_mute = self.future_out_mute
75 self.slider_adjustment.connect("volume-changed", self.on_volume_changed)
76 self.balance_adjustment.connect("value-changed", self.on_balance_changed)
79 self.create_slider_widget()
82 self.meter = meter.StereoMeterWidget(self.meter_scale)
84 self.meter = meter.MonoMeterWidget(self.meter_scale)
85 self.on_vumeter_color_changed(self.gui_factory)
87 self.meter.set_events(gtk.gdk.SCROLL_MASK)
89 self.gui_factory.connect("default-meter-scale-changed", self.on_default_meter_scale_changed)
90 self.gui_factory.connect("default-slider-scale-changed", self.on_default_slider_scale_changed)
91 self.gui_factory.connect('vumeter-color-changed', self.on_vumeter_color_changed)
92 self.gui_factory.connect('vumeter-color-scheme-changed', self.on_vumeter_color_changed)
93 self.gui_factory.connect('use-custom-widgets-changed', self.on_custom_widgets_changed)
95 self.abspeak = abspeak.AbspeakWidget()
96 self.abspeak.connect("reset", self.on_abspeak_reset)
97 self.abspeak.connect("volume-adjust", self.on_abspeak_adjust)
99 self.volume_digits = gtk.Entry()
100 self.volume_digits.connect("key-press-event", self.on_volume_digits_key_pressed)
101 self.volume_digits.connect("focus-out-event", self.on_volume_digits_focus_out)
103 self.connect("key-press-event", self.on_key_pressed)
104 self.connect("scroll-event", self.on_scroll)
107 #print "Unrealizing channel \"%s\"" % self.channel_name
110 def create_balance_widget(self):
111 if self.gui_factory.use_custom_widgets and phat:
112 self.balance = phat.HFanSlider()
113 self.balance.set_default_value(0)
114 self.balance.set_adjustment(self.balance_adjustment)
116 self.balance = gtk.HScale(self.balance_adjustment)
117 self.balance.set_draw_value(False)
118 self.pack_start(self.balance, False)
119 if self.monitor_button:
120 self.reorder_child(self.monitor_button, -1)
123 def create_slider_widget(self):
126 parent = self.slider.get_parent()
127 self.slider.destroy()
128 if self.gui_factory.use_custom_widgets:
129 self.slider = slider.CustomSliderWidget(self.slider_adjustment)
131 self.slider = slider.GtkSlider(self.slider_adjustment)
133 parent.pack_start(self.slider)
134 parent.reorder_child(self.slider, 0)
137 def on_default_meter_scale_changed(self, gui_factory, scale):
138 #print "Default meter scale change detected."
139 self.meter.set_scale(scale)
141 def on_default_slider_scale_changed(self, gui_factory, scale):
142 #print "Default slider scale change detected."
143 self.slider_scale = scale
144 self.slider_adjustment.set_scale(scale)
145 self.channel.midi_scale = self.slider_scale.scale
147 def on_vumeter_color_changed(self, gui_factory, *args):
148 color = gui_factory.get_vumeter_color()
149 color_scheme = gui_factory.get_vumeter_color_scheme()
150 if color_scheme != 'solid':
151 self.meter.set_color(None)
153 self.meter.set_color(gtk.gdk.color_parse(color))
155 def on_custom_widgets_changed(self, gui_factory, value):
156 self.balance.destroy()
157 self.create_balance_widget()
158 self.create_slider_widget()
160 def on_abspeak_adjust(self, abspeak, adjust):
161 #print "abspeak adjust %f" % adjust
162 self.slider_adjustment.set_value_db(self.slider_adjustment.get_value_db() + adjust)
163 self.channel.abspeak = None
164 #self.update_volume(False) # We want to update gui even if actual decibels have not changed (scale wrap for example)
166 def on_abspeak_reset(self, abspeak):
167 #print "abspeak reset"
168 self.channel.abspeak = None
170 def on_volume_digits_key_pressed(self, widget, event):
171 if (event.keyval == gtk.keysyms.Return or event.keyval == gtk.keysyms.KP_Enter):
172 db_text = self.volume_digits.get_text()
175 #print "Volume digits confirmation \"%f dBFS\"" % db
176 except (ValueError), e:
177 #print "Volume digits confirmation ignore, reset to current"
178 self.update_volume(False)
180 self.slider_adjustment.set_value_db(db)
182 #self.update_volume(False) # We want to update gui even if actual decibels have not changed (scale wrap for example)
184 def on_volume_digits_focus_out(self, widget, event):
185 #print "volume digits focus out detected"
186 self.update_volume(False)
188 def read_meter(self):
192 meter_left, meter_right = self.channel.meter
193 self.meter.set_values(meter_left, meter_right)
195 self.meter.set_value(self.channel.meter[0])
197 self.abspeak.set_peak(self.channel.abspeak)
199 def on_scroll(self, widget, event):
200 if event.direction == gtk.gdk.SCROLL_DOWN:
201 self.slider_adjustment.step_down()
202 elif event.direction == gtk.gdk.SCROLL_UP:
203 self.slider_adjustment.step_up()
206 def update_volume(self, update_engine):
207 db = self.slider_adjustment.get_value_db()
209 db_text = "%.2f" % db
210 self.volume_digits.set_text(db_text)
213 self.channel.volume = db
214 self.app.update_monitor(self)
216 def on_volume_changed(self, adjustment):
217 self.update_volume(True)
219 def on_balance_changed(self, adjustment):
220 balance = self.balance_adjustment.get_value()
221 #print "%s balance: %f" % (self.channel_name, balance)
222 self.channel.balance = balance
223 self.app.update_monitor(self)
225 def on_key_pressed(self, widget, event):
226 if (event.keyval == gtk.keysyms.Up):
227 #print self.channel_name + " Up"
228 self.slider_adjustment.step_up()
230 elif (event.keyval == gtk.keysyms.Down):
231 #print self.channel_name + " Down"
232 self.slider_adjustment.step_down()
237 def serialize(self, object_backend):
238 object_backend.add_property("volume", "%f" % self.slider_adjustment.get_value_db())
239 object_backend.add_property("balance", "%f" % self.balance_adjustment.get_value())
241 if hasattr(self.channel, 'out_mute'):
242 object_backend.add_property('out_mute', str(self.channel.out_mute))
243 if self.channel.volume_midi_cc != -1:
244 object_backend.add_property('volume_midi_cc', str(self.channel.volume_midi_cc))
245 if self.channel.balance_midi_cc != -1:
246 object_backend.add_property('balance_midi_cc', str(self.channel.balance_midi_cc))
247 if self.channel.mute_midi_cc != -1:
248 object_backend.add_property('mute_midi_cc', str(self.channel.mute_midi_cc))
249 if self.channel.solo_midi_cc != -1:
250 object_backend.add_property('solo_midi_cc', str(self.channel.solo_midi_cc))
253 def unserialize_property(self, name, value):
255 self.slider_adjustment.set_value_db(float(value))
257 if name == "balance":
258 self.balance_adjustment.set_value(float(value))
260 if name == 'out_mute':
261 self.future_out_mute = (value == 'True')
263 if name == 'volume_midi_cc':
264 self.future_volume_midi_cc = int(value)
266 if name == 'balance_midi_cc':
267 self.future_balance_midi_cc = int(value)
269 if name == 'mute_midi_cc':
270 self.future_mute_midi_cc = int(value)
272 if name == 'solo_midi_cc':
273 self.future_solo_midi_cc = int(value)
277 def on_midi_event_received(self, *args):
278 self.slider_adjustment.set_value_db(self.channel.volume)
279 self.balance_adjustment.set_value(self.channel.balance)
281 def on_monitor_button_toggled(self, button):
282 if button.get_active():
283 for channel in self.app.channels + self.app.output_channels:
284 if channel.monitor_button.get_active() and channel.monitor_button is not button:
285 channel.monitor_button.handler_block_by_func(
286 channel.on_monitor_button_toggled)
287 channel.monitor_button.set_active(False)
288 channel.monitor_button.handler_unblock_by_func(
289 channel.on_monitor_button_toggled)
290 self.app.set_monitored_channel(self)
292 def set_monitored(self):
294 self.app.set_monitored_channel(self)
295 self.monitor_button.set_active(True)
297 class InputChannel(Channel):
298 post_fader_output_channel = None
300 def __init__(self, app, name, stereo):
301 Channel.__init__(self, app, name, stereo)
304 self.channel = self.mixer.add_channel(self.channel_name, self.stereo)
305 if self.channel == None:
306 raise Exception,"Cannot create a channel"
307 Channel.realize(self)
308 if self.future_volume_midi_cc != None:
309 self.channel.volume_midi_cc = self.future_volume_midi_cc
310 if self.future_balance_midi_cc != None:
311 self.channel.balance_midi_cc = self.future_balance_midi_cc
312 if self.future_mute_midi_cc != None:
313 self.channel.mute_midi_cc = self.future_mute_midi_cc
314 if self.future_solo_midi_cc != None:
315 self.channel.solo_midi_cc = self.future_solo_midi_cc
316 if self.app._init_solo_channels and self.channel_name in self.app._init_solo_channels:
317 self.channel.solo = True
319 self.channel.midi_scale = self.slider_scale.scale
321 self.on_volume_changed(self.slider_adjustment)
322 self.on_balance_changed(self.balance_adjustment)
324 # vbox child at upper part
325 self.vbox = gtk.VBox()
326 self.pack_start(self.vbox, False)
327 self.label_name = gtk.Label()
328 self.label_name.set_text(self.channel_name)
329 self.label_name.set_size_request(0, -1)
330 self.label_name_event_box = gtk.EventBox()
331 self.label_name_event_box.connect("button-press-event", self.on_label_mouse)
332 self.label_name_event_box.add(self.label_name)
333 self.vbox.pack_start(self.label_name_event_box, True)
334 # self.label_stereo = gtk.Label()
336 # self.label_stereo.set_text("stereo")
338 # self.label_stereo.set_text("mono")
339 # self.label_stereo.set_size_request(0, -1)
340 # self.vbox.pack_start(self.label_stereo, True)
342 self.hbox_mutesolo = gtk.HBox()
344 self.mute = gtk.ToggleButton()
345 self.mute.set_label("M")
346 self.mute.set_active(self.channel.out_mute)
347 self.mute.connect("toggled", self.on_mute_toggled)
348 self.hbox_mutesolo.pack_start(self.mute, True)
350 self.solo = gtk.ToggleButton()
351 self.solo.set_label("S")
352 self.solo.set_active(self.channel.solo)
353 self.solo.connect("toggled", self.on_solo_toggled)
354 self.hbox_mutesolo.pack_start(self.solo, True)
356 self.vbox.pack_start(self.hbox_mutesolo, False)
359 frame.set_shadow_type(gtk.SHADOW_IN)
360 frame.add(self.abspeak);
361 self.pack_start(frame, False)
363 # hbox child at lower part
364 self.hbox = gtk.HBox()
365 self.hbox.pack_start(self.slider, True)
367 frame.set_shadow_type(gtk.SHADOW_IN)
368 frame.add(self.meter);
369 self.hbox.pack_start(frame, True)
371 frame.set_shadow_type(gtk.SHADOW_IN)
372 frame.add(self.hbox);
373 self.pack_start(frame, True)
375 self.volume_digits.set_size_request(0, -1)
376 self.pack_start(self.volume_digits, False)
378 self.create_balance_widget()
380 self.monitor_button = gtk.ToggleButton('MON')
381 self.monitor_button.connect('toggled', self.on_monitor_button_toggled)
382 self.pack_start(self.monitor_button, False, False)
384 def add_control_group(self, channel):
385 control_group = ControlGroup(channel, self)
386 control_group.show_all()
387 self.vbox.pack_start(control_group, False)
390 def remove_control_group(self, channel):
391 ctlgroup = self.get_control_group(channel)
392 self.vbox.remove(ctlgroup)
394 def update_control_group(self, channel):
395 for control_group in self.vbox.get_children():
396 if isinstance(control_group, ControlGroup):
397 if control_group.output_channel is channel:
398 control_group.update()
400 def get_control_group(self, channel):
401 for control_group in self.vbox.get_children():
402 if isinstance(control_group, ControlGroup):
403 if control_group.output_channel is channel:
408 Channel.unrealize(self)
409 if self.post_fader_output_channel:
410 self.post_fader_output_channel.remove()
411 self.post_fader_output_channel = None
412 self.channel.remove()
415 channel_properties_dialog = None
416 def on_channel_properties(self):
417 if not self.channel_properties_dialog:
418 self.channel_properties_dialog = ChannelPropertiesDialog(self, self.app)
419 self.channel_properties_dialog.show()
420 self.channel_properties_dialog.present()
422 def on_label_mouse(self, widget, event):
423 if event.type == gtk.gdk._2BUTTON_PRESS:
424 if event.button == 1:
425 self.on_channel_properties()
427 def on_mute_toggled(self, button):
428 self.channel.out_mute = self.mute.get_active()
430 def on_solo_toggled(self, button):
431 self.channel.solo = self.solo.get_active()
433 def midi_events_check(self):
434 if self.channel.midi_in_got_events:
435 self.mute.set_active(self.channel.out_mute)
436 self.solo.set_active(self.channel.solo)
437 Channel.on_midi_event_received(self)
439 def on_solo_button_pressed(self, button, event, *args):
440 if event.button == 3:
441 # right click on the solo button, act on all output channels
442 if button.get_active(): # was soloed
443 button.set_active(False)
444 if hasattr(button, 'touched_channels'):
445 touched_channels = button.touched_channels
446 for chan in touched_channels:
447 ctlgroup = self.get_control_group(chan)
448 ctlgroup.solo.set_active(False)
449 del button.touched_channels
450 else: # was not soloed
451 button.set_active(True)
452 touched_channels = []
453 for chan in self.app.output_channels:
454 ctlgroup = self.get_control_group(chan)
455 if not ctlgroup.solo.get_active():
456 ctlgroup.solo.set_active(True)
457 touched_channels.append(chan)
458 button.touched_channels = touched_channels
463 def serialization_name(cls):
464 return 'input_channel'
466 def serialize(self, object_backend):
467 object_backend.add_property("name", self.channel_name)
469 object_backend.add_property("type", "stereo")
471 object_backend.add_property("type", "mono")
472 Channel.serialize(self, object_backend)
474 def unserialize_property(self, name, value):
476 self.channel_name = str(value)
479 if value == "stereo":
485 return Channel.unserialize_property(self, name, value)
488 available_colours = [
489 ('#ef2929', '#cc0000', '#840000'),
490 ('#729fcf', '#3465a4', '#204a67'),
491 ('#8aa234', '#73d216', '#4e7a06'),
492 ('#fce84f', '#edd400', '#c48000'),
493 ('#fcaf3e', '#f57900', '#ae5c00'),
494 ('#ad7fa8', '#75507b', '#4c3556'),
495 ('#e9b96e', '#c17d11', '#6f4902'),
498 class OutputChannel(Channel):
499 colours = available_colours[:]
500 _display_solo_buttons = False
502 _init_muted_channels = None
503 _init_solo_channels = None
505 def __init__(self, app, name, stereo):
506 Channel.__init__(self, app, name, stereo)
508 def get_display_solo_buttons(self):
509 return self._display_solo_buttons
511 def set_display_solo_buttons(self, value):
512 self._display_solo_buttons = value
513 # notifying control groups
514 for inputchannel in self.app.channels:
515 inputchannel.update_control_group(self)
517 display_solo_buttons = property(get_display_solo_buttons, set_display_solo_buttons)
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)
524 if self.future_volume_midi_cc != None:
525 self.channel.volume_midi_cc = self.future_volume_midi_cc
526 if self.future_balance_midi_cc != None:
527 self.channel.balance_midi_cc = self.future_balance_midi_cc
528 if self.future_mute_midi_cc != None:
529 self.channel.mute_midi_cc = self.future_mute_midi_cc
530 self.channel.midi_scale = self.slider_scale.scale
532 self.on_volume_changed(self.slider_adjustment)
533 self.on_balance_changed(self.balance_adjustment)
535 # vbox child at upper part
536 self.vbox = gtk.VBox()
537 self.pack_start(self.vbox, False)
538 self.label_name = gtk.Label()
539 self.label_name.set_text(self.channel_name)
540 self.label_name.set_size_request(0, -1)
541 self.label_name_event_box = gtk.EventBox()
542 self.label_name_event_box.connect('button-press-event', self.on_label_mouse)
543 self.label_name_event_box.add(self.label_name)
545 OutputChannel.colours = available_colours[:]
546 for color in self.colours:
547 self.color_tuple = [gtk.gdk.color_parse(color[x]) for x in range(3)]
548 self.colours.remove(color)
550 self.label_name_event_box.modify_bg(gtk.STATE_NORMAL, self.color_tuple[1])
551 self.vbox.pack_start(self.label_name_event_box, True)
552 self.mute = gtk.ToggleButton()
553 self.mute.set_label("M")
554 self.mute.set_active(self.channel.out_mute)
555 self.mute.connect("toggled", self.on_mute_toggled)
556 self.vbox.pack_start(self.mute, False)
559 frame.set_shadow_type(gtk.SHADOW_IN)
560 frame.add(self.abspeak);
561 self.vbox.pack_start(frame, False)
563 # hbox child at lower part
564 self.hbox = gtk.HBox()
565 self.hbox.pack_start(self.slider, True)
567 frame.set_shadow_type(gtk.SHADOW_IN)
568 frame.add(self.meter);
569 self.hbox.pack_start(frame, True)
571 frame.set_shadow_type(gtk.SHADOW_IN)
572 frame.add(self.hbox);
573 self.pack_start(frame, True)
575 self.volume_digits.set_size_request(0, -1)
576 self.pack_start(self.volume_digits, False)
578 self.create_balance_widget()
580 self.monitor_button = gtk.ToggleButton('MON')
581 self.monitor_button.connect('toggled', self.on_monitor_button_toggled)
582 self.pack_start(self.monitor_button, False, False)
584 # add control groups to the input channels, and initialize them
586 for input_channel in self.app.channels:
587 ctlgroup = input_channel.add_control_group(self)
588 if self._init_muted_channels and input_channel.channel.name in self._init_muted_channels:
589 ctlgroup.mute.set_active(True)
590 if self._init_solo_channels and input_channel.channel.name in self._init_solo_channels:
591 ctlgroup.solo.set_active(True)
592 self._init_muted_channels = None
593 self._init_solo_channels = None
595 channel_properties_dialog = None
596 def on_channel_properties(self):
597 if not self.channel_properties_dialog:
598 self.channel_properties_dialog = OutputChannelPropertiesDialog(self, self.app)
599 self.channel_properties_dialog.show()
600 self.channel_properties_dialog.present()
602 def on_label_mouse(self, widget, event):
603 if event.type == gtk.gdk._2BUTTON_PRESS:
604 if event.button == 1:
605 self.on_channel_properties()
607 def on_mute_toggled(self, button):
608 self.channel.out_mute = self.mute.get_active()
610 def midi_events_check(self):
611 if self.channel.midi_in_got_events:
612 self.mute.set_active(self.channel.out_mute)
613 Channel.on_midi_event_received(self)
616 # remove control groups from input channels
617 for input_channel in self.app.channels:
618 input_channel.remove_control_group(self)
620 Channel.unrealize(self)
621 self.channel.remove()
625 def serialization_name(cls):
626 return 'output_channel'
628 def serialize(self, object_backend):
629 object_backend.add_property("name", self.channel_name)
631 object_backend.add_property("type", "stereo")
633 object_backend.add_property("type", "mono")
634 if self.display_solo_buttons:
635 object_backend.add_property("solo_buttons", "true")
638 for input_channel in self.app.channels:
639 if self.channel.is_muted(input_channel.channel):
640 muted_channels.append(input_channel)
641 if self.channel.is_solo(input_channel.channel):
642 solo_channels.append(input_channel)
644 object_backend.add_property('muted_channels', '|'.join([x.channel.name for x in muted_channels]))
646 object_backend.add_property('solo_channels', '|'.join([x.channel.name for x in solo_channels]))
647 Channel.serialize(self, object_backend)
649 def unserialize_property(self, name, value):
651 self.channel_name = str(value)
654 if value == "stereo":
660 if name == "solo_buttons":
662 self.display_solo_buttons = True
664 if name == 'muted_channels':
665 self._init_muted_channels = value.split('|')
667 if name == 'solo_channels':
668 self._init_solo_channels = value.split('|')
670 return Channel.unserialize_property(self, name, value)
672 class ChannelPropertiesDialog(gtk.Dialog):
675 def __init__(self, parent, app):
676 self.channel = parent
678 self.mixer = self.channel.mixer
679 gtk.Dialog.__init__(self,
680 'Channel "%s" Properties' % self.channel.channel_name,
681 self.channel.gui_factory.topwindow)
683 self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
684 self.ok_button = self.add_button(gtk.STOCK_APPLY, gtk.RESPONSE_APPLY)
685 self.set_default_response(gtk.RESPONSE_APPLY);
690 self.connect('response', self.on_response_cb)
691 self.connect('delete-event', self.on_response_cb)
693 def create_frame(self, label, child):
694 frame = gtk.Frame('')
695 frame.set_border_width(3)
696 #frame.set_shadow_type(gtk.SHADOW_NONE)
697 frame.get_label_widget().set_markup('<b>%s</b>' % label)
699 alignment = gtk.Alignment(0, 0, 1, 1)
700 alignment.set_padding(0, 0, 12, 0)
710 table = gtk.Table(2, 3, False)
711 vbox.pack_start(self.create_frame('Properties', table))
712 table.set_row_spacings(5)
713 table.set_col_spacings(5)
715 table.attach(gtk.Label('Name'), 0, 1, 0, 1)
716 self.entry_name = gtk.Entry()
717 self.entry_name.set_activates_default(True)
718 self.entry_name.connect('changed', self.on_entry_name_changed)
719 table.attach(self.entry_name, 1, 2, 0, 1)
721 table.attach(gtk.Label('Mode'), 0, 1, 1, 2)
722 self.mode_hbox = gtk.HBox()
723 table.attach(self.mode_hbox, 1, 2, 1, 2)
724 self.mono = gtk.RadioButton(label='Mono')
725 self.stereo = gtk.RadioButton(label='Stereo', group=self.mono)
726 self.mode_hbox.pack_start(self.mono)
727 self.mode_hbox.pack_start(self.stereo)
729 table = gtk.Table(2, 3, False)
730 vbox.pack_start(self.create_frame('MIDI Control Channels', table))
731 table.set_row_spacings(5)
732 table.set_col_spacings(5)
734 table.attach(gtk.Label('Volume'), 0, 1, 0, 1)
735 self.entry_volume_cc = gtk.Entry()
736 self.entry_volume_cc.set_activates_default(True)
737 self.entry_volume_cc.set_editable(False)
738 self.entry_volume_cc.set_width_chars(3)
739 table.attach(self.entry_volume_cc, 1, 2, 0, 1)
740 self.button_sense_midi_volume = gtk.Button('Autoset')
741 self.button_sense_midi_volume.connect('clicked',
742 self.on_sense_midi_volume_clicked)
743 table.attach(self.button_sense_midi_volume, 2, 3, 0, 1)
745 table.attach(gtk.Label('Balance'), 0, 1, 1, 2)
746 self.entry_balance_cc = gtk.Entry()
747 self.entry_balance_cc.set_activates_default(True)
748 self.entry_balance_cc.set_width_chars(3)
749 self.entry_balance_cc.set_editable(False)
750 table.attach(self.entry_balance_cc, 1, 2, 1, 2)
751 self.button_sense_midi_balance = gtk.Button('Autoset')
752 self.button_sense_midi_balance.connect('clicked',
753 self.on_sense_midi_balance_clicked)
754 table.attach(self.button_sense_midi_balance, 2, 3, 1, 2)
756 table.attach(gtk.Label('Mute'), 0, 1, 2, 3)
757 self.entry_mute_cc = gtk.Entry()
758 self.entry_mute_cc.set_activates_default(True)
759 self.entry_mute_cc.set_editable(False)
760 self.entry_mute_cc.set_width_chars(3)
761 table.attach(self.entry_mute_cc, 1, 2, 2, 3)
762 self.button_sense_midi_mute = gtk.Button('Autoset')
763 self.button_sense_midi_mute.connect('clicked',
764 self.on_sense_midi_mute_clicked)
765 table.attach(self.button_sense_midi_mute, 2, 3, 2, 3)
767 if (isinstance(self, NewChannelDialog) or (self.channel and
768 isinstance(self.channel, InputChannel))):
769 table.attach(gtk.Label('Solo'), 0, 1, 3, 4)
770 self.entry_solo_cc = gtk.Entry()
771 self.entry_solo_cc.set_activates_default(True)
772 self.entry_solo_cc.set_editable(False)
773 self.entry_solo_cc.set_width_chars(3)
774 table.attach(self.entry_solo_cc, 1, 2, 3, 4)
775 self.button_sense_midi_solo = gtk.Button('Autoset')
776 self.button_sense_midi_solo.connect('clicked',
777 self.on_sense_midi_solo_clicked)
778 table.attach(self.button_sense_midi_solo, 2, 3, 3, 4)
783 self.entry_name.set_text(self.channel.channel_name)
784 if self.channel.channel.is_stereo:
785 self.stereo.set_active(True)
787 self.mono.set_active(True)
788 self.mode_hbox.set_sensitive(False)
789 self.entry_volume_cc.set_text('%s' % self.channel.channel.volume_midi_cc)
790 self.entry_balance_cc.set_text('%s' % self.channel.channel.balance_midi_cc)
791 self.entry_mute_cc.set_text('%s' % self.channel.channel.mute_midi_cc)
792 if (self.channel and isinstance(self.channel, InputChannel)):
793 self.entry_solo_cc.set_text('%s' % self.channel.channel.solo_midi_cc)
795 def sense_popup_dialog(self, entry):
796 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
797 window.set_destroy_with_parent(True)
798 window.set_transient_for(self)
799 window.set_decorated(False)
800 window.set_modal(True)
801 window.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
802 window.set_border_width(10)
807 vbox.pack_start(gtk.Label('Please move the MIDI control you want to use for this function.'))
808 timeout_label = gtk.Label('This window will close in 5 seconds')
809 vbox.pack_start(timeout_label)
810 def close_sense_timeout(window, entry):
812 timeout_label.set_text('This window will close in %d seconds.' % window.timeout)
813 if window.timeout == 0:
815 entry.set_text('%s' % self.mixer.last_midi_channel)
819 gobject.timeout_add_seconds(1, close_sense_timeout, window, entry)
821 def on_sense_midi_volume_clicked(self, *args):
822 self.mixer.last_midi_channel = int(self.entry_volume_cc.get_text())
823 self.sense_popup_dialog(self.entry_volume_cc)
825 def on_sense_midi_balance_clicked(self, *args):
826 self.mixer.last_midi_channel = int(self.entry_balance_cc.get_text())
827 self.sense_popup_dialog(self.entry_balance_cc)
829 def on_sense_midi_mute_clicked(self, *args):
830 self.mixer.last_midi_channel = int(self.entry_mute_cc.get_text())
831 self.sense_popup_dialog(self.entry_mute_cc)
833 def on_sense_midi_solo_clicked(self, *args):
834 self.mixer.last_midi_channel = int(self.entry_solo_cc.get_text())
835 self.sense_popup_dialog(self.entry_solo_cc)
837 def on_response_cb(self, dlg, response_id, *args):
838 self.channel.channel_properties_dialog = None
839 name = self.entry_name.get_text()
840 if response_id == gtk.RESPONSE_APPLY:
841 self.channel.channel_name = name
843 if self.entry_volume_cc.get_text() != '-1':
844 self.channel.channel.volume_midi_cc = int(self.entry_volume_cc.get_text())
848 if self.entry_balance_cc.get_text() != '-1':
849 self.channel.channel.balance_midi_cc = int(self.entry_balance_cc.get_text())
853 if self.entry_mute_cc.get_text() != '-1':
854 self.channel.channel.mute_midi_cc = int(self.entry_mute_cc.get_text())
858 if hasattr(self, 'entry_solo_cc') and self.entry_solo_cc.get_text() != '-1':
859 self.channel.channel.solo_midi_cc = int(self.entry_solo_cc.get_text())
864 def on_entry_name_changed(self, entry):
866 if len(entry.get_text()):
867 if self.channel and self.channel.channel.name == entry.get_text():
869 elif entry.get_text() not in [x.channel.name for x in self.app.channels] + \
870 [x.channel.name for x in self.app.output_channels] + ['MAIN']:
872 self.ok_button.set_sensitive(sensitive)
875 class NewChannelDialog(ChannelPropertiesDialog):
876 def __init__(self, app):
877 gtk.Dialog.__init__(self, 'New Channel', app.window)
878 self.mixer = app.mixer
883 self.stereo.set_active(True) # default to stereo
885 self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
886 self.ok_button = self.add_button(gtk.STOCK_ADD, gtk.RESPONSE_OK)
887 self.ok_button.set_sensitive(False)
888 self.set_default_response(gtk.RESPONSE_OK);
891 self.entry_volume_cc.set_text('-1')
892 self.entry_balance_cc.set_text('-1')
893 self.entry_mute_cc.set_text('-1')
894 self.entry_solo_cc.set_text('-1')
896 def get_result(self):
897 return {'name': self.entry_name.get_text(),
898 'stereo': self.stereo.get_active(),
899 'volume_cc': self.entry_volume_cc.get_text(),
900 'balance_cc': self.entry_balance_cc.get_text(),
901 'mute_cc': self.entry_mute_cc.get_text(),
902 'solo_cc': self.entry_solo_cc.get_text()
905 class OutputChannelPropertiesDialog(ChannelPropertiesDialog):
907 ChannelPropertiesDialog.create_ui(self)
910 self.vbox.pack_start(self.create_frame('Input Channels', vbox))
912 self.display_solo_buttons = gtk.CheckButton('Display solo buttons')
913 vbox.pack_start(self.display_solo_buttons)
918 ChannelPropertiesDialog.fill_ui(self)
919 self.display_solo_buttons.set_active(self.channel.display_solo_buttons)
921 def on_response_cb(self, dlg, response_id, *args):
922 if response_id == gtk.RESPONSE_APPLY:
923 self.channel.display_solo_buttons = self.display_solo_buttons.get_active()
924 ChannelPropertiesDialog.on_response_cb(self, dlg, response_id, *args)
927 class NewOutputChannelDialog(OutputChannelPropertiesDialog):
928 def __init__(self, app):
929 gtk.Dialog.__init__(self, 'New Output Channel', app.window)
930 self.mixer = app.mixer
935 # TODO: disable mode for output channels as mono output channels may
936 # not be correctly handled yet.
937 self.mode_hbox.set_sensitive(False)
938 self.stereo.set_active(True) # default to stereo
940 self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
941 self.ok_button = self.add_button(gtk.STOCK_ADD, gtk.RESPONSE_OK)
942 self.ok_button.set_sensitive(False)
943 self.set_default_response(gtk.RESPONSE_OK);
946 self.entry_volume_cc.set_text('-1')
947 self.entry_balance_cc.set_text('-1')
948 self.entry_mute_cc.set_text('-1')
950 def get_result(self):
951 return {'name': self.entry_name.get_text(),
952 'stereo': self.stereo.get_active(),
953 'volume_cc': self.entry_volume_cc.get_text(),
954 'balance_cc': self.entry_balance_cc.get_text(),
955 'mute_cc': self.entry_mute_cc.get_text(),
956 'display_solo_buttons': self.display_solo_buttons.get_active(),
960 class ControlGroup(gtk.Alignment):
961 def __init__(self, output_channel, input_channel):
962 gtk.Alignment.__init__(self, 0.5, 0.5, 0, 0)
963 self.output_channel = output_channel
964 self.input_channel = input_channel
965 self.app = input_channel.app
971 mute = gtk.ToggleButton()
974 mute.connect("toggled", self.on_mute_toggled)
975 muteevent = gtk.EventBox()
977 hbox.pack_start(muteevent, False)
979 solo = gtk.ToggleButton()
982 solo.connect("toggled", self.on_solo_toggled)
983 soloevent = gtk.EventBox()
985 if self.output_channel.display_solo_buttons:
986 hbox.pack_start(soloevent, True)
988 print output_channel.color_tuple
989 muteevent.modify_bg(gtk.STATE_PRELIGHT, output_channel.color_tuple[0])
990 muteevent.modify_bg(gtk.STATE_NORMAL, output_channel.color_tuple[1])
991 muteevent.modify_bg(gtk.STATE_ACTIVE, output_channel.color_tuple[2])
992 soloevent.modify_bg(gtk.STATE_PRELIGHT, output_channel.color_tuple[0])
993 soloevent.modify_bg(gtk.STATE_NORMAL, output_channel.color_tuple[1])
994 soloevent.modify_bg(gtk.STATE_ACTIVE, output_channel.color_tuple[2])
997 if self.output_channel.display_solo_buttons:
998 if not self.solo in self.hbox.get_children():
999 self.hbox.pack_start(self.solo, True)
1002 if self.solo in self.hbox.get_children():
1003 self.hbox.remove(self.solo)
1005 def on_mute_toggled(self, button):
1006 self.output_channel.channel.set_muted(self.input_channel.channel, button.get_active())
1007 self.app.update_monitor(self)
1009 def on_solo_toggled(self, button):
1010 self.output_channel.channel.set_solo(self.input_channel.channel, button.get_active())
1011 self.app.update_monitor(self)