1 //
2 // vumeter.cxx
3 //
4 // vumeter bar widget routines.
5 //
6 // A part of the fldigi.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library 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 GNU
16 // Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 // ----------------------------------------------------------------------------
21 
22 #include <iostream>
23 #include <config.h>
24 #include <cmath>
25 
26 #include <FL/Fl.H>
27 #include <FL/fl_draw.H>
28 
29 #include "vumeter.h"
30 
31 #define min(a,b) ((a) <= (b) ? (a) : (b) )
32 #define max(a,b) ((a) >= (b) ? (a) : (b) )
33 
34 //
35 // vumeter is a vumeter bar widget based off Fl_Widget that shows a
36 // standard vumeter bar in horizontal format
37 
38 const char * vumeter::meter_face = "|.-120.-110.-100..-90..-80..-70..-60..-50..-40..-30..-20..-10...|";
draw()39 void vumeter::draw()
40 {
41 	int	bx, by, bw;//, bh;	// Box areas...
42 	int	tx, tw, th;		// Temporary X + width
43 	int meter_width, meter_height;
44 
45 // Get the box borders...
46 	bx = Fl::box_dx(box());
47 	by = Fl::box_dy(box());
48 	bw = Fl::box_dw(box());
49 //	bh = Fl::box_dh(box());
50 // Defne the inner box
51 	tx = x() + bx;
52 	tw = w() - bw;
53 	th = h() - 2 * by - 2;//bh;
54 // Determine optimal meter face height
55 	int fsize = 1;
56 	fl_font(FL_COURIER, fsize);
57 	meter_height = fl_height();
58 	while (meter_height < th) {
59 		fsize++;
60 		fsize++;
61 		fl_font(FL_COURIER, fsize);
62 		meter_height = fl_height();
63 	}
64 	fsize--;
65 	fl_font(FL_COURIER, fsize);
66 	meter_height = fl_height();
67 // Find visible scale
68 	const char *meter = meter_face;
69 	minimum_ = -130;
70 	maximum_ = 0;
71 
72 	meter_width = fl_width(meter);
73 	while (meter_width > tw && *meter != 0) {
74 		meter++;
75 		meter_width = fl_width(meter);
76 		minimum_ += 2;
77 	}
78 
79 	int mwidth = round(meter_width * (value_ - minimum_) / (maximum_ - minimum_));
80 	int PeakPos = round (meter_width * (peakv_ - minimum_) / (maximum_ - minimum_));
81 
82 	mwidth = max ( min ( mwidth, meter_width), 0 );
83 	PeakPos = max ( min ( PeakPos, meter_width), 0 );
84 
85 // Draw the box and label...
86 	fl_push_clip(x(), y(), w(), h());
87 	draw_box(box(), x(), y(), w(), h(), bgnd_);
88 	draw_box(FL_FLAT_BOX, tx, y() + by, tw, th, bgnd_);
89 	if (mwidth > 0) {
90 		draw_box(FL_FLAT_BOX,
91 			tx + (w() - meter_width) / 2, y() + by + (th - meter_height) / 2 + 1,
92 			mwidth,
93 			meter_height,
94 			fgnd_);
95 		draw_box(FL_FLAT_BOX,
96 			tx + (w() - meter_width) / 2 + PeakPos, y() + by + (th - meter_height) / 2 + 1,
97 			2,
98 			meter_height,
99 			peak_color);
100 	}
101 	label(meter);
102 	labelfont(FL_COURIER);
103 	labelsize(fsize);
104 	labelcolor(scale_color);
105 	draw_label();
106 	fl_pop_clip();
107 }
108 
vumeter(int X,int Y,int W,int H,const char * label)109 vumeter::vumeter(int X, int Y, int W, int H, const char *label)
110 : Fl_Widget(X, Y, W, H, "")
111 {
112 	align(FL_ALIGN_INSIDE);
113 	box(FL_DOWN_BOX);
114 	bgnd_ = FL_BACKGROUND2_COLOR;
115 	fgnd_ = FL_GREEN;
116 	peak_color  = FL_RED;
117 	scale_color = FL_BLACK;
118 
119 	minimum_ = -100.0;
120 	maximum_ = 0.0;
121 	value_ = -50;
122 	avg_ = 10;
123 	aging_ = 10;
124 	clear();
125 	cbFunc = 0;
126 }
127 
value(double v)128 void vumeter::value(double v) {
129 	double vdb = 20 * log10(v == 0 ? 1e-9 : v);
130 //	if (vdb < minimum_) vdb = minimum_;
131 //	if (vdb > maximum_) vdb = maximum_;
132 
133 	peakv_ = -100;
134 	for (int i = 1; i < aging_; i++) {
135 		peak_[i-1] = peak_[i];
136 		if (peakv_ < peak_[i])
137 			peakv_ = peak_[i];
138 	}
139 	peak_[aging_ - 1] = vdb;
140 	if (peakv_ < peak_[aging_ - 1])
141 		peakv_ = peak_[aging_ - 1];
142 
143 	value_ -= vals_[0];
144 	for (int i = 1; i < avg_; i++)
145 		vals_[i-1] = vals_[i];
146 	value_ += (vals_[avg_- 1] = vdb / avg_);
147 
148 	redraw();
149 }
150 
value()151 double vumeter::value()
152 {
153 	return (value_);
154 }
155 
aging(int n)156 void vumeter::aging (int n)
157 {
158 	if (n <= 10 && n > 0) aging_ = n;
159 	else aging_ = 5;
160 	for (int i = 0; i < aging_; i++) peak_[i] = peakv_;
161 }
162 
avg(int n)163 void vumeter::avg (int n)
164 {
165 	if (n <= 10 && n > 0) avg_ = n;
166 	else avg_ = 5;
167 	for (int i = 0; i < avg_; i++) vals_[i] = value_ / avg_;
168 }
169 
clear()170 void vumeter::clear ()
171 {
172 	for (int i = 0; i < 10; i++) {
173 		vals_[i] = peak_[i] = 0;
174 	}
175 	peakv_ = value_ = 0;
176 }
177 
178 //
179 // End of vumeter.cxx
180 //
181