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