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 self
.channel
.volume
= db
209 self
.app
.update_monitor(self
)
211 def on_volume_changed(self
, adjustment
):
212 self
.update_volume(True)
214 def on_balance_changed(self
, adjustment
):
215 balance
= self
.balance_adjustment
.get_value()
216 #print "%s balance: %f" % (self.channel_name, balance)
217 self
.channel
.balance
= balance
218 self
.app
.update_monitor(self
)
220 def on_key_pressed(self
, widget
, event
):
221 if (event
.keyval
== gtk
.keysyms
.Up
):
222 #print self.channel_name + " Up"
223 self
.slider_adjustment
.step_up()
225 elif (event
.keyval
== gtk
.keysyms
.Down
):
226 #print self.channel_name + " Down"
227 self
.slider_adjustment
.step_down()
232 def serialize(self
, object_backend
):
233 object_backend
.add_property("volume", "%f" % self
.slider_adjustment
.get_value_db())
234 object_backend
.add_property("balance", "%f" % self
.balance_adjustment
.get_value())
236 if self
.channel
.volume_midi_cc
:
237 object_backend
.add_property('volume_midi_cc', str(self
.channel
.volume_midi_cc
))
238 if self
.channel
.balance_midi_cc
:
239 object_backend
.add_property('balance_midi_cc', str(self
.channel
.balance_midi_cc
))
241 def unserialize_property(self
, name
, value
):
243 self
.slider_adjustment
.set_value_db(float(value
))
245 if name
== "balance":
246 self
.balance_adjustment
.set_value(float(value
))
248 if name
== 'volume_midi_cc':
249 self
.future_volume_midi_cc
= int(value
)
251 if name
== 'balance_midi_cc':
252 self
.future_balance_midi_cc
= int(value
)
256 def 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)
269 for channel
in self
.app
.channels
+ self
.app
.output_channels
+ [self
.app
.main_mix
]:
270 if channel
.monitor_button
.get_active() and channel
.monitor_button
is not button
:
271 channel
.monitor_button
.handler_block_by_func(
272 channel
.on_monitor_button_toggled
)
273 channel
.monitor_button
.set_active(False)
274 channel
.monitor_button
.handler_unblock_by_func(
275 channel
.on_monitor_button_toggled
)
276 self
.app
.set_monitored_channel(self
)
278 def set_monitored(self
):
280 self
.app
.set_monitored_channel(self
)
281 self
.monitor_button
.set_active(True)
283 class InputChannel(Channel
):
284 post_fader_output_channel
= None
286 def __init__(self
, app
, name
, stereo
):
287 Channel
.__init
__(self
, app
, name
, stereo
)
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()
315 # self.label_stereo.set_text("stereo")
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)
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)
349 frame
.set_shadow_type(gtk
.SHADOW_IN
)
350 frame
.add(self
.meter
);
351 self
.hbox
.pack_start(frame
, True)
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)
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
:
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()
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
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
464 def serialization_name(cls
):
465 return 'input_channel'
467 def serialize(self
, object_backend
):
468 object_backend
.add_property("name", self
.channel_name
)
470 object_backend
.add_property("type", "stereo")
472 object_backend
.add_property("type", "mono")
473 Channel
.serialize(self
, object_backend
)
475 def unserialize_property(self
, name
, value
):
477 self
.channel_name
= str(value
)
480 if value
== "stereo":
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
)
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
)
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
)
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)
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)
558 frame
.set_shadow_type(gtk
.SHADOW_IN
)
559 frame
.add(self
.meter
);
560 self
.hbox
.pack_start(frame
, True)
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
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()
599 # remove control groups from input channels
600 for input_channel
in self
.app
.channels
:
601 input_channel
.remove_control_group(self
)
603 Channel
.unrealize(self
)
604 self
.channel
.remove()
608 def serialization_name(cls
):
609 return 'output_channel'
611 def serialize(self
, object_backend
):
612 object_backend
.add_property("name", self
.channel_name
)
614 object_backend
.add_property("type", "stereo")
616 object_backend
.add_property("type", "mono")
617 if self
.display_solo_buttons
:
618 object_backend
.add_property("solo_buttons", "true")
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
)
627 object_backend
.add_property('muted_channels', '|'.join([x
.channel
.name
for x
in muted_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
):
634 self
.channel_name
= str(value
)
637 if value
== "stereo":
643 if name
== "solo_buttons":
645 self
.display_solo_buttons
= True
647 if name
== 'muted_channels':
648 self
._init
_muted
_channels
= value
.split('|')
650 if name
== 'solo_channels':
651 self
._init
_solo
_channels
= value
.split('|')
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)
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)
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)
686 frame
.set_shadow_type(gtk
.SHADOW_IN
)
687 frame
.add(self
.meter
);
688 self
.hbox
.pack_start(frame
, True)
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
712 Channel
.unrealize(self
)
716 def serialization_name(cls
):
717 return 'main_mix_channel'
719 def serialize(self
, object_backend
):
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
)
728 object_backend
.add_property('muted_channels', '|'.join([x
.channel
.name
for x
in muted_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('|')
737 if name
== 'solo_channels':
738 self
._init
_solo
_channels
= value
.split('|')
740 return Channel
.unserialize_property(self
, name
, value
)
743 class ChannelPropertiesDialog(gtk
.Dialog
):
746 def __init__(self
, parent
, app
):
747 self
.channel
= parent
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
);
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)
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)
830 self
.entry_name
.set_text(self
.channel
.channel_name
)
831 if self
.channel
.channel
.is_stereo
:
832 self
.stereo
.set_active(True)
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)
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
):
856 timeout_label
.set_text('This window will close in %d seconds.' % window
.timeout
)
857 if window
.timeout
== 0:
859 entry
.set_text('%s' % self
.mixer
.last_midi_channel
)
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
877 self
.channel
.channel
.volume_midi_cc
= int(self
.entry_volume_cc
.get_text())
881 self
.channel
.channel
.balance_midi_cc
= int(self
.entry_balance_cc
.get_text())
886 def on_entry_name_changed(self
, entry
):
888 if len(entry
.get_text()):
889 if self
.channel
and self
.channel
.channel
.name
== entry
.get_text():
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']:
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
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
):
920 ChannelPropertiesDialog
.create_ui(self
)
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
)
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
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
977 mute
= gtk
.ToggleButton()
980 mute
.connect("toggled", self
.on_mute_toggled
)
981 hbox
.pack_start(mute
, False)
983 solo
= gtk
.ToggleButton()
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])
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)
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
)