1 /*
2 * point_modulator.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 "audio.h"
9 #include "point_modulator.h"
10 #include "ui_list.h"
11 #include "console.h"
12 #include "file-utils.h"
13 #include <map>
14 using namespace std;
15 
16 #define DECLARE_WIDGET_ARRAY_wa widget* wa [] = {&title, &all, &none, &invert, &sync, &play, &kill, &plus, &fold, &x.depth, &x.bpm, &y.depth, &y.bpm, &scrub};
17 #define NUM_WIDGETS 14
18 #define NUM_WIDGETS_1 (NUM_WIDGETS - 1)
19 
20 extern audio_out aout;
21 extern char BUFFER[];
22 
23 typedef std::vector<mod_dat>::iterator mod_dat_iter;
24 
setup(curve_editor * _ed)25 void point_modulator::setup (curve_editor* _ed) {
26 
27 	ed = _ed;
28 	name = ed->name;
29 
30 	DECLARE_WIDGET_ARRAY_wa
31 	const char* texts [] = {"All", "None", "Invert", "Sync"};
32 	for (int i = 1; i < 5; ++i)  {
33 		label* l = dynamic_cast<label*>(wa[i]);
34 		l->set_text (texts[i-1]);
35 	}
36 
37 	for (int i = 1; i < 9; ++i) dynamic_cast<button*>(wa[i])->set_listener (this);
38 
39 	makefam (&title, &wa[1], NUM_WIDGETS_1);
40 
41 	for (int i = 5; i < 8; ++i) {
42 		button* wi = dynamic_cast<button*>(wa [i]);
43 		wi->set_size (16);
44 	}
45 
46 	title.set_moveable (1);
47 	title.movlis = this;
48 
49 	fold.set_dir (arrow_button::right);
50 	play.set_dir (arrow_button::right);
51 
52 	widget_load ("d_point_modulator", wa, NUM_WIDGETS);
53 
54 	x.depth.set ("X depth", 0.01f, -MILLION, MILLION, this, 0);
55 	x.depth.orient = mouse_slider_listener::Y;
56 
57 	x.bpm.set ("X BPM", 0.1f, 0, MILLION, this, 0);
58 	x.bpm.orient = mouse_slider_listener::Y;
59 
60 	y.depth.set ("Y depth", 0.01f, -MILLION, MILLION, this, 0);
61 	y.bpm.set ("Y BPM", 0.1f, 0, MILLION, this, 0);
62 
63 	scrub.set ("Scrub", 0.01f, -MILLION, MILLION, this, 0);
64 	scrub.set_value (0.0f);
65 	scrub.orient = mouse_slider_listener::Y;
66 
67 	folded = 1;
68 
69 	nlst = nsel = 0;
70 	multisel = 0;
71 
72 	load ();
73 
74 	set_title ();
75 
76 	moved ();
77 
78 	synced = 0;
79 
80 }
81 
82 extern multi_curve pomo_x_crv, pomo_y_crv;
mod_dat(hit_t & h,state_button * _sb,float _bpm)83 mod_dat::mod_dat (hit_t& h, state_button* _sb, float _bpm) : hit (h), sb (_sb), mod (&pomo_x_crv, &pomo_y_crv), init (h.get()) {
84 	mod.active = 1;
85 	mod.am.bv.set_bpm (_bpm);
86 	mod.fm.bv.set_bpm (_bpm);
87 }
88 
mod_dat()89 mod_dat::mod_dat () : sb (0), mod (&pomo_x_crv, &pomo_y_crv) {}
90 
91 
set_title()92 void point_modulator::set_title () {
93 	sprintf (BUFFER, "Point Modulator [%d]", nlst);
94 	title.set_text (BUFFER);
95 }
96 
point_modulator()97 point_modulator::point_modulator () {
98 	++ref;
99 }
100 
~point_modulator()101 point_modulator::~point_modulator () {
102 
103 	save ();
104 
105 	if (nlst) {
106 		for (int i = 0; i < nlst; ++i) {
107 			mod_dat& md = lst[i];
108 			state_button* sb = md.sb;
109 			delete sb;
110 		}
111 	}
112 
113 	if (--ref == 0) {
114 		DECLARE_WIDGET_ARRAY_wa
115 		widget_save ("d_point_modulator", wa, NUM_WIDGETS);
116 	}
117 
118 }
119 
load()120 void point_modulator::load () {
121 
122 	file_in fi ("pomo." + name);
123 	if (fi.opened) {
124 		ifstream& f = fi ();
125 
126 		string ignore;
127 		f >> ignore >> nlst;
128 
129 		if (nlst) {
130 			for (int i = 0; i < nlst; ++i) {
131 				hit_t h;
132 				f >> h.crv_id >> h.what >> h.id;
133 				h.crv = ed->curveinfo[h.crv_id].curve;
134 				mod_dat md;
135 				md.hit = h;
136 				modulator& mod = md.mod;
137 				f >> mod.active >> mod.am.depth >> mod.am.bv.bpm >> mod.fm.depth >> mod.fm.bv.bpm;
138 				f >> md.init.x >> md.init.y;
139 				f >> mod.am.bv.now >> mod.fm.bv.now;
140 				mod.am.bv.set_bpm (mod.am.bv.bpm);
141 				mod.fm.bv.set_bpm (mod.fm.bv.bpm);
142 				state_button* sb = new state_button;
143 				sb->set_listener (this);
144 				md.sb = sb;
145 				lst.push_back (md);
146 			}
147 		}
148 	}
149 }
150 
save()151 void point_modulator::save () {
152 	file_out fo ("pomo." + name);
153 	ofstream& f = fo ();
154 	f << "num_pomos " << nlst << endl;
155 	if (nlst) {
156 		for (int i = 0; i < nlst; ++i) {
157 			mod_dat& md = lst[i];
158 			hit_t& hit = md.hit;
159 			modulator& mod = md.mod;
160 			f << hit.crv_id << spc << hit.what << spc << hit.id << spc ;
161 			f << mod.active << spc << mod.am.depth << spc << mod.am.bv.bpm << spc << mod.fm.depth << spc << mod.fm.bv.bpm << spc;
162 			f << md.init.x << spc << md.init.y << spc;
163 			f << mod.am.bv.now << spc << mod.fm.bv.now << spc;
164 		}
165 	}
166 }
167 
handle_input()168 int point_modulator::handle_input () {
169 
170 	if (folded == 0) {
171 
172 		for (int i = 0; i < nlst; ++i) {
173 			mod_dat& md = lst[i];
174 			state_button* sb = md.sb;
175 			if (sb->handle_input()) return 1;
176 		}
177 
178 		DECLARE_WIDGET_ARRAY_wa
179 		for (int i = 0; i < NUM_WIDGETS; ++i) {
180 			widget* wi = wa[i];
181 			if (wi->handle_input()) return 1;
182 		}
183 
184 		multisel = SHIFT;
185 
186 	} else {
187 		if (fold.handle_input ()) return 1;
188 		else return title.handle_input ();
189 	}
190 
191 	return 0;
192 
193 }
194 
remove(const hit_t & h)195 void point_modulator::remove (const hit_t& h) {
196 	int p = nlst;
197 	int hv = h();
198 	for (mod_dat_iter i = lst.begin (), j = lst.end(); i != j;) {
199 		mod_dat& md = *i;
200 		state_button* sb = md.sb;
201 		int s;
202 		if (hv)
203 			s = md.hit.matched_id (h);
204 		else {
205 			s = sb->state;
206 			nsel -= s;
207 		}
208 		if (s) {
209 			title.remove_child (sb);
210 			delete sb;
211 			i = lst.erase (i);
212 			j = lst.end ();
213 			--nlst;
214 		} else ++i;
215 	}
216 	ensure_hit_ids ();
217 	rearrange ();
218 	int q = p - nlst;
219 	if (q) cons << RED << "Removed " << q << " point modulations" << eol;
220 	set_title ();
221 }
222 
ensure_hit_ids()223 void point_modulator::ensure_hit_ids () {
224 	for (mod_dat_iter i = lst.begin (), j = lst.end(); i != j; ++i) {
225 		mod_dat& md = *i;
226 		md.hit.ensure_id ();
227 	}
228 }
229 
rearrange()230 void point_modulator::rearrange () {
231 	int sx = title.extents.left;
232 	if (nlst) {
233 		for (int i = 0; i < nlst; ++i) {
234 			mod_dat& md = lst[i];
235 			state_button* sb = md.sb;
236 			sb->set_pos (sx, sby);
237 			sx += state_button::SIZE2;
238 		}
239 	}
240 	sbx = sx;
241 }
242 
on_lst(const item_op & op)243 void point_modulator::on_lst (const item_op& op) {
244 	int st;
245 	nsel = 0;
246 	for (int i = 0; i < nlst; ++i) {
247 		mod_dat& md = lst[i];
248 		state_button* sb = md.sb;
249 		st = op (sb->state);
250 		sb->set_state (st, 0);
251 		nsel += st;
252 	}
253 }
254 
changed(checkbutton & cb)255 void point_modulator::changed (checkbutton& cb) {
256 	int cbs = cb.state;
257 	if (multisel == 0) {
258 		on_lst (_desel);
259 		if (cbs == 0) cbs = 1;
260 		cb.set_state (cbs, 0);
261 	}
262 	if (cbs) ++nsel; else if (--nsel < 0) nsel = 0;
263 	set_ui ();
264 }
265 
set_ui()266 void point_modulator::set_ui () {
267 	if (nsel != 1) {
268 		spinner<float>* sp[] = {&x.depth, &x.bpm, &y.depth, &y.bpm};
269 		for (int i = 0; i < 4; ++i) sp[i]->set_value (0.0f);
270 		x.bpm.set_limits (-MILLION, MILLION);
271 		y.bpm.set_limits (-MILLION, MILLION);
272 	} else {
273 		for (int i = 0; i < nlst; ++i) {
274 			mod_dat& md = lst[i];
275 			modulator& mod = md.mod;
276 			if (md.sb->state) {
277 				float v [] = {mod.fm.depth, mod.fm.bv.bpm, mod.am.depth, mod.am.bv.bpm};
278 				spinner<float>* sp[] = {&x.depth, &x.bpm, &y.depth, &y.bpm};
279 				for (int i = 0; i < 4; ++i) sp[i]->set_value (v[i]);
280 				x.bpm.set_limits (0, MILLION);
281 				y.bpm.set_limits (0, MILLION);
282 				break;
283 			}
284 		}
285 	}
286 }
287 
changed(field & f)288 void point_modulator::changed (field& f) {
289 	if (&f == &x.depth.f_value) {
290 		for (int i = 0; i < nlst; ++i) {
291 			mod_dat& md = lst[i];
292 			if (md.sb->state) {
293 				md.mod.fm.depth += x.depth();
294 				cons << "modulator " << i << ", X depth = " << md.mod.fm.depth << eol;
295 			}
296 		}
297 	} else if (&f == &y.depth.f_value) {
298 		for (int i = 0; i < nlst; ++i) {
299 			mod_dat& md = lst[i];
300 			if (md.sb->state) {
301 				md.mod.am.depth += y.depth();
302 				cons << "modulator " << i << ", Y depth = " << md.mod.am.depth << eol;
303 			}
304 		}
305 	} else if (&f == &x.bpm.f_value) {
306 		for (int i = 0; i < nlst; ++i) {
307 			mod_dat& md = lst[i];
308 			if (md.sb->state) {
309 				md.mod.fm.bv.set_bpm (md.mod.fm.bv.bpm + x.bpm());
310 				cons << "modulator " << i << ", X BPM = " << md.mod.fm.bv.bpm << eol;
311 			}
312 		}
313 	} else if (&f == &y.bpm.f_value) {
314 		for (int i = 0; i < nlst; ++i) {
315 			mod_dat& md = lst[i];
316 			if (md.sb->state) {
317 				md.mod.am.bv.set_bpm (md.mod.am.bv.bpm + y.bpm());
318 				cons << "modulator " << i << ", Y BPM = " << md.mod.am.bv.bpm << eol;
319 			}
320 		}
321 	} else {
322 		for (int i = 0; i < nlst; ++i) {
323 			mod_dat& md = lst[i];
324 			if (md.sb->state) {
325 				float s = scrub();
326 				modulator& mod = md.mod;
327 				mod.am.bv.now += s;
328 				mod.fm.bv.now += s;
329 				mod.scrubbed = 1;
330 			}
331 		}
332 	}
333 }
334 
clicked(button & b)335 void point_modulator::clicked (button& b) {
336 	if (&b == &plus) {
337 		ed->modulate_point ();
338 	} else if (&b == &play) {
339 		if (nlst) {
340 			int g = 0;
341 			for (int i = 0; i < nlst; ++i) {
342 				mod_dat& md = lst[i];
343 				modulator& mod = md.mod;
344 				if (md.sb->state) {
345 					mod.active = !mod.active;
346 					++g;
347 				}
348 			}
349 			cons << GREEN << "Toggled " << g << " modulations" << eol;
350 		}
351 	} else if (&b == &kill) {
352 		remove ();
353 	} else if (&b == &all) {
354 		on_lst (_sel); set_ui ();
355 	} else if (&b == &invert) {
356 		on_lst (_togg); set_ui ();
357 	} else if (&b == &none) {
358 		on_lst (_desel); set_ui ();
359 	} else if (&b == &sync) {
360 		if (nlst) {
361 			int g = 0;
362 			for (int i = 0; i < nlst; ++i) {
363 				mod_dat& md = lst[i];
364 				modulator& mod = md.mod;
365 				if (md.sb->state) {
366 					mod.am.bv.now = mod.fm.bv.now = 0;
367 					++g;
368 				}
369 			}
370 			cons << GREEN << "Synced " << g << " modulations" << eol;
371 		}
372 	} else if (&b == &fold) {
373 		if (fold.dir == arrow_button::down) {
374 			title.hide (widget::only_children);
375 			fold.show ();
376 			fold.set_dir (arrow_button::right);
377 			folded = 1;
378 		} else {
379 			title.show ();
380 			fold.set_dir (arrow_button::down);
381 			folded = 0;
382 		}
383 	}
384 }
385 
draw()386 void point_modulator::draw () {
387 	if (folded == 0) {
388 		DECLARE_WIDGET_ARRAY_wa
389 		for (int i = 0; i < NUM_WIDGETS; ++i) {
390 			widget* wi = wa[i];
391 			if (wi->visible) wi->draw ();
392 		}
393 		for (int i = 0; i < nlst; ++i) {
394 			mod_dat& md = lst[i];
395 			state_button* sb = md.sb;
396 			if (sb->visible) sb->draw ();
397 		}
398 		glEnable (GL_LINE_STIPPLE);
399 		glLineStipple (1, 0xf00f);
400 		for (int i = 0; i < nlst; ++i) {
401 			mod_dat& md = lst[i];
402 			state_button* sb = md.sb;
403 			const point<float>& p = md.hit.get ();
404 			int vx, vy; ed->obj2view (p.x, p.y, vx, vy);
405 			if (sb->state) glColor3f (0, 1, 0); else glColor3f (1, 0, 0);
406 			glBegin (GL_LINES);
407 				glVertex2i (vx, vy);
408 				glVertex2i (sb->extents.midx, sb->extents.midy);
409 			glEnd ();
410 		}
411 		glDisable (GL_LINE_STIPPLE);
412 	} else {
413 		fold.draw ();
414 		title.draw ();
415 	}
416 
417 }
418 
moved()419 void point_modulator::moved () {
420 	sbx = title.extents.left + nlst * state_button::SIZE2;
421 	sby = title.extents.bottom - title.extents.height;
422 	rearrange ();
423 }
424 
validate()425 void point_modulator::validate () {
426 	if (nlst) {
427 		on_lst (_desel);
428 		for (int i = 0; i < nlst; ++i) {
429 			mod_dat& md = lst[i];
430 			state_button* sb = md.sb;
431 			if (md.hit(1)) // curve item exists?
432 				;
433 			else
434 				sb->set_state (1);
435 		}
436 		remove ();
437 	}
438 }
439 
hit(hit_t & h)440 int point_modulator::hit (hit_t& h) {
441 	if (nlst) {
442 		for (int i = 0; i < nlst; ++i) {
443 			mod_dat& md = lst[i];
444 			if (md.hit == h) {
445 				state_button* sb = md.sb;
446 				sb->toggle ();
447 				return 1;
448 			}
449 		}
450 	}
451 	return 0;
452 }
453 
bg()454 void point_modulator::bg () {
455 	if (nlst) {
456 		int ncrvs = ed->num_curves;
457 		int evals [ncrvs];
458 		int nevals = 0;
459 		for (int i = 0; i < nlst; ++i) {
460 			mod_dat& md = lst[i];
461 			modulator& mod = md.mod;
462 			if (mod.active || mod.scrubbed) {
463 				mod.calc ();
464 				ed->move (md.hit, md.init.x + mod.fm.result, md.init.y + mod.am.result, 0);
465 				evals [md.hit.crv_id] = 1;
466 				++nevals;
467 				mod.scrubbed = 0;
468 			}
469 		}
470 		if (nevals) {
471 			for (int i = 0, j = ncrvs; i < j; ++i) {
472 				if (evals[i]) {
473 					curve_info& ci = ed->curveinfo[i];
474 					multi_curve* crv = ci.curve;
475 					crv->evaluate ();
476 					ci.lisner->edited (ed, i);
477 				}
478 			}
479 		}
480 	}
481 }
482 
update_solvers(int k)483 void point_modulator::update_solvers (int k) {
484 	if (nlst) {
485 		if (k) {
486 			for (int i = 0; i < nlst; ++i) {
487 				mod_dat& md = lst[i];
488 				md.mod.am.bv.sol.update ();
489 			}
490 		} else {
491 			for (int i = 0; i < nlst; ++i) {
492 				mod_dat& md = lst[i];
493 				md.mod.fm.bv.sol.update ();
494 			}
495 		}
496 	}
497 }
498