cleanup unused calc_channel_volumes funcs
[jack_mixer.git] / channel.py
blobc24702e09d3a38353fb7d1872551c8302f6d2fdb
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.
18 import gtk
19 import gobject
20 import slider
21 import meter
22 import abspeak
23 from serialization import SerializedObject
25 try:
26 import phat
27 except:
28 phat = None
31 class Channel(gtk.VBox, SerializedObject):
32 '''Widget with slider and meter used as base class for more specific
33 channel widgets'''
34 monitor_button = None
36 def __init__(self, app, name, stereo):
37 gtk.VBox.__init__(self)
38 self.app = app
39 self.mixer = app.mixer
40 self.gui_factory = app.gui_factory
41 self._channel_name = name
42 self.stereo = stereo
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_volume_midi_cc = None
48 self.future_balance_midi_cc = None
50 def get_channel_name(self):
51 return self._channel_name
53 label_name = None
54 channel = None
55 post_fader_output_channel = None
56 def set_channel_name(self, name):
57 self.app.on_channel_rename(self._channel_name, name);
58 self._channel_name = name
59 if self.label_name:
60 self.label_name.set_text(name)
61 if self.channel:
62 self.channel.name = name
63 if self.post_fader_output_channel:
64 self.post_fader_output_channel.name = "%s Out" % name;
65 channel_name = property(get_channel_name, set_channel_name)
67 def realize(self):
68 #print "Realizing channel \"%s\"" % self.channel_name
70 self.slider_adjustment.connect("volume-changed", self.on_volume_changed)
71 self.balance_adjustment.connect("value-changed", self.on_balance_changed)
73 self.slider = None
74 self.create_slider_widget()
76 if self.stereo:
77 self.meter = meter.StereoMeterWidget(self.meter_scale)
78 else:
79 self.meter = meter.MonoMeterWidget(self.meter_scale)
80 self.on_vumeter_color_changed(self.gui_factory)
82 self.meter.set_events(gtk.gdk.SCROLL_MASK)
84 self.gui_factory.connect("default-meter-scale-changed", self.on_default_meter_scale_changed)
85 self.gui_factory.connect("default-slider-scale-changed", self.on_default_slider_scale_changed)
86 self.gui_factory.connect('vumeter-color-changed', self.on_vumeter_color_changed)
87 self.gui_factory.connect('vumeter-color-scheme-changed', self.on_vumeter_color_changed)
88 self.gui_factory.connect('use-custom-widgets-changed', self.on_custom_widgets_changed)
90 self.abspeak = abspeak.AbspeakWidget()
91 self.abspeak.connect("reset", self.on_abspeak_reset)
92 self.abspeak.connect("volume-adjust", self.on_abspeak_adjust)
94 self.volume_digits = gtk.Entry()
95 self.volume_digits.connect("key-press-event", self.on_volume_digits_key_pressed)
96 self.volume_digits.connect("focus-out-event", self.on_volume_digits_focus_out)
98 self.connect("key-press-event", self.on_key_pressed)
99 self.connect("scroll-event", self.on_scroll)
101 def unrealize(self):
102 #print "Unrealizing channel \"%s\"" % self.channel_name
103 pass
105 def create_balance_widget(self):
106 if self.gui_factory.use_custom_widgets and phat:
107 self.balance = phat.HFanSlider()
108 self.balance.set_default_value(0)
109 self.balance.set_adjustment(self.balance_adjustment)
110 else:
111 self.balance = gtk.HScale(self.balance_adjustment)
112 self.balance.set_draw_value(False)
113 self.pack_start(self.balance, False)
114 if self.monitor_button:
115 self.reorder_child(self.monitor_button, -1)
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.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 not self.channel:
185 return
186 if self.stereo:
187 meter_left, meter_right = self.channel.meter
188 self.meter.set_values(meter_left, meter_right)
189 else:
190 self.meter.set_value(self.channel.meter[0])
192 self.abspeak.set_peak(self.channel.abspeak)
194 def on_scroll(self, widget, event):
195 if event.direction == gtk.gdk.SCROLL_DOWN:
196 self.slider_adjustment.step_down()
197 elif event.direction == gtk.gdk.SCROLL_UP:
198 self.slider_adjustment.step_up()
199 return True
201 def update_volume(self, update_engine):
202 db = self.slider_adjustment.get_value_db()
204 db_text = "%.2f" % db
205 self.volume_digits.set_text(db_text)
207 if update_engine:
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()
224 return True
225 elif (event.keyval == gtk.keysyms.Down):
226 #print self.channel_name + " Down"
227 self.slider_adjustment.step_down()
228 return True
230 return False
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):
242 if name == "volume":
243 self.slider_adjustment.set_value_db(float(value))
244 return True
245 if name == "balance":
246 self.balance_adjustment.set_value(float(value))
247 return True
248 if name == 'volume_midi_cc':
249 self.future_volume_midi_cc = int(value)
250 return True
251 if name == 'balance_midi_cc':
252 self.future_balance_midi_cc = int(value)
253 return True
254 return False
256 def midi_events_check(self):
257 if self.channel.midi_in_got_events:
258 self.slider_adjustment.set_value_db(self.channel.volume)
259 self.balance_adjustment.set_value(self.channel.balance)
261 def on_midi_event_received(self, *args):
262 self.slider_adjustment.set_value_db(self.channel.volume)
263 self.balance_adjustment.set_value(self.channel.balance)
265 def on_monitor_button_toggled(self, button):
266 if not button.get_active():
267 self.app.main_mix.monitor_button.set_active(True)
268 else:
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):
279 if self.channel:
280 self.app.set_monitored_channel(self)
281 self.monitor_button.set_active(True)
283 class InputChannel(Channel):
284 post_fader_output_channel = None
286 def __init__(self, app, name, stereo):
287 Channel.__init__(self, app, name, stereo)
289 def realize(self):
290 self.channel = self.mixer.add_channel(self.channel_name, self.stereo)
291 if self.channel == None:
292 raise Exception,"Cannot create a channel"
293 Channel.realize(self)
294 if self.future_volume_midi_cc:
295 self.channel.volume_midi_cc = self.future_volume_midi_cc
296 if self.future_balance_midi_cc:
297 self.channel.balance_midi_cc = self.future_balance_midi_cc
298 self.channel.midi_scale = self.slider_scale.scale
300 self.on_volume_changed(self.slider_adjustment)
301 self.on_balance_changed(self.balance_adjustment)
303 # vbox child at upper part
304 self.vbox = gtk.VBox()
305 self.pack_start(self.vbox, False)
306 self.label_name = gtk.Label()
307 self.label_name.set_text(self.channel_name)
308 self.label_name.set_size_request(0, -1)
309 self.label_name_event_box = gtk.EventBox()
310 self.label_name_event_box.connect("button-press-event", self.on_label_mouse)
311 self.label_name_event_box.add(self.label_name)
312 self.vbox.pack_start(self.label_name_event_box, True)
313 # self.label_stereo = gtk.Label()
314 # if self.stereo:
315 # self.label_stereo.set_text("stereo")
316 # else:
317 # self.label_stereo.set_text("mono")
318 # self.label_stereo.set_size_request(0, -1)
319 # self.vbox.pack_start(self.label_stereo, True)
321 # hbox for mute and solo buttons
322 self.hbox_mutesolo = gtk.HBox()
324 self.mute = gtk.ToggleButton()
325 self.mute.set_label("M")
326 self.mute.set_active(self.channel.mute)
327 self.mute.connect("button-press-event", self.on_mute_button_pressed)
328 self.mute.connect("toggled", self.on_mute_toggled)
329 self.hbox_mutesolo.pack_start(self.mute, True)
331 self.solo = gtk.ToggleButton()
332 self.solo.set_label("S")
333 self.solo.set_active(self.channel.solo)
334 self.solo.connect("button-press-event", self.on_solo_button_pressed)
335 self.solo.connect("toggled", self.on_solo_toggled)
336 self.hbox_mutesolo.pack_start(self.solo, True)
338 self.vbox.pack_start(self.hbox_mutesolo, False)
340 frame = gtk.Frame()
341 frame.set_shadow_type(gtk.SHADOW_IN)
342 frame.add(self.abspeak);
343 self.pack_start(frame, False)
345 # hbox child at lower part
346 self.hbox = gtk.HBox()
347 self.hbox.pack_start(self.slider, True)
348 frame = gtk.Frame()
349 frame.set_shadow_type(gtk.SHADOW_IN)
350 frame.add(self.meter);
351 self.hbox.pack_start(frame, True)
352 frame = gtk.Frame()
353 frame.set_shadow_type(gtk.SHADOW_IN)
354 frame.add(self.hbox);
355 self.pack_start(frame, True)
357 self.volume_digits.set_size_request(0, -1)
358 self.pack_start(self.volume_digits, False)
360 self.create_balance_widget()
362 self.monitor_button = gtk.ToggleButton('MON')
363 self.monitor_button.connect('toggled', self.on_monitor_button_toggled)
364 self.pack_start(self.monitor_button, False, False)
366 def add_control_group(self, channel):
367 control_group = ControlGroup(channel, self)
368 control_group.show_all()
369 self.vbox.pack_start(control_group, False)
370 return control_group
372 def remove_control_group(self, channel):
373 ctlgroup = self.get_control_group(channel)
374 self.vbox.remove(ctlgroup)
376 def update_control_group(self, channel):
377 for control_group in self.vbox.get_children():
378 if isinstance(control_group, ControlGroup):
379 if control_group.output_channel is channel:
380 control_group.update()
382 def get_control_group(self, channel):
383 for control_group in self.vbox.get_children():
384 if isinstance(control_group, ControlGroup):
385 if control_group.output_channel is channel:
386 return control_group
387 return None
389 def unrealize(self):
390 Channel.unrealize(self)
391 if self.post_fader_output_channel:
392 self.post_fader_output_channel.remove()
393 self.post_fader_output_channel = None
394 self.channel.remove()
395 self.channel = None
397 channel_properties_dialog = None
398 def on_channel_properties(self):
399 if not self.channel_properties_dialog:
400 self.channel_properties_dialog = ChannelPropertiesDialog(self, self.app)
401 self.channel_properties_dialog.show()
402 self.channel_properties_dialog.present()
404 def on_label_mouse(self, widget, event):
405 if event.type == gtk.gdk._2BUTTON_PRESS:
406 if event.button == 1:
407 self.on_channel_properties()
409 def on_mute_toggled(self, button):
410 self.channel.mute = self.mute.get_active()
411 self.app.update_monitor(self.app.main_mix)
413 def on_mute_button_pressed(self, button, event, *args):
414 if event.button == 3:
415 # right click on the mute button, act on all output channels
416 if button.get_active(): # was muted
417 button.set_active(False)
418 if hasattr(button, 'touched_channels'):
419 touched_channels = button.touched_channels
420 for chan in touched_channels:
421 ctlgroup = self.get_control_group(chan)
422 ctlgroup.mute.set_active(False)
423 del button.touched_channels
424 else: # was not muted
425 button.set_active(True)
426 touched_channels = []
427 for chan in self.app.output_channels:
428 ctlgroup = self.get_control_group(chan)
429 if not ctlgroup.mute.get_active():
430 ctlgroup.mute.set_active(True)
431 touched_channels.append(chan)
432 button.touched_channels = touched_channels
433 return True
434 return False
436 def on_solo_toggled(self, button):
437 self.channel.solo = self.solo.get_active()
438 self.app.update_monitor(self.app.main_mix)
440 def on_solo_button_pressed(self, button, event, *args):
441 if event.button == 3:
442 # right click on the solo button, act on all output channels
443 if button.get_active(): # was soloed
444 button.set_active(False)
445 if hasattr(button, 'touched_channels'):
446 touched_channels = button.touched_channels
447 for chan in touched_channels:
448 ctlgroup = self.get_control_group(chan)
449 ctlgroup.solo.set_active(False)
450 del button.touched_channels
451 else: # was not soloed
452 button.set_active(True)
453 touched_channels = []
454 for chan in self.app.output_channels:
455 ctlgroup = self.get_control_group(chan)
456 if not ctlgroup.solo.get_active():
457 ctlgroup.solo.set_active(True)
458 touched_channels.append(chan)
459 button.touched_channels = touched_channels
460 return True
461 return False
463 @classmethod
464 def serialization_name(cls):
465 return 'input_channel'
467 def serialize(self, object_backend):
468 object_backend.add_property("name", self.channel_name)
469 if self.stereo:
470 object_backend.add_property("type", "stereo")
471 else:
472 object_backend.add_property("type", "mono")
473 Channel.serialize(self, object_backend)
475 def unserialize_property(self, name, value):
476 if name == "name":
477 self.channel_name = str(value)
478 return True
479 if name == "type":
480 if value == "stereo":
481 self.stereo = True
482 return True
483 if value == "mono":
484 self.stereo = False
485 return True
486 return Channel.unserialize_property(self, name, value)
489 available_colours = [
490 ('#ef2929', '#cc0000', '#840000'),
491 ('#729fcf', '#3465a4', '#204a67'),
492 ('#8aa234', '#73d216', '#4e7a06'),
493 ('#fce84f', '#edd400', '#c48000'),
494 ('#fcaf3e', '#f57900', '#ae5c00'),
495 ('#ad7fa8', '#75507b', '#4c3556'),
496 ('#e9b96e', '#c17d11', '#6f4902'),
499 class OutputChannel(Channel):
500 colours = available_colours[:]
501 _display_solo_buttons = False
503 _init_muted_channels = None
504 _init_solo_channels = None
506 def __init__(self, app, name, stereo):
507 Channel.__init__(self, app, name, stereo)
509 def get_display_solo_buttons(self):
510 return self._display_solo_buttons
512 def set_display_solo_buttons(self, value):
513 self._display_solo_buttons = value
514 # notifying control groups
515 for inputchannel in self.app.channels:
516 inputchannel.update_control_group(self)
518 display_solo_buttons = property(get_display_solo_buttons, set_display_solo_buttons)
520 def realize(self):
521 Channel.realize(self)
522 self.channel = self.mixer.add_output_channel(self.channel_name, self.stereo)
523 if self.channel == None:
524 raise Exception,"Cannot create a channel"
525 Channel.realize(self)
527 self.channel.midi_scale = self.slider_scale.scale
529 self.on_volume_changed(self.slider_adjustment)
530 self.on_balance_changed(self.balance_adjustment)
532 # vbox child at upper part
533 self.vbox = gtk.VBox()
534 self.pack_start(self.vbox, False)
535 self.label_name = gtk.Label()
536 self.label_name.set_text(self.channel_name)
537 self.label_name.set_size_request(0, -1)
538 self.label_name_event_box = gtk.EventBox()
539 self.label_name_event_box.connect('button-press-event', self.on_label_mouse)
540 self.label_name_event_box.add(self.label_name)
541 if not self.colours:
542 OutputChannel.colours = available_colours[:]
543 for color in self.colours:
544 self.color_tuple = [gtk.gdk.color_parse(color[x]) for x in range(3)]
545 self.colours.remove(color)
546 break
547 self.label_name_event_box.modify_bg(gtk.STATE_NORMAL, self.color_tuple[1])
548 self.vbox.pack_start(self.label_name_event_box, True)
549 frame = gtk.Frame()
550 frame.set_shadow_type(gtk.SHADOW_IN)
551 frame.add(self.abspeak);
552 self.vbox.pack_start(frame, False)
554 # hbox child at lower part
555 self.hbox = gtk.HBox()
556 self.hbox.pack_start(self.slider, True)
557 frame = gtk.Frame()
558 frame.set_shadow_type(gtk.SHADOW_IN)
559 frame.add(self.meter);
560 self.hbox.pack_start(frame, True)
561 frame = gtk.Frame()
562 frame.set_shadow_type(gtk.SHADOW_IN)
563 frame.add(self.hbox);
564 self.pack_start(frame, True)
566 self.volume_digits.set_size_request(0, -1)
567 self.pack_start(self.volume_digits, False)
569 self.create_balance_widget()
571 self.monitor_button = gtk.ToggleButton('MON')
572 self.monitor_button.connect('toggled', self.on_monitor_button_toggled)
573 self.pack_start(self.monitor_button, False, False)
575 # add control groups to the input channels, and initialize them
576 # appropriately
577 for input_channel in self.app.channels:
578 ctlgroup = input_channel.add_control_group(self)
579 if self._init_muted_channels and input_channel.channel.name in self._init_muted_channels:
580 ctlgroup.mute.set_active(True)
581 if self._init_solo_channels and input_channel.channel.name in self._init_solo_channels:
582 ctlgroup.solo.set_active(True)
583 self._init_muted_channels = None
584 self._init_solo_channels = None
586 channel_properties_dialog = None
587 def on_channel_properties(self):
588 if not self.channel_properties_dialog:
589 self.channel_properties_dialog = OutputChannelPropertiesDialog(self, self.app)
590 self.channel_properties_dialog.show()
591 self.channel_properties_dialog.present()
593 def on_label_mouse(self, widget, event):
594 if event.type == gtk.gdk._2BUTTON_PRESS:
595 if event.button == 1:
596 self.on_channel_properties()
598 def unrealize(self):
599 # remove control groups from input channels
600 for input_channel in self.app.channels:
601 input_channel.remove_control_group(self)
602 # then remove itself
603 Channel.unrealize(self)
604 self.channel.remove()
605 self.channel = None
607 @classmethod
608 def serialization_name(cls):
609 return 'output_channel'
611 def serialize(self, object_backend):
612 object_backend.add_property("name", self.channel_name)
613 if self.stereo:
614 object_backend.add_property("type", "stereo")
615 else:
616 object_backend.add_property("type", "mono")
617 if self.display_solo_buttons:
618 object_backend.add_property("solo_buttons", "true")
619 muted_channels = []
620 solo_channels = []
621 for input_channel in self.app.channels:
622 if self.channel.is_muted(input_channel.channel):
623 muted_channels.append(input_channel)
624 if self.channel.is_solo(input_channel.channel):
625 solo_channels.append(input_channel)
626 if muted_channels:
627 object_backend.add_property('muted_channels', '|'.join([x.channel.name for x in muted_channels]))
628 if solo_channels:
629 object_backend.add_property('solo_channels', '|'.join([x.channel.name for x in solo_channels]))
630 Channel.serialize(self, object_backend)
632 def unserialize_property(self, name, value):
633 if name == "name":
634 self.channel_name = str(value)
635 return True
636 if name == "type":
637 if value == "stereo":
638 self.stereo = True
639 return True
640 if value == "mono":
641 self.stereo = False
642 return True
643 if name == "solo_buttons":
644 if value == "true":
645 self.display_solo_buttons = True
646 return True
647 if name == 'muted_channels':
648 self._init_muted_channels = value.split('|')
649 return True
650 if name == 'solo_channels':
651 self._init_solo_channels = value.split('|')
652 return True
653 return Channel.unserialize_property(self, name, value)
655 class MainMixChannel(Channel):
656 _init_muted_channels = None
657 _init_solo_channels = None
659 def __init__(self, app):
660 Channel.__init__(self, app, "MAIN", True)
662 def realize(self):
663 Channel.realize(self)
664 self.channel = self.mixer.main_mix_channel
665 self.channel.midi_scale = self.slider_scale.scale
667 self.on_volume_changed(self.slider_adjustment)
668 self.on_balance_changed(self.balance_adjustment)
670 # vbox child at upper part
671 self.vbox = gtk.VBox()
672 self.pack_start(self.vbox, False)
673 self.label_name = gtk.Label()
674 self.label_name.set_text(self.channel_name)
675 self.label_name.set_size_request(0, -1)
676 self.vbox.pack_start(self.label_name, False)
677 frame = gtk.Frame()
678 frame.set_shadow_type(gtk.SHADOW_IN)
679 frame.add(self.abspeak);
680 self.vbox.pack_start(frame, False)
682 # hbox child at lower part
683 self.hbox = gtk.HBox()
684 self.hbox.pack_start(self.slider, True)
685 frame = gtk.Frame()
686 frame.set_shadow_type(gtk.SHADOW_IN)
687 frame.add(self.meter);
688 self.hbox.pack_start(frame, True)
689 frame = gtk.Frame()
690 frame.set_shadow_type(gtk.SHADOW_IN)
691 frame.add(self.hbox);
692 self.pack_start(frame, True)
694 self.volume_digits.set_size_request(0, -1)
695 self.pack_start(self.volume_digits, False)
697 self.create_balance_widget()
699 self.monitor_button = gtk.ToggleButton('MON')
700 self.monitor_button.connect('toggled', self.on_monitor_button_toggled)
701 self.pack_start(self.monitor_button, False, False)
703 for input_channel in self.app.channels:
704 if self._init_muted_channels and input_channel.channel.name in self._init_muted_channels:
705 input_channel.mute.set_active(True)
706 if self._init_solo_channels and input_channel.channel.name in self._init_solo_channels:
707 input_channel.solo.set_active(True)
708 self._init_muted_channels = None
709 self._init_solo_channels = None
711 def unrealize(self):
712 Channel.unrealize(self)
713 self.channel = False
715 @classmethod
716 def serialization_name(cls):
717 return 'main_mix_channel'
719 def serialize(self, object_backend):
720 muted_channels = []
721 solo_channels = []
722 for input_channel in self.app.channels:
723 if input_channel.channel.mute:
724 muted_channels.append(input_channel)
725 if input_channel.channel.solo:
726 solo_channels.append(input_channel)
727 if muted_channels:
728 object_backend.add_property('muted_channels', '|'.join([x.channel.name for x in muted_channels]))
729 if solo_channels:
730 object_backend.add_property('solo_channels', '|'.join([x.channel.name for x in solo_channels]))
731 Channel.serialize(self, object_backend)
733 def unserialize_property(self, name, value):
734 if name == 'muted_channels':
735 self._init_muted_channels = value.split('|')
736 return True
737 if name == 'solo_channels':
738 self._init_solo_channels = value.split('|')
739 return True
740 return Channel.unserialize_property(self, name, value)
743 class ChannelPropertiesDialog(gtk.Dialog):
744 channel = None
746 def __init__(self, parent, app):
747 self.channel = parent
748 self.app = app
749 self.mixer = self.channel.mixer
750 gtk.Dialog.__init__(self,
751 'Channel "%s" Properties' % self.channel.channel_name,
752 self.channel.gui_factory.topwindow)
754 self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
755 self.ok_button = self.add_button(gtk.STOCK_APPLY, gtk.RESPONSE_APPLY)
756 self.set_default_response(gtk.RESPONSE_APPLY);
758 self.create_ui()
759 self.fill_ui()
761 self.connect('response', self.on_response_cb)
762 self.connect('delete-event', self.on_response_cb)
764 def create_frame(self, label, child):
765 frame = gtk.Frame('')
766 frame.set_border_width(3)
767 #frame.set_shadow_type(gtk.SHADOW_NONE)
768 frame.get_label_widget().set_markup('<b>%s</b>' % label)
770 alignment = gtk.Alignment(0, 0, 1, 1)
771 alignment.set_padding(0, 0, 12, 0)
772 frame.add(alignment)
773 alignment.add(child)
775 return frame
777 def create_ui(self):
778 vbox = gtk.VBox()
779 self.vbox.add(vbox)
781 table = gtk.Table(2, 2, False)
782 vbox.pack_start(self.create_frame('Properties', table))
783 table.set_row_spacings(5)
784 table.set_col_spacings(5)
786 table.attach(gtk.Label('Name'), 0, 1, 0, 1)
787 self.entry_name = gtk.Entry()
788 self.entry_name.set_activates_default(True)
789 self.entry_name.connect('changed', self.on_entry_name_changed)
790 table.attach(self.entry_name, 1, 2, 0, 1)
792 table.attach(gtk.Label('Mode'), 0, 1, 1, 2)
793 self.mode_hbox = gtk.HBox()
794 table.attach(self.mode_hbox, 1, 2, 1, 2)
795 self.mono = gtk.RadioButton(label='Mono')
796 self.stereo = gtk.RadioButton(label='Stereo', group=self.mono)
797 self.mode_hbox.pack_start(self.mono)
798 self.mode_hbox.pack_start(self.stereo)
800 table = gtk.Table(2, 3, False)
801 vbox.pack_start(self.create_frame('MIDI Control Channels', table))
802 table.set_row_spacings(5)
803 table.set_col_spacings(5)
805 table.attach(gtk.Label('Volume'), 0, 1, 0, 1)
806 self.entry_volume_cc = gtk.Entry()
807 self.entry_volume_cc.set_activates_default(True)
808 self.entry_volume_cc.set_editable(False)
809 self.entry_volume_cc.set_width_chars(3)
810 table.attach(self.entry_volume_cc, 1, 2, 0, 1)
811 self.button_sense_midi_volume = gtk.Button('Autoset')
812 self.button_sense_midi_volume.connect('clicked',
813 self.on_sense_midi_volume_clicked)
814 table.attach(self.button_sense_midi_volume, 2, 3, 0, 1)
816 table.attach(gtk.Label('Balance'), 0, 1, 1, 2)
817 self.entry_balance_cc = gtk.Entry()
818 self.entry_balance_cc.set_activates_default(True)
819 self.entry_balance_cc.set_width_chars(3)
820 self.entry_balance_cc.set_editable(False)
821 table.attach(self.entry_balance_cc, 1, 2, 1, 2)
822 self.button_sense_midi_balance = gtk.Button('Autoset')
823 self.button_sense_midi_balance.connect('clicked',
824 self.on_sense_midi_balance_clicked)
825 table.attach(self.button_sense_midi_balance, 2, 3, 1, 2)
827 self.vbox.show_all()
829 def fill_ui(self):
830 self.entry_name.set_text(self.channel.channel_name)
831 if self.channel.channel.is_stereo:
832 self.stereo.set_active(True)
833 else:
834 self.mono.set_active(True)
835 self.mode_hbox.set_sensitive(False)
836 self.entry_volume_cc.set_text('%s' % self.channel.channel.volume_midi_cc)
837 self.entry_balance_cc.set_text('%s' % self.channel.channel.balance_midi_cc)
839 def sense_popup_dialog(self, entry):
840 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
841 window.set_destroy_with_parent(True)
842 window.set_transient_for(self)
843 window.set_decorated(False)
844 window.set_modal(True)
845 window.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
846 window.set_border_width(10)
848 vbox = gtk.VBox(10)
849 window.add(vbox)
850 window.timeout = 5
851 vbox.pack_start(gtk.Label('Please move the MIDI control you want to use for this function.'))
852 timeout_label = gtk.Label('This window will close in 5 seconds')
853 vbox.pack_start(timeout_label)
854 def close_sense_timeout(window, entry):
855 window.timeout -= 1
856 timeout_label.set_text('This window will close in %d seconds.' % window.timeout)
857 if window.timeout == 0:
858 window.destroy()
859 entry.set_text('%s' % self.mixer.last_midi_channel)
860 return False
861 return True
862 window.show_all()
863 gobject.timeout_add_seconds(1, close_sense_timeout, window, entry)
865 def on_sense_midi_volume_clicked(self, *args):
866 self.sense_popup_dialog(self.entry_volume_cc)
868 def on_sense_midi_balance_clicked(self, *args):
869 self.sense_popup_dialog(self.entry_balance_cc)
871 def on_response_cb(self, dlg, response_id, *args):
872 self.channel.channel_properties_dialog = None
873 name = self.entry_name.get_text()
874 if response_id == gtk.RESPONSE_APPLY:
875 self.channel.channel_name = name
876 try:
877 self.channel.channel.volume_midi_cc = int(self.entry_volume_cc.get_text())
878 except ValueError:
879 pass
880 try:
881 self.channel.channel.balance_midi_cc = int(self.entry_balance_cc.get_text())
882 except ValueError:
883 pass
884 self.destroy()
886 def on_entry_name_changed(self, entry):
887 sensitive = False
888 if len(entry.get_text()):
889 if self.channel and self.channel.channel.name == entry.get_text():
890 sensitive = True
891 elif entry.get_text() not in [x.channel.name for x in self.app.channels] + \
892 [x.channel.name for x in self.app.output_channels] + ['MAIN']:
893 sensitive = True
894 self.ok_button.set_sensitive(sensitive)
897 class NewChannelDialog(ChannelPropertiesDialog):
898 def __init__(self, app):
899 gtk.Dialog.__init__(self, 'New Channel', app.window)
900 self.mixer = app.mixer
901 self.app = app
902 self.create_ui()
904 self.stereo.set_active(True) # default to stereo
906 self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
907 self.ok_button = self.add_button(gtk.STOCK_ADD, gtk.RESPONSE_OK)
908 self.ok_button.set_sensitive(False)
909 self.set_default_response(gtk.RESPONSE_OK);
911 def get_result(self):
912 return {'name': self.entry_name.get_text(),
913 'stereo': self.stereo.get_active(),
914 'volume_cc': self.entry_volume_cc.get_text(),
915 'balance_cc': self.entry_balance_cc.get_text()
918 class OutputChannelPropertiesDialog(ChannelPropertiesDialog):
919 def create_ui(self):
920 ChannelPropertiesDialog.create_ui(self)
922 vbox = gtk.VBox()
923 self.vbox.pack_start(self.create_frame('Input Channels', vbox))
925 self.display_solo_buttons = gtk.CheckButton('Display solo buttons')
926 vbox.pack_start(self.display_solo_buttons)
928 self.vbox.show_all()
930 def fill_ui(self):
931 ChannelPropertiesDialog.fill_ui(self)
932 self.display_solo_buttons.set_active(self.channel.display_solo_buttons)
934 def on_response_cb(self, dlg, response_id, *args):
935 if response_id == gtk.RESPONSE_APPLY:
936 self.channel.display_solo_buttons = self.display_solo_buttons.get_active()
937 ChannelPropertiesDialog.on_response_cb(self, dlg, response_id, *args)
940 class NewOutputChannelDialog(OutputChannelPropertiesDialog):
941 def __init__(self, app):
942 gtk.Dialog.__init__(self, 'New Output Channel', app.window)
943 self.mixer = app.mixer
944 self.app = app
945 self.create_ui()
947 # TODO: disable mode for output channels as mono output channels may
948 # not be correctly handled yet.
949 self.mode_hbox.set_sensitive(False)
950 self.stereo.set_active(True) # default to stereo
952 self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
953 self.ok_button = self.add_button(gtk.STOCK_ADD, gtk.RESPONSE_OK)
954 self.ok_button.set_sensitive(False)
955 self.set_default_response(gtk.RESPONSE_OK);
957 def get_result(self):
958 return {'name': self.entry_name.get_text(),
959 'stereo': self.stereo.get_active(),
960 'volume_cc': self.entry_volume_cc.get_text(),
961 'balance_cc': self.entry_balance_cc.get_text(),
962 'display_solo_buttons': self.display_solo_buttons.get_active(),
966 class ControlGroup(gtk.Alignment):
967 def __init__(self, output_channel, input_channel):
968 gtk.Alignment.__init__(self, 0.5, 0.5, 0, 0)
969 self.output_channel = output_channel
970 self.input_channel = input_channel
971 self.app = input_channel.app
973 hbox = gtk.HBox()
974 self.hbox = hbox
975 self.add(hbox)
977 mute = gtk.ToggleButton()
978 self.mute = mute
979 mute.set_label("M")
980 mute.connect("toggled", self.on_mute_toggled)
981 hbox.pack_start(mute, False)
983 solo = gtk.ToggleButton()
984 self.solo = solo
985 solo.set_label("S")
986 solo.connect("toggled", self.on_solo_toggled)
987 if self.output_channel.display_solo_buttons:
988 hbox.pack_start(solo, True)
990 mute.modify_bg(gtk.STATE_PRELIGHT, output_channel.color_tuple[0])
991 mute.modify_bg(gtk.STATE_NORMAL, output_channel.color_tuple[1])
992 mute.modify_bg(gtk.STATE_ACTIVE, output_channel.color_tuple[2])
993 solo.modify_bg(gtk.STATE_PRELIGHT, output_channel.color_tuple[0])
994 solo.modify_bg(gtk.STATE_NORMAL, output_channel.color_tuple[1])
995 solo.modify_bg(gtk.STATE_ACTIVE, output_channel.color_tuple[2])
997 def update(self):
998 if self.output_channel.display_solo_buttons:
999 if not self.solo in self.hbox.get_children():
1000 self.hbox.pack_start(self.solo, True)
1001 self.solo.show()
1002 else:
1003 if self.solo in self.hbox.get_children():
1004 self.hbox.remove(self.solo)
1006 def on_mute_toggled(self, button):
1007 self.output_channel.channel.set_muted(self.input_channel.channel, button.get_active())
1008 self.app.update_monitor(self)
1010 def on_solo_toggled(self, button):
1011 self.output_channel.channel.set_solo(self.input_channel.channel, button.get_active())
1012 self.app.update_monitor(self)