Move channel buffers from stack to structs so theyt can be reused when mixing with...
[jack_mixer.git] / channel.py
blobbe0a435ba7d05b71c593f333bcf11873f7f746bc
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 on_scroll(self, widget, event):
130 if event.direction == gtk.gdk.SCROLL_DOWN:
131 self.slider_adjustment.step_down()
132 elif event.direction == gtk.gdk.SCROLL_UP:
133 self.slider_adjustment.step_up()
134 return True
136 def update_volume(self, update_engine):
137 db = self.slider_adjustment.get_value_db()
139 db_text = "%.2f" % db
140 self.volume_digits.set_text(db_text)
142 if update_engine:
143 #print "Setting engine volume to " + db_text
144 jack_mixer_c.channel_volume_write(self.channel, db)
146 def on_volume_changed(self, adjustment):
147 self.update_volume(True)
149 def on_balance_changed(self, adjustment):
150 balance = self.balance_adjustment.get_value()
151 #print "%s balance: %f" % (self.channel_name, balance)
152 jack_mixer_c.channel_balance_write(self.channel, balance)
154 def on_key_pressed(self, widget, event):
155 if (event.keyval == gtk.keysyms.Up):
156 #print self.channel_name + " Up"
157 self.slider_adjustment.step_up()
158 return True
159 elif (event.keyval == gtk.keysyms.Down):
160 #print self.channel_name + " Down"
161 self.slider_adjustment.step_down()
162 return True
164 return False
166 def serialize(self, object_backend):
167 object_backend.add_property("volume", "%f" % self.slider_adjustment.get_value_db())
168 object_backend.add_property("balance", "%f" % self.balance_adjustment.get_value())
170 def unserialize_property(self, name, value):
171 if name == "volume":
172 self.slider_adjustment.set_value_db(float(value))
173 return True
174 if name == "balance":
175 self.balance_adjustment.set_value(float(value))
176 return True
177 return False
179 class input_channel(channel):
180 def __init__(self, mixer, gui_factory, name, stereo):
181 channel.__init__(self, mixer, gui_factory, name, stereo)
183 def realize(self):
184 channel.realize(self)
185 self.channel = jack_mixer_c.add_channel(self.mixer, self.channel_name, self.stereo)
187 self.on_volume_changed(self.slider_adjustment)
188 self.on_balance_changed(self.balance_adjustment)
190 # vbox child at upper part
191 self.vbox = gtk.VBox()
192 self.pack_start(self.vbox, False)
193 self.label_name = gtk.Label()
194 self.label_name.set_text(self.channel_name)
195 self.label_name.set_size_request(0, -1)
196 self.label_name_event_box = gtk.EventBox()
197 self.label_name_event_box.connect("button-press-event", self.on_label_mouse)
198 self.label_name_event_box.add(self.label_name)
199 self.vbox.pack_start(self.label_name_event_box, True)
200 # self.label_stereo = gtk.Label()
201 # if self.stereo:
202 # self.label_stereo.set_text("stereo")
203 # else:
204 # self.label_stereo.set_text("mono")
205 # self.label_stereo.set_size_request(0, -1)
206 # self.vbox.pack_start(self.label_stereo, True)
208 # hbox for mute and solo buttons
209 self.hbox_mutesolo = gtk.HBox()
211 self.mute = gtk.ToggleButton()
212 self.mute.set_label("M")
213 self.mute.set_active(jack_mixer_c.channel_is_muted(self.channel))
214 self.mute.connect("toggled", self.on_mute_toggled)
215 self.hbox_mutesolo.pack_start(self.mute, True)
217 self.solo = gtk.ToggleButton()
218 self.solo.set_label("S")
219 self.solo.set_active(jack_mixer_c.channel_is_soloed(self.channel))
220 self.solo.connect("toggled", self.on_solo_toggled)
221 self.hbox_mutesolo.pack_start(self.solo, True)
223 self.vbox.pack_start(self.hbox_mutesolo, False)
225 frame = gtk.Frame()
226 frame.set_shadow_type(gtk.SHADOW_IN)
227 frame.add(self.abspeak);
228 self.vbox.pack_start(frame, False)
230 # hbox child at lower part
231 self.hbox = gtk.HBox()
232 self.hbox.pack_start(self.slider, True)
233 frame = gtk.Frame()
234 frame.set_shadow_type(gtk.SHADOW_IN)
235 frame.add(self.meter);
236 self.hbox.pack_start(frame, True)
237 frame = gtk.Frame()
238 frame.set_shadow_type(gtk.SHADOW_IN)
239 frame.add(self.hbox);
240 self.pack_start(frame, True)
242 self.volume_digits.set_size_request(0, -1)
243 self.pack_start(self.volume_digits, False)
245 if phat:
246 self.balance = phat.HFanSlider()
247 self.balance.set_default_value(0)
248 self.balance.set_adjustment(self.balance_adjustment)
249 self.pack_start(self.balance, False)
251 def unrealize(self):
252 channel.unrealize(self)
253 jack_mixer_c.remove_channel(self.channel)
254 self.channel = False
256 def on_rename_channel(self):
257 result = self.gui_factory.run_dialog_rename_channel(self.channel_name)
258 if result != None:
259 #print "renaming to \"%s\"" % result
260 self.channel_name = result
261 self.label_name.set_text(self.channel_name)
262 jack_mixer_c.channel_rename(self.channel, self.channel_name)
264 def on_label_mouse(self, widget, event):
265 if event.type == gtk.gdk._2BUTTON_PRESS:
266 if event.button == 1:
267 self.on_rename_channel()
269 def on_mute_toggled(self, button):
270 if self.mute.get_active():
271 #print "muted"
272 jack_mixer_c.channel_mute(self.channel)
273 else:
274 #print "unmuted"
275 jack_mixer_c.channel_unmute(self.channel)
277 def on_solo_toggled(self, button):
278 if self.solo.get_active():
279 #print "soloed"
280 jack_mixer_c.channel_solo(self.channel)
281 else:
282 #print "unsoloed"
283 jack_mixer_c.channel_unsolo(self.channel)
285 def serialization_name(self):
286 return input_channel_serialization_name()
288 def serialize(self, object_backend):
289 object_backend.add_property("name", self.channel_name)
290 if self.stereo:
291 object_backend.add_property("type", "stereo")
292 else:
293 object_backend.add_property("type", "mono")
294 channel.serialize(self, object_backend)
296 def unserialize_property(self, name, value):
297 if name == "name":
298 self.channel_name = str(value)
299 return True
300 if name == "type":
301 if value == "stereo":
302 self.stereo = True
303 return True
304 if value == "mono":
305 self.stereo = False
306 return True
307 return channel.unserialize_property(self, name, value)
309 def input_channel_serialization_name():
310 return "input_channel"
312 class main_mix(channel):
313 def __init__(self, mixer, gui_factory):
314 channel.__init__(self, mixer, gui_factory, "MAIN", True)
316 def realize(self):
317 channel.realize(self)
318 self.channel = jack_mixer_c.get_main_mix_channel(self.mixer)
320 self.on_volume_changed(self.slider_adjustment)
321 self.on_balance_changed(self.balance_adjustment)
323 # vbox child at upper part
324 self.vbox = gtk.VBox()
325 self.pack_start(self.vbox, False)
326 self.label_name = gtk.Label()
327 self.label_name.set_text(self.channel_name)
328 self.label_name.set_size_request(0, -1)
329 self.vbox.pack_start(self.label_name, False)
330 frame = gtk.Frame()
331 frame.set_shadow_type(gtk.SHADOW_IN)
332 frame.add(self.abspeak);
333 self.vbox.pack_start(frame, False)
335 # hbox child at lower part
336 self.hbox = gtk.HBox()
337 self.hbox.pack_start(self.slider, True)
338 frame = gtk.Frame()
339 frame.set_shadow_type(gtk.SHADOW_IN)
340 frame.add(self.meter);
341 self.hbox.pack_start(frame, True)
342 frame = gtk.Frame()
343 frame.set_shadow_type(gtk.SHADOW_IN)
344 frame.add(self.hbox);
345 self.pack_start(frame, True)
347 self.volume_digits.set_size_request(0, -1)
348 self.pack_start(self.volume_digits, False)
350 if phat:
351 self.balance = phat.HFanSlider()
352 self.balance.set_default_value(0)
353 self.balance.set_adjustment(self.balance_adjustment)
354 self.pack_start(self.balance, False)
356 def unrealize(self):
357 channel.unrealize(self)
358 self.channel = False
360 def serialization_name(self):
361 return main_mix_serialization_name()
363 def main_mix_serialization_name():
364 return "main_mix_channel"