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