1 /*
2 * oscilloscope.cc
3 * DIN Is Noise is copyright (c) 2006-2021 Jagannathan Sampath
4 * DIN Is Noise is released under GNU Public License 2.0
5 * For more information, please visit https://dinisnoise.org/
6 */
7
8 #include "dingl.h"
9 #include "oscilloscope.h"
10 #include "font.h"
11 #include "viewwin.h"
12 #include "input.h"
13 #include "log.h"
14 #include "console.h"
15 #include <string>
16 #include <algorithm>
17 using namespace std;
18
19 extern string user_data_dir;
20 extern int FPS;
21 extern int CURRENT_INSTRUMENT;
22 extern const int NUM_INSTRUMENTS;
23 extern int lmb;
24 extern int mousex, mouseyy;
25 extern viewport view;
26 extern int line_height;
27
oscilloscope(const string & _settingsf)28 oscilloscope::oscilloscope (const string& _settingsf) : win (0, 0, 2 * MAX_SAMPLES, 250) {
29 vertex_array = new int [8 * MAX_SAMPLES];
30 color_array = new float [16 * MAX_SAMPLES];
31 viewr = 0;
32 addr = 1;
33 settingsf = _settingsf;
34 label_counter = MILLION;
35 fld.set_listener (this);
36 load ();
37 px = py = -1;
38 lmb_clicked = move = stop_move = 0;
39 sample_t::lmin = sample_t::lmax = sample_t::rmin = sample_t::rmax = 0; // ok for oscilloscope.
40 sprintf (lbuf1, "min %2.2f, max %2.2f", sample_t::lmin, sample_t::lmax);
41 sprintf (rbuf1, "min %2.2f, max %2.2f", sample_t::rmin, sample_t::rmax);
42 lr = lg = lb = 0.0f;
43 rr = rg = rb = 0.0f;
44 }
45
load()46 int oscilloscope::load () {
47 ifstream file ((user_data_dir + settingsf).c_str(), ios::in);
48 if (!file) return 0;
49 string ignore;
50 for (int i = 0; i < NUM_INSTRUMENTS; ++i) {
51 file >> ignore >> left;
52 file >> ignore >> base;
53 file >> ignore >> height;
54 file >> ignore >> num_samples;
55 file >> ignore >> visible;
56 file >> ignore >> folded;
57 params.push_back (oscilloscope_params_t (left, base, height, num_samples, visible, folded));
58 }
59 return 1;
60 }
61
save()62 int oscilloscope::save () {
63 ofstream file ((user_data_dir + settingsf).c_str(), ios::out);
64 if (!file) return false;
65 for (int i = 0; i < NUM_INSTRUMENTS; ++i) {
66 oscilloscope_params_t& op = params[i];
67 file << "left " << op.left << endl;
68 file << "base " << op.base << endl;
69 file << "height " << op.height << endl;
70 file << "num_samples " << op.num_samples << endl;
71 file << "visible " << op.visible << endl;
72 file << "folded " << op.folded << endl;
73 }
74 return 1;
75 }
76
load_current_instrument()77 void oscilloscope::load_current_instrument () {
78 oscilloscope_params_t& op = params[CURRENT_INSTRUMENT];
79 left = op.left;
80 base = op.base;
81 height = op.height;
82 num_samples = op.num_samples;
83 visible = op.visible;
84 folded = op.folded;
85 win (left, base - height, left + 2 * num_samples, base + height);
86 set_folded (folded);
87 set_num_samples (num_samples); // calls calc_draw_params
88 // if (visible) show (); else hide ();
89 }
90
save_current_instrument()91 void oscilloscope::save_current_instrument () {
92 oscilloscope_params_t& op = params[CURRENT_INSTRUMENT];
93 op.left = win.left;
94 op.base = base;
95 op.height = height;
96 op.num_samples = num_samples;
97 op.visible = visible;
98 op.folded = folded;
99 }
100
~oscilloscope()101 oscilloscope::~oscilloscope () {
102 save ();
103 delete[] vertex_array;
104 delete[] color_array;
105 }
106
calc_draw_params()107 void oscilloscope::calc_draw_params () {
108 base = win.midy;
109 leftx = win.left;
110 rightx = leftx + num_samples;
111 endx = rightx + num_samples - 1;
112 ndraw = 4 * num_samples;
113 win (leftx, base - height, endx, base + height);
114 int dheight = 5;
115 pick_win (win.left, base - dheight, win.right, base + dheight);
116 lh = line_height;
117 lly = base - lh;
118 lry = lly;
119 fld.set_pos (leftx - 1.5 * fld.size, base - fld.size);
120 }
121
set_height(int h)122 void oscilloscope::set_height (int h) {
123 height = h;
124 calc_draw_params ();
125 }
126
set_num_samples(int n)127 void oscilloscope::set_num_samples (int n) {
128 num_samples = min (n, MAX_SAMPLES);
129 viewr = 0;
130 addr = 1;
131 calc_draw_params ();
132 }
133
handle_input()134 int oscilloscope::handle_input () {
135
136 int result = fld.handle_input ();
137 if (result) return result;
138
139 int x = mousex;
140 int y = mouseyy;
141
142 if (is_lmb (this)) {
143 if (lmb_clicked == 0) {
144 lmb_clicked = 1;
145 if (move) {
146 move = 0;
147 stop_move = 1;
148 } else if (inbox (pick_win, x, y)) { // pick_win is small window along zero line of oscilloscope
149 move = 1;
150 is_lmb.tie = this;
151 }
152 }
153 } else {
154 if (move) {
155 int dx = x - px, dy = y - py;
156 win.move (dx, dy);
157 calc_draw_params ();
158 } else if (stop_move) {
159 stop_move = 0;
160 is_lmb.clear (this);
161 }
162 lmb_clicked = 0;
163 }
164
165 px = x;
166 py = y;
167 result = move;
168 return result;
169 }
170
add_samples(float * outl,float * outr,int n)171 void oscilloscope::add_samples (float* outl, float* outr, int n) {
172 for (int i = 0; i < n; ++i) {
173 sample_t& sa = samples[addr];
174 float l = outl[i], r = outr[i];
175 sa.left = l; sa.right = r;
176 sample_t::lmin = min (sa.left, sample_t::lmin);
177 sample_t::lmax = max (sa.left, sample_t::lmax);
178 sample_t::rmin = min (sa.right, sample_t::rmin);
179 sample_t::rmax = max (sa.right, sample_t::rmax);
180 if (sample_t::lmin < -1 || sample_t::rmin < -1 || sample_t::lmax > 1 || sample_t::rmax > 1) limit = 1; else limit = 0;
181 if (++addr >= num_samples) addr = 0;
182 if (addr == viewr) {if (++viewr >= num_samples) viewr = 0;}
183 }
184 }
185
draw()186 void oscilloscope::draw () {
187
188 // calc left & right labels
189 if (++label_counter >= FPS) { // update labels once a second
190 char lb = '.', rb = '.';
191 float lsum = sample_t::lmin * sample_t::lmin + sample_t::lmax * sample_t::lmax;
192 float rsum = sample_t::rmin * sample_t::rmin + sample_t::rmax * sample_t::rmax;
193 if (lsum > rsum) lb = '@';
194 else if (rsum > lsum) rb = '@';
195 sprintf (lbuf1, "min %2.2f, max %2.2f %c", sample_t::lmin, sample_t::lmax, lb);
196 sprintf (rbuf1, "min %2.2f, max %2.2f %c", sample_t::rmin, sample_t::rmax, rb);
197 sample_t::lmin = sample_t::lmax = sample_t::rmin = sample_t::rmax = 0; // ok for oscilloscope.
198 label_counter = 0;
199 }
200
201 if (folded == 0) {
202
203 // draw left & right channels
204 int x1 = leftx, x2 = rightx, y0 = base;
205 for (int i = 0, j = viewr, vi = 0, ci = 0; i < num_samples; ++i, vi += 8, ci += 16) {
206
207 float l = samples[j].left;
208 float r = samples[j].right;
209
210 int ly = (int)(l * win.height + 0.5);
211 int ry = (int)(r * win.height + 0.5);
212
213 // distortion is red
214 //
215 float lrr = lr, lgg = lg, lbb = lb;
216 if (l > 1 || l < -1) {lrr = 1; lgg = 0; lbb = 0;}
217 float rrr = rr, rgg = rg, rbb = rb;
218 if (r > 1 || r < -1) {rrr = 1; rgg = 0; rbb = 0;}
219
220 vertex_array [vi] = x1;
221 vertex_array [vi+1] = y0;
222 vertex_array [vi+2] = x1;
223 vertex_array [vi+3] = y0 + ly;
224 vertex_array [vi+4] = x2;
225 vertex_array [vi+5] = y0;
226 vertex_array [vi+6] = x2;
227 vertex_array [vi+7] = y0 + ry;
228
229 color_array [ci] = color_array[ci+4] = lrr;
230 color_array [ci+1] = color_array[ci+5] = lgg;
231 color_array [ci+2] = color_array[ci+6] = lbb;
232 color_array [ci+3] = color_array[ci+7] = 1;
233 color_array [ci+8] = color_array[ci+12] = rrr;
234 color_array [ci+9] = color_array[ci+13] = rgg;
235 color_array [ci+10] = color_array[ci+14] = rbb;
236 color_array [ci+11] = color_array[ci+15] = 1;
237
238 if (++j >= num_samples) j = 0;
239 ++x1; ++x2;
240 }
241 glEnableClientState (GL_COLOR_ARRAY);
242 glColorPointer (4, GL_FLOAT, 0, color_array);
243 glVertexPointer (2, GL_INT, 0, vertex_array);
244 glDrawArrays (GL_LINES, 0, ndraw);
245 glDisableClientState (GL_COLOR_ARRAY);
246 }
247
248 glColor3f (lr , lg, lb);
249 draw_string (lbuf1, leftx, lly, 0);
250 vertex_array[0]=leftx;vertex_array[1]=win.midy;
251 vertex_array[2]=rightx;vertex_array[3]=win.midy;
252 glVertexPointer (2, GL_INT, 0, vertex_array);
253 glDrawArrays (GL_LINES, 0, 2);
254
255 glColor3f (rr, rg, rb);
256 draw_string (rbuf1, rightx, lry, 0);
257 vertex_array[0]=rightx;vertex_array[1]=win.midy;
258 vertex_array[2]=endx;vertex_array[3]=win.midy;
259 glVertexPointer (2, GL_INT, 0, vertex_array);
260 glDrawArrays (GL_LINES, 0, 2);
261
262 fld.draw ();
263
264 }
265
set_folded(int f)266 void oscilloscope::set_folded (int f) {
267 folded = f;
268 if (folded) {
269 fld.set_dir (arrow_button::right);
270 } else {
271 fld.set_dir (arrow_button::up);
272 }
273 }
274
clicked(button & b)275 void oscilloscope::clicked (button& b) {
276 set_folded (!folded);
277 }
278
oscilloscope_params_t(int l,int b,int h,int ns,int v,int f)279 oscilloscope_params_t::oscilloscope_params_t (int l, int b, int h, int ns, int v, int f) {
280 left = l;
281 base = b;
282 height = h;
283 num_samples = ns;
284 visible = v;
285 folded = f;
286 }
287
288
289
290