2 # -*- coding: utf-8 -*-
4 # This file is part of jack_mixer
6 # Copyright (C) 2006-2009 Nedko Arnaudov <nedko@arnaudov.name>
7 # Copyright (C) 2009 Frederic Peters <fpeters@0d.be>
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; version 2 of the License
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22 from optparse
import OptionParser
34 print >> sys
.stderr
, "Cannot load LASH python bindings, you want them unless you enjoy manual jack plumbing each time you use this app"
36 # temporary change Python modules lookup path to look into installation
37 # directory ($prefix/share/jack_mixer/)
39 sys
.path
.insert(0, os
.path
.join(os
.path
.dirname(sys
.argv
[0]), '..', 'share', 'jack_mixer'))
46 from preferences
import PreferencesDialog
48 from serialization_xml
import XmlSerialization
49 from serialization
import SerializedObject
, Serializator
51 # restore Python modules lookup path
54 class JackMixer(SerializedObject
):
56 # scales suitable as meter scales
57 meter_scales
= [scale
.IEC268(), scale
.Linear70dB(), scale
.IEC268Minimalistic()]
59 # scales suitable as volume slider scales
60 slider_scales
= [scale
.Linear30dB(), scale
.Linear70dB()]
62 # name of settngs file that is currently open
63 current_filename
= None
65 def __init__(self
, name
, lash_client
):
66 self
.mixer
= jack_mixer_c
.Mixer(name
)
69 self
.monitor_channel
= self
.mixer
.add_output_channel("Monitor", True, True)
74 # Send our client name to server
75 lash_event
= lash
.lash_event_new_with_type(lash
.LASH_Client_Name
)
76 lash
.lash_event_set_string(lash_event
, name
)
77 lash
.lash_send_event(lash_client
, lash_event
)
79 lash
.lash_jack_client_name(lash_client
, name
)
81 gtk
.window_set_default_icon_name('jack_mixer')
83 self
.window
= gtk
.Window(gtk
.WINDOW_TOPLEVEL
)
84 self
.window
.set_title(name
)
86 self
.gui_factory
= gui
.Factory(self
.window
, self
.meter_scales
, self
.slider_scales
)
88 self
.vbox_top
= gtk
.VBox()
89 self
.window
.add(self
.vbox_top
)
91 self
.menubar
= gtk
.MenuBar()
92 self
.vbox_top
.pack_start(self
.menubar
, False)
94 mixer_menu_item
= gtk
.MenuItem("_Mixer")
95 self
.menubar
.append(mixer_menu_item
)
96 edit_menu_item
= gtk
.MenuItem('_Edit')
97 self
.menubar
.append(edit_menu_item
)
98 help_menu_item
= gtk
.MenuItem('_Help')
99 self
.menubar
.append(help_menu_item
)
101 self
.window
.set_default_size(120, 300)
103 mixer_menu
= gtk
.Menu()
104 mixer_menu_item
.set_submenu(mixer_menu
)
106 add_input_channel
= gtk
.ImageMenuItem('New _Input Channel')
107 mixer_menu
.append(add_input_channel
)
108 add_input_channel
.connect("activate", self
.on_add_input_channel
)
110 add_output_channel
= gtk
.ImageMenuItem('New _Output Channel')
111 mixer_menu
.append(add_output_channel
)
112 add_output_channel
.connect("activate", self
.on_add_output_channel
)
114 mixer_menu
.append(gtk
.SeparatorMenuItem())
115 open = gtk
.ImageMenuItem(gtk
.STOCK_OPEN
)
116 mixer_menu
.append(open)
117 open.connect('activate', self
.on_open_cb
)
118 save
= gtk
.ImageMenuItem(gtk
.STOCK_SAVE
)
119 mixer_menu
.append(save
)
120 save
.connect('activate', self
.on_save_cb
)
121 save_as
= gtk
.ImageMenuItem(gtk
.STOCK_SAVE_AS
)
122 mixer_menu
.append(save_as
)
123 save_as
.connect('activate', self
.on_save_as_cb
)
125 mixer_menu
.append(gtk
.SeparatorMenuItem())
127 quit
= gtk
.ImageMenuItem(gtk
.STOCK_QUIT
)
128 mixer_menu
.append(quit
)
129 quit
.connect('activate', self
.on_quit_cb
)
131 edit_menu
= gtk
.Menu()
132 edit_menu_item
.set_submenu(edit_menu
)
134 self
.channel_edit_input_menu_item
= gtk
.MenuItem('_Edit Input Channel')
135 edit_menu
.append(self
.channel_edit_input_menu_item
)
136 self
.channel_edit_input_menu
= gtk
.Menu()
137 self
.channel_edit_input_menu_item
.set_submenu(self
.channel_edit_input_menu
)
139 self
.channel_edit_output_menu_item
= gtk
.MenuItem('Edit _Output Channel')
140 edit_menu
.append(self
.channel_edit_output_menu_item
)
141 self
.channel_edit_output_menu
= gtk
.Menu()
142 self
.channel_edit_output_menu_item
.set_submenu(self
.channel_edit_output_menu
)
144 self
.channel_remove_input_menu_item
= gtk
.MenuItem('Remove _Input Channel')
145 edit_menu
.append(self
.channel_remove_input_menu_item
)
146 self
.channel_remove_input_menu
= gtk
.Menu()
147 self
.channel_remove_input_menu_item
.set_submenu(self
.channel_remove_input_menu
)
149 self
.channel_remove_output_menu_item
= gtk
.MenuItem('_Remove Output Channel')
150 edit_menu
.append(self
.channel_remove_output_menu_item
)
151 self
.channel_remove_output_menu
= gtk
.Menu()
152 self
.channel_remove_output_menu_item
.set_submenu(self
.channel_remove_output_menu
)
154 channel_remove_all_menu_item
= gtk
.ImageMenuItem(gtk
.STOCK_CLEAR
)
155 edit_menu
.append(channel_remove_all_menu_item
)
156 channel_remove_all_menu_item
.connect("activate", self
.on_channels_clear
)
158 edit_menu
.append(gtk
.SeparatorMenuItem())
160 preferences
= gtk
.ImageMenuItem(gtk
.STOCK_PREFERENCES
)
161 preferences
.connect('activate', self
.on_preferences_cb
)
162 edit_menu
.append(preferences
)
164 help_menu
= gtk
.Menu()
165 help_menu_item
.set_submenu(help_menu
)
167 about
= gtk
.ImageMenuItem(gtk
.STOCK_ABOUT
)
168 help_menu
.append(about
)
169 about
.connect("activate", self
.on_about
)
171 self
.hbox_top
= gtk
.HBox()
172 self
.vbox_top
.pack_start(self
.hbox_top
, True)
174 self
.scrolled_window
= gtk
.ScrolledWindow()
175 self
.hbox_top
.pack_start(self
.scrolled_window
, True)
177 self
.hbox_inputs
= gtk
.HBox()
178 self
.hbox_inputs
.set_spacing(0)
179 self
.hbox_inputs
.set_border_width(0)
180 self
.hbox_top
.set_spacing(0)
181 self
.hbox_top
.set_border_width(0)
183 self
.output_channels
= []
185 self
.scrolled_window
.set_policy(gtk
.POLICY_AUTOMATIC
, gtk
.POLICY_AUTOMATIC
)
186 self
.scrolled_window
.add_with_viewport(self
.hbox_inputs
)
188 self
.main_mix
= MainMixChannel(self
)
189 self
.hbox_outputs
= gtk
.HBox()
190 self
.hbox_outputs
.set_spacing(0)
191 self
.hbox_outputs
.set_border_width(0)
193 frame
.add(self
.main_mix
)
194 self
.hbox_outputs
.pack_start(frame
, False)
195 self
.hbox_top
.pack_start(self
.hbox_outputs
, False)
197 self
.window
.connect("destroy", gtk
.main_quit
)
199 gobject
.timeout_add(80, self
.read_meters
)
200 self
.lash_client
= lash_client
202 gobject
.timeout_add(200, self
.lash_check_events
)
204 gobject
.timeout_add(50, self
.midi_events_check
)
206 def sighandler(self
, signum
, frame
):
207 #print "Signal %d received" % signum
208 if signum
== signal
.SIGUSR1
:
210 elif signum
== signal
.SIGTERM
:
212 elif signum
== signal
.SIGINT
:
215 print "Unknown signal %d received" % signum
218 print "Cleaning jack_mixer"
222 for channel
in self
.channels
:
227 def on_open_cb(self
, *args
):
228 dlg
= gtk
.FileChooserDialog(title
='Open', parent
=self
.window
,
229 action
=gtk
.FILE_CHOOSER_ACTION_OPEN
,
230 buttons
=(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
,
231 gtk
.STOCK_OPEN
, gtk
.RESPONSE_OK
))
232 dlg
.set_default_response(gtk
.RESPONSE_OK
)
233 if dlg
.run() == gtk
.RESPONSE_OK
:
234 filename
= dlg
.get_filename()
236 f
= file(filename
, 'r')
237 self
.load_from_xml(f
)
239 err
= gtk
.MessageDialog(self
.window
,
243 "Failed loading settings.")
247 self
.current_filename
= filename
252 def on_save_cb(self
, *args
):
253 if not self
.current_filename
:
254 return self
.on_save_as_cb()
255 f
= file(self
.current_filename
, 'w')
259 def on_save_as_cb(self
, *args
):
260 dlg
= gtk
.FileChooserDialog(title
='Save', parent
=self
.window
,
261 action
=gtk
.FILE_CHOOSER_ACTION_SAVE
,
262 buttons
=(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
,
263 gtk
.STOCK_SAVE
, gtk
.RESPONSE_OK
))
264 dlg
.set_default_response(gtk
.RESPONSE_OK
)
265 if dlg
.run() == gtk
.RESPONSE_OK
:
266 self
.current_filename
= dlg
.get_filename()
270 def on_quit_cb(self
, *args
):
273 preferences_dialog
= None
274 def on_preferences_cb(self
, widget
):
275 if not self
.preferences_dialog
:
276 self
.preferences_dialog
= PreferencesDialog(self
)
277 self
.preferences_dialog
.show()
278 self
.preferences_dialog
.present()
280 def on_add_input_channel(self
, widget
):
281 dialog
= NewChannelDialog(app
=self
)
282 dialog
.set_transient_for(self
.window
)
287 if ret
== gtk
.RESPONSE_OK
:
288 result
= dialog
.get_result()
289 channel
= self
.add_channel(**result
)
290 self
.window
.show_all()
292 def on_add_output_channel(self
, widget
):
293 dialog
= NewOutputChannelDialog(app
=self
)
294 dialog
.set_transient_for(self
.window
)
299 if ret
== gtk
.RESPONSE_OK
:
300 result
= dialog
.get_result()
301 channel
= self
.add_output_channel(**result
)
302 self
.window
.show_all()
304 def on_edit_input_channel(self
, widget
, channel
):
305 print 'Editing channel "%s"' % channel
.channel_name
306 channel
.on_channel_properties()
308 def remove_channel_edit_input_menuitem_by_label(self
, widget
, label
):
309 if (widget
.get_label() == label
):
310 self
.channel_edit_input_menu
.remove(widget
)
312 def on_remove_input_channel(self
, widget
, channel
):
313 print 'Removing channel "%s"' % channel
.channel_name
314 self
.channel_remove_input_menu
.remove(widget
)
315 self
.channel_edit_input_menu
.foreach(
316 self
.remove_channel_edit_input_menuitem_by_label
,
317 channel
.channel_name
);
318 if self
.monitored_channel
is channel
:
319 channel
.monitor_button
.set_active(False)
320 for i
in range(len(self
.channels
)):
321 if self
.channels
[i
] is channel
:
324 self
.hbox_inputs
.remove(channel
.parent
)
326 if len(self
.channels
) == 0:
327 self
.channel_remove_input_menu_item
.set_sensitive(False)
329 def on_edit_output_channel(self
, widget
, channel
):
330 print 'Editing channel "%s"' % channel
.channel_name
331 channel
.on_channel_properties()
333 def remove_channel_edit_output_menuitem_by_label(self
, widget
, label
):
334 if (widget
.get_label() == label
):
335 self
.channel_edit_output_menu
.remove(widget
)
337 def on_remove_output_channel(self
, widget
, channel
):
338 print 'Removing channel "%s"' % channel
.channel_name
339 self
.channel_remove_output_menu
.remove(widget
)
340 self
.channel_edit_output_menu
.foreach(
341 self
.remove_channel_edit_output_menuitem_by_label
,
342 channel
.channel_name
);
343 if self
.monitored_channel
is channel
:
344 channel
.monitor_button
.set_active(False)
345 for i
in range(len(self
.channels
)):
346 if self
.output_channels
[i
] is channel
:
348 del self
.output_channels
[i
]
349 self
.hbox_outputs
.remove(channel
.parent
)
351 if len(self
.output_channels
) == 0:
352 self
.channel_remove_output_menu_item
.set_sensitive(False)
354 def rename_channels(self
, container
, parameters
):
355 if (container
.get_label() == parameters
['oldname']):
356 container
.set_label(parameters
['newname'])
358 def on_channel_rename(self
, oldname
, newname
):
359 rename_parameters
= { 'oldname' : oldname
, 'newname' : newname
}
360 self
.channel_edit_input_menu
.foreach(self
.rename_channels
,
362 self
.channel_edit_output_menu
.foreach(self
.rename_channels
,
364 self
.channel_remove_input_menu
.foreach(self
.rename_channels
,
366 self
.channel_remove_output_menu
.foreach(self
.rename_channels
,
368 print "Renaming channel from %s to %s\n" % (oldname
, newname
)
371 def on_channels_clear(self
, widget
):
372 for channel
in self
.output_channels
:
374 self
.hbox_outputs
.remove(channel
.parent
)
375 for channel
in self
.channels
:
377 self
.hbox_inputs
.remove(channel
.parent
)
379 self
.output_channels
= []
380 self
.channel_edit_input_menu
= gtk
.Menu()
381 self
.channel_edit_input_menu_item
.set_submenu(self
.channel_edit_input_menu
)
382 self
.channel_edit_input_menu_item
.set_sensitive(False)
383 self
.channel_remove_input_menu
= gtk
.Menu()
384 self
.channel_remove_input_menu_item
.set_submenu(self
.channel_remove_input_menu
)
385 self
.channel_remove_input_menu_item
.set_sensitive(False)
386 self
.channel_edit_output_menu
= gtk
.Menu()
387 self
.channel_edit_output_menu_item
.set_submenu(self
.channel_edit_output_menu
)
388 self
.channel_edit_output_menu_item
.set_sensitive(False)
389 self
.channel_remove_output_menu
= gtk
.Menu()
390 self
.channel_remove_output_menu_item
.set_submenu(self
.channel_remove_output_menu
)
391 self
.channel_remove_output_menu_item
.set_sensitive(False)
393 def add_channel(self
, name
, stereo
, volume_cc
, balance_cc
):
395 channel
= InputChannel(self
, name
, stereo
)
396 self
.add_channel_precreated(channel
)
398 err
= gtk
.MessageDialog(self
.window
,
399 gtk
.DIALOG_MODAL | gtk
.DIALOG_DESTROY_WITH_PARENT
,
402 "Channel creation failed")
407 channel
.channel
.volume_midi_cc
= int(volume_cc
)
409 channel
.channel
.balance_midi_cc
= int(balance_cc
)
410 if not (volume_cc
or balance_cc
):
411 channel
.channel
.autoset_midi_cc()
415 def add_channel_precreated(self
, channel
):
418 self
.hbox_inputs
.pack_start(frame
, False)
421 channel_edit_menu_item
= gtk
.MenuItem(channel
.channel_name
)
422 self
.channel_edit_input_menu
.append(channel_edit_menu_item
)
423 channel_edit_menu_item
.connect("activate", self
.on_edit_input_channel
, channel
)
424 self
.channel_edit_input_menu_item
.set_sensitive(True)
426 channel_remove_menu_item
= gtk
.MenuItem(channel
.channel_name
)
427 self
.channel_remove_input_menu
.append(channel_remove_menu_item
)
428 channel_remove_menu_item
.connect("activate", self
.on_remove_input_channel
, channel
)
429 self
.channel_remove_input_menu_item
.set_sensitive(True)
431 self
.channels
.append(channel
)
433 for outputchannel
in self
.output_channels
:
434 channel
.add_control_group(outputchannel
)
436 # create post fader output channel matching the input channel
437 channel
.post_fader_output_channel
= self
.mixer
.add_output_channel(
438 channel
.channel
.name
+ ' Out', channel
.channel
.is_stereo
, True)
439 channel
.post_fader_output_channel
.volume
= 0
440 channel
.post_fader_output_channel
.set_solo(channel
.channel
, True)
442 def read_meters(self
):
443 for channel
in self
.channels
:
445 self
.main_mix
.read_meter()
446 for channel
in self
.output_channels
:
450 def midi_events_check(self
):
451 for channel
in self
.channels
+ [self
.main_mix
] + self
.output_channels
:
452 channel
.midi_events_check()
455 def add_output_channel(self
, name
, stereo
, volume_cc
, balance_cc
, display_solo_buttons
):
457 channel
= OutputChannel(self
, name
, stereo
)
458 channel
.display_solo_buttons
= display_solo_buttons
459 self
.add_output_channel_precreated(channel
)
461 err
= gtk
.MessageDialog(self
.window
,
462 gtk
.DIALOG_MODAL | gtk
.DIALOG_DESTROY_WITH_PARENT
,
465 "Channel creation failed")
470 channel
.channel
.volume_midi_cc
= int(volume_cc
)
472 channel
.channel
.balance_midi_cc
= int(balance_cc
)
475 def add_output_channel_precreated(self
, channel
):
478 self
.hbox_outputs
.pack_start(frame
, False)
481 channel_edit_menu_item
= gtk
.MenuItem(channel
.channel_name
)
482 self
.channel_edit_output_menu
.append(channel_edit_menu_item
)
483 channel_edit_menu_item
.connect("activate", self
.on_edit_output_channel
, channel
)
484 self
.channel_edit_output_menu_item
.set_sensitive(True)
486 channel_remove_menu_item
= gtk
.MenuItem(channel
.channel_name
)
487 self
.channel_remove_output_menu
.append(channel_remove_menu_item
)
488 channel_remove_menu_item
.connect("activate", self
.on_remove_output_channel
, channel
)
489 self
.channel_remove_output_menu_item
.set_sensitive(True)
491 self
.output_channels
.append(channel
)
493 _monitored_channel
= None
494 def get_monitored_channel(self
):
495 return self
._monitored
_channel
497 def set_monitored_channel(self
, channel
):
498 if self
._monitored
_channel
:
499 if channel
.channel
.name
== self
._monitored
_channel
.channel
.name
:
501 self
._monitored
_channel
= channel
502 if type(channel
) is InputChannel
:
503 # reset all solo/mute settings
504 for in_channel
in self
.channels
:
505 self
.monitor_channel
.set_solo(in_channel
.channel
, False)
506 self
.monitor_channel
.set_muted(in_channel
.channel
, False)
507 self
.monitor_channel
.set_solo(channel
.channel
, True)
508 self
.monitor_channel
.prefader
= True
510 self
.monitor_channel
.prefader
= False
511 self
.update_monitor(channel
)
512 monitored_channel
= property(get_monitored_channel
, set_monitored_channel
)
514 def update_monitor(self
, channel
):
515 if self
.monitored_channel
is not channel
:
517 self
.monitor_channel
.volume
= channel
.channel
.volume
518 self
.monitor_channel
.balance
= channel
.channel
.balance
519 if type(self
.monitored_channel
) is OutputChannel
:
520 # sync solo/muted channels
521 for input_channel
in self
.channels
:
522 self
.monitor_channel
.set_solo(input_channel
.channel
,
523 channel
.channel
.is_solo(input_channel
.channel
))
524 self
.monitor_channel
.set_muted(input_channel
.channel
,
525 channel
.channel
.is_muted(input_channel
.channel
))
526 elif type(self
.monitored_channel
) is MainMixChannel
:
527 # sync solo/muted channels
528 for input_channel
in self
.channels
:
529 self
.monitor_channel
.set_solo(input_channel
.channel
,
530 input_channel
.channel
.solo
)
531 self
.monitor_channel
.set_muted(input_channel
.channel
,
532 input_channel
.channel
.mute
)
534 def get_input_channel_by_name(self
, name
):
535 for input_channel
in self
.channels
:
536 if input_channel
.channel
.name
== name
:
540 def on_about(self
, *args
):
541 about
= gtk
.AboutDialog()
542 about
.set_name('jack_mixer')
543 about
.set_copyright('Copyright © 2006-2010\nNedko Arnaudov, Frederic Peters, Arnout Engelen')
544 about
.set_license('''\
545 jack_mixer is free software; you can redistribute it and/or modify it
546 under the terms of the GNU General Public License as published by the
547 Free Software Foundation; either version 2 of the License, or (at your
548 option) any later version.
550 jack_mixer is distributed in the hope that it will be useful, but
551 WITHOUT ANY WARRANTY; without even the implied warranty of
552 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
553 General Public License for more details.
555 You should have received a copy of the GNU General Public License along
556 with jack_mixer; if not, write to the Free Software Foundation, Inc., 51
557 Franklin Street, Fifth Floor, Boston, MA 02110-130159 USA''')
558 about
.set_authors(['Nedko Arnaudov <nedko@arnaudov.name>',
559 'Frederic Peters <fpeters@0d.be>'])
560 about
.set_logo_icon_name('jack_mixer')
561 about
.set_website('http://home.gna.org/jackmixer/')
566 def lash_check_events(self
):
569 if self
.current_filename
:
570 print "saving on SIGUSR1 request"
574 print "not saving because filename is not known"
577 if not self
.lash_client
:
580 while lash
.lash_get_pending_event_count(self
.lash_client
):
581 event
= lash
.lash_get_event(self
.lash_client
)
585 event_type
= lash
.lash_event_get_type(event
)
586 if event_type
== lash
.LASH_Quit
:
587 print "jack_mixer: LASH ordered quit."
590 elif event_type
== lash
.LASH_Save_File
:
591 directory
= lash
.lash_event_get_string(event
)
592 print "jack_mixer: LASH ordered to save data in directory %s" % directory
593 filename
= directory
+ os
.sep
+ "jack_mixer.xml"
594 f
= file(filename
, "w")
597 lash
.lash_send_event(self
.lash_client
, event
) # we crash with double free
598 elif event_type
== lash
.LASH_Restore_File
:
599 directory
= lash
.lash_event_get_string(event
)
600 print "jack_mixer: LASH ordered to restore data from directory %s" % directory
601 filename
= directory
+ os
.sep
+ "jack_mixer.xml"
602 f
= file(filename
, "r")
603 self
.load_from_xml(f
, silence_errors
=True)
605 lash
.lash_send_event(self
.lash_client
, event
)
607 print "jack_mixer: Got unhandled LASH event, type " + str(event_type
)
610 #lash.lash_event_destroy(event)
614 def save_to_xml(self
, file):
615 #print "Saving to XML..."
616 b
= XmlSerialization()
621 def load_from_xml(self
, file, silence_errors
=False):
622 #print "Loading from XML..."
623 self
.on_channels_clear(None)
624 self
.unserialized_channels
= []
625 b
= XmlSerialization()
633 s
.unserialize(self
, b
)
634 for channel
in self
.unserialized_channels
:
635 if isinstance(channel
, InputChannel
):
636 self
.add_channel_precreated(channel
)
637 for channel
in self
.unserialized_channels
:
638 if isinstance(channel
, OutputChannel
):
639 self
.add_output_channel_precreated(channel
)
640 del self
.unserialized_channels
641 self
.window
.show_all()
643 def serialize(self
, object_backend
):
644 object_backend
.add_property('geometry',
645 '%sx%s' % (self
.window
.allocation
.width
, self
.window
.allocation
.height
))
647 def unserialize_property(self
, name
, value
):
648 if name
== 'geometry':
649 width
, height
= value
.split('x')
650 self
.window
.resize(int(width
), int(height
))
653 def unserialize_child(self
, name
):
654 if name
== MainMixChannel
.serialization_name():
657 if name
== InputChannel
.serialization_name():
658 channel
= InputChannel(self
, "", True)
659 self
.unserialized_channels
.append(channel
)
662 if name
== OutputChannel
.serialization_name():
663 channel
= OutputChannel(self
, "", True)
664 self
.unserialized_channels
.append(channel
)
667 def serialization_get_childs(self
):
668 '''Get child objects tha required and support serialization'''
669 childs
= self
.channels
[:] + self
.output_channels
[:]
670 childs
.append(self
.main_mix
)
673 def serialization_name(self
):
677 self
.main_mix
.realize()
678 self
.main_mix
.set_monitored()
683 self
.window
.show_all()
685 signal
.signal(signal
.SIGUSR1
, self
.sighandler
)
686 signal
.signal(signal
.SIGTERM
, self
.sighandler
)
687 signal
.signal(signal
.SIGINT
, self
.sighandler
)
691 #f = file("/dev/stdout", "w")
696 print "Usage: %s [mixer_name]" % sys
.argv
[0]
699 # Connect to LASH if Python bindings are available, and the user did not
701 if lash
and not '--no-lash' in sys
.argv
:
702 # sys.argv is modified by this call
703 lash_client
= lash
.init(sys
.argv
, "jack_mixer", lash
.LASH_Config_File
)
707 parser
= OptionParser(usage
='usage: %prog [options] [jack_client_name]')
708 parser
.add_option('-c', '--config', dest
='config',
709 help='use a non default configuration file')
710 # --no-lash here is not acted upon, it is specified for completeness when
712 parser
.add_option('--no-lash', dest
='nolash', action
='store_true',
713 help='do not connect to LASH')
714 options
, args
= parser
.parse_args()
716 # Yeah , this sounds stupid, we connected earlier, but we dont want to show this if we got --help option
717 # This issue should be fixed in pylash, there is a reason for having two functions for initialization after all
719 server_name
= lash
.lash_get_server_name(lash_client
)
721 print "Successfully connected to LASH server at " + server_name
723 # getting the server name failed, probably not worth trying to do
724 # further things with as a lash client.
736 mixer
= JackMixer(name
, lash_client
)
738 err
= gtk
.MessageDialog(None,
742 "Mixer creation failed (%s)" % str(e
))
748 f
= file(options
.config
)
749 mixer
.current_filename
= options
.config
751 mixer
.load_from_xml(f
)
753 err
= gtk
.MessageDialog(mixer
.window
,
757 "Failed loading settings.")
760 mixer
.window
.set_default_size(60*(1+len(mixer
.channels
)+len(mixer
.output_channels
)), 300)
767 if __name__
== "__main__":