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_volume_midi_cc
= None
48 self
.future_balance_midi_cc
= None
50 def get_channel_name(self
):
51 return self
._channel
_name
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
60 self
.label_name
.set_text(name
)
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
)
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
)
74 self
.create_slider_widget()
77 self
.meter
= meter
.StereoMeterWidget(self
.meter_scale
)
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
)
102 #print "Unrealizing channel \"%s\"" % self.channel_name
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
)
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)
118 def create_slider_widget(self
):
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
)
126 self
.slider
= slider
.GtkSlider(self
.slider_adjustment
)
128 parent
.pack_start(self
.slider
)
129 parent
.reorder_child(self
.slider
, 0)
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)
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()
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)
175 self
.slider_adjustment
.set_value_db(db
)
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
):
187 meter_left
, meter_right
= self
.channel
.meter
188 self
.meter
.set_values(meter_left
, meter_right
)
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()
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
)
208 #print "Setting engine volume to " + db_text
209 self
.channel
.volume
= db
210 self
.app
.update_monitor(self
)
212 def on_volume_changed(self
, adjustment
):
213 self
.update_volume(True)
215 def on_balance_changed(self
, adjustment
):
216 balance
= self
.balance_adjustment
.get_value()
217 #print "%s balance: %f" % (self.channel_name, balance)
218 self
.channel
.balance
= balance
219 self
.app
.update_monitor(self
)
221 def on_key_pressed(self
, widget
, event
):
222 if (event
.keyval
== gtk
.keysyms
.Up
):
223 #print self.channel_name + " Up"
224 self
.slider_adjustment
.step_up()
226 elif (event
.keyval
== gtk
.keysyms
.Down
):
227 #print self.channel_name + " Down"
228 self
.slider_adjustment
.step_down()
233 def serialize(self
, object_backend
):
234 object_backend
.add_property("volume", "%f" % self
.slider_adjustment
.get_value_db())
235 object_backend
.add_property("balance", "%f" % self
.balance_adjustment
.get_value())
237 if self
.channel
.volume_midi_cc
:
238 object_backend
.add_property('volume_midi_cc', str(self
.channel
.volume_midi_cc
))
239 if self
.channel
.balance_midi_cc
:
240 object_backend
.add_property('balance_midi_cc', str(self
.channel
.balance_midi_cc
))
242 def unserialize_property(self
, name
, value
):
244 self
.slider_adjustment
.set_value_db(float(value
))
246 if name
== "balance":
247 self
.balance_adjustment
.set_value(float(value
))
249 if name
== 'volume_midi_cc':
250 self
.future_volume_midi_cc
= int(value
)
252 if name
== 'balance_midi_cc':
253 self
.future_balance_midi_cc
= int(value
)
257 def midi_events_check(self
):
258 if self
.channel
.midi_got_events
:
259 self
.slider_adjustment
.set_value_db(self
.channel
.volume
)
260 self
.balance_adjustment
.set_value(self
.channel
.balance
)
262 def on_midi_event_received(self
, *args
):
263 self
.slider_adjustment
.set_value_db(self
.channel
.volume
)
264 self
.balance_adjustment
.set_value(self
.channel
.balance
)
266 def on_monitor_button_toggled(self
, button
):
267 if not button
.get_active():
268 self
.app
.main_mix
.monitor_button
.set_active(True)
270 for channel
in self
.app
.channels
+ self
.app
.output_channels
+ [self
.app
.main_mix
]:
271 if channel
.monitor_button
.get_active() and channel
.monitor_button
is not button
:
272 channel
.monitor_button
.handler_block_by_func(
273 channel
.on_monitor_button_toggled
)
274 channel
.monitor_button
.set_active(False)
275 channel
.monitor_button
.handler_unblock_by_func(
276 channel
.on_monitor_button_toggled
)
277 self
.app
.set_monitored_channel(self
)
279 def set_monitored(self
):
281 self
.app
.set_monitored_channel(self
)
282 self
.monitor_button
.set_active(True)
284 class InputChannel(Channel
):
285 post_fader_output_channel
= None
287 def __init__(self
, app
, name
, stereo
):
288 Channel
.__init
__(self
, app
, name
, stereo
)
291 self
.channel
= self
.mixer
.add_channel(self
.channel_name
, self
.stereo
)
292 if self
.channel
== None:
293 raise Exception,"Cannot create a channel"
294 Channel
.realize(self
)
295 if self
.future_volume_midi_cc
:
296 self
.channel
.volume_midi_cc
= self
.future_volume_midi_cc
297 if self
.future_balance_midi_cc
:
298 self
.channel
.balance_midi_cc
= self
.future_balance_midi_cc
299 self
.channel
.midi_scale
= self
.slider_scale
.scale
301 self
.on_volume_changed(self
.slider_adjustment
)
302 self
.on_balance_changed(self
.balance_adjustment
)
304 # vbox child at upper part
305 self
.vbox
= gtk
.VBox()
306 self
.pack_start(self
.vbox
, False)
307 self
.label_name
= gtk
.Label()
308 self
.label_name
.set_text(self
.channel_name
)
309 self
.label_name
.set_size_request(0, -1)
310 self
.label_name_event_box
= gtk
.EventBox()
311 self
.label_name_event_box
.connect("button-press-event", self
.on_label_mouse
)
312 self
.label_name_event_box
.add(self
.label_name
)
313 self
.vbox
.pack_start(self
.label_name_event_box
, True)
314 # self.label_stereo = gtk.Label()
316 # self.label_stereo.set_text("stereo")
318 # self.label_stereo.set_text("mono")
319 # self.label_stereo.set_size_request(0, -1)
320 # self.vbox.pack_start(self.label_stereo, True)
322 # hbox for mute and solo buttons
323 self
.hbox_mutesolo
= gtk
.HBox()
325 self
.mute
= gtk
.ToggleButton()
326 self
.mute
.set_label("M")
327 self
.mute
.set_active(self
.channel
.mute
)
328 self
.mute
.connect("button-press-event", self
.on_mute_button_pressed
)
329 self
.mute
.connect("toggled", self
.on_mute_toggled
)
330 self
.hbox_mutesolo
.pack_start(self
.mute
, True)
332 self
.solo
= gtk
.ToggleButton()
333 self
.solo
.set_label("S")
334 self
.solo
.set_active(self
.channel
.solo
)
335 self
.solo
.connect("button-press-event", self
.on_solo_button_pressed
)
336 self
.solo
.connect("toggled", self
.on_solo_toggled
)
337 self
.hbox_mutesolo
.pack_start(self
.solo
, True)
339 self
.vbox
.pack_start(self
.hbox_mutesolo
, False)
342 frame
.set_shadow_type(gtk
.SHADOW_IN
)
343 frame
.add(self
.abspeak
);
344 self
.pack_start(frame
, False)
346 # hbox child at lower part
347 self
.hbox
= gtk
.HBox()
348 self
.hbox
.pack_start(self
.slider
, True)
350 frame
.set_shadow_type(gtk
.SHADOW_IN
)
351 frame
.add(self
.meter
);
352 self
.hbox
.pack_start(frame
, True)
354 frame
.set_shadow_type(gtk
.SHADOW_IN
)
355 frame
.add(self
.hbox
);
356 self
.pack_start(frame
, True)
358 self
.volume_digits
.set_size_request(0, -1)
359 self
.pack_start(self
.volume_digits
, False)
361 self
.create_balance_widget()
363 self
.monitor_button
= gtk
.ToggleButton('MON')
364 self
.monitor_button
.connect('toggled', self
.on_monitor_button_toggled
)
365 self
.pack_start(self
.monitor_button
, False, False)
367 def add_control_group(self
, channel
):
368 control_group
= ControlGroup(channel
, self
)
369 control_group
.show_all()
370 self
.vbox
.pack_start(control_group
, False)
373 def remove_control_group(self
, channel
):
374 ctlgroup
= self
.get_control_group(channel
)
375 self
.vbox
.remove(ctlgroup
)
377 def update_control_group(self
, channel
):
378 for control_group
in self
.vbox
.get_children():
379 if isinstance(control_group
, ControlGroup
):
380 if control_group
.output_channel
is channel
:
381 control_group
.update()
383 def get_control_group(self
, channel
):
384 for control_group
in self
.vbox
.get_children():
385 if isinstance(control_group
, ControlGroup
):
386 if control_group
.output_channel
is channel
:
391 Channel
.unrealize(self
)
392 if self
.post_fader_output_channel
:
393 self
.post_fader_output_channel
.remove()
394 self
.post_fader_output_channel
= None
395 self
.channel
.remove()
398 channel_properties_dialog
= None
399 def on_channel_properties(self
):
400 if not self
.channel_properties_dialog
:
401 self
.channel_properties_dialog
= ChannelPropertiesDialog(self
, self
.app
)
402 self
.channel_properties_dialog
.show()
403 self
.channel_properties_dialog
.present()
405 def on_label_mouse(self
, widget
, event
):
406 if event
.type == gtk
.gdk
._2BUTTON
_PRESS
:
407 if event
.button
== 1:
408 self
.on_channel_properties()
410 def on_mute_toggled(self
, button
):
411 self
.channel
.mute
= self
.mute
.get_active()
412 self
.app
.update_monitor(self
.app
.main_mix
)
414 def on_mute_button_pressed(self
, button
, event
, *args
):
415 if event
.button
== 3:
416 # right click on the mute button, act on all output channels
417 if button
.get_active(): # was muted
418 button
.set_active(False)
419 if hasattr(button
, 'touched_channels'):
420 touched_channels
= button
.touched_channels
421 for chan
in touched_channels
:
422 ctlgroup
= self
.get_control_group(chan
)
423 ctlgroup
.mute
.set_active(False)
424 del button
.touched_channels
425 else: # was not muted
426 button
.set_active(True)
427 touched_channels
= []
428 for chan
in self
.app
.output_channels
:
429 ctlgroup
= self
.get_control_group(chan
)
430 if not ctlgroup
.mute
.get_active():
431 ctlgroup
.mute
.set_active(True)
432 touched_channels
.append(chan
)
433 button
.touched_channels
= touched_channels
437 def on_solo_toggled(self
, button
):
438 self
.channel
.solo
= self
.solo
.get_active()
439 self
.app
.update_monitor(self
.app
.main_mix
)
441 def on_solo_button_pressed(self
, button
, event
, *args
):
442 if event
.button
== 3:
443 # right click on the solo button, act on all output channels
444 if button
.get_active(): # was soloed
445 button
.set_active(False)
446 if hasattr(button
, 'touched_channels'):
447 touched_channels
= button
.touched_channels
448 for chan
in touched_channels
:
449 ctlgroup
= self
.get_control_group(chan
)
450 ctlgroup
.solo
.set_active(False)
451 del button
.touched_channels
452 else: # was not soloed
453 button
.set_active(True)
454 touched_channels
= []
455 for chan
in self
.app
.output_channels
:
456 ctlgroup
= self
.get_control_group(chan
)
457 if not ctlgroup
.solo
.get_active():
458 ctlgroup
.solo
.set_active(True)
459 touched_channels
.append(chan
)
460 button
.touched_channels
= touched_channels
465 def serialization_name(cls
):
466 return 'input_channel'
468 def serialize(self
, object_backend
):
469 object_backend
.add_property("name", self
.channel_name
)
471 object_backend
.add_property("type", "stereo")
473 object_backend
.add_property("type", "mono")
474 Channel
.serialize(self
, object_backend
)
476 def unserialize_property(self
, name
, value
):
478 self
.channel_name
= str(value
)
481 if value
== "stereo":
487 return Channel
.unserialize_property(self
, name
, value
)
490 available_colours
= [
491 ('#ef2929', '#cc0000', '#840000'),
492 ('#729fcf', '#3465a4', '#204a67'),
493 ('#8aa234', '#73d216', '#4e7a06'),
494 ('#fce84f', '#edd400', '#c48000'),
495 ('#fcaf3e', '#f57900', '#ae5c00'),
496 ('#ad7fa8', '#75507b', '#4c3556'),
497 ('#e9b96e', '#c17d11', '#6f4902'),
500 class OutputChannel(Channel
):
501 colours
= available_colours
[:]
502 _display_solo_buttons
= False
504 _init_muted_channels
= None
505 _init_solo_channels
= None
507 def __init__(self
, app
, name
, stereo
):
508 Channel
.__init
__(self
, app
, name
, stereo
)
510 def get_display_solo_buttons(self
):
511 return self
._display
_solo
_buttons
513 def set_display_solo_buttons(self
, value
):
514 self
._display
_solo
_buttons
= value
515 # notifying control groups
516 for inputchannel
in self
.app
.channels
:
517 inputchannel
.update_control_group(self
)
519 display_solo_buttons
= property(get_display_solo_buttons
, set_display_solo_buttons
)
522 Channel
.realize(self
)
523 self
.channel
= self
.mixer
.add_output_channel(self
.channel_name
, self
.stereo
)
524 if self
.channel
== None:
525 raise Exception,"Cannot create a channel"
526 Channel
.realize(self
)
528 self
.channel
.midi_scale
= self
.slider_scale
.scale
530 self
.on_volume_changed(self
.slider_adjustment
)
531 self
.on_balance_changed(self
.balance_adjustment
)
533 # vbox child at upper part
534 self
.vbox
= gtk
.VBox()
535 self
.pack_start(self
.vbox
, False)
536 self
.label_name
= gtk
.Label()
537 self
.label_name
.set_text(self
.channel_name
)
538 self
.label_name
.set_size_request(0, -1)
539 self
.label_name_event_box
= gtk
.EventBox()
540 self
.label_name_event_box
.connect('button-press-event', self
.on_label_mouse
)
541 self
.label_name_event_box
.add(self
.label_name
)
543 OutputChannel
.colours
= available_colours
[:]
544 for color
in self
.colours
:
545 self
.color_tuple
= [gtk
.gdk
.color_parse(color
[x
]) for x
in range(3)]
546 self
.colours
.remove(color
)
548 self
.label_name_event_box
.modify_bg(gtk
.STATE_NORMAL
, self
.color_tuple
[1])
549 self
.vbox
.pack_start(self
.label_name_event_box
, True)
551 frame
.set_shadow_type(gtk
.SHADOW_IN
)
552 frame
.add(self
.abspeak
);
553 self
.vbox
.pack_start(frame
, False)
555 # hbox child at lower part
556 self
.hbox
= gtk
.HBox()
557 self
.hbox
.pack_start(self
.slider
, True)
559 frame
.set_shadow_type(gtk
.SHADOW_IN
)
560 frame
.add(self
.meter
);
561 self
.hbox
.pack_start(frame
, True)
563 frame
.set_shadow_type(gtk
.SHADOW_IN
)
564 frame
.add(self
.hbox
);
565 self
.pack_start(frame
, True)
567 self
.volume_digits
.set_size_request(0, -1)
568 self
.pack_start(self
.volume_digits
, False)
570 self
.create_balance_widget()
572 self
.monitor_button
= gtk
.ToggleButton('MON')
573 self
.monitor_button
.connect('toggled', self
.on_monitor_button_toggled
)
574 self
.pack_start(self
.monitor_button
, False, False)
576 # add control groups to the input channels, and initialize them
578 for input_channel
in self
.app
.channels
:
579 ctlgroup
= input_channel
.add_control_group(self
)
580 if self
._init
_muted
_channels
and input_channel
.channel
.name
in self
._init
_muted
_channels
:
581 ctlgroup
.mute
.set_active(True)
582 if self
._init
_solo
_channels
and input_channel
.channel
.name
in self
._init
_solo
_channels
:
583 ctlgroup
.solo
.set_active(True)
584 self
._init
_muted
_channels
= None
585 self
._init
_solo
_channels
= None
587 channel_properties_dialog
= None
588 def on_channel_properties(self
):
589 if not self
.channel_properties_dialog
:
590 self
.channel_properties_dialog
= OutputChannelPropertiesDialog(self
, self
.app
)
591 self
.channel_properties_dialog
.show()
592 self
.channel_properties_dialog
.present()
594 def on_label_mouse(self
, widget
, event
):
595 if event
.type == gtk
.gdk
._2BUTTON
_PRESS
:
596 if event
.button
== 1:
597 self
.on_channel_properties()
600 # remove control groups from input channels
601 for input_channel
in self
.app
.channels
:
602 input_channel
.remove_control_group(self
)
604 Channel
.unrealize(self
)
605 self
.channel
.remove()
609 def serialization_name(cls
):
610 return 'output_channel'
612 def serialize(self
, object_backend
):
613 object_backend
.add_property("name", self
.channel_name
)
615 object_backend
.add_property("type", "stereo")
617 object_backend
.add_property("type", "mono")
618 if self
.display_solo_buttons
:
619 object_backend
.add_property("solo_buttons", "true")
622 for input_channel
in self
.app
.channels
:
623 if self
.channel
.is_muted(input_channel
.channel
):
624 muted_channels
.append(input_channel
)
625 if self
.channel
.is_solo(input_channel
.channel
):
626 solo_channels
.append(input_channel
)
628 object_backend
.add_property('muted_channels', '|'.join([x
.channel
.name
for x
in muted_channels
]))
630 object_backend
.add_property('solo_channels', '|'.join([x
.channel
.name
for x
in solo_channels
]))
631 Channel
.serialize(self
, object_backend
)
633 def unserialize_property(self
, name
, value
):
635 self
.channel_name
= str(value
)
638 if value
== "stereo":
644 if name
== "solo_buttons":
646 self
.display_solo_buttons
= True
648 if name
== 'muted_channels':
649 self
._init
_muted
_channels
= value
.split('|')
651 if name
== 'solo_channels':
652 self
._init
_solo
_channels
= value
.split('|')
654 return Channel
.unserialize_property(self
, name
, value
)
656 class MainMixChannel(Channel
):
657 _init_muted_channels
= None
658 _init_solo_channels
= None
660 def __init__(self
, app
):
661 Channel
.__init
__(self
, app
, "MAIN", True)
664 Channel
.realize(self
)
665 self
.channel
= self
.mixer
.main_mix_channel
666 self
.channel
.midi_scale
= self
.slider_scale
.scale
668 self
.on_volume_changed(self
.slider_adjustment
)
669 self
.on_balance_changed(self
.balance_adjustment
)
671 # vbox child at upper part
672 self
.vbox
= gtk
.VBox()
673 self
.pack_start(self
.vbox
, False)
674 self
.label_name
= gtk
.Label()
675 self
.label_name
.set_text(self
.channel_name
)
676 self
.label_name
.set_size_request(0, -1)
677 self
.vbox
.pack_start(self
.label_name
, False)
679 frame
.set_shadow_type(gtk
.SHADOW_IN
)
680 frame
.add(self
.abspeak
);
681 self
.vbox
.pack_start(frame
, False)
683 # hbox child at lower part
684 self
.hbox
= gtk
.HBox()
685 self
.hbox
.pack_start(self
.slider
, True)
687 frame
.set_shadow_type(gtk
.SHADOW_IN
)
688 frame
.add(self
.meter
);
689 self
.hbox
.pack_start(frame
, True)
691 frame
.set_shadow_type(gtk
.SHADOW_IN
)
692 frame
.add(self
.hbox
);
693 self
.pack_start(frame
, True)
695 self
.volume_digits
.set_size_request(0, -1)
696 self
.pack_start(self
.volume_digits
, False)
698 self
.create_balance_widget()
700 self
.monitor_button
= gtk
.ToggleButton('MON')
701 self
.monitor_button
.connect('toggled', self
.on_monitor_button_toggled
)
702 self
.pack_start(self
.monitor_button
, False, False)
704 for input_channel
in self
.app
.channels
:
705 if self
._init
_muted
_channels
and input_channel
.channel
.name
in self
._init
_muted
_channels
:
706 input_channel
.mute
.set_active(True)
707 if self
._init
_solo
_channels
and input_channel
.channel
.name
in self
._init
_solo
_channels
:
708 input_channel
.solo
.set_active(True)
709 self
._init
_muted
_channels
= None
710 self
._init
_solo
_channels
= None
713 Channel
.unrealize(self
)
717 def serialization_name(cls
):
718 return 'main_mix_channel'
720 def serialize(self
, object_backend
):
723 for input_channel
in self
.app
.channels
:
724 if input_channel
.channel
.mute
:
725 muted_channels
.append(input_channel
)
726 if input_channel
.channel
.solo
:
727 solo_channels
.append(input_channel
)
729 object_backend
.add_property('muted_channels', '|'.join([x
.channel
.name
for x
in muted_channels
]))
731 object_backend
.add_property('solo_channels', '|'.join([x
.channel
.name
for x
in solo_channels
]))
732 Channel
.serialize(self
, object_backend
)
734 def unserialize_property(self
, name
, value
):
735 if name
== 'muted_channels':
736 self
._init
_muted
_channels
= value
.split('|')
738 if name
== 'solo_channels':
739 self
._init
_solo
_channels
= value
.split('|')
741 return Channel
.unserialize_property(self
, name
, value
)
744 class ChannelPropertiesDialog(gtk
.Dialog
):
747 def __init__(self
, parent
, app
):
748 self
.channel
= parent
750 self
.mixer
= self
.channel
.mixer
751 gtk
.Dialog
.__init
__(self
,
752 'Channel "%s" Properties' % self
.channel
.channel_name
,
753 self
.channel
.gui_factory
.topwindow
)
755 self
.add_button(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
)
756 self
.ok_button
= self
.add_button(gtk
.STOCK_APPLY
, gtk
.RESPONSE_APPLY
)
757 self
.set_default_response(gtk
.RESPONSE_APPLY
);
762 self
.connect('response', self
.on_response_cb
)
763 self
.connect('delete-event', self
.on_response_cb
)
765 def create_frame(self
, label
, child
):
766 frame
= gtk
.Frame('')
767 frame
.set_border_width(3)
768 #frame.set_shadow_type(gtk.SHADOW_NONE)
769 frame
.get_label_widget().set_markup('<b>%s</b>' % label
)
771 alignment
= gtk
.Alignment(0, 0, 1, 1)
772 alignment
.set_padding(0, 0, 12, 0)
782 table
= gtk
.Table(2, 2, False)
783 vbox
.pack_start(self
.create_frame('Properties', table
))
784 table
.set_row_spacings(5)
785 table
.set_col_spacings(5)
787 table
.attach(gtk
.Label('Name'), 0, 1, 0, 1)
788 self
.entry_name
= gtk
.Entry()
789 self
.entry_name
.set_activates_default(True)
790 self
.entry_name
.connect('changed', self
.on_entry_name_changed
)
791 table
.attach(self
.entry_name
, 1, 2, 0, 1)
793 table
.attach(gtk
.Label('Mode'), 0, 1, 1, 2)
794 self
.mode_hbox
= gtk
.HBox()
795 table
.attach(self
.mode_hbox
, 1, 2, 1, 2)
796 self
.mono
= gtk
.RadioButton(label
='Mono')
797 self
.stereo
= gtk
.RadioButton(label
='Stereo', group
=self
.mono
)
798 self
.mode_hbox
.pack_start(self
.mono
)
799 self
.mode_hbox
.pack_start(self
.stereo
)
801 table
= gtk
.Table(2, 3, False)
802 vbox
.pack_start(self
.create_frame('MIDI Control Channels', table
))
803 table
.set_row_spacings(5)
804 table
.set_col_spacings(5)
806 table
.attach(gtk
.Label('Volume'), 0, 1, 0, 1)
807 self
.entry_volume_cc
= gtk
.Entry()
808 self
.entry_volume_cc
.set_activates_default(True)
809 self
.entry_volume_cc
.set_editable(False)
810 self
.entry_volume_cc
.set_width_chars(3)
811 table
.attach(self
.entry_volume_cc
, 1, 2, 0, 1)
812 self
.button_sense_midi_volume
= gtk
.Button('Autoset')
813 self
.button_sense_midi_volume
.connect('clicked',
814 self
.on_sense_midi_volume_clicked
)
815 table
.attach(self
.button_sense_midi_volume
, 2, 3, 0, 1)
817 table
.attach(gtk
.Label('Balance'), 0, 1, 1, 2)
818 self
.entry_balance_cc
= gtk
.Entry()
819 self
.entry_balance_cc
.set_activates_default(True)
820 self
.entry_balance_cc
.set_width_chars(3)
821 self
.entry_balance_cc
.set_editable(False)
822 table
.attach(self
.entry_balance_cc
, 1, 2, 1, 2)
823 self
.button_sense_midi_balance
= gtk
.Button('Autoset')
824 self
.button_sense_midi_balance
.connect('clicked',
825 self
.on_sense_midi_balance_clicked
)
826 table
.attach(self
.button_sense_midi_balance
, 2, 3, 1, 2)
831 self
.entry_name
.set_text(self
.channel
.channel_name
)
832 if self
.channel
.channel
.is_stereo
:
833 self
.stereo
.set_active(True)
835 self
.mono
.set_active(True)
836 self
.mode_hbox
.set_sensitive(False)
837 self
.entry_volume_cc
.set_text('%s' % self
.channel
.channel
.volume_midi_cc
)
838 self
.entry_balance_cc
.set_text('%s' % self
.channel
.channel
.balance_midi_cc
)
840 def sense_popup_dialog(self
, entry
):
841 window
= gtk
.Window(gtk
.WINDOW_TOPLEVEL
)
842 window
.set_destroy_with_parent(True)
843 window
.set_transient_for(self
)
844 window
.set_decorated(False)
845 window
.set_modal(True)
846 window
.set_position(gtk
.WIN_POS_CENTER_ON_PARENT
)
847 window
.set_border_width(10)
852 vbox
.pack_start(gtk
.Label('Please move the MIDI control you want to use for this function.'))
853 timeout_label
= gtk
.Label('This window will close in 5 seconds')
854 vbox
.pack_start(timeout_label
)
855 def close_sense_timeout(window
, entry
):
857 timeout_label
.set_text('This window will close in %d seconds.' % window
.timeout
)
858 if window
.timeout
== 0:
860 entry
.set_text('%s' % self
.mixer
.last_midi_channel
)
864 gobject
.timeout_add_seconds(1, close_sense_timeout
, window
, entry
)
866 def on_sense_midi_volume_clicked(self
, *args
):
867 self
.sense_popup_dialog(self
.entry_volume_cc
)
869 def on_sense_midi_balance_clicked(self
, *args
):
870 self
.sense_popup_dialog(self
.entry_balance_cc
)
872 def on_response_cb(self
, dlg
, response_id
, *args
):
873 self
.channel
.channel_properties_dialog
= None
875 if response_id
== gtk
.RESPONSE_APPLY
:
876 name
= self
.entry_name
.get_text()
877 self
.channel
.channel_name
= name
879 self
.channel
.channel
.volume_midi_cc
= int(self
.entry_volume_cc
.get_text())
883 self
.channel
.channel
.balance_midi_cc
= int(self
.entry_balance_cc
.get_text())
887 def on_entry_name_changed(self
, entry
):
889 if len(entry
.get_text()):
890 if self
.channel
and self
.channel
.channel
.name
== entry
.get_text():
892 elif entry
.get_text() not in [x
.channel
.name
for x
in self
.app
.channels
] + \
893 [x
.channel
.name
for x
in self
.app
.output_channels
] + ['MAIN']:
895 self
.ok_button
.set_sensitive(sensitive
)
898 class NewChannelDialog(ChannelPropertiesDialog
):
899 def __init__(self
, app
):
900 gtk
.Dialog
.__init
__(self
, 'New Channel', app
.window
)
901 self
.mixer
= app
.mixer
905 self
.stereo
.set_active(True) # default to stereo
907 self
.add_button(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
)
908 self
.ok_button
= self
.add_button(gtk
.STOCK_ADD
, gtk
.RESPONSE_OK
)
909 self
.ok_button
.set_sensitive(False)
910 self
.set_default_response(gtk
.RESPONSE_OK
);
912 def get_result(self
):
913 return {'name': self
.entry_name
.get_text(),
914 'stereo': self
.stereo
.get_active(),
915 'volume_cc': self
.entry_volume_cc
.get_text(),
916 'balance_cc': self
.entry_balance_cc
.get_text()
919 class OutputChannelPropertiesDialog(ChannelPropertiesDialog
):
921 ChannelPropertiesDialog
.create_ui(self
)
924 self
.vbox
.pack_start(self
.create_frame('Input Channels', vbox
))
926 self
.display_solo_buttons
= gtk
.CheckButton('Display solo buttons')
927 vbox
.pack_start(self
.display_solo_buttons
)
932 ChannelPropertiesDialog
.fill_ui(self
)
933 self
.display_solo_buttons
.set_active(self
.channel
.display_solo_buttons
)
935 def on_response_cb(self
, dlg
, response_id
, *args
):
936 ChannelPropertiesDialog
.on_response_cb(self
, dlg
, response_id
, *args
)
937 if response_id
== gtk
.RESPONSE_APPLY
:
938 self
.channel
.display_solo_buttons
= self
.display_solo_buttons
.get_active()
941 class NewOutputChannelDialog(OutputChannelPropertiesDialog
):
942 def __init__(self
, app
):
943 gtk
.Dialog
.__init
__(self
, 'New Output Channel', app
.window
)
944 self
.mixer
= app
.mixer
948 # TODO: disable mode for output channels as mono output channels may
949 # not be correctly handled yet.
950 self
.mode_hbox
.set_sensitive(False)
951 self
.stereo
.set_active(True) # default to stereo
953 self
.add_button(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
)
954 self
.ok_button
= self
.add_button(gtk
.STOCK_ADD
, gtk
.RESPONSE_OK
)
955 self
.ok_button
.set_sensitive(False)
956 self
.set_default_response(gtk
.RESPONSE_OK
);
958 def get_result(self
):
959 return {'name': self
.entry_name
.get_text(),
960 'stereo': self
.stereo
.get_active(),
961 'volume_cc': self
.entry_volume_cc
.get_text(),
962 'balance_cc': self
.entry_balance_cc
.get_text(),
963 'display_solo_buttons': self
.display_solo_buttons
.get_active(),
967 class ControlGroup(gtk
.Alignment
):
968 def __init__(self
, output_channel
, input_channel
):
969 gtk
.Alignment
.__init
__(self
, 0.5, 0.5, 0, 0)
970 self
.output_channel
= output_channel
971 self
.input_channel
= input_channel
972 self
.app
= input_channel
.app
978 mute
= gtk
.ToggleButton()
981 mute
.connect("toggled", self
.on_mute_toggled
)
982 hbox
.pack_start(mute
, False)
984 solo
= gtk
.ToggleButton()
987 solo
.connect("toggled", self
.on_solo_toggled
)
988 if self
.output_channel
.display_solo_buttons
:
989 hbox
.pack_start(solo
, True)
991 mute
.modify_bg(gtk
.STATE_PRELIGHT
, output_channel
.color_tuple
[0])
992 mute
.modify_bg(gtk
.STATE_NORMAL
, output_channel
.color_tuple
[1])
993 mute
.modify_bg(gtk
.STATE_ACTIVE
, output_channel
.color_tuple
[2])
994 solo
.modify_bg(gtk
.STATE_PRELIGHT
, output_channel
.color_tuple
[0])
995 solo
.modify_bg(gtk
.STATE_NORMAL
, output_channel
.color_tuple
[1])
996 solo
.modify_bg(gtk
.STATE_ACTIVE
, output_channel
.color_tuple
[2])
999 if self
.output_channel
.display_solo_buttons
:
1000 if not self
.solo
in self
.hbox
.get_children():
1001 self
.hbox
.pack_start(self
.solo
, True)
1004 if self
.solo
in self
.hbox
.get_children():
1005 self
.hbox
.remove(self
.solo
)
1007 def on_mute_toggled(self
, button
):
1008 self
.output_channel
.channel
.set_muted(self
.input_channel
.channel
, button
.get_active())
1009 self
.app
.update_monitor(self
)
1011 def on_solo_toggled(self
, button
):
1012 self
.output_channel
.channel
.set_solo(self
.input_channel
.channel
, button
.get_active())
1013 self
.app
.update_monitor(self
)