Rev 2302 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
964 | jag | 1 | /* |
2 | * oscilloscope.cc |
||
2302 | jag | 3 | * DIN Is Noise is copyright (c) 2006-2025 Jagannathan Sampath |
1713 | jag | 4 | * DIN Is Noise is released under GNU Public License 2.0 |
1479 | jag | 5 | * For more information, please visit https://dinisnoise.org/ |
964 | jag | 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 CURRENT_INSTRUMENT; |
||
21 | extern const int NUM_INSTRUMENTS; |
||
22 | extern int lmb; |
||
23 | extern int mousex, mouseyy; |
||
24 | extern viewport view; |
||
25 | extern int line_height; |
||
26 | |||
1924 | jag | 27 | oscilloscope::oscilloscope (const string& _settingsf) : win (0, 0, 2048, 250) { |
1925 | jag | 28 | samples = 0; |
1927 | jag | 29 | vertices = 0; |
30 | colors = 0; |
||
964 | jag | 31 | settingsf = _settingsf; |
1927 | jag | 32 | fold.set_listener (this); |
964 | jag | 33 | load (); |
34 | px = py = -1; |
||
35 | lmb_clicked = move = stop_move = 0; |
||
36 | sample_t::lmin = sample_t::lmax = sample_t::rmin = sample_t::rmax = 0; // ok for oscilloscope. |
||
2278 | jag | 37 | sprintf (lbuf1, "min %1.2f / max %1.2f", sample_t::lmin, sample_t::lmax); |
38 | sprintf (rbuf1, "min %1.2f / max %1.2f", sample_t::rmin, sample_t::rmax); |
||
1925 | jag | 39 | lr = 0; lg = lb = 1.0f; |
40 | rr = rg = 1.0; rb = 0.0f; |
||
1920 | jag | 41 | opacity = 1.0f; |
2304 | jag | 42 | distort = 0; |
964 | jag | 43 | } |
44 | |||
1924 | jag | 45 | oscilloscope::~oscilloscope () { |
46 | save (); |
||
47 | delete[] samples; |
||
1927 | jag | 48 | delete[] vertices; |
49 | delete[] colors; |
||
1924 | jag | 50 | } |
51 | |||
52 | void oscilloscope::alloc (int n) { |
||
1925 | jag | 53 | max_samples = n; |
1924 | jag | 54 | if (samples) delete[] samples; |
1927 | jag | 55 | if (vertices) delete[] vertices; |
56 | if (colors) delete[] colors; |
||
1925 | jag | 57 | samples = new sample_t [max_samples]; |
1927 | jag | 58 | vertices = new int [8 * max_samples]; |
59 | colors = new float [16 * max_samples]; |
||
1925 | jag | 60 | set_num_samples (num_samples); |
1924 | jag | 61 | } |
62 | |||
2113 | jag | 63 | int oscilloscope::set_num_samples (int n) { |
1925 | jag | 64 | num_samples = min (n, max_samples); |
65 | startsamp = max_samples - num_samples; |
||
66 | calc_draw_params (); |
||
2113 | jag | 67 | return num_samples; |
1925 | jag | 68 | } |
69 | |||
70 | void oscilloscope::calc_draw_params () { |
||
71 | base = win.midy; |
||
72 | leftx = win.left; |
||
73 | rightx = leftx + num_samples; |
||
74 | endx = rightx + num_samples - 1; |
||
75 | ndraw = 4 * num_samples; |
||
76 | win (leftx, base - height, endx, base + height); |
||
77 | int dheight = 5; |
||
78 | pick_win (win.left, base - dheight, win.right, base + dheight); |
||
79 | lh = line_height; |
||
80 | lly = base - lh; |
||
81 | lry = lly; |
||
1927 | jag | 82 | fold.set_pos (leftx - 1.5 * fold.size, base - fold.size); |
1925 | jag | 83 | } |
84 | |||
964 | jag | 85 | int oscilloscope::load () { |
86 | ifstream file ((user_data_dir + settingsf).c_str(), ios::in); |
||
87 | if (!file) return 0; |
||
88 | string ignore; |
||
2278 | jag | 89 | file >> ignore >> updlbl.triggert; |
964 | jag | 90 | for (int i = 0; i < NUM_INSTRUMENTS; ++i) { |
91 | file >> ignore >> left; |
||
92 | file >> ignore >> base; |
||
93 | file >> ignore >> height; |
||
94 | file >> ignore >> num_samples; |
||
1920 | jag | 95 | file >> ignore >> opacity; |
964 | jag | 96 | file >> ignore >> visible; |
97 | file >> ignore >> folded; |
||
1920 | jag | 98 | params.push_back (oscilloscope_params_t (left, base, height, num_samples, opacity, visible, folded)); |
964 | jag | 99 | } |
2278 | jag | 100 | updlbl.start (); |
964 | jag | 101 | return 1; |
102 | } |
||
103 | |||
104 | int oscilloscope::save () { |
||
105 | ofstream file ((user_data_dir + settingsf).c_str(), ios::out); |
||
106 | if (!file) return false; |
||
2278 | jag | 107 | file << "update-label-every " << updlbl.triggert << endl; |
964 | jag | 108 | for (int i = 0; i < NUM_INSTRUMENTS; ++i) { |
109 | oscilloscope_params_t& op = params[i]; |
||
110 | file << "left " << op.left << endl; |
||
111 | file << "base " << op.base << endl; |
||
112 | file << "height " << op.height << endl; |
||
113 | file << "num_samples " << op.num_samples << endl; |
||
1920 | jag | 114 | file << "opacity " << op.opacity << endl; |
964 | jag | 115 | file << "visible " << op.visible << endl; |
116 | file << "folded " << op.folded << endl; |
||
117 | } |
||
118 | return 1; |
||
119 | } |
||
120 | |||
121 | void oscilloscope::load_current_instrument () { |
||
122 | oscilloscope_params_t& op = params[CURRENT_INSTRUMENT]; |
||
123 | left = op.left; |
||
124 | base = op.base; |
||
125 | height = op.height; |
||
126 | num_samples = op.num_samples; |
||
1920 | jag | 127 | opacity = op.opacity; |
1518 | jag | 128 | visible = op.visible; |
964 | jag | 129 | folded = op.folded; |
130 | win (left, base - height, left + 2 * num_samples, base + height); |
||
131 | set_folded (folded); |
||
132 | set_num_samples (num_samples); // calls calc_draw_params |
||
133 | } |
||
134 | |||
135 | void oscilloscope::save_current_instrument () { |
||
136 | oscilloscope_params_t& op = params[CURRENT_INSTRUMENT]; |
||
137 | op.left = win.left; |
||
138 | op.base = base; |
||
139 | op.height = height; |
||
140 | op.num_samples = num_samples; |
||
1920 | jag | 141 | op.opacity = opacity; |
964 | jag | 142 | op.visible = visible; |
143 | op.folded = folded; |
||
144 | } |
||
145 | |||
146 | void oscilloscope::set_height (int h) { |
||
147 | height = h; |
||
148 | calc_draw_params (); |
||
149 | } |
||
150 | |||
151 | int oscilloscope::handle_input () { |
||
152 | |||
1927 | jag | 153 | int result = fold.handle_input (); |
964 | jag | 154 | if (result) return result; |
155 | |||
156 | int x = mousex; |
||
157 | int y = mouseyy; |
||
158 | |||
159 | if (is_lmb (this)) { |
||
160 | if (lmb_clicked == 0) { |
||
161 | lmb_clicked = 1; |
||
162 | if (move) { |
||
163 | move = 0; |
||
164 | stop_move = 1; |
||
165 | } else if (inbox (pick_win, x, y)) { // pick_win is small window along zero line of oscilloscope |
||
166 | move = 1; |
||
167 | is_lmb.tie = this; |
||
168 | } |
||
169 | } |
||
170 | } else { |
||
171 | if (move) { |
||
172 | int dx = x - px, dy = y - py; |
||
173 | win.move (dx, dy); |
||
174 | calc_draw_params (); |
||
175 | } else if (stop_move) { |
||
176 | stop_move = 0; |
||
177 | is_lmb.clear (this); |
||
178 | } |
||
179 | lmb_clicked = 0; |
||
180 | } |
||
181 | |||
182 | px = x; |
||
183 | py = y; |
||
184 | result = move; |
||
185 | return result; |
||
186 | } |
||
187 | |||
188 | void oscilloscope::add_samples (float* outl, float* outr, int n) { |
||
1924 | jag | 189 | |
964 | jag | 190 | for (int i = 0; i < n; ++i) { |
1925 | jag | 191 | sample_t& sa = samples [i]; |
192 | sa.left = outl[i]; sa.right = outr[i]; |
||
964 | jag | 193 | sample_t::lmin = min (sa.left, sample_t::lmin); |
194 | sample_t::lmax = max (sa.left, sample_t::lmax); |
||
195 | sample_t::rmin = min (sa.right, sample_t::rmin); |
||
196 | sample_t::rmax = max (sa.right, sample_t::rmax); |
||
197 | } |
||
1924 | jag | 198 | |
2066 | jag | 199 | // used by mondrian |
1927 | jag | 200 | float lm = sample_t::lmin * sample_t::rmin, rm = sample_t::lmax * sample_t::rmax; |
201 | limit = (lm > 1 || rm > 1); |
||
1924 | jag | 202 | |
1925 | jag | 203 | { |
204 | char lb = '.', rb = '.'; |
||
205 | float lsum = sample_t::lmin * sample_t::lmin + sample_t::lmax * sample_t::lmax; |
||
206 | float rsum = sample_t::rmin * sample_t::rmin + sample_t::rmax * sample_t::rmax; |
||
207 | if (lsum > rsum) lb = '@'; else if (rsum > lsum) rb = '@'; |
||
2278 | jag | 208 | if (updlbl (ui_clk())) { |
209 | sprintf (lbuf1, "min %1.2f / max %1.2f %c", sample_t::lmin, sample_t::lmax, lb); |
||
210 | sprintf (rbuf1, "min %1.2f / max %1.2f %c", sample_t::rmin, sample_t::rmax, rb); |
||
211 | updlbl.start (); |
||
212 | } |
||
1925 | jag | 213 | sample_t::lmin = sample_t::lmax = sample_t::rmin = sample_t::rmax = 0; |
214 | } |
||
1924 | jag | 215 | |
964 | jag | 216 | if (folded == 0) { |
217 | |||
218 | int x1 = leftx, x2 = rightx, y0 = base; |
||
1924 | jag | 219 | for (int i = 0, j = startsamp, vi = 0, ci = 0; i < num_samples; ++i, ++j, vi += 8, ci += 16) { |
964 | jag | 220 | |
221 | float l = samples[j].left; |
||
1925 | jag | 222 | float r = samples[j].right; |
964 | jag | 223 | |
1925 | jag | 224 | int ly = int (l * win.height); |
225 | int ry = int (r * win.height); |
||
964 | jag | 226 | |
1925 | jag | 227 | // distortion is red |
228 | // |
||
2304 | jag | 229 | |
1920 | jag | 230 | float l2 = l * l; |
964 | jag | 231 | float lrr = lr, lgg = lg, lbb = lb; |
1920 | jag | 232 | |
2304 | jag | 233 | if (l2 > 1.0f) {lrr = 1; lgg = 0; lbb = 0; distort = 1;} |
234 | |||
964 | jag | 235 | float rrr = rr, rgg = rg, rbb = rb; |
1920 | jag | 236 | float r2 = r * r; |
2304 | jag | 237 | if (r2 > 1.0f) {rrr = 1; rgg = 0; rbb = 0; distort = 1;} |
964 | jag | 238 | |
1927 | jag | 239 | vertices [vi] = x1; |
240 | vertices [vi+1] = y0; |
||
241 | vertices [vi+2] = x1; |
||
242 | vertices [vi+3] = y0 + ly; |
||
243 | vertices [vi+4] = x2; |
||
244 | vertices [vi+5] = y0; |
||
245 | vertices [vi+6] = x2; |
||
246 | vertices [vi+7] = y0 + ry; |
||
964 | jag | 247 | |
1927 | jag | 248 | colors [ci] = colors[ci+4] = lrr; |
249 | colors [ci+1] = colors[ci+5] = lgg; |
||
250 | colors [ci+2] = colors[ci+6] = lbb; |
||
251 | colors [ci+3] = colors[ci+7] = opacity; |
||
252 | colors [ci+8] = colors[ci+12] = rrr; |
||
253 | colors [ci+9] = colors[ci+13] = rgg; |
||
254 | colors [ci+10] = colors[ci+14] = rbb; |
||
255 | colors [ci+11] = colors[ci+15] = opacity; |
||
964 | jag | 256 | |
257 | ++x1; ++x2; |
||
1925 | jag | 258 | |
964 | jag | 259 | } |
1925 | jag | 260 | |
261 | } |
||
262 | |||
263 | } |
||
264 | |||
265 | void oscilloscope::draw () { |
||
266 | |||
267 | if (folded == 0) { |
||
1927 | jag | 268 | // draw samples |
269 | // |
||
1925 | jag | 270 | glEnable (GL_BLEND); |
271 | glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
||
1146 | jag | 272 | glEnableClientState (GL_COLOR_ARRAY); |
1927 | jag | 273 | glColorPointer (4, GL_FLOAT, 0, colors); |
274 | glVertexPointer (2, GL_INT, 0, vertices); |
||
964 | jag | 275 | glDrawArrays (GL_LINES, 0, ndraw); |
276 | glDisableClientState (GL_COLOR_ARRAY); |
||
1920 | jag | 277 | glDisable (GL_BLEND); |
1927 | jag | 278 | |
964 | jag | 279 | } |
280 | |||
1927 | jag | 281 | // draw L and R labels |
282 | // |
||
2304 | jag | 283 | if (limit) glColor3f (1, 0, 0); else glColor3f (lr , lg, lb); |
964 | jag | 284 | draw_string (lbuf1, leftx, lly, 0); |
1920 | jag | 285 | glBegin (GL_LINES); |
286 | glVertex2i (leftx, win.midy); |
||
287 | glVertex2i (rightx, win.midy); |
||
288 | glEnd (); |
||
964 | jag | 289 | |
2304 | jag | 290 | if (limit) glColor3f (1, 0, 0); else glColor3f (rr, rg, rb); |
2278 | jag | 291 | draw_string (rbuf1, rightx, lry, 0); |
1920 | jag | 292 | glBegin (GL_LINES); |
293 | glVertex2i (rightx, win.midy); |
||
294 | glVertex2i (endx, win.midy); |
||
295 | glEnd (); |
||
964 | jag | 296 | |
2304 | jag | 297 | //distort = 0; |
298 | |||
1927 | jag | 299 | fold.draw (); |
964 | jag | 300 | |
301 | } |
||
302 | |||
303 | void oscilloscope::set_folded (int f) { |
||
304 | folded = f; |
||
305 | if (folded) { |
||
1927 | jag | 306 | fold.set_dir (arrow_button::right); |
964 | jag | 307 | } else { |
1927 | jag | 308 | fold.set_dir (arrow_button::up); |
964 | jag | 309 | } |
310 | } |
||
311 | |||
312 | void oscilloscope::clicked (button& b) { |
||
313 | set_folded (!folded); |
||
314 | } |
||
315 | |||
1920 | jag | 316 | oscilloscope_params_t::oscilloscope_params_t (int l, int b, int h, int ns, float op, int v, int f) { |
964 | jag | 317 | left = l; |
318 | base = b; |
||
319 | height = h; |
||
320 | num_samples = ns; |
||
1920 | jag | 321 | opacity = op; |
964 | jag | 322 | visible = v; |
323 | folded = f; |
||
324 | } |