* Detect NaNs
[jack_mixer.git] / channel.py
blob7a6ef1142a6b60c070a86599468a5d73870bc079
1 #!/usr/bin/env python
3 # This file is part of jack_mixer
5 # Copyright (C) 2006 Nedko Arnaudov <nedko@arnaudov.name>
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; version 2 of the License
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 import gtk
21 import scale
22 import slider
23 import meter
24 import abspeak
25 import jack_mixer_c
26 import math
27 import random
28 from serialization import serialized_object
30 try:
31 import phat
32 except:
33 print "PHAT audio widgets not found, some features will not be available"
34 phat = None
36 import fpconst
38 class channel(gtk.VBox, serialized_object):
39 '''Widget with slider and meter used as base class for more specific channel widgets'''
40 def __init__(self, gui_factory, name, stereo):
41 gtk.VBox.__init__(self)
42 self.gui_factory = gui_factory
43 self.channel_name = name
44 self.stereo = stereo
45 self.meter_scale = gui_factory.get_default_meter_scale()
46 self.slider_scale = gui_factory.get_default_slider_scale()
47 self.slider_adjustment = slider.adjustment_dBFS(self.slider_scale, 0.0)
48 self.balance_adjustment = gtk.Adjustment(0.0, -1.0, 1.0, 0.02)
50 def realize(self):
51 #print "Realizing channel \"%s\"" % self.channel_name
53 self.slider_adjustment.connect("volume-changed", self.on_volume_changed)
54 self.balance_adjustment.connect("value-changed", self.on_balance_changed)
56 self.slider = slider.widget(self.slider_adjustment)
58 if self.stereo:
59 self.meter = meter.stereo(self.meter_scale)
60 else:
61 self.meter = meter.mono(self.meter_scale)
63 self.meter.set_events(gtk.gdk.SCROLL_MASK)
65 self.gui_factory.connect("default-meter-scale-changed", self.on_default_meter_scale_changed)
66 self.gui_factory.connect("default-slider-scale-changed", self.on_default_slider_scale_changed)
68 self.abspeak = abspeak.widget()
69 self.abspeak.connect("reset", self.on_abspeak_reset)
70 self.abspeak.connect("volume-adjust", self.on_abspeak_adjust)
72 self.volume_digits = gtk.Entry()
73 self.volume_digits.connect("key-press-event", self.on_volume_digits_key_pressed)
74 self.volume_digits.connect("focus-out-event", self.on_volume_digits_focus_out)
76 self.connect("key-press-event", self.on_key_pressed)
77 self.connect("scroll-event", self.on_scroll)
79 def unrealize(self):
80 #print "Unrealizing channel \"%s\"" % self.channel_name
81 pass
83 def on_default_meter_scale_changed(self, gui_factory, scale):
84 #print "Default meter scale change detected."
85 self.meter.set_scale(scale)
87 def on_default_slider_scale_changed(self, gui_factory, scale):
88 #print "Default slider scale change detected."
89 self.slider_adjustment.set_scale(scale)
91 def on_abspeak_adjust(self, abspeak, adjust):
92 #print "abspeak adjust %f" % adjust
93 self.slider_adjustment.set_value_db(self.slider_adjustment.get_value_db() + adjust)
94 jack_mixer_c.channel_abspeak_reset(self.channel)
95 #self.update_volume(False) # We want to update gui even if actual decibels have not changed (scale wrap for example)
97 def on_abspeak_reset(self, abspeak):
98 #print "abspeak reset"
99 jack_mixer_c.channel_abspeak_reset(self.channel)
101 def on_volume_digits_key_pressed(self, widget, event):
102 if (event.keyval == gtk.keysyms.Return or event.keyval == gtk.keysyms.KP_Enter):
103 db_text = self.volume_digits.get_text()
104 try:
105 db = float(db_text)
106 #print "Volume digits confirmation \"%f dBFS\"" % db
107 except (ValueError), e:
108 #print "Volume digits confirmation ignore, reset to current"
109 self.update_volume(False)
110 return
111 self.slider_adjustment.set_value_db(db)
112 #self.grab_focus()
113 #self.update_volume(False) # We want to update gui even if actual decibels have not changed (scale wrap for example)
115 def on_volume_digits_focus_out(self, widget, event):
116 #print "volume digits focus out detected"
117 self.update_volume(False)
119 def read_meter(self):
120 if self.stereo:
121 meter_left, meter_right = jack_mixer_c.channel_stereo_meter_read(self.channel)
122 self.meter.set_values(meter_left, meter_right)
123 else:
124 self.meter.set_value(jack_mixer_c.channel_mono_meter_read(self.channel))
126 self.abspeak.set_peak(jack_mixer_c.channel_abspeak_read(self.channel))
128 def on_scroll(self, widget, event):
129 if event.direction == gtk.gdk.SCROLL_DOWN:
130 self.slider_adjustment.step_down()
131 elif event.direction == gtk.gdk.SCROLL_UP:
132 self.slider_adjustment.step_up()
133 return True
135 def update_volume(self, update_engine):
136 db = self.slider_adjustment.get_value_db()
138 db_text = "%.2f" % db
139 self.volume_digits.set_text(db_text)
141 if update_engine:
142 #print "Setting engine volume to " + db_text
143 jack_mixer_c.channel_volume_write(self.channel, db)
145 def on_volume_changed(self, adjustment):
146 self.update_volume(True)
148 def on_balance_changed(self, adjustment):
149 balance = self.balance_adjustment.get_value()
150 #print "%s balance: %f" % (self.channel_name, balance)
151 jack_mixer_c.channel_balance_write(self.channel, balance)
153 def on_key_pressed(self, widget, event):
154 if (event.keyval == gtk.keysyms.Up):
155 #print self.channel_name + " Up"
156 self.slider_adjustment.step_up()
157 return True
158 elif (event.keyval == gtk.keysyms.Down):
159 #print self.channel_name + " Down"
160 self.slider_adjustment.step_down()
161 return True
163 return False
165 def serialize(self, object_backend):
166 object_backend.add_property("volume", "%f" % self.slider_adjustment.get_value_db())
167 object_backend.add_property("balance", "%f" % self.balance_adjustment.get_value())
169 def unserialize_property(self, name, value):
170 if name == "volume":
171 self.slider_adjustment.set_value_db(float(value))
172 return True
173 if name == "balance":
174 self.balance_adjustment.set_value(float(value))
175 return True
176 return False
178 class input_channel(channel):
179 def __init__(self, gui_factory, name, stereo):
180 channel.__init__(self, gui_factory, name, stereo)
182 def realize(self):
183 channel.realize(self)
184 self.channel = jack_mixer_c.add_channel(self.channel_name, self.stereo)
186 self.on_volume_changed(self.slider_adjustment)
187 self.on_balance_changed(self.balance_adjustment)
189 # vbox child at upper part
190 self.vbox = gtk.VBox()
191 self.pack_start(self.vbox, False)
192 self.label_name = gtk.Label()
193 self.label_name.set_text(self.channel_name)
194 self.label_name.set_size_request(0, -1)
195 self.label_name_event_box = gtk.EventBox()
196 self.label_name_event_box.connect("button-press-event", self.on_label_mouse)
197 self.label_name_event_box.add(self.label_name)
198 self.vbox.pack_start(self.label_name_event_box, True)
199 # self.label_stereo = gtk.Label()
200 # if self.stereo:
201 # self.label_stereo.set_text("stereo")
202 # else:
203 # self.label_stereo.set_text("mono")
204 # self.label_stereo.set_size_request(0, -1)
205 # self.vbox.pack_start(self.label_stereo, True)
207 # hbox for mute and solo buttons
208 self.hbox_mutesolo = gtk.HBox()
210 self.mute = gtk.ToggleButton()
211 self.mute.set_label("M")
212 self.mute.set_active(jack_mixer_c.channel_is_muted(self.channel))
213 self.mute.connect("toggled", self.on_mute_toggled)
214 self.hbox_mutesolo.pack_start(self.mute, True)
216 self.solo = gtk.ToggleButton()
217 self.solo.set_label("S")
218 self.solo.set_active(jack_mixer_c.channel_is_soloed(self.channel))
219 self.solo.connect("toggled", self.on_solo_toggled)
220 self.hbox_mutesolo.pack_start(self.solo, True)
222 self.vbox.pack_start(self.hbox_mutesolo, False)
224 frame = gtk.Frame()
225 frame.set_shadow_type(gtk.SHADOW_IN)
226 frame.add(self.abspeak);
227 self.vbox.pack_start(frame, False)
229 # hbox child at lower part
230 self.hbox = gtk.HBox()
231 self.hbox.pack_start(self.slider, True)
232 frame = gtk.Frame()
233 frame.set_shadow_type(gtk.SHADOW_IN)
234 frame.add(self.meter);
235 self.hbox.pack_start(frame, True)
236 frame = gtk.Frame()
237 frame.set_shadow_type(gtk.SHADOW_IN)
238 frame.add(self.hbox);
239 self.pack_start(frame, True)
241 self.volume_digits.set_size_request(0, -1)
242 self.pack_start(self.volume_digits, False)
244 if phat:
245 self.balance = phat.HFanSlider()
246 self.balance.set_default_value(0)
247 self.balance.set_adjustment(self.balance_adjustment)
248 self.pack_start(self.balance, False)
250 def unrealize(self):
251 channel.unrealize(self)
252 jack_mixer_c.remove_channel(self.channel)
253 self.channel = False
255 def on_rename_channel(self):
256 result = self.gui_factory.run_dialog_rename_channel(self.channel_name)
257 if result != None:
258 #print "renaming to \"%s\"" % result
259 self.channel_name = result
260 self.label_name.set_text(self.channel_name)
261 jack_mixer_c.channel_rename(self.channel, self.channel_name)
263 def on_label_mouse(self, widget, event):
264 if event.type == gtk.gdk._2BUTTON_PRESS:
265 if event.button == 1:
266 self.on_rename_channel()
268 def on_mute_toggled(self, button):
269 if self.mute.get_active():
270 #print "muted"
271 jack_mixer_c.channel_mute(self.channel)
272 else:
273 #print "unmuted"
274 jack_mixer_c.channel_unmute(self.channel)
276 def on_solo_toggled(self, button):
277 if self.solo.get_active():
278 #print "soloed"
279 jack_mixer_c.channel_solo(self.channel)
280 else:
281 #print "unsoloed"
282 jack_mixer_c.channel_unsolo(self.channel)
284 def serialization_name(self):
285 return input_channel_serialization_name()
287 def serialize(self, object_backend):
288 object_backend.add_property("name", self.channel_name)
289 if self.stereo:
290 object_backend.add_property("type", "stereo")
291 else:
292 object_backend.add_property("type", "mono")
293 channel.serialize(self, object_backend)
295 def unserialize_property(self, name, value):
296 if name == "name":
297 self.channel_name = str(value)
298 return True
299 if name == "type":
300 if value == "stereo":
301 self.stereo = True
302 return True
303 if value == "mono":
304 self.stereo = False
305 return True
306 return channel.unserialize_property(self, name, value)
308 def input_channel_serialization_name():
309 return "input_channel"
311 class main_mix(channel):
312 def __init__(self, gui_factory):
313 channel.__init__(self, gui_factory, "MAIN", True)
315 def realize(self):
316 channel.realize(self)
317 self.channel = jack_mixer_c.get_main_mix_channel()
319 self.on_volume_changed(self.slider_adjustment)
320 self.on_balance_changed(self.balance_adjustment)
322 # vbox child at upper part
323 self.vbox = gtk.VBox()
324 self.pack_start(self.vbox, False)
325 self.label_name = gtk.Label()
326 self.label_name.set_text(self.channel_name)
327 self.label_name.set_size_request(0, -1)
328 self.vbox.pack_start(self.label_name, False)
329 frame = gtk.Frame()
330 frame.set_shadow_type(gtk.SHADOW_IN)
331 frame.add(self.abspeak);
332 self.vbox.pack_start(frame, False)
334 # hbox child at lower part
335 self.hbox = gtk.HBox()
336 self.hbox.pack_start(self.slider, True)
337 frame = gtk.Frame()
338 frame.set_shadow_type(gtk.SHADOW_IN)
339 frame.add(self.meter);
340 self.hbox.pack_start(frame, True)
341 frame = gtk.Frame()
342 frame.set_shadow_type(gtk.SHADOW_IN)
343 frame.add(self.hbox);
344 self.pack_start(frame, True)
346 self.volume_digits.set_size_request(0, -1)
347 self.pack_start(self.volume_digits, False)
349 if phat:
350 self.balance = phat.HFanSlider()
351 self.balance.set_default_value(0)
352 self.balance.set_adjustment(self.balance_adjustment)
353 self.pack_start(self.balance, False)
355 def unrealize(self):
356 channel.unrealize(self)
357 self.channel = False
359 def serialization_name(self):
360 return main_mix_serialization_name()
362 def main_mix_serialization_name():
363 return "main_mix_channel"