Initial commit
[fillmore] / src / marina / AudioMeter.vala
1 /* Copyright 2009-2010 Yorba Foundation
2  *
3  * This software is licensed under the GNU Lesser General Public License
4  * (version 2.1 or later).  See the COPYING file in this distribution. 
5  */
6
7 using Logging;
8
9 namespace View {
10 public class AudioMeter : Gtk.DrawingArea {
11     Cairo.ImageSurface meter = null;
12     Cairo.ImageSurface silkscreen;
13     
14     bool stereo = false;
15     double current_level_left = -100;
16     double current_level_right = -100;
17     const double minDB = -70;
18     
19     public AudioMeter(Model.AudioTrack track) {
20         int number_of_channels;
21         if (track.get_num_channels(out number_of_channels)) {
22             stereo = number_of_channels < 1;
23         }
24
25         this.requisition.height = 10;
26         expose_event.connect(on_expose_event);
27         track.level_changed.connect(on_level_changed);
28         track.channel_count_changed.connect(on_channel_count_changed);
29     }
30
31     void initialize_meter() {
32         meter = new Cairo.ImageSurface(Cairo.Format.ARGB32, 
33             allocation.width, allocation.height);
34         Cairo.Context context2 = new Cairo.Context(meter);
35         Cairo.Pattern pat = new Cairo.Pattern.linear(0, 0, allocation.width, 0);
36         pat.add_color_stop_rgb(0, 0.1, 1, 0.4);
37         pat.add_color_stop_rgb(0.8, 1, 1, 0);
38         pat.add_color_stop_rgb(1, 1, 0, 0);
39         context2.set_source(pat);
40         context2.rectangle(0, 0, allocation.width, allocation.height);
41         context2.fill();
42
43         silkscreen = new Cairo.ImageSurface(Cairo.Format.ARGB32,
44             allocation.width, allocation.height);
45         context2 = new Cairo.Context(silkscreen);
46         context2.set_source_rgba(0, 0, 0, 0);
47         context2.rectangle(0, 0, allocation.width, allocation.height);
48         context2.fill();
49
50         // draw the segment edges
51         for (int i=0;i<20;++i) {
52             context2.set_source_rgba(0, 0, 0, 1);
53             context2.rectangle(i * allocation.width / 20, 0, 3, allocation.height);
54             context2.fill();
55         }
56
57         // draw a bevel around the edge
58         context2.set_line_width(1.1);
59         context2.set_source_rgba(0.9, 0.9, 0.9, 0.5);
60         context2.rectangle(0, 0, allocation.width, allocation.height);
61         context2.stroke();
62     }
63
64     public bool on_expose_event(Gdk.EventExpose event) {
65         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_expose_event");
66         Gdk.Window window = get_window();
67         Cairo.Context context = Gdk.cairo_create(window);
68         if (meter == null) {
69             initialize_meter();
70         }
71
72         context.set_source_rgb(0, 0, 0);
73         context.rectangle(0, 0, allocation.width, allocation.height);
74         context.fill();
75
76         int bar_height = stereo ? (allocation.height / 2) - 1 : allocation.height - 2;
77
78         if (stereo) {
79             context.set_source_rgb(1, 1, 1);
80             context.rectangle(0, bar_height + 1, allocation.width, 0.3);
81             context.fill();
82         }
83
84         context.set_source_surface(meter, 0, 0);
85         int width = (int) (Math.pow10(current_level_left / 40) * allocation.width);
86         context.rectangle(0, 1, width, bar_height);
87
88         if (stereo) {
89             width = (int) (Math.pow10(current_level_right / 40) * allocation.width);
90             context.rectangle(0, bar_height + 2, width, bar_height);
91         }
92
93         context.clip();
94         context.paint_with_alpha(1);
95
96         context.set_source_surface(silkscreen, 0, 0);
97         context.paint_with_alpha(1);
98
99         return true;
100     }
101
102     public void on_level_changed(double level_left, double level_right) {
103         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_level_changed");
104         current_level_left = level_left < minDB ? minDB : level_left;
105         current_level_right = level_right < minDB ? minDB : level_right;
106         Gdk.Window window = get_window();
107         window.invalidate_rect(null, false);
108     }
109
110     public void on_channel_count_changed(int number_of_channels) {
111         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_channel_count_changed");
112         stereo = number_of_channels > 1;
113         window.invalidate_rect(null, false);
114     }
115 }
116 }