Cleanup scale code by removing threshold objects in python part (replaced with mark...
[jack_mixer.git] / channel.py
blob9af706ce411e1a642f6eac65fe2e1ce2c6761056
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, mixer, gui_factory, name, stereo):
41 gtk.VBox.__init__(self)
42 self.mixer = mixer
43 self.gui_factory = gui_factory
44 self.channel_name = name
45 self.stereo = stereo
46 self.meter_scale = gui_factory.get_default_meter_scale()
47 self.slider_scale = gui_factory.get_default_slider_scale()
48 self.slider_adjustment = slider.adjustment_dBFS(self.slider_scale, 0.0)
49 self.balance_adjustment = gtk.Adjustment(0.0, -1.0, 1.0, 0.02)
51 def realize(self):
52 #print "Realizing channel \"%s\"" % self.channel_name
54 self.slider_adjustment.connect("volume-changed", self.on_volume_changed)
55 self.balance_adjustment.connect("value-changed", self.on_balance_changed)
57 self.slider = slider.widget(self.slider_adjustment)
59 if self.stereo:
60 self.meter = meter.stereo(self.meter_scale)
61 else:
62 self.meter = meter.mono(self.meter_scale)
64 self.meter.set_events(gtk.gdk.SCROLL_MASK)
66 self.gui_factory.connect("default-meter-scale-changed", self.on_default_meter_scale_changed)
67 self.gui_factory.connect("default-slider-scale-changed", self.on_default_slider_scale_changed)
69 self.abspeak = abspeak.widget()
70 self.abspeak.connect("reset", self.on_abspeak_reset)
71 self.abspeak.connect("volume-adjust", self.on_abspeak_adjust)
73 self.volume_digits = gtk.Entry()
74 self.volume_digits.connect("key-press-event", self.on_volume_digits_key_pressed)
75 self.volume_digits.connect("focus-out-event", self.on_volume_digits_focus_out)
77 self.connect("key-press-event", self.on_key_pressed)
78 self.connect("scroll-event", self.on_scroll)
80 def unrealize(self):
81 #print "Unrealizing channel \"%s\"" % self.channel_name
82 pass
84 def on_default_meter_scale_changed(self, gui_factory, scale):
85 #print "Default meter scale change detected."
86 self.meter.set_scale(scale)
88 def on_default_slider_scale_changed(self, gui_factory, scale):
89 #print "Default slider scale change detected."
90 self.slider_adjustment.set_scale(scale)
92 def on_abspeak_adjust(self, abspeak, adjust):
93 #print "abspeak adjust %f" % adjust
94 self.slider_adjustment.set_value_db(self.slider_adjustment.get_value_db() + adjust)
95 jack_mixer_c.channel_abspeak_reset(self.channel)
96 #self.update_volume(False) # We want to update gui even if actual decibels have not changed (scale wrap for example)
98 def on_abspeak_reset(self, abspeak):
99 #print "abspeak reset"
100 jack_mixer_c.channel_abspeak_reset(self.channel)
102 def on_volume_digits_key_pressed(self, widget, event):
103 if (event.keyval == gtk.keysyms.Return or event.keyval == gtk.keysyms.KP_Enter):
104 db_text = self.volume_digits.get_text()
105 try:
106 db = float(db_text)
107 #print "Volume digits confirmation \"%f dBFS\"" % db
108 except (ValueError), e:
109 #print "Volume digits confirmation ignore, reset to current"
110 self.update_volume(False)
111 return
112 self.slider_adjustment.set_value_db(db)
113 #self.grab_focus()
114 #self.update_volume(False) # We want to update gui even if actual decibels have not changed (scale wrap for example)
116 def on_volume_digits_focus_out(self, widget, event):
117 #print "volume digits focus out detected"
118 self.update_volume(False)
120 def read_meter(self):
121 if self.stereo:
122 meter_left, meter_right = jack_mixer_c.channel_stereo_meter_read(self.channel)
123 self.meter.set_values(meter_left, meter_right)
124 else:
125 self.meter.set_value(jack_mixer_c.channel_mono_meter_read(self.channel))
127 self.abspeak.set_peak(jack_mixer_c.channel_abspeak_read(self.channel))
129 def midi_change_check(self):
130 if jack_mixer_c.channel_is_midi_modified(self.channel):
131 volume = jack_mixer_c.channel_volume_read(self.channel)
132 balance = jack_mixer_c.channel_balance_read(self.channel)
133 #print volume, balance
134 self.slider_adjustment.set_value_db(volume)
135 self.balance.set_value(balance)
137 def on_scroll(self, widget, event):
138 if event.direction == gtk.gdk.SCROLL_DOWN:
139 self.slider_adjustment.step_down()
140 elif event.direction == gtk.gdk.SCROLL_UP:
141 self.slider_adjustment.step_up()
142 return True
144 def update_volume(self, update_engine):
145 db = self.slider_adjustment.get_value_db()
147 db_text = "%.2f" % db
148 self.volume_digits.set_text(db_text)
150 if update_engine:
151 #print "Setting engine volume to " + db_text
152 jack_mixer_c.channel_volume_write(self.channel, db)
154 def on_volume_changed(self, adjustment):
155 self.update_volume(True)
157 def on_balance_changed(self, adjustment):
158 balance = self.balance_adjustment.get_value()
159 #print "%s balance: %f" % (self.channel_name, balance)
160 jack_mixer_c.channel_balance_write(self.channel, balance)
162 def on_key_pressed(self, widget, event):
163 if (event.keyval == gtk.keysyms.Up):
164 #print self.channel_name + " Up"
165 self.slider_adjustment.step_up()
166 return True
167 elif (event.keyval == gtk.keysyms.Down):
168 #print self.channel_name + " Down"
169 self.slider_adjustment.step_down()
170 return True
172 return False
174 def serialize(self, object_backend):
175 object_backend.add_property("volume", "%f" % self.slider_adjustment.get_value_db())
176 object_backend.add_property("balance", "%f" % self.balance_adjustment.get_value())
178 def unserialize_property(self, name, value):
179 if name == "volume":
180 self.slider_adjustment.set_value_db(float(value))
181 return True
182 if name == "balance":
183 self.balance_adjustment.set_value(float(value))
184 return True
185 return False
187 class input_channel(channel):
188 def __init__(self, mixer, gui_factory, name, stereo):
189 channel.__init__(self, mixer, gui_factory, name, stereo)
191 def realize(self):
192 channel.realize(self)
193 self.channel = jack_mixer_c.add_channel(self.mixer, self.channel_name, self.stereo)
195 self.on_volume_changed(self.slider_adjustment)
196 self.on_balance_changed(self.balance_adjustment)
198 # vbox child at upper part
199 self.vbox = gtk.VBox()
200 self.pack_start(self.vbox, False)
201 self.label_name = gtk.Label()
202 self.label_name.set_text(self.channel_name)
203 self.label_name.set_size_request(0, -1)
204 self.label_name_event_box = gtk.EventBox()
205 self.label_name_event_box.connect("button-press-event", self.on_label_mouse)
206 self.label_name_event_box.add(self.label_name)
207 self.vbox.pack_start(self.label_name_event_box, True)
208 # self.label_stereo = gtk.Label()
209 # if self.stereo:
210 # self.label_stereo.set_text("stereo")
211 # else:
212 # self.label_stereo.set_text("mono")
213 # self.label_stereo.set_size_request(0, -1)
214 # self.vbox.pack_start(self.label_stereo, True)
216 # hbox for mute and solo buttons
217 self.hbox_mutesolo = gtk.HBox()
219 self.mute = gtk.ToggleButton()
220 self.mute.set_label("M")
221 self.mute.set_active(jack_mixer_c.channel_is_muted(self.channel))
222 self.mute.connect("toggled", self.on_mute_toggled)
223 self.hbox_mutesolo.pack_start(self.mute, True)
225 self.solo = gtk.ToggleButton()
226 self.solo.set_label("S")
227 self.solo.set_active(jack_mixer_c.channel_is_soloed(self.channel))
228 self.solo.connect("toggled", self.on_solo_toggled)
229 self.hbox_mutesolo.pack_start(self.solo, True)
231 self.vbox.pack_start(self.hbox_mutesolo, False)
233 frame = gtk.Frame()
234 frame.set_shadow_type(gtk.SHADOW_IN)
235 frame.add(self.abspeak);
236 self.vbox.pack_start(frame, False)
238 # hbox child at lower part
239 self.hbox = gtk.HBox()
240 self.hbox.pack_start(self.slider, True)
241 frame = gtk.Frame()
242 frame.set_shadow_type(gtk.SHADOW_IN)
243 frame.add(self.meter);
244 self.hbox.pack_start(frame, True)
245 frame = gtk.Frame()
246 frame.set_shadow_type(gtk.SHADOW_IN)
247 frame.add(self.hbox);
248 self.pack_start(frame, True)
250 self.volume_digits.set_size_request(0, -1)
251 self.pack_start(self.volume_digits, False)
253 if phat:
254 self.balance = phat.HFanSlider()
255 self.balance.set_default_value(0)
256 self.balance.set_adjustment(self.balance_adjustment)
257 self.pack_start(self.balance, False)
259 def unrealize(self):
260 channel.unrealize(self)
261 jack_mixer_c.remove_channel(self.channel)
262 self.channel = False
264 def on_rename_channel(self):
265 result = self.gui_factory.run_dialog_rename_channel(self.channel_name)
266 if result != None:
267 #print "renaming to \"%s\"" % result
268 self.channel_name = result
269 self.label_name.set_text(self.channel_name)
270 jack_mixer_c.channel_rename(self.channel, self.channel_name)
272 def on_label_mouse(self, widget, event):
273 if event.type == gtk.gdk._2BUTTON_PRESS:
274 if event.button == 1:
275 self.on_rename_channel()
277 def on_mute_toggled(self, button):
278 if self.mute.get_active():
279 #print "muted"
280 jack_mixer_c.channel_mute(self.channel)
281 else:
282 #print "unmuted"
283 jack_mixer_c.channel_unmute(self.channel)
285 def on_solo_toggled(self, button):
286 if self.solo.get_active():
287 #print "soloed"
288 jack_mixer_c.channel_solo(self.channel)
289 else:
290 #print "unsoloed"
291 jack_mixer_c.channel_unsolo(self.channel)
293 def serialization_name(self):
294 return input_channel_serialization_name()
296 def serialize(self, object_backend):
297 object_backend.add_property("name", self.channel_name)
298 if self.stereo:
299 object_backend.add_property("type", "stereo")
300 else:
301 object_backend.add_property("type", "mono")
302 channel.serialize(self, object_backend)
304 def unserialize_property(self, name, value):
305 if name == "name":
306 self.channel_name = str(value)
307 return True
308 if name == "type":
309 if value == "stereo":
310 self.stereo = True
311 return True
312 if value == "mono":
313 self.stereo = False
314 return True
315 return channel.unserialize_property(self, name, value)
317 def input_channel_serialization_name():
318 return "input_channel"
320 class main_mix(channel):
321 def __init__(self, mixer, gui_factory):
322 channel.__init__(self, mixer, gui_factory, "MAIN", True)
324 def realize(self):
325 channel.realize(self)
326 self.channel = jack_mixer_c.get_main_mix_channel(self.mixer)
328 self.on_volume_changed(self.slider_adjustment)
329 self.on_balance_changed(self.balance_adjustment)
331 # vbox child at upper part
332 self.vbox = gtk.VBox()
333 self.pack_start(self.vbox, False)
334 self.label_name = gtk.Label()
335 self.label_name.set_text(self.channel_name)
336 self.label_name.set_size_request(0, -1)
337 self.vbox.pack_start(self.label_name, False)
338 frame = gtk.Frame()
339 frame.set_shadow_type(gtk.SHADOW_IN)
340 frame.add(self.abspeak);
341 self.vbox.pack_start(frame, False)
343 # hbox child at lower part
344 self.hbox = gtk.HBox()
345 self.hbox.pack_start(self.slider, True)
346 frame = gtk.Frame()
347 frame.set_shadow_type(gtk.SHADOW_IN)
348 frame.add(self.meter);
349 self.hbox.pack_start(frame, True)
350 frame = gtk.Frame()
351 frame.set_shadow_type(gtk.SHADOW_IN)
352 frame.add(self.hbox);
353 self.pack_start(frame, True)
355 self.volume_digits.set_size_request(0, -1)
356 self.pack_start(self.volume_digits, False)
358 if phat:
359 self.balance = phat.HFanSlider()
360 self.balance.set_default_value(0)
361 self.balance.set_adjustment(self.balance_adjustment)
362 self.pack_start(self.balance, False)
364 def unrealize(self):
365 channel.unrealize(self)
366 self.channel = False
368 def serialization_name(self):
369 return main_mix_serialization_name()
371 def main_mix_serialization_name():
372 return "main_mix_channel"