1 /*
2 * din.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 "main.h"
9 #include "din.h"
10 #include "console.h"
11 #include "solver.h"
12 #include "container.h"
13 #include "utils.h"
14 #include "input.h"
15 #include "color.h"
16 #include "random.h"
17 #include "command.h"
18 #include "delay.h"
19 #include "chrono.h"
20 #include "delay.h"
21 #include "tcl_interp.h"
22 #include "font.h"
23 #include "scale_info.h"
24 #include "ui_list.h"
25 #include "vector2d.h"
26 #include "keyboard_keyboard.h"
27 #include "defvelaccel.h"
28 #include "log.h"
29 #include <sstream>
30 #include <algorithm>
31 
32 #define ENDER -1
33 
34 extern string user_data_dir; // user data directory
35 extern console cons; // console
36 extern viewport view; // viewport
37 extern int mousex, mousey, mouseyy; // mouse pos
38 extern int lmb, rmb, mmb; // mouse button state
39 extern int LEFT, BOTTOM, RIGHT, TOP; // microtonal keyboard extents
40 extern int HEIGHT; // default number of volumes on the microtonal keyboard
41 extern int WIDTH; // default number of microtones in a range
42 extern int NUM_OCTAVES; // number of octaves the board spans
43 extern map<string, int> NOTE_POS; // interval name -> value, 1 - 1, 1# - 2, 2 - 3  etc
44 extern int SAMPLE_RATE; // sampling rate
45 extern map<string, float> INTERVALS; // interval name -> value
46 extern audio_out aout; // audio output
47 extern tcl_interp interpreter; // integrated tcl interpreter
48 extern int TRAILSIZE; // drone trail size (== number of trail points)
49 extern audio_clock clk; // audio clock
50 extern din din0; // microtonal-keyboard
51 extern float VOLUME; // volume of voice on microtonal-keyboard
52 extern curve_library wav_lib; // waveform library
53 extern float FRAME_TIME; // time per frame in seconds
54 extern int quit; // user wants to quit?
55 extern int line_height; // of text
56 extern keyboard_keyboard keybd2; // keyboard-keyboard
57 extern int IPS; // inputs per second
58 extern beat2value octave_shift; // octave shift over bpm
59 
60 extern const float PI_BY_180;
61 extern const float PI;
62 extern mouse_slider mouse_slider0;
63 extern const char* s_drones;
64 extern float VOICE_VOLUME;
65 
66 typedef std::list<mesh>::iterator mesh_iterator;
67 
68 
69 // din::din () in eval.cc
70 
setup()71 void din::setup () {
72 
73   droneed.add (&drone_wave, &dronelis);
74   droneed.attach_library (&wav_lib);
75 
76   wavsol (&wave);
77   wavplay.set_wave (&wavsol);
78 
79   waved.add (&wave, &wavlis);
80   waved.attach_library (&wav_lib);
81 
82   gatr.setup ();
83 	gated.attach_library (&gatlib);
84   gated.add (gatr.crv, &gatrlis);
85   gated.bv.push_back (&gatr);
86 
87   am_depth = 0;
88   fm_depth = 0;
89 
90   fm.setup ();
91   am.setup ();
92 
93   moded.add (fm.crv, &fmlis);
94   moded.add (am.crv, &amlis);
95   moded.bv.push_back (&fm);
96   moded.bv.push_back (&am);
97 
98   fmlis.set (&fm);
99   amlis.set (&am);
100   gatrlis.set (&gatr);
101 
102   dinfo.gravity.calc ();
103 
104 }
105 
scale_loaded()106 void din::scale_loaded () {
107 	int load_drones_too = 1, load_ranges_too = 1;
108 	load_scale (load_drones_too, load_ranges_too);
109 }
110 
scale_changed()111 void din::scale_changed () {
112 	reset_all_ranges ();
113 }
114 
load_scale(int _load_drones_,int _load_ranges_)115 void din::load_scale (int _load_drones_, int _load_ranges_) {
116 	setup_ranges (NUM_OCTAVES, _load_ranges_);
117 	if (_load_drones_) load_drones ();
118 	refresh_all_drones ();
119 }
120 
load_ranges()121 int din::load_ranges () {
122 
123   string fname = user_data_dir + scaleinfo.name + ".ranges";
124   dlog << "<< loading ranges from: " << fname;
125   ifstream file (fname.c_str(), ios::in);
126   if (!file) {
127     dlog << "!!! couldnt load range pos from " << fname << ", will use defaults +++" << endl;
128     return 0;
129   }
130 
131   string ignore;
132 
133   file >> ignore >> NUM_OCTAVES;
134   int n; file >> ignore >> n;
135   create_ranges (n);
136 
137   int l = LEFT, r, w, h;
138   for (int i = 0; i < num_ranges; ++i) {
139     range& R = ranges[i];
140     file >> w >> h;
141     r = l + w;
142     R.extents (l, BOTTOM, r, BOTTOM + h);
143     l = r;
144 		file >> R.mod.active >>
145 						R.fixed >>
146 						R.mod.am.depth >> R.mod.am.bv.bpm >> R.mod.am.bv.now >> R.mod.am.bv.bps >> R.mod.am.initial >>
147 						R.mod.fm.depth >> R.mod.fm.bv.bpm >> R.mod.fm.bv.now >> R.mod.fm.bv.bps >> R.mod.fm.initial;
148 						R.notes[0].load (file) >> R.intervals[0];
149 						R.notes[1].load (file) >> R.intervals[1];
150     R.fixed = range::CENTER;
151   }
152 
153   dlog << ", done >>>" << endl;
154 
155   return 1;
156 
157 }
158 
save_ranges()159 void din::save_ranges () {
160 
161   string fname = user_data_dir + scaleinfo.name + ".ranges";
162   ofstream file (fname.c_str(), ios::out);
163   if (file) {
164     file << "num_octaves " << NUM_OCTAVES << endl;
165     file << "num_ranges " << num_ranges << endl;
166     for (int i = 0; i < num_ranges; ++i) {
167       range& r = ranges[i];
168       file << r.extents.width << spc << r.extents.height << spc << r.mod.active << spc
169 						<< r.fixed << spc
170             << r.mod.am.depth << spc << r.mod.am.bv.bpm << spc << r.mod.am.bv.now << spc << r.mod.am.bv.bps << spc << r.mod.am.initial << spc
171 						<< r.mod.fm.depth << spc << r.mod.fm.bv.bpm << spc << r.mod.fm.bv.now << spc << r.mod.fm.bv.bps << spc << r.mod.fm.initial << spc;
172 						r.notes[0].save (file) << r.intervals[0] << spc;
173 						r.notes[1].save (file) << r.intervals[1] << spc;
174     }
175     dlog << "+++ saved ranges in " << fname << " +++" << endl;
176   }
177 
178 }
179 
create_ranges(int n)180 void din::create_ranges (int n) {
181   ranges.resize (n);
182   initranpar (n);
183 }
184 
setup_ranges(int last_num_octaves,int load)185 void din::setup_ranges (int last_num_octaves, int load) {
186 
187   if (load) {
188 		load_ranges ();
189   } else {
190     int last_num_ranges = num_ranges;
191 		create_ranges (NUM_OCTAVES * scaleinfo.num_ranges);
192 		set_range_width (last_num_ranges, last_range, WIDTH);
193 		set_range_height (last_num_ranges, last_range, HEIGHT);
194 		init_range_mod (last_num_ranges, last_range);
195 		if (last_num_octaves < NUM_OCTAVES) calc_added_range_notes (last_num_octaves, last_num_ranges);
196   }
197 
198   find_current_range ();
199 
200 }
201 
reset_all_ranges()202 void din::reset_all_ranges () {
203 	create_ranges (NUM_OCTAVES * scaleinfo.num_ranges);
204 	set_range_width (0, last_range, WIDTH);
205 	set_range_height (0, last_range, HEIGHT);
206 	init_range_mod (0, last_range);
207 	calc_added_range_notes (0, 0);
208 	refresh_all_drones ();
209 }
210 
calc_added_range_notes(int p,int r)211 void din::calc_added_range_notes (int p, int r) {
212 	int rn = r;
213   for (; p < NUM_OCTAVES; ++p) {
214     for (int i = 0, j = 1; i < scaleinfo.num_ranges; ++i, ++j) {
215       range& R = ranges[r++];
216 			note& n0 = R.notes[0];
217 			note& n1 = R.notes[1];
218 			n0.scale_pos = i;
219 			n1.scale_pos = j;
220 			n0.octave = n1.octave = p;
221 			string& i0 = R.intervals[0];
222 			string& i1 = R.intervals[1];
223       i0 = scaleinfo.notes[i];
224       i1 = scaleinfo.notes[j];
225 			R.calc (scaleinfo);
226 			n0.set_name (i0, scaleinfo.western);
227 			n1.set_name (i1, scaleinfo.western);
228     }
229   }
230 	if (rn) {
231 		range	&R1 = ranges[rn-1], &R = ranges[rn];
232 		// last note of existing ranges should be = to first note of first new range
233 		if (!equals (R.notes[0].hz, R1.notes[1].hz)) {
234 			R.notes[0]=R1.notes[1];
235 			R.intervals[0]=R1.intervals[1];
236 			R.delta_step = R.notes[1].step - R.notes[0].step;
237 		}
238 	}
239 }
240 
init_range_mod(int s,int t)241 void din::init_range_mod (int s, int t) {
242 	for (int i = s; i <= t; ++i) ranges[i].init_mod ();
243 }
244 
set_range_width(int ran,int sz)245 void din::set_range_width (int ran, int sz) {
246   range& R = ranges[ran];
247   int delta = sz - R.extents.width;
248   R.extents (R.extents.left, R.extents.bottom, R.extents.left + sz, R.extents.top);
249 	R.mod.fm.initial = R.extents.width;
250 	R.mod.fm.bv.now = 0;
251   for (int i = ran + 1; i < num_ranges; ++i) {
252     range& Ri = ranges[i];
253     Ri.extents (Ri.extents.left + delta, Ri.extents.bottom, Ri.extents.right + delta, Ri.extents.top);
254   }
255 	refresh_drones (ran, last_range);
256   find_visible_ranges ();
257 }
258 
set_range_width(int s,int t,int sz)259 void din::set_range_width (int s, int t, int sz) {
260 	int r, l;
261 	if (s < 1) r = LEFT; else r = ranges[s-1].extents.right;
262 	for (int i = s; i <= t; ++i) {
263 		l = r;
264 		r = l + sz;
265 		range& R = ranges[i];
266 		R.extents (l, R.extents.bottom, r, R.extents.top);
267 		R.mod.fm.initial = R.extents.width;
268 		R.mod.fm.bv.now = 0;
269 	}
270 	refresh_drones (s, t);
271 	find_visible_ranges ();
272 }
273 
set_range_height(int s,int t,int h)274 void din::set_range_height (int s, int t, int h) {
275 	for (int i = s; i <= t; ++i) {
276 		range& R = ranges[i];
277 		R.extents (R.extents.left, BOTTOM, R.extents.right, BOTTOM+h);
278 		R.mod.am.initial = h;
279 		R.mod.am.bv.now = 0;
280 	}
281 	refresh_drones (s, t);
282 }
283 
set_range_height(int r,int h)284 void din::set_range_height (int r, int h) {
285 	range& R = ranges[r];
286 	R.extents (R.extents.left, BOTTOM, R.extents.right, BOTTOM + h);
287 	R.mod.am.initial = h;
288 	R.mod.am.bv.now = 0;
289 	refresh_drones (r);
290 }
291 
default_range_to_all(int h)292 void din::default_range_to_all (int h) {
293 	extern multi_curve ran_width_crv, ran_height_crv;
294 	if (h) {
295 		set_range_height (0, last_range, HEIGHT);
296 		ran_height_crv.load ("range-height.crv.default");
297 
298 	}
299   else {
300 		set_range_width (0, last_range, WIDTH);
301 		ran_width_crv.load ("range-width.crv.default");
302 	}
303 }
304 
selected_range_to_all(int h)305 void din::selected_range_to_all (int h) {
306 	if (h)
307 		set_range_height (0, last_range, ranges[dinfo.sel_range].extents.height);
308 	else
309 		set_range_width (0, last_range, ranges[dinfo.sel_range].extents.width);
310 }
311 
default_range_to_selected(int h)312 void din::default_range_to_selected (int h) {
313 	if (h)
314 		set_range_height (dinfo.sel_range, HEIGHT);
315 	else
316   	set_range_width (dinfo.sel_range, WIDTH);
317 }
318 
range_left_changed(int r,int dx,int mr)319 int din::range_left_changed (int r, int dx, int mr) {
320 	int valid = 0;
321   range& R = ranges [r];
322   int oldleft = R.extents.left;
323   if (dx != 0) {
324 		int newleft = oldleft + dx;
325 		valid = newleft < R.extents.right ? 1 : 0;
326 		if (valid) {
327       if (adjustranges.others) {
328         R.extents (newleft, R.extents.bottom, R.extents.right, R.extents.top);
329         for (int i = 0; i < r; ++i) {
330           range& ir = ranges [i];
331           ir.extents (ir.extents.left + dx, ir.extents.bottom, ir.extents.right + dx, ir.extents.top);
332         }
333       } else {
334         int j = r - 1;
335         if (j > -1) {
336           range& rl = ranges[j];
337           box<int>& rle = rl.extents;
338           if (rle.left < newleft) {
339             R.extents (newleft, R.extents.bottom, R.extents.right, R.extents.top);
340             rle (rle.left, rle.bottom, R.extents.left, rle.top);
341           }
342         } else {
343           R.extents (newleft, R.extents.bottom, R.extents.right, R.extents.top);
344         }
345       }
346 			if (mr) { // reset modulation
347 				R.mod.fm.initial = R.extents.width;
348 				R.mod.fm.bv.now = 0;
349 			}
350       if (R.mod.active == 0) R.print_hz_per_pixel ();
351 		}
352 		LEFT = ranges[0].extents.left;
353   }
354 	return valid;
355 }
356 
range_right_changed(int r,int dx,int mr)357 int din::range_right_changed (int r, int dx, int mr) {
358 	int valid = 0;
359   range& R = ranges [r];
360   int oldright = R.extents.right;
361   if (dx != 0) {
362 		int newright = oldright + dx;
363 		valid = newright > R.extents.left ? 1 : 0;
364 		if (valid) {
365       if (adjustranges.others) {
366         R.extents (R.extents.left, R.extents.bottom, newright, R.extents.top);
367         for (int i = r + 1; i < num_ranges; ++i) {
368           range& ir = ranges [i];
369           ir.extents (ir.extents.left + dx, ir.extents.bottom, ir.extents.right + dx, ir.extents.top);
370         }
371       } else {
372         int j = r + 1;
373         if (j < num_ranges) {
374           range& rr = ranges[j];
375           box<int>& rre = rr.extents;
376           if (newright < rre.right) {
377             R.extents (R.extents.left, R.extents.bottom, newright, R.extents.top);
378             rre (newright, rre.bottom, rre.right, rre.top);
379           }
380         } else {
381           R.extents (R.extents.left, R.extents.bottom, newright, R.extents.top);
382         }
383       }
384 			if (mr) { // reset modulation
385 				R.mod.fm.initial = R.extents.width;
386 				R.mod.fm.bv.now = 0;
387 			}
388       if (R.mod.active == 0) R.print_hz_per_pixel ();
389 		}
390   }
391 	return valid;
392 }
393 
calc_all_range_notes()394 void din::calc_all_range_notes () {
395 	int r = 0;
396 	for (int i = 0; i < num_ranges; ++i) ranges[r++].calc (scaleinfo);
397 }
398 
tonic_changed()399 void din::tonic_changed () {
400 	all_notes.set_tonic (scaleinfo.tonic);
401 	calc_all_range_notes ();
402 	refresh_all_drones ();
403   notate_all_ranges ();
404 }
405 
notate_all_ranges()406 void din::notate_all_ranges () {
407   extern int NOTATION;
408 	int western = scaleinfo.western;
409 
410   switch (NOTATION) {
411 
412     case WESTERN:
413       extern const char* WESTERN_FLAT [];
414       for (int i = 0; i < num_ranges; ++i) {
415         range& ri = ranges [i];
416         string i0 = ri.intervals[0], i1 = ri.intervals[1];
417         int ii0 = NOTE_POS[i0], ii1 = NOTE_POS[i1];
418         int kii0 = (western + ii0) % 12;
419         int kii1 = (western + ii1) % 12;
420         ri.notes[0].set_name (WESTERN_FLAT[kii0]);
421         ri.notes[1].set_name (WESTERN_FLAT[kii1]);
422       }
423       break;
424 
425     case NUMERIC:
426       for (int i = 0; i < num_ranges; ++i) {
427         range& ri = ranges [i];
428         ri.notes[0].set_name (ri.intervals[0]);
429         ri.notes[1].set_name (ri.intervals[1]);
430       }
431       break;
432 
433     default:
434       extern map<string, string> INT2IND;
435       for (int i = 0; i < num_ranges; ++i) {
436         range& ri = ranges [i];
437         ri.notes[0].set_name (INT2IND[ri.intervals[0]]);
438         ri.notes[1].set_name (INT2IND[ri.intervals[1]]);
439       }
440   }
441 }
442 
mouse2tonic()443 void din::mouse2tonic () {
444   // set mouse at tonic
445   range& r = ranges[scaleinfo.notes.size () - 1]; // range of middle tonic
446 	int wx = r.extents.left;
447 	if (wx >= 0 && wx <= view.xmax) {
448 		warp_mouse (wx, mousey);
449     dinfo.gravity.forcetrack = 1;
450 		MENU.screen_mousex = wx;
451 		MENU.screen_mousey = mousey;
452 	}
453 }
454 
get_note_value(const string & s)455 float din::get_note_value (const string& s) {
456   return scaleinfo.intervals[s];
457 }
458 
tuning_changed()459 void din::tuning_changed () {
460   scaleinfo.intervals = INTERVALS;
461 	calc_all_range_notes ();
462 	refresh_all_drones ();
463 }
464 
save_scale()465 void din::save_scale () {
466   save_ranges ();
467   save_drones ();
468   wave.save ("microtonal-keyboard-waveform.crv");
469   scaleinfo.save_scale ();
470 }
471 
~din()472 din::~din () {
473   if (dvap) delete[] dvap;
474   if (dap) delete[] dap;
475   if (dcol) delete[] dcol;
476 	if (con_pts) delete[] con_pts;
477 	if (con_clr) delete[] con_clr;
478   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) delete *i;
479 	for (int i = 0, j = drone_pendulums.size (); i < j; ++i) {
480 		group* grp = drone_pendulums[i];
481 		if (grp) delete grp;
482 	}
483   dlog << "--- destroyed microtonal-keyboard ---" << endl;
484 }
485 
sample_rate_changed()486 void din::sample_rate_changed () {
487   for (int i = 0; i < num_ranges; ++i) ranges[i].sample_rate_changed ();
488   beat2value* bv [] = {&fm, &am, &gatr, &octave_shift};
489   for (int i = 0; i < 4; ++i) bv[i]->set_bpm (bv[i]->bpm);
490   select_all_drones ();
491   change_drone_bpm (modulator::FM, 0);
492   change_drone_bpm (modulator::AM, 0);
493   update_drone_tone ();
494 }
495 
samples_per_channel_changed()496 void din::samples_per_channel_changed () {
497 	wavplay.realloc ();
498 	for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
499 		drone& di = *(*i);
500 		di.player.realloc ();
501 		di.update_pv = drone::EMPLACE;
502 	}
503 }
504 
load_drones()505 void din::load_drones () {
506 
507   string fdrone = user_data_dir + scaleinfo.name + ".drone";
508   ifstream file (fdrone.c_str(), ios::in);
509   drones.clear ();
510 
511   rising = falling = 0;
512 
513   if (!file) return; else {
514     string ignore;
515     num_drones = 0;
516 		file >> ignore >> drone::UID;
517     file >> ignore >> num_drones;
518     print_num_drones ();
519     file >> ignore >> drone::mastervolume;
520     dlog << "<<< loading " << num_drones << " drones from: " << fdrone;
521 
522     int T = 0;
523     for (int i = 0; i < num_drones; ++i) {
524       drone* pdi = new drone;
525       drone& di = *pdi;
526 			file >> ignore >> di.id;
527 			file >> ignore >> di.is;
528       file >> ignore >> di.cx >> di.cy >> di.posafxvel.pt.x >> di.posafxvel.pt.y >> di.posafxvel.yes;
529       file >> ignore >> di.player.x >> di.vol;
530       file >> ignore >> di.r >> di.g >> di.b;
531 			//file >> ignore >> di.arrow.u >> di.arrow.v;
532       file >> ignore >> di.arrow;
533       file >> ignore >> di.mod.am.result >> di.mod.am.bv.now >> di.mod.am.bv.delta >> di.mod.am.depth >> di.mod.am.bv.bpm >> di.mod.am.bv.bps >> di.mod.fm.result >> di.mod.fm.bv.now >> di.mod.fm.bv.delta >> di.mod.fm.depth >> di.mod.fm.bv.bpm >> di.mod.fm.bv.bps >> di.mod.am.id >> di.autorot.v >> di.mod.fm.id >> di.autorot.a;
534       di.mod.am.calcdir (di);
535       di.mod.fm.calcdir (di);
536       file >> ignore >> di.trail.total; if (T < di.trail.total) T = di.trail.total;
537       file >> di.handle_size;
538 			file >> ignore >> di.orbiting;
539 			file >> ignore >> di.V >> di.A >> di.vx >> di.vy >> di.v_mult >> di.ax >> di.ay;
540 
541 			file >> ignore >> di.attractor;
542 			if (di.attractor) {
543 				int n = di.attractor;
544 				for (int i = 0; i < n; ++i) {
545 					attractee ae;
546 					file >> ae.id;
547 					di.attractees.push_back (ae);
548 				}
549         attractors.push_back (pdi);
550 			}
551       file >> ignore >> di.launcher;
552       if (di.launcher) {
553         float tt, dt; file >> tt >> dt >> di.dpm;
554         di.launch_every.triggert = tt;
555         di.launch_every.startt = ui_clk () - dt;
556         launchers.push_back (pdi);
557       }
558 
559 			file >> ignore >> di.num_targets;
560 			if (di.num_targets) {
561 				file >> ignore >> di.cur_target;
562 				vector<drone*>& targets = di.targets;
563 				targets.clear ();
564 				for (int i = 0; i < di.num_targets; ++i) {
565 					uintptr_t pt; file >> pt;
566 					targets.push_back ((drone*) pt);
567 				}
568 			}
569 
570 			file >> ignore >> di.tracking;
571       if (di.tracking) {
572         uintptr_t id; file >> id;
573         di.tracked_drone = (drone *) id;
574         trackers.push_back (pdi);
575       }
576 
577       file >> ignore >> di.gravity;
578       if (di.gravity) gravitated.push_back (pdi);
579 
580 			uintptr_t pt; file >> ignore >> pt;
581 			di.target = (drone *) pt;
582 			if (di.target) satellites.push_back (pdi);
583 
584       file >> ignore >> di.reincarnate;
585       file >> ignore >> di.birth;
586       if (di.birth != -1) {
587         float elapsed = di.birth;
588         di.birth = ui_clk () - elapsed;
589       }
590 
591 			file >> ignore >> di.life;
592 			file >> ignore >> di.insert;
593 			file >> ignore >> di.snap;
594 			file >> ignore >> di.frozen;
595 			if (di.frozen) {
596 				di.frozen = 1;
597 				di.froze_at = ui_clk ();
598 				di.set_pos (di.cx + di.mod.fm.result, di.cy + di.mod.am.result);
599 			} else {
600 				di.set_pos (di.cx, di.cy);
601 				di.froze_at = -1;
602 			}
603 
604       di.state = drone::RISING;
605       di.fdr.set (0.0f, 1.0f, 1, MENU.riset());
606       risers.push_back (pdi);
607       ++rising;
608       drones.push_back (pdi);
609 
610 			float smp, spr;
611 			file >> ignore >> smp >> spr;
612 			di.nsr.set_samples (smp);
613 			di.nsr.set_spread (spr);
614 
615 			file >> ignore;
616 			drone::proc_conn [pdi] = false;
617 			long long cd;
618 			double mag;
619 			while (file.eof () == 0) {
620 				file >> cd;
621 				if (cd == ENDER)
622 					break;
623 				else {
624 					di.connections.push_back ((drone *)cd);
625 					file >> mag; di.mags.push_back (mag);
626 					++di.nconn;
627 					++totcon;
628 				}
629 			}
630 
631       {
632         float start, end, amount;
633         file >> ignore >> start >> end >> amount;
634         di.gab.set (start, end);
635         di.gab.amount = amount;
636       }
637 
638       {
639         file >> ignore >> di.chuck.yes;
640         if (di.chuck.yes) file >> di.chuck;
641       }
642 
643     } // load complete
644 
645     trail_t::alloc (T);
646 
647 		_2totcon = 2 * totcon;
648 		alloc_conns ();
649 
650     // load the meshes
651     //
652     map<int, drone*> dmap;
653     file >> ignore >> meshh.num;
654     if (meshh.num) {
655       for (int m = 0; m < meshh.num; ++m) {
656         mesh a_mesh;
657         file >> ignore >> a_mesh.r >> a_mesh.g >> a_mesh.b;
658         int num_polys;
659         file >> ignore >> num_polys;
660         for (int i = 0; i < num_polys; ++i) {
661           drone* drones[4] = {0}; // 4 drones to a poly
662           file >> ignore;
663           for (int p = 0; p < 4; ++p) {
664             int id; file >> id;
665             drone* did = dmap [id];
666             if (did == 0) {
667               did = get_drone (id);
668               dmap[id] = did;
669             }
670             drones[p] = did;
671           }
672           a_mesh.add_poly (drones[0], drones[1], drones[2], drones[3]);
673         }
674         meshes.push_back (a_mesh);
675       }
676     }
677 		file >> ignore >> meshh.draw;
678 
679     // load drone tracked by gravity
680 		int tid = 0;
681     file >> ignore >> tid;
682     if (tid) dinfo.gravity.tracked_drone = get_drone (tid);
683 
684 
685 		load_selected_drones (file);
686 
687 		load_drone_pendulum_groups (file);
688 
689     // convert attractees
690     for (drone_iterator i = attractors.begin (), j = attractors.end(); i != j; ++i) {
691       drone& di = *(*i);
692 			for (list<attractee>::iterator iter = di.attractees.begin (), jter = di.attractees.end (); iter != jter; ++iter) {
693 				attractee& ae = *iter;
694         ae.d = get_drone (ae.id);
695       }
696     }
697 
698     // convert tracked drone
699     for (drone_iterator i = trackers.begin (), j = trackers.end(); i != j; ++i) {
700       drone& di = *(*i);
701       di.tracked_drone = get_drone ((uintptr_t) di.tracked_drone);
702     }
703 
704 		// convert targets and connections
705 		for (drone_iterator i = drones.begin (), j = drones.end (); i != j; ++i) {
706 			drone& di = *(*i);
707 			if (di.num_targets) for (int i = 0; i < di.num_targets; ++i) di.targets[i] = get_drone ((uintptr_t) di.targets[i]);
708 			if (di.nconn) for (drone_iterator p = di.connections.begin (), q = di.connections.end (); p != q; ++p) *p = get_drone ((uintptr_t) *p);
709       if (di.chuck.yes) {
710         if (di.chuck.sun) di.chuck.sun = get_drone ((uintptr_t) di.chuck.sun);
711         if (di.chuck.sat) di.chuck.sat = get_drone ((uintptr_t) di.chuck.sat);
712       }
713 		}
714 
715 		// convert satellites
716 		for (drone_iterator i = satellites.begin (), j = satellites.end (); i != j; ++i) {
717 			drone& di = *(*i);
718 			di.target = get_drone ((uintptr_t) di.target);
719 		}
720 
721     update_drone_players ();
722 
723     if (num_drones)
724       prep_modulate (MODULATE_DRONES);
725     else
726       prep_modulate (MODULATE_VOICE);
727 
728     dlog << ", done. >>>" << endl;
729   }
730 
731 }
732 
save_drones()733 void din::save_drones () {
734   drone_wave.save ("drone.crv");
735   string drone_file = user_data_dir + scaleinfo.name + ".drone";
736   ofstream file (drone_file.c_str(), ios::out);
737   if (file) {
738 		file << "uid " << drone::UID << endl;
739 		file << "num_drones " << num_drones << endl;
740     file << "master_volume " << drone::mastervolume << endl;
741     for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
742       drone& di = *(*i);
743 			file << "id " << di.id << endl;
744 			file << "is " << di.is << endl;
745       file << "positon " << di.cx << spc << di.cy << spc << di.posafxvel.pt.x << spc << di.posafxvel.pt.y << spc << di.posafxvel.yes << endl;
746       file << "wavepos " << di.player.x << spc << di.vol << endl;
747       file << "color " << di.r << spc << di.g << spc << di.b << endl;
748 			file << "arrow " << di.arrow << endl;
749       file << "modulation " << di.mod.am.result << spc << di.mod.am.bv.now << spc << di.mod.am.bv.delta << spc << di.mod.am.depth << spc << di.mod.am.bv.bpm << spc << di.mod.am.bv.bps << spc << di.mod.fm.result << spc << di.mod.fm.bv.now << spc << di.mod.fm.bv.delta << spc << di.mod.fm.depth << spc << di.mod.fm.bv.bpm << spc << di.mod.fm.bv.bps << spc << di.mod.am.id << spc << di.autorot.v << spc << di.mod.fm.id << spc << di.autorot.a << endl;
750 			file << "trail+handle " << di.trail.total << spc << di.handle_size << endl;
751 			file << "orbiting " << di.orbiting << endl;
752 			file << "vel+accel " << di.V << spc << di.A << spc << di.vx << spc << di.vy << spc << di.v_mult << spc << di.ax << spc << di.ay << endl;
753 			file << "attractor " << di.attractor;
754 			if (di.attractor) { // save attractees
755 			  for (list<attractee>::iterator iter = di.attractees.begin (), jter = di.attractees.end (); iter != jter; ++iter) {
756 				  attractee& ae = *iter;
757 				  file << spc << ae.id; // only save unique id, rebuild on load
758 			  }
759 			}
760       file << endl;
761 
762       file << "launcher " << di.launcher;
763       if (di.launcher)
764 				file << spc << di.launch_every.triggert << spc << (ui_clk()-di.launch_every.startt) << spc << di.dpm << spc << endl;
765 			else
766 				file << endl;
767 
768 			file << "launcher_targets " << di.num_targets << endl;
769 			if (di.num_targets) {
770 				file << "cur_target " << di.cur_target;
771 				for (int t = 0; t < di.num_targets; ++t) {
772 					drone* pdt = di.targets[t];
773 					file << spc << pdt->id;
774 				}
775 				file << endl;
776 			}
777 
778 			file << "tracking " << di.tracking;
779 			if (di.tracking) file << spc << di.tracked_drone->id << endl; else file << endl;
780 
781       file << "gravity " << di.gravity << endl;
782 
783 			if (di.target) {
784 				file << "satellite_target " << di.target->id << endl;
785 			} else file << "satellite_target 0" << endl;
786 
787       file << "reincarnate " << di.reincarnate << endl;
788       if (di.birth != -1)
789         file << "birth " << (ui_clk() - di.birth) << endl;
790       else
791         file << "birth -1" << endl;
792 
793 			file << "life-time " << di.life << endl;
794 			file << "insert-time " << di.insert << endl;
795 			file << "snap " << di.snap << endl;
796       file << "frozen " << di.frozen << endl;
797 
798 			file << "noiser ";
799 			file << di.nsr << endl;
800 
801 			file << "connections ";
802 			if (di.nconn) {
803 				list<double>::iterator mi = di.mags.begin ();
804 				for (drone_iterator p = di.connections.begin(), q = di.connections.end(); p != q; ++p, ++mi) {
805 					file << (*p)->id << spc << *mi << spc;
806 				}
807 			}
808 			file << ENDER << endl;
809 
810       file << "gab " << di.gab.start <<  spc << di.gab.end << spc << di.gab.amount << endl;
811 
812       file << "chuck " << di.chuck.yes << spc;
813       if (di.chuck.yes) file << di.chuck << endl; else file << endl;
814 
815     }
816 
817     file << "num_meshes " << meshh.num << endl;
818     if (meshh.num) {
819       for (mesh_iterator m = meshes.begin (), n = meshes.end(); m != n; ++m) { // save meshes
820         mesh& mi = *m;
821         file << "color " << mi.r << spc << mi.g << spc << mi.b << endl;
822         file << "num_polys " << mi.num_polys << endl;
823         for (poly_iterator p = mi.polys.begin (), q = mi.polys.end (); p != q; ++p) { // save polys
824           poly& pp = *p;
825           file << "poly";
826           for (int r = 0; r < 4; ++r) file << spc << pp.drones[r]->id; // save drone id, on reload we will point to right drone
827           file << endl;
828         }
829       }
830     }
831 		file << "draw_meshes " << meshh.draw << endl;
832 
833     file << "drone_tracked_by_gravity ";
834     if (dinfo.gravity.tracked_drone) {
835       file << dinfo.gravity.tracked_drone->id << endl;
836     } else file << '0' << endl;
837 
838 
839 		save_selected_drones (file);
840 
841 		save_drone_pendulum_groups (file);
842 
843     dlog << "+++ saved " << num_drones << " drones in: " << drone_file << " +++" << endl;
844   }
845 
846 }
847 
save_drone_pendulum_groups(ofstream & file)848 void din::save_drone_pendulum_groups (ofstream& file) {
849 	int ng = drone_pendulums.size ();
850 	file << "groups " << ng << spc;
851 	for (int i = 0; i < ng; ++i) {
852 		drone_pendulum_group& dpg = *drone_pendulums[i];
853 		file << dpg.n << spc << dpg.orient << spc << dpg.depth << spc;
854 		vector<drone*> dpgd = dpg.drones;
855 		for (int j = 0, k = dpg.n; j < k; ++j) {
856 			drone* dj = dpgd[j];
857 			file << dj->id << spc;
858 		}
859 	}
860   file << endl;
861 }
862 
load_drone_pendulum_groups(ifstream & file)863 void din::load_drone_pendulum_groups (ifstream& file) {
864 	string ignore;
865 	int ng; file >> ignore >> ng;
866   if (ng) {
867     drone_pendulums.resize (ng);
868     for (int i = 0; i < ng; ++i) {
869       drone_pendulum_group* pdpg = new drone_pendulum_group ();
870       drone_pendulum_group& dpg = *pdpg;
871       drone_pendulums[i] = pdpg;
872       file >> dpg.n >> dpg.orient >> dpg.depth;
873       vector<drone*>& dpgd = dpg.drones;
874       dpgd.resize (dpg.n);
875       int did;
876       for (int j = 0, k = dpg.n; j < k; ++j) {
877         file >> did;
878         dpgd[j] = get_drone (did);
879       }
880     }
881   }
882 }
883 
update_drone_tone()884 void din::update_drone_tone () {
885   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
886     drone& di = *(*i);
887     range& r = ranges[di.range];
888     di.step = (1 - di.pos) * r.notes[0].step + di.pos * r.notes[1].step;
889 		di.update_pv = drone::EMPLACE;
890   }
891 }
892 
refresh_all_drones()893 void din::refresh_all_drones () {
894 	for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
895 		drone& di = *(*i);
896 		di.set_pos (di.x, di.y);
897 	}
898 }
899 
refresh_drones(int r1,int r2)900 void din::refresh_drones (int r1, int r2) {
901 	for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
902 		drone& di = *(*i);
903 		if ((di.range >= r1) && (di.range <= r2)) di.set_pos (di.x, di.y);
904 	}
905 }
906 
refresh_drones(int r)907 void din::refresh_drones (int r) {
908 	for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
909 		drone& di = *(*i);
910 		if (di.range == r) di.set_pos (di.x, di.y);
911 	}
912 }
913 
update_drone_x(int s,int t)914 void din::update_drone_x (int s, int t) {
915 	for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
916 		drone& di = *(*i);
917 		if ((di.range >= s) && (di.range <= t)) di.set_pos (di.x, di.y);
918 	}
919 }
920 
update_drone_anchors()921 void din::update_drone_anchors () {
922   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
923     drone& di = *(*i);
924     di.calc_handle ();
925   }
926 }
927 
update_drone_ranges()928 void din::update_drone_ranges () {
929 	for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
930 		drone& di = *(*i);
931 		if (di.range > last_range) di.range = last_range;
932 	}
933 }
934 
set_drone(drone & dd,float wx,float wy)935 void din::set_drone (drone& dd, float wx, float wy) {
936 
937 		// create drone at position
938 		dd.cx = dd.posafxvel.pt.x = wx;
939 		dd.cy = dd.posafxvel.pt.y = wy;
940 
941 		// install waveform, pitch and volume
942 		dd.sol (&drone_wave);
943 		dd.player.set_wave (&dd.sol);
944 
945 		// prep to rise the drones
946 		dd.fdr.set (0.0f, 1.0f, 1, MENU.riset());
947 		dd.set_pos (dd.cx, dd.cy);
948 		dd.state = drone::RISING;
949 		risers.push_back (&dd);
950 		++rising;
951 
952 		drone::proc_conn [&dd] = false;
953 
954     dd.setcolor ();
955 
956 }
957 
movedrone(drone & dd)958 void din::movedrone (drone& dd) {
959 	float cx = dd.cx, cy = dd.cy;
960 	if (!SHIFT) cx += delta_mousex;
961 	if (!CTRL) cy -= delta_mousey;
962 	dd.set_center (cx, cy);
963   dd.update_pv = drone::EMPLACE;
964   if (dd.chuck.yes) RESETCHUCKTRAILS(dd)
965 	ec = &dd;
966 }
967 
color_selected_drones()968 void din::color_selected_drones () {
969 	if (num_selected_drones) {
970 		int last = num_selected_drones - 1;
971 		float _1bylast = 1.0f / last;
972 		for (int i = 0; i < num_selected_drones; ++i) {
973 			drone& ds = *selected_drones[i];
974 			get_color::data.p = i * _1bylast;
975       ds.setcolor ();
976 		}
977 	} else cons << RED_PSD << eol;
978 }
979 
mortalize_drones(int reincarnate)980 void din::mortalize_drones (int reincarnate) {
981 	if (num_selected_drones) {
982 		for (int i = 0; i < num_selected_drones; ++i) {
983 			drone& ds = *selected_drones[i];
984       ds.birth = ui_clk ();
985       ds.reincarnate = reincarnate;
986     }
987   } else cons << RED_PSD << eol;
988 }
989 
immortalize_drones()990 void din::immortalize_drones () {
991 	if (num_selected_drones) {
992 		for (int i = 0; i < num_selected_drones; ++i) {
993 			drone& ds = *selected_drones[i];
994       ds.birth = -1;
995       ds.reincarnate = 0;
996     }
997   } else cons << RED_PSD << eol;
998 }
999 
delete_selected_drones()1000 void din::delete_selected_drones () {
1001 	if (num_selected_drones) {
1002 		for (int i = 0; i < num_selected_drones; ++i) {
1003 			drone& ds = *selected_drones[i];
1004       if (ds.reincarnate) ds.reincarnate = 0;
1005       if (ds.state == drone::FALLING)
1006         ds.fdr.retime (MENU.fallt());
1007 			else
1008         delete_drone (ds);
1009 		}
1010 		clear_selected_drones ();
1011 	} else cons << RED_PSD << eol;
1012 }
1013 
delete_all_drones()1014 int din::delete_all_drones () {
1015   select_all_drones ();
1016   delete_selected_drones ();
1017   return 1;
1018 }
1019 
delete_drone(drone & ds)1020 void din::delete_drone (drone& ds) {
1021   drone* pds = &ds;
1022   if (ds.state == drone::RISING) if (erase (risers, pds)) --rising;
1023   if (push_back (fallers, pds)) {
1024     ++falling;
1025     ds.state = drone::FALLING;
1026     ds.fdr.set (ds.fdr.alpha, 0.0f, 1, MENU.fallt());
1027   }
1028 }
1029 
select_all_drones()1030 int din::select_all_drones () {
1031   clear_selected_drones ();
1032   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
1033     drone* pdi = *i;
1034 		pdi->sel = 1;
1035     selected_drones.push_back (pdi);
1036   }
1037   print_selected_drones ();
1038   return 1;
1039 }
1040 
select_launchers()1041 int din::select_launchers () {
1042 	CLEAR_SELECTED_DRONES
1043 	for (drone_iterator i = launchers.begin(), j = launchers.end(); i != j; ++i) {
1044 		drone* pdi = *i;
1045 		add_drone_to_selection (pdi);
1046 	}
1047 	print_selected_drones ();
1048 	return 1;
1049 }
1050 
clear_selected_drones()1051 void din::clear_selected_drones () {
1052   for (int i = 0; i < num_selected_drones; ++i) selected_drones[i]->sel = 0;
1053   selected_drones.clear ();
1054 	num_selected_drones = 0;
1055 }
1056 
orbit_selected_drones()1057 void din::orbit_selected_drones () { // attach selected drones to attractor
1058 	if (num_selected_drones > 1) {
1059 		int last = num_selected_drones - 1;
1060     drone* p_att = selected_drones [last];  // last selected drone is attractor
1061     push_back (attractors, p_att);
1062     drone& att = *p_att;
1063     list<attractee>& lae = att.attractees;
1064     for (int i = 0; i < last; ++i) { // other drones are attractees
1065       drone* pae = selected_drones [i];
1066 			if (!pae->orbiting) {
1067 				attractee ae (pae->id, pae);
1068 				if (push_back (lae, ae)) {
1069 					++att.attractor;
1070 					pae->orbiting = 1;
1071 				}
1072 			} else {
1073 				cons << RED << "Drone orbits already, ignored!" << eol;
1074 			}
1075     }
1076 	} else cons << RED_A2D << ". Drones will orbit around the last drone!" << eol;
1077 }
1078 
remove_attractee(drone * d)1079 void din::remove_attractee (drone* d) {
1080   for (drone_iterator i = attractors.begin(); i != attractors.end();) { // run thru list of attractors
1081     drone* p_att = *i;
1082 		drone& att = *p_att;
1083 	  list<attractee>& lae = att.attractees;
1084     int erased = 0;
1085 	  for (list<attractee>::iterator iter = lae.begin (); iter != lae.end();) { // run thru list of attractees
1086 		  attractee& ae = *iter;
1087       if (ae.d != d)
1088         ++iter;
1089       else { // remove attractee
1090         lae.erase (iter);
1091         if (--att.attractor == 0) {
1092           i = attractors.erase (i);
1093           erased = 1;
1094         }
1095         break;
1096       }
1097 	  }
1098     if (!erased) ++i;
1099 	}
1100 }
1101 
set_drones_under_gravity()1102 void din::set_drones_under_gravity () {
1103   if (num_selected_drones) {
1104     for (int i = 0; i < num_selected_drones; ++i) {
1105       drone* pdg = selected_drones[i];
1106       if (pdg->y < BOTTOM) pdg->gravity = -1; else pdg->gravity = 1;
1107       push_back (gravitated, pdg);
1108       pdg->birth = ui_clk ();
1109     }
1110   } else cons << RED_PSD << eol;
1111 }
1112 
move_drones_under_gravity()1113 void din::move_drones_under_gravity () {
1114 
1115   for (drone_iterator i = gravitated.begin(), j = gravitated.end(); i != j; ++i) { // run thru list of drones driven by gravity
1116 
1117 		drone* pdi = *i;
1118     drone& di = *pdi; // get the ith drone
1119 
1120 		if (di.frozen == 0) {
1121 
1122 			// current position
1123 			di.xi = di.x;
1124 			di.yi = di.y;
1125 
1126 			// calculate new position along its velocity
1127 			di.set_pos (di.x + di.V * di.vx, di.y + di.V * di.vy);
1128 
1129 			// acceleration is due to gravity!
1130 			di.ax = dinfo.gravity.gx;
1131 			di.ay = di.gravity * dinfo.gravity.gy; // reverse gravity effect if drone launched below 0 volume line
1132 
1133 			// update velocity ie we accelerate
1134 			di.vx += di.ax;
1135 			di.vy += di.ay;
1136 
1137 			// bounce when reached bottom line of microtonal keyboard
1138 			if ((di.target == 0) && ((di.gravity == 1 && di.y <= BOTTOM) || (di.gravity == -1 && di.y >= BOTTOM))) {
1139 				if (di.bounces.n++ >= di.bounces.max) {
1140 					delete_drone (di);
1141 				} else {
1142 					float dx = di.x - di.xi;
1143 					if (dx == 0.0f) { // slope is infinite
1144 						di.set_pos (di.x, BOTTOM);
1145 					} else { // slope is available
1146 						float dy = di.y - di.yi;
1147 						if (dy == 0.0f)
1148 							di.set_pos (di.x, BOTTOM);
1149 						else {
1150 							float m = dy * 1.0f / dx;
1151 							di.set_pos (di.xi + (BOTTOM - di.yi) / m, BOTTOM);
1152 						}
1153 					}
1154 					float reduction = MENU.sp_rebound() / 100.0;
1155           int style = dinfo.bounce.style;
1156           if (style == din_info::bouncet::RANDOM) style = get_rand_bit ();
1157 					if (style == din_info::bouncet::BACK) di.vx *= -reduction;
1158 					di.vy = reduction * -di.vy;
1159 				}
1160 			}
1161 
1162 			di.move_center ();
1163 
1164 		}
1165 	}
1166 }
1167 
set_targets()1168 void din::set_targets () {
1169 
1170 	if (num_selected_drones == 0) {
1171 		cons << RED << "Select a launcher and drones to target" << eol;
1172 		return;
1173 	}
1174 
1175 	drone* pd0 = selected_drones[0];
1176 	if (pd0->launcher == 0) make_launcher (pd0); // first drone is launcher
1177 	pd0->clear_targets ();
1178 
1179 	if (num_selected_drones == 1) {
1180 		pd0->targets.push_back (pd0);
1181 		pd0->num_targets = pd0->targets.size ();
1182 		cons << GREEN << "Selected drone is a launcher and also the target" << eol;
1183 		return;
1184 	}
1185 
1186 	for (int i = 1; i < num_selected_drones; ++i) { // make other drones in selection the targets
1187 		drone* pdi = selected_drones[i];
1188 		vector<drone*> targets = pd0->targets;
1189 		vector<drone*>::iterator te = targets.end (), f = find (targets.begin (), targets.end (), pdi);
1190 		if (f == te) pd0->targets.push_back (pdi);
1191 	}
1192 	pd0->num_targets = pd0->targets.size ();
1193 	cons << GREEN << "First drone is launcher, it targets " << pd0->num_targets << " other drones" << eol;
1194 
1195 }
1196 
remove_drone_from_targets(drone * T)1197 void din::remove_drone_from_targets (drone* T) {
1198 
1199   for (drone_iterator i = satellites.begin(), j = satellites.end(); i != j;) { // remove satellites going towards T
1200 		drone* pdi = *i;
1201 		drone& di = *pdi;
1202 		if (di.target == T) {
1203 			di.target = 0;
1204 			i = satellites.erase (i);
1205 			j = satellites.end ();
1206 		} else ++i;
1207 	}
1208 
1209   for (drone_iterator i = launchers.begin(), j = launchers.end (); i != j; ++i) { // remove target from launcher
1210 		drone* pdi = *i;
1211 		vector<drone*>& targets = pdi->targets;
1212 		vector<drone*>::iterator te = targets.end (), f = find (targets.begin (), te,  T);
1213 		if (f != te) {
1214 			targets.erase (f);
1215 			pdi->num_targets = targets.size ();
1216 			clamp (0, pdi->cur_target, pdi->num_targets - 1);
1217 		}
1218 	}
1219 }
1220 
clear_targets()1221 void din::clear_targets () {
1222 	int n = 0;
1223   for (int i = 0; i < num_selected_drones; ++i) {
1224 		drone* pdi = selected_drones[i];
1225 		if (pdi->num_targets) {
1226 			pdi->clear_targets ();
1227 			++n;
1228 		}
1229 	}
1230 	if (n) cons << GREEN << "Cleared targets of " << n << s_drones << eol; else cons << RED << "No targets found!" << eol;
1231 }
1232 
kill_old_drones()1233 void din::kill_old_drones () {
1234 	for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
1235 		drone& di = *(*i);
1236 		if (!di.frozen && (di.birth != -1) && (di.state != drone::FALLING)) {
1237 			double elapsed = ui_clk() - di.birth;
1238 			if (elapsed >= di.life) delete_drone (di);
1239 		}
1240 	}
1241 }
1242 
carry_satellites_to_orbit()1243 void din::carry_satellites_to_orbit () { // satellites is a bunch of drones to be inserted into orbit around another drone
1244   for (drone_iterator i = satellites.begin(), j = satellites.end(); i != j;) { // run thru satellites to be inserted into circular orbit
1245 		drone* pdi = *i;
1246 		drone& di = *pdi;
1247 		if (di.frozen == 0) {
1248 			drone& dt = *di.target; // the target we want the satellite to orbit
1249 			unit_vector (di.ax, di.ay, dt.x - di.x, dt.y - di.y); // centripetal acceleration ie unit vector joining satellite & target
1250 			float pvx = -di.ay, pvy = di.ax; // velocity to insert into orbit (just perpendicular to centripetal acceleration so its centrifugal velocity)
1251 			double now = ui_clk(), delta = now - di.birth;
1252 			float alpha = delta / di.insert; // alpha is how far we are b4 we must insert satellite into orbit; 0 => at the start, 1 => orbit now!
1253 			if (alpha >= 1.0f) { // insert drone into orbit now!
1254 				list<attractee>& lae = dt.attractees;
1255 				lae.push_back (attractee (pdi->id, pdi));
1256 				push_back (attractors, di.target);
1257 				di.target = 0; // inserted into orbit, so clear
1258 				++dt.attractor;
1259 				i = satellites.erase (i); j = satellites.end (); // no longer a satellite we need to insert
1260 			} else { // continue carrying satellites into orbit
1261 				float dot = di.vx * pvx + di.vy * pvy; // dot product current velocity and insertion velocity to see if they are facing the same direction
1262 				if (dot < 0) { // no so flip insertion velocity so it faces the same direction as current velocity
1263 					pvx = -pvx;
1264 					pvy = -pvy;
1265 					di.v_mult = -1; // see attract_drones ()
1266 				} else di.v_mult = 1;
1267 				// set interpolated velocity as current satellite velocity
1268 				float ivx, ivy;
1269 				unit_vector (ivx, ivy, di.vx + alpha * (pvx - di.vx), di.vy + alpha * (pvy - di.vy)); // interpolate current velocity and insertion velocity
1270 				di.vx = ivx; di.vy = ivy;
1271 				float newx = di.x + di.V * di.vx + di.A * di.ax, newy = di.y + di.V * di.vy + di.A * di.ay; // update drone position
1272 				di.xi = di.x;
1273 				di.yi = di.y;
1274 				di.set_pos (newx, newy);
1275 				di.move_center ();
1276 				++i;
1277 			}
1278 		} else ++i;
1279 	}
1280 }
1281 
toggle_launchers()1282 void din::toggle_launchers () {
1283   if (num_selected_drones == 0) {
1284     cons << RED_PSD << eol;
1285     return;
1286   }
1287 	double startt = ui_clk();
1288 	int nl = 0, nd = 0;
1289   for (int i = 0; i < num_selected_drones; ++i) {
1290     drone* pdi = selected_drones[i];
1291     drone& di = *pdi;
1292     di.launcher = !di.launcher;
1293     if (di.launcher) {
1294       di.launch_every.startt = startt - di.launch_every.triggert; // for immediate launch
1295       launchers.push_back (pdi);
1296 			++nl;
1297     } else {
1298 			erase (launchers, pdi);
1299 			++nd;
1300 		}
1301   }
1302 	cons << GREEN << "Launching from " << nl << " drones, Stopped Launching from " << nd << s_drones << eol;
1303 }
1304 
make_launcher(drone * pl)1305 void din::make_launcher (drone* pl) {
1306 	double startt = ui_clk();
1307   pl->launcher = 1;
1308   pl->launch_every.startt = startt - pl->launch_every.triggert;
1309   launchers.push_back (pl);
1310 }
1311 
make_launchers()1312 void din::make_launchers () {
1313   if (num_selected_drones == 0) {
1314     cons << RED_PSD << eol;
1315     return;
1316   }
1317   int nl = 0;
1318   for (int i = 0; i < num_selected_drones; ++i) {
1319     drone* pdi = selected_drones[i];
1320 		if (pdi->launcher == 0) {
1321 			make_launcher (pdi);
1322 			++nl;
1323 		}
1324   }
1325   if (nl) cons << GREEN << "Made " << nl << " launchers" << eol; else cons << RED << "All selected drones are launchers!" << eol;
1326 }
1327 
destroy_launchers()1328 void din::destroy_launchers () {
1329 	if (num_selected_drones == 0) {
1330 		cons << RED_PSD << eol;
1331 		return;
1332 	}
1333   int nl = 0;
1334   for (int i = 0; i < num_selected_drones; ++i) {
1335     drone* pdi = selected_drones[i];
1336     drone& di = *pdi;
1337     if (di.launcher) {
1338       di.launcher = 0;
1339       erase (launchers, pdi);
1340       if (di.tracking) {
1341         di.tracking = 0;
1342         di.tracked_drone = 0;
1343         erase (trackers, pdi);
1344       }
1345       ++nl;
1346     }
1347   }
1348   if (nl) cons << GREEN << "Stopped launching from " << nl << s_drones << eol; else cons << RED << "No drone launchers found!" << eol;
1349 }
1350 
1351 
seloncre(drone * d)1352 void din::seloncre (drone* d) {
1353   if (dinfo.seloncre) {
1354     d->sel = 1;
1355     selected_drones.push_back (d);
1356     print_selected_drones ();
1357   }
1358 }
1359 
add_drone(float wx,float wy,int fromlauncher)1360 drone* din::add_drone (float wx, float wy, int fromlauncher) {
1361 
1362   drone* newdrone = new drone (wy);
1363 
1364   seloncre (newdrone);
1365 
1366   drones.push_back (newdrone);
1367 
1368   ++num_drones;
1369   print_num_drones ();
1370 
1371   set_drone (*newdrone, wx, wy);
1372   if (!fromlauncher && !drone::anchored) balloon (newdrone);
1373 
1374   return newdrone;
1375 
1376 }
1377 
balloon(drone * d)1378 void din::balloon (drone* d) {
1379   d->reincarnate = 0;
1380   if (d->y < BOTTOM) d->gravity = -1; else d->gravity = 1;
1381   gravitated.push_back (d);
1382   d->birth = ui_clk ();
1383 }
1384 
launch_drones()1385 void din::launch_drones () {
1386 
1387   for (drone_iterator i = launchers.begin(); i != launchers.end(); ++i) {
1388 
1389 		drone* pdi = *i;
1390     drone& di = *pdi;
1391 
1392     if (di.frozen == 0 && di.launch_every (ui_clk())) { // time to launch a drone
1393 
1394       #define CALLEDFROMLAUNCHER 1
1395       drone* newdronep = add_drone (di.x, di.y, CALLEDFROMLAUNCHER);
1396       drone& newdrone = *newdronep;
1397 
1398 			if (newdrone.y < BOTTOM)
1399         newdrone.gravity = -1;
1400       else
1401         newdrone.gravity = 1; // reverse gravity vector if launched below microtonal keyboard
1402 
1403       // newdrone.is = di.is;
1404 
1405       newdrone.setcolor ();
1406       /*newdrone.r = di.r;
1407       newdrone.g = di.g;
1408       newdrone.b = di.b;*/
1409 
1410       newdrone.V = di.V;
1411       newdrone.vx = di.vx;
1412       newdrone.vy = di.vy;
1413       if (drone::v0.rndrot) rotate_vector (newdrone.vx, newdrone.vy, drone::v0.rotrd());
1414 
1415       newdrone.A = di.A;
1416       newdrone.ax = di.ax;
1417       newdrone.ay = di.ay;
1418       if (drone::a0.rndrot) rotate_vector (newdrone.ax, newdrone.ay, drone::a0.rotrd());
1419 
1420       /*newdrone.autorot.v = di.autorot.v;
1421       newdrone.autorot.a = di.autorot.a;
1422 
1423       newdrone.handle_size = di.handle_size;
1424       newdrone.trail.total = di.trail.total;
1425       newdrone.life = di.life; */
1426 
1427 			newdrone.launched_by = pdi;
1428 
1429 			newdrone.snap = di.snap;
1430       newdrone.gab = di.gab;
1431 
1432       newdrone.arrow = di.arrow;
1433 
1434 			int num_targets = di.num_targets;
1435 			if (num_targets) { // launch a satellite
1436 				newdrone.insert = di.insert;
1437 				int& cur_target = di.cur_target;
1438 				newdrone.target = di.targets [cur_target];
1439 				if (++cur_target >= num_targets) cur_target = 0;
1440 				satellites.push_back (newdronep);
1441 				newdrone.orbiting = 1;
1442 			} else {
1443         gravitated.push_back (newdronep);
1444       }
1445 
1446       spinner2<float>& lifet = MENU.lifetime;
1447       spinner2<float>::variancet& vart = lifet.variance;
1448       if (vart.cb.state) {
1449         newdrone.life = vart.rd () * di.life;
1450       } else {
1451         newdrone.life = di.life;
1452       }
1453 			newdrone.birth = ui_clk();
1454       newdrone.reincarnate = 0;
1455 
1456     }
1457   }
1458 }
1459 
attract_drones()1460 void din::attract_drones () {
1461   // attract drones that orbit other drones
1462   //
1463   for (drone_iterator i = attractors.begin(), j = attractors.end(); i != j; ++i) {
1464     drone* pda = *i;
1465     drone& da = *pda;
1466 		list<attractee>& lae = da.attractees;
1467 		for (list<attractee>::iterator iter = lae.begin (), jter = lae.end(); iter != jter; ++iter) { // run thru list of attractees
1468 			attractee& ae = *iter;
1469 			drone& de = *ae.d;
1470 			unit_vector (de.ax, de.ay, (float)(da.sx - de.x), (float)(da.y - de.y)); // centripetal acceleration
1471 			de.vx = -de.ay; de.vy = de.ax; // centrifugal velocity is just perpendacular to centripetal acceleration
1472 			de.vx *= de.v_mult; de.vy *= de.v_mult; // flip if necessary - see carry_satellites_to_orbit ()
1473 			if (de.frozen == 0) {
1474 				// calculate position of the drones
1475 				de.xi = de.x;
1476 				de.yi = de.y;
1477 				de.x = de.xi + de.V * de.vx + de.A * de.ax;
1478 				de.y = de.yi + de.V * de.vy + de.A * de.ay;
1479 				de.move_center ();
1480 				de.set_pos (de.x, de.y);
1481 			}
1482 		}
1483 	}
1484 }
1485 
add_drone_to_selection(drone * pd)1486 void din::add_drone_to_selection (drone* pd) {
1487 	int& sel = pd->sel;
1488 	if (CTRL) {
1489 		if (sel) {
1490 			remove_drone_from_selection (pd);
1491 			return;
1492 		}
1493 	}
1494 	if (sel) ; else {
1495 		pd->sel = 1;
1496 		selected_drones.push_back (pd);
1497 	}
1498 }
1499 
get_selected_drone_id(drone * d)1500 int din::get_selected_drone_id (drone* d) {
1501 	for (int i = 0; i < num_selected_drones; ++i) {
1502 		if (selected_drones[i] == d) return i;
1503 	}
1504 	return -1;
1505 }
1506 
remove_drone_from_selection(drone * pd)1507 void din::remove_drone_from_selection (drone* pd) {
1508   pd->sel = 0;
1509 	if (xforming) {
1510 		int id = get_selected_drone_id (pd);
1511 		if (id != -1) {
1512 			if (xforming == SCALE)
1513 				erase_id (svec, id);
1514 			else
1515 				erase_id (rvec, id);
1516 		}
1517 	}
1518 	if (erase (selected_drones, pd)) --num_selected_drones;
1519 	if (erase (browsed_drones, pd)) {
1520 		--num_browsed_drones;
1521 		last_browseable_drone = num_browsed_drones - 1;
1522 	}
1523 }
1524 
update_drone_players()1525 void din::update_drone_players () {
1526   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
1527     drone& di = *(*i);
1528     di.sol (&drone_wave);
1529     di.player.set_wave (&di.sol);
1530   }
1531 }
1532 
make_arrow(float * A,int k,int cap,int & n,float x,float y,float ux,float uy,float vx,float vy,float u,float v,float t)1533 void make_arrow (float* A, int k, int cap, int& n, float x, float y, float ux, float uy, float vx, float vy, float u, float v, float t) {
1534 
1535   // make arrow
1536   //
1537 
1538   float ak2, ak3, ak2t, ak3t;
1539 
1540   // base to neck
1541   A[k]=x;
1542   A[k+1]=y;
1543   A[k+2] = ak2 = x + ux;
1544   A[k+3] = ak3 = y + uy;
1545   ak2t = x + t * ux;
1546   ak3t = y + t * uy;
1547 
1548   float arx = x + u * ux, ary = y + u * uy;
1549   float vvx = v * vx, vvy = v * vy;
1550 
1551   // flank1 to neck
1552   float ak4, ak5;
1553   ak4 = A[k+4] = arx + vvx;
1554   ak5 = A[k+5] = ary + vvy;
1555   A[k+6] = ak2t;
1556   A[k+7] = ak3t;
1557 
1558   // flank2 to neck
1559   float ak8, ak9;
1560   ak8 = A[k+8]= arx - vvx;
1561   ak9 = A[k+9]= ary - vvy;
1562   A[k+10]= ak2t;
1563   A[k+11]= ak3t;
1564 
1565   if (cap) {
1566     A[k+12]=ak4;
1567     A[k+13]=ak5;
1568     A[k+14]=ak2;
1569     A[k+15]=ak3;
1570     A[k+16]=ak2;
1571     A[k+17]=ak3;
1572     A[k+18]=ak8;
1573     A[k+19]=ak9;
1574     n = 20;
1575   } else n = 12;
1576 
1577 }
1578 
draw_drones()1579 void din::draw_drones () {
1580 
1581   glEnable (GL_BLEND);
1582   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1583 
1584 	draw_connections ();
1585   drawchuck ();
1586 
1587   // draw drone mesh
1588   if (meshh.num && meshh.draw) {
1589     for (mesh_iterator i = meshes.begin (), j = meshes.end(); i != j; ++i) (*i).draw ();
1590   }
1591 
1592   // draw drone trails
1593   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
1594     drone& di = *(*i);
1595     if (di.range >= visl && di.range <= visr) {
1596       glColor4f (di.r * di.gab.amount, di.g * di.gab.amount, di.b * di.gab.amount, di.fdr.amount);
1597 			di.trail.draw ();
1598 		}
1599   }
1600 
1601   // hilite browsed drone
1602   int dhp [12] = {0};
1603   glVertexPointer (2, GL_INT, 0, dhp);
1604 	if (num_selected_drones == 1 && num_browsed_drones) {
1605 		drone& ds = *selected_drones[0];
1606 		glEnable (GL_LINE_STIPPLE);
1607 		glLineStipple (1, 0xf0f0);
1608 		glColor3f (ds.r, ds.g, ds.b);
1609 		dhp[0]=ds.handle.midx;dhp[1]=win.top;
1610 		dhp[2]=ds.handle.midx;dhp[3]=win.bottom;
1611 		dhp[4]=win.left;dhp[5]=ds.handle.midy;
1612 		dhp[6]=win.right;dhp[7]=ds.handle.midy;
1613 		glDrawArrays (GL_LINES, 0, 4);
1614 		glDisable (GL_LINE_STIPPLE);
1615 	}
1616 
1617   // draw drone handles and pitch/volume info
1618 	if (dinfo.show_pitch_volume.drones) tb_hz_vol.clear ();
1619   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
1620     drone& di = *(*i);
1621     if (inbox<int> (win, di.x, di.y)) {
1622       glColor4f (di.r * di.gab.amount, di.g * di.gab.amount, di.b * di.gab.amount, di.fdr.amount);
1623 			if (dinfo.show_pitch_volume.drones && di.sel) {
1624 				sprintf (BUFFER, " %0.3f @ %d%%", di.step * SAMPLE_RATE, int(di.vol*di.gab.amount*100.0+0.5)); // draw pitch/volume
1625 				tb_hz_vol.add (text (BUFFER, di.handle.right, di.handle.bottom, di.r, di.g, di.b, text::temporary,
1626 														 text::normal,
1627 														 di.handle.right - win.left + fnt.spacing.word,
1628 														 di.handle.top - win.bottom - fnt.spacing.ch));
1629 			}
1630 
1631       glRecti (di.handle.left, di.handle.bottom, di.handle.right, di.handle.top); // fill handle
1632       if (di.sel) glColor4f (0, 1, 0, di.fdr.amount); else glColor4f (1, 1, 1, di.fdr.amount);
1633       dhp[0]=di.handle.left; dhp[1] = di.handle.bottom; dhp[2]=di.handle.right; dhp[3]=di.handle.bottom;
1634       dhp[4]=di.handle.right; dhp[5]=di.handle.top; dhp[6]=di.handle.left; dhp[7]=di.handle.top;
1635 			glDrawArrays (GL_LINE_LOOP, 0, 4); // draw handle outline with selection status
1636 
1637 			if (di.attractor) { // mark + on attractor
1638         dhp[0]=di.handle.midx; dhp[1] = di.handle.top; dhp[2]=di.handle.midx; dhp[3]=di.handle.bottom;
1639         dhp[4]=di.handle.left; dhp[5]=di.handle.midy; dhp[6]=di.handle.right; dhp[7]=di.handle.midy;
1640         glDrawArrays (GL_LINES, 0, 4);
1641 			}
1642       if (di.launcher) { // mark x on launcher
1643         dhp[0]=di.handle.left; dhp[1] = di.handle.top; dhp[2]=di.handle.right; dhp[3]=di.handle.bottom;
1644         dhp[4]=di.handle.left; dhp[5]=di.handle.bottom; dhp[6]=di.handle.right; dhp[7]=di.handle.top;
1645         glDrawArrays (GL_LINES, 0, 4);
1646       }
1647 	  }
1648   }
1649 
1650 	if (dinfo.anchor) { // draw drone anchors
1651     if (n_dap < num_drones) {
1652       if (dap) delete[] dap;
1653       dap = new float [4 * num_drones];
1654       n_dap = num_drones;
1655     }
1656     glVertexPointer (2, GL_FLOAT, 0, dap);
1657     int ai = 0, ad = 0;
1658     for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
1659       drone& di = *(*i);
1660       if (di.range >= visl && di.range <= visr) {
1661         dap[ai++] = di.sx; dap[ai++] = di.y; dap[ai++] = di.sx; dap[ai++] = BOTTOM;
1662         ++ad;
1663       }
1664     }
1665     glColor3f (0.25, 0.25, 0.25);
1666     glDrawArrays (GL_LINES, 0, 2 * ad);
1667   }
1668 
1669   // draw velocity and acceleration vectors
1670   if (num_drones && (dinfo.vel || dinfo.accel)) {
1671 
1672 	  static const int v_size = 4, a_size = 8 * v_size;
1673 
1674     int nn_dvap = 20 * num_drones;
1675     if (n_dvap < nn_dvap) {
1676       if (dvap) delete[] dvap;
1677       if (dcol) delete[] dcol;
1678       dvap = new float [nn_dvap];
1679       dcol = new float [2 * nn_dvap];
1680       n_dvap = nn_dvap;
1681     }
1682     int v = 0, nv = 0;
1683     if (dinfo.vel) {
1684       int ci = 0;
1685       for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
1686         drone& di = *(*i);
1687         if (di.range >= visl && di.range <= visr) {
1688           float vl = di.V * v_size, vdx = vl * di.vx, vdy = vl * di.vy, pvdx = -vdy, pvdy = vdx;
1689           int dv = 12;
1690           make_arrow (dvap, v, di.arrow.cap, dv, di.sx, di.y, vdx, vdy, pvdx, pvdy, di.arrow.u, di.arrow.v, di.arrow.t);
1691           di.xv = di.sx + vdx; di.yv = di.y + vdy;
1692           v += dv;
1693 
1694           color dic (di.r * di.gab.amount, di.g * di.gab.amount, di.b * di.gab.amount);
1695           for (int s = 0, t = dv / 2; s < t; ++s) {
1696             dcol[ci++] = dic.r;
1697             dcol[ci++] = dic.g;
1698             dcol[ci++] = dic.b;
1699             dcol[ci++] = 1.0f;
1700           }
1701           ++nv;
1702         }
1703       }
1704       if (nv) {
1705         glEnableClientState (GL_COLOR_ARRAY);
1706         glColorPointer (4, GL_FLOAT, 0, dcol);
1707 				glVertexPointer (2, GL_FLOAT, 0, dvap);
1708         glDrawArrays (GL_LINES, 0, v / 2);
1709         glDisableClientState (GL_COLOR_ARRAY);
1710       }
1711     }
1712 
1713     if (dinfo.accel) {
1714       int a = 0, na = 0;
1715       for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
1716         drone& di = *(*i);
1717         if (di.range >= visl && di.range <= visr) {
1718           float al = di.A * a_size, adx = al * di.ax, ady = al * di.ay, padx = -ady, pady = adx;
1719           int da = 12;
1720           make_arrow (dvap, a, di.arrow.cap, da, di.sx, di.y, adx, ady, padx, pady, di.arrow.u, di.arrow.v, di.arrow.t);
1721           di.xa = di.sx + adx; di.ya = di.y + ady;
1722           a += da;
1723           ++na;
1724         }
1725       }
1726       if (na) {
1727         glColor4f (1, 0.25, 0.5, 1);
1728 				glVertexPointer (2, GL_FLOAT, 0, dvap);
1729         glDrawArrays (GL_LINES, 0, a / 2);
1730       }
1731     }
1732 
1733   }
1734 
1735 	if (dinfo.show_pitch_volume.drones) tb_hz_vol.draw ();
1736 
1737 	glDisable (GL_BLEND);
1738 
1739 
1740 }
1741 
setdronemastervolume(float d)1742 void din::setdronemastervolume (float d) {
1743   drone::mastervolume = d;
1744 	for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
1745 		drone& di = *(*i);
1746 		di.update_pv = drone::EMPLACE;
1747 	}
1748 	MENU.sp_drone_master_vol.set_value (d);
1749 	sprintf (BUFFER, "Drone master volume = %0.3f", d);
1750 	cons << YELLOW << BUFFER << eol;
1751 }
1752 
update_drone_solvers(multi_curve & crv)1753 void din::update_drone_solvers (multi_curve& crv) {
1754   static const char* dw = "drone-waveform";
1755   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
1756     drone& di = *(*i);
1757     di.sol.update ();
1758 		if (crv.num_vertices) di.player.set_mix (crv, dw);
1759   }
1760 }
1761 
get_selected_drones()1762 string din::get_selected_drones () {
1763   stringstream ss;
1764   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
1765     drone& di = *(*i);
1766     if (di.sel) ss << di.id << spc;
1767   }
1768   return ss.str();
1769 }
1770 
set_drone_volume(int i,float v)1771 void din::set_drone_volume (int i, float v) {
1772 	drone* pd = get_drone (i);
1773 	if (pd) {
1774 		pd->xi = pd->x; pd->yi = pd->y;
1775 		int x = pd->x, y = (int) (BOTTOM + v *  HEIGHT + 0.5f);
1776 		pd->set_pos (x, y);
1777 		pd->move_center ();
1778 	}
1779 }
1780 
calc_win_mouse()1781 void din::calc_win_mouse () {
1782 
1783   if (MENU.show == 0) {
1784 
1785     delta_mousex = mousex - prev_mousex;
1786     delta_mousey = mousey - prev_mousey;
1787 
1788 		prev_mousex = mousex;
1789 		prev_mousey = mousey;
1790 
1791 		prev_win_mousex = win_mousex;
1792 		prev_win_mousey = win_mousey;
1793 
1794     win_mousex += delta_mousex;
1795     win_mousey -= delta_mousey;
1796 
1797     tonex = win_mousex;
1798     toney = win_mousey;
1799 
1800   }
1801 
1802 }
1803 
is_drone_hit(drone & di,const box<float> & rgn)1804 int din::is_drone_hit (drone& di, const box<float>& rgn) {
1805   float x [] = {di.handle.midx, di.handle.left, di.handle.right};
1806   float y [] = {di.handle.midy, di.handle.bottom, di.handle.top};
1807   for (int i = 0; i < 3; ++i)
1808     for (int j = 0; j < 3; ++j)
1809       if (inbox<float> (rgn, x[i], y[j])) return 1;
1810   return 0;
1811 }
1812 
calc_selector_range(const box<float> & rgn,int & left,int & right)1813 void din::calc_selector_range (const box<float>& rgn, int& left, int& right) {
1814   float xl = rgn.left, xr = rgn.right;
1815   left = right = 0;
1816   for (int i = 0; i < num_ranges; ++i) {
1817     range& ri = ranges[i];
1818     if (xl >= ri.extents.left) left = max (0, i - 1);
1819     if (xr >= ri.extents.right) right = min (last_range, i + 1);
1820   }
1821 }
1822 
find_selected_drones(const box<float> & rgn)1823 void din::find_selected_drones (const box<float>& rgn) {
1824   // select drones that lie inside selected region
1825   // supports ctrl & shift keys
1826   int sell, selr; calc_selector_range (rgn, sell, selr);
1827 	CLEAR_SELECTED_DRONES
1828   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
1829     drone* pdi = *i;
1830     drone& di = *pdi;
1831     if ((di.state > drone::DEAD) && (di.range >= sell) && (di.range <= selr) && is_drone_hit (di, rgn))
1832 			add_drone_to_selection (pdi);
1833   }
1834   print_selected_drones ();
1835 }
1836 
invert_selected_drones()1837 void din::invert_selected_drones () {
1838   selected_drones.clear ();
1839   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
1840     drone* pdi = *i;
1841     drone& di = *pdi;
1842     if (di.sel)
1843 			di.sel = 0;
1844 		else {
1845       di.sel = 1;
1846       selected_drones.push_back (pdi);
1847     }
1848   }
1849   print_selected_drones ();
1850 }
1851 
print_selected_drones()1852 void din::print_selected_drones () {
1853   num_selected_drones = selected_drones.size ();
1854   if (num_selected_drones) {
1855 		if (num_selected_drones != 1) {
1856 			browsed_drones = selected_drones;
1857 			num_browsed_drones = num_selected_drones;
1858 			last_browseable_drone = num_browsed_drones - 1;
1859 			browsed_drone = -1;
1860 			MENU.sp_browse_drone.set_listener (MENUP.brwdl);
1861 			MENU.sp_browse_drone.set_value (browsed_drone);
1862 		} else {
1863 			MENU.sp_browse_drone.set_listener (0);
1864 			ec = selected_drones[0];
1865 		}
1866     cons << GREEN;
1867     prep_modulate (MODULATE_DRONES);
1868 		MENU.next_tab = MENUP.cb_mkb_drone_params;
1869 		MENU.next_tab_instr = this;
1870 		if (xforming) resize_xform_vectors ();
1871   } else {
1872     cons << RED;
1873 		browsed_drones.clear ();
1874 		num_browsed_drones = 0;
1875 		browsed_drone = last_browseable_drone = -1;
1876 		ec = 0;
1877   }
1878   cons << "Selected " << num_selected_drones << s_drones << eol;
1879 }
1880 
handle_input()1881 int din::handle_input () {
1882 
1883 	// if (butting) butt_drones ();
1884 
1885   static const double reptf = 1./7, repts = 1./64.;
1886 	static const double first_repeat_time = 0.3, other_repeat_time = 0.05;
1887   static double start_time, repeat_time = first_repeat_time;
1888 	static int lmb_clicked = 0;
1889 
1890   // mov
1891   if (keypressedd (SDLK_a, dinfo.scroll.rept, dinfo.scroll.rept)) scroll (-dinfo.scroll.dx, 0); else
1892   if (keypressedd (SDLK_d, dinfo.scroll.rept, dinfo.scroll.rept)) scroll (+dinfo.scroll.dx, 0); else
1893   if (keypressedd (SDLK_w, dinfo.scroll.rept, dinfo.scroll.rept)) scroll (0, +dinfo.scroll.dy); else
1894   if (keypressedd (SDLK_s, dinfo.scroll.rept, dinfo.scroll.rept)) scroll (0, -dinfo.scroll.dy);
1895   if (wheel && !MENU.show && !mouse_slider0.active) {
1896     if (SHIFT) scroll (0, wheel * dinfo.scroll.dy); else scroll (-wheel * dinfo.scroll.dx, 0);
1897   }
1898 
1899   if (lmb) {
1900 
1901     if (lmb_clicked == 0) {
1902       lmb_clicked = 1;
1903       if (adding) {
1904         add_drone (win_mousex, win_mousey);
1905         start_time = ui_clk();
1906       }
1907     } else {
1908       if (adding) {
1909         // for spraying drones
1910         double delta_time = ui_clk() - start_time;
1911         if (delta_time >= repeat_time) { // click repeat
1912           lmb_clicked = 0;
1913           repeat_time = other_repeat_time;
1914         }
1915       }
1916     }
1917 
1918   } else {
1919     lmb_clicked = 0;
1920     repeat_time = first_repeat_time;
1921   }
1922 
1923   if (phrasor0.state == phrasor::recording) { // record mouse pos for playback l8r
1924     static point<int> pt;
1925     pt.x = win_mousex; pt.y = win_mousey;
1926     phrasor0.add (pt);
1927     ++phrasor0.size;
1928   }
1929 
1930   // octave shift
1931   if (keypressed (SDLK_z)) modulate_down ();
1932   else if (keypressed (SDLK_x)) modulate_up ();
1933 
1934   else if (keypressed (SDLK_e)) {
1935     if (!mouse_slider0.active) {
1936       if (SHIFT) MENU.bsdl.clicked (MENU.b_scale_drones); else
1937       if (CTRL) MENU.brdl.clicked (MENU.b_rotate_drones);
1938       else { // move drones
1939         if (moving_drones) set_moving_drones (0); // stop moving
1940         else if (mouse_slider0.deactivate()) ; // bcos scale or rotate
1941         else if (!MENU.show) start_moving_drones (); // start moving
1942       }
1943     }
1944   }
1945 
1946   else if (moving_drones) {
1947     if (num_selected_drones) {
1948       if (prev_win_mousex != win_mousex || prev_win_mousey != win_mousey) {
1949         for (int i = 0; i < num_selected_drones; ++i) {
1950           drone& di = *selected_drones[i];
1951           movedrone (di);
1952         }
1953       }
1954       return 1;
1955     } else {
1956       cons << RED_PSD << eol;
1957     }
1958   }
1959 
1960   else if (keypressed (SDLK_f)) {
1961       if (SHIFT) {
1962         dinfo.sel_range = current_range;
1963         MENU.load_range (current_range);
1964         MENU.next_tab = MENUP.cb_mkb_ranges;
1965         MENU.next_tab_instr = this;
1966       } else if (CTRL) {
1967         MENU.cnol.picked (MENU.ol_change_note.option, 0);
1968         print_range_info (ranges[dinfo.sel_range]);
1969       } else {
1970         do_phrase_recording ();
1971       }
1972 	}
1973 	else if (keypressed (SDLK_v)) {
1974       if (SHIFT) {
1975         MENU.rwl.clicked (MENU.b_adjust_range_both); // adjust range left and right
1976       } else if (CTRL) {
1977         MENU.cnb.clicked (MENU.b_change_note_both); // change both notes of range
1978       } else { // phrase play/pause
1979         if (phrasor0.state == phrasor::playing) {
1980           if (MENU.show == 0) {
1981             phrasor0.state = phrasor::paused;
1982             find_current_range ();
1983             cons << YELLOW << "phrasor has PAUSED." << eol;
1984           } else cons << RED << "Close menu!" << eol;
1985         } else {
1986           if (phrasor0.validate ()) {
1987             phrasor0.play ();
1988             if (phrasor0.state == phrasor::playing) cons << GREEN << "Phrasor is PLAYING" << eol;
1989           } else {
1990             pos_afx_vel (-1);
1991           }
1992         }
1993       }
1994 	}
1995 	else if (keypressed (SDLK_g)) { // phrase clear
1996       if (SHIFT) {
1997         MENU.rwl.clicked (MENU.b_adjust_range_left); // adjust range left
1998       } else if (CTRL) {
1999         MENU.cnl.clicked (MENU.b_change_note_left); // change range left note
2000       } else {
2001         clear_all_phrases ();
2002       }
2003 	}
2004 	else if (keypressed (SDLK_h)) {
2005 		if (SHIFT) {
2006 			MENU.rwl.clicked (MENU.b_adjust_range_right); // adjust range right
2007 		} else
2008 		if (CTRL) {
2009 			MENU.cnr.clicked (MENU.b_change_note_right); // change range right note
2010 		} else
2011 			toggle_launchers ();
2012 	}
2013 	else if (keypressedd (SDLK_n)) --MENU.sp_drones_per_min;
2014 	else if (keypressedd (SDLK_m)) ++MENU.sp_drones_per_min;
2015 	else if (keypressed (SDLK_b)) {
2016 		if (SHIFT) {
2017 			MENU.rhl.clicked (MENU.b_adjust_range_height);
2018 		} else if (CTRL) {
2019 			MENU.bhl.clicked (MENU.b_adjust_board_height);
2020 		} else uis.cb_gater.toggle ();
2021 	}
2022 
2023   // drones
2024   //
2025   else if (keypressedd (SDLK_q)) {
2026     if (!mouse_slider0.active) {
2027       if (SHIFT) {
2028         MENU.picked (MENU.ol_drone_is.option, 0);
2029       } else {
2030         if (dinfo.wand)  {
2031           if (wanding)
2032             stopwanding ();
2033           else
2034             MENU.dcl.startwanding ();
2035         }
2036         else
2037           add_drone (win_mousex, win_mousey);
2038       }
2039     }
2040 	}
2041   else if (keypressedd (SDLK_c)) {
2042     if (SHIFT)
2043       set_drones_under_gravity ();
2044     else
2045       delete_selected_drones ();
2046   }
2047 	else if (keypressedd (SDLK_LEFTBRACKET, reptf, repts)) {
2048     if (SHIFT) --MENU.sp_rotate_drone_vel; else --MENU.sp_change_drone_vel;
2049   }
2050   else if (keypressedd (SDLK_RIGHTBRACKET, reptf, repts)) {
2051     if (SHIFT) ++MENU.sp_rotate_drone_vel;
2052     else if (CTRL)
2053       toggle_this (dinfo.vel, MENU.cb_show_vel);
2054     else
2055       ++MENU.sp_change_drone_vel;
2056   }
2057 	else if (keypressed (SDLK_l)) {
2058 		if (SHIFT)
2059 			select_launchers ();
2060 		else
2061 			select_all_drones ();
2062 	}
2063 	else if (keypressed (SDLK_i)) {
2064 		if (SHIFT) {
2065 			dinfo.show_pitch_volume.board = !dinfo.show_pitch_volume.board;
2066 			dont_call_listener (uis.cb_show_pitch_volume_board, dinfo.show_pitch_volume.board);
2067 		}
2068 		else
2069 			invert_selected_drones ();
2070 	}
2071 
2072 	else if (keypressedd (SDLK_LEFT)) {
2073 		if (SHIFT) browse_range (-1); else browse_drone (-1);
2074 	} else if (keypressedd (SDLK_RIGHT)) {
2075 		if (SHIFT) browse_range (+1); else browse_drone (+1);
2076 	}
2077 
2078 	else if (keypressed (SDLK_j)) {
2079 		if (SHIFT) {
2080 			dinfo.show_pitch_volume.drones = !dinfo.show_pitch_volume.drones;
2081 			dont_call_listener (uis.cb_show_pitch_volume_drones, dinfo.show_pitch_volume.drones);
2082 		} else
2083 			toggle_freeze_drones ();
2084 	}
2085 	else if (keypressed (SDLK_k)) {
2086 		if (SHIFT)
2087 			snap_drones (1);
2088 		else if (CTRL)
2089 			snap_drones (0);
2090 		else snap_drones (-1); // toggle
2091 	}
2092   else if (keypressedd (SDLK_o, reptf, repts))
2093 		--MENU.sp_change_drone_accel;
2094   else if (keypressedd (SDLK_p, reptf, repts)) {
2095     if (CTRL)
2096       toggle_this (dinfo.accel, MENU.cb_show_accel);
2097     else
2098 			++MENU.sp_change_drone_accel;
2099   }
2100 	/*else if (keypressed (SDLK_F3)) {
2101 		butting = !butting;
2102 	}
2103 	else if (keypressed (SDLK_F4)) {
2104 		ring.x = win_mousex;
2105 		ring.y = win_mousey;
2106 	}*/
2107 
2108   else if (keypressed (SDLK_SEMICOLON)) select_attractors ();
2109   else if (keypressed (SDLK_QUOTE)) select_attractees ();
2110 
2111 	else if (keypressedd (SDLK_COMMA, reptf, repts)) {
2112       if (SHIFT)
2113         gab.set (this, 0.0f, "muting drones");
2114       else if (CTRL)
2115         noise2drone ();
2116       else
2117         setdronemastervolume (drone::mastervolume - float(MENU.sp_drone_master_vol.f_delta));
2118   }
2119 	else if (keypressedd (SDLK_PERIOD, reptf, repts)) {
2120       if (SHIFT)
2121         gab.set (this, 1.0f, "unmuting drones");
2122       else if (CTRL)
2123         drone2noise ();
2124       else
2125         setdronemastervolume (drone::mastervolume + float(MENU.sp_drone_master_vol.f_delta));
2126   }
2127 
2128   else if (keypressed (SDLK_F4)) switch_modulation ();
2129 	else if (keypressed (SDLK_BACKSLASH)) set_key_to_pitch_at_cursor ();
2130 	else if (keypressed (SDLK_SPACE)) {
2131     if (adjustranges.active) {
2132       adjustranges.others = !adjustranges.others;
2133       if (adjustranges.others) cons << GREEN << "Adjust other ranges too" << eol; else cons << YELLOW << "Adjusting this range only" << eol;
2134     } else
2135       uis.cb_voice.toggle (); // toggle lead voice
2136   }
2137 	else if (keypressed (SDLK_F1)) helptext();
2138 
2139   // bpms
2140   if (keypressedd (SDLK_F5)) { // decrease gater bpm upto limit
2141 		if (SHIFT)
2142 			lower_delta (gater_delta.bpm, -1, "delta_gater_bpm = ");
2143 		else if (CTRL) {
2144 			gatr.min_bpm = gatr.bpm;
2145 			cons << YELLOW << "set minimum gater bpm to " << gatr.bpm << eol;
2146 		}
2147 		else
2148     	change_bpm (gatr, -gater_delta.bpm); //-(float)MENU.sp_gater_bpm.f_delta);
2149   } else if (keypressedd (SDLK_F6)) { // increase gater bpm
2150 		if (SHIFT)
2151 			raise_delta (gater_delta.bpm, +1, "delta_gater_bpm = ");
2152 		else if (CTRL) {
2153 			gatr.min_bpm = 0;
2154 			cons << YELLOW << "set minimum gater bpm to " << gatr.min_bpm << eol;
2155 		}
2156 		else
2157     	change_bpm (gatr, gater_delta.bpm); //MENU.sp_gater_bpm.f_delta);
2158   } else if (keypressedd (SDLK_F7)) { // decrease fm bpm
2159 		if (SHIFT)
2160 			lower_delta (fm_delta.bpm, -1, "delta_fm_bpm = ");
2161 		else
2162     	change__bpm (modulator::FM, fm, -fm_delta.bpm); //-(float)MENU.sp_fm_bpm.f_delta);
2163   } else if (keypressedd (SDLK_F8)) { // increase fm bpm
2164 		if (SHIFT)
2165 			raise_delta (fm_delta.bpm, +1, "delta_fm_bpm = ");
2166 		else
2167     	change__bpm (modulator::FM, fm, fm_delta.bpm); //MENU.sp_fm_bpm.f_delta);
2168   } else if (keypressedd (SDLK_F9)) { // decrease am bpm
2169 		if (SHIFT)
2170 			lower_delta (am_delta.bpm, -1, "delta_am_bpm = ");
2171 		else
2172     	change__bpm (modulator::AM, am, -am_delta.bpm); //-(float)MENU.sp_am_bpm.f_delta);
2173   } else if (keypressedd (SDLK_F10)) { // increase am bpm
2174 		if (SHIFT)
2175 			raise_delta (am_delta.bpm, 1, "delta_am_bpm = ");
2176 		else
2177     	change__bpm (modulator::AM, am, am_delta.bpm); //MENU.sp_am_bpm.f_delta);
2178   } else if (keypressedd (SDLK_F11)) { // decrease octave shift bpm
2179 		if (SHIFT)
2180 			lower_delta (os_delta.bpm, -1, "delta_octave_shift_bpm = ");
2181 		else
2182     	change_bpm (octave_shift, -os_delta.bpm); //-(float)MENU.sp_octave_shift_bpm.f_delta);
2183   } else if (keypressedd (SDLK_F12)) { // increase octave shift bpm
2184 		if (SHIFT)
2185 			raise_delta (os_delta.bpm, +1, "delta_octave_shift_bpm = ");
2186 		else
2187     	change_bpm (octave_shift, os_delta.bpm); //MENU.sp_octave_shift_bpm.f_delta);
2188   }
2189 
2190   // depths
2191   else if (keypressedd (SDLK_r)) { // decrease am depth
2192       if (SHIFT)
2193         lower_delta (p_am_delta->depth, -float(MENU.sp_am_depth.f_delta), "delta_am_depth = ", 0.0f);
2194       else
2195         change__depth (modulator::AM, -dam_delta.depth, 0, -am_delta.depth);
2196   } else if (keypressedd (SDLK_t)) { // increase am depth
2197 		if (SHIFT)
2198 			raise_delta (p_am_delta->depth, float(MENU.sp_am_depth.f_delta), "delta_am_depth = ");
2199 		else
2200     	change__depth (modulator::AM, dam_delta.depth, 0, am_delta.depth);
2201   } else if (keypressedd (SDLK_y)) { // decrease fm depth
2202 		if (SHIFT)
2203 			lower_delta (fm_delta.depth, -float (MENU.sp_fm_depth.f_delta), "delta_fm_depth = ");
2204 		else
2205     	change__depth (modulator::FM, -fm_delta.depth, 1, -fm_delta.depth);
2206   } else if (keypressedd (SDLK_u)) { // increase fm depth
2207 		if (SHIFT)
2208 			raise_delta (fm_delta.depth, float (MENU.sp_fm_depth.f_delta), "delta_fm_depth = ");
2209 		else
2210     change__depth (modulator::FM, fm_delta.depth, 1, fm_delta.depth);
2211   }
2212 
2213   else if (keypressedd (SDLK_MINUS)) {
2214 		--MENU.sp_change_drone_trail_length;
2215   } else if (keypressedd (SDLK_EQUALS)) {
2216 		++MENU.sp_change_drone_trail_length;
2217   } else if (keypressedd (SDLK_9)) {
2218 		if (!mouse_slider0.active) --MENU.sp_change_drone_handle_size;
2219   } else if (keypressedd (SDLK_0)) {
2220 		if (!mouse_slider0.active) ++MENU.sp_change_drone_handle_size;
2221   }
2222 
2223 	else if (keypressed (SDLK_INSERT)) {
2224 		dinfo.dist.vol = !dinfo.dist.vol;
2225 		MENU.cb_vol_dis.set_state (dinfo.dist.vol);
2226 	} else if (keypressed (SDLK_DELETE)) {
2227 		dinfo.dist.pitch = !dinfo.dist.pitch;
2228 		MENU.cb_pitch_dis.set_state (dinfo.dist.pitch);
2229 	}
2230 
2231 	/*else if (keypressedd (SDLK_INSERT, reptf, repts)){
2232 		if (SHIFT) ++inter_butt;
2233 		else if (CTRL) ring.r += 10;
2234 		else ++butt;
2235 	}
2236 	else if (keypressedd (SDLK_DELETE, reptf, repts)) {
2237 		if (SHIFT) --inter_butt;
2238 		else if (CTRL) ring.r -= 10;
2239 		else --butt;
2240 		if (inter_butt < 0) inter_butt = 0;
2241 		if (butt < 0) butt = 0;
2242 		if (ring.r < 0) ring.r = 0;
2243 	}*/
2244 
2245   return 1;
2246 
2247 }
2248 
2249 #ifdef __SVG__
write_trail()2250 void din::write_trail () {
2251   dlog << "<svg>" << endl;
2252   for (int i = 0; i < num_selected_drones; ++i) {
2253     drone& ds = *selected_drones[i];
2254     ds.trail.write ();
2255   }
2256   dlog << "</svg>" << endl;
2257 }
2258 #endif
2259 
change_drone_lifetime(spinner<float> & s)2260 void din::change_drone_lifetime (spinner<float>& s) {
2261 	if (num_selected_drones) {
2262 		for (int i = 0; i < num_selected_drones; ++i) {
2263 			drone& ds = *selected_drones[i];
2264 			ds.life += s ();
2265 			if (ds.life < 0) ds.life = 0;
2266 			cons << GREEN << "Drone: " << i << ", lifetime = " << ds.life << " secs" << eol;
2267 		}
2268 	} else {
2269 		cons << RED_PSD << eol;
2270 	}
2271 }
2272 
change_orbit_insertion_time(spinner<float> & s)2273 void din::change_orbit_insertion_time (spinner<float>& s) {
2274 	if (num_selected_drones) {
2275 		for (int i = 0; i < num_selected_drones; ++i) {
2276 			drone& ds = *selected_drones[i];
2277 			if (ds.launcher) {
2278 				ds.insert += s ();
2279 				if (ds.insert < 0) ds.insert = 0;
2280 				cons << "Drone: " << i << ", orbit insertion time = " << ds.insert << " secs" << eol;
2281 			}
2282 		}
2283 	} else {
2284 		cons << RED_PSD << eol;
2285 	}
2286 }
2287 
change_drone_trail_points(spinner<int> & s)2288 void din::change_drone_trail_points (spinner<int>& s) {
2289 	if (num_selected_drones) {
2290 		for (int i = 0; i < num_selected_drones; ++i) {
2291 			drone& ds = *selected_drones[i];
2292 			ds.trail.change (s());
2293 			cons << GREEN << "Drone: " << i << ", trail points = " << ds.trail.total << eol;
2294 		}
2295 	} else cons << RED_PSD << eol;
2296 }
2297 
change_drone_handle_size(spinner<int> & s)2298 void din::change_drone_handle_size (spinner<int>& s) {
2299 	if (num_selected_drones) {
2300 		for (int i = 0; i < num_selected_drones; ++i) {
2301 			drone& ds = *selected_drones[i];
2302 			ds.handle_size += s();
2303 			if (ds.handle_size < 0) ds.handle_size = 0; else cons << GREEN << "Drone " << i << ", handle size = " << ds.handle_size << eol;
2304 		}
2305 		update_drone_anchors ();
2306 	} else cons << RED_PSD << eol;
2307 }
2308 
2309 
2310 /*void din::change_drone_label_offset (int w, int sz) {
2311 	rnd<float> rd (-1.0f, +1.0f);
2312 	if (num_selected_drones) {
2313 		for (int i = 0; i < num_selected_drones; ++i) {
2314 			drone& ds = *selected_drones[i];
2315 			float* xy [2] = {&ds.lbloff.x, &ds.lbloff.y};
2316 			*xy[w] += (sz + rd());
2317 		}
2318 	} else cons << RED_PSD << eol;
2319 }*/
2320 
change_drone_arrow(spinner<float> & s,int w)2321 void din::change_drone_arrow (spinner<float>& s, int w) {
2322 	if (num_selected_drones) {
2323 		for (int i = 0; i < num_selected_drones; ++i) {
2324 			drone& ds = *selected_drones[i];
2325       drone::arrowt& ar = ds.arrow;
2326       float* wa [] = {&ar.u, &ar.v, &ar.t};
2327       *wa[w] += s ();
2328 		}
2329 	} else cons << RED_PSD << eol;
2330 }
2331 
2332 
capdronearrows(int c)2333 void din::capdronearrows (int c) {
2334 	if (num_selected_drones) {
2335 		for (int i = 0; i < num_selected_drones; ++i) {
2336 			drone& ds = *selected_drones[i];
2337       ds.arrow.cap = c;
2338     }
2339   } else cons << RED_PSD << eol;
2340 }
2341 
scroll(int dx,int dy,int warp_mouse)2342 void din::scroll (int dx, int dy, int warp_mouse) {
2343 
2344   mousex -= dx;
2345   prev_mousex -= dx;
2346   mousey += dy;
2347   prev_mousey += dy;
2348 
2349   win (win.left + dx, win.bottom + dy, win.right + dx, win.top + dy);
2350   find_visible_ranges (dx);
2351 
2352   if (warp_mouse) {
2353     if ((mousex > 0 && mousex < view.width) && (mousey > 0 && mousey < view.height)) SDL_WarpMouse (mousex, mousey);
2354     dinfo.gravity.forcetrack = 1;
2355   }
2356 
2357   dinfo.gravity.ldwx = dinfo.gravity.ldwy = -1; // see din::evalgravity ()
2358 
2359 }
2360 
find_current_range()2361 void din::find_current_range () {
2362   // find the range where mouse is found
2363   if (win_mousex <= ranges[0].extents.left) current_range = 0; else
2364   if (win_mousex >= ranges[last_range].extents.right) current_range = last_range; else
2365   for (int i = 0; i < num_ranges; ++i) {
2366     range& curr = ranges[i];
2367     box<int>& ext = curr.extents;
2368     if ( (win_mousex >= ext.left) && (win_mousex <= ext.right)) {
2369       current_range = i;
2370       break;
2371     }
2372   }
2373   find_visible_ranges ();
2374 }
2375 
find_visible_ranges(int dir)2376 void din::find_visible_ranges (int dir) {
2377   // we only draw visible ranges
2378   if (dir > 0) {
2379     while ((visr < last_range) && (ranges[visr].extents.right < win.right)) ++visr;
2380     while ((visl < last_range) && (ranges[visl].extents.right < win.left)) ++visl;
2381   } else if (dir < 0) {
2382     while ((visl > 0) && (ranges[visl].extents.left > win.left)) --visl;
2383     while ((visr > 0) && (ranges[visr].extents.left > win.right)) --visr;
2384   } else {
2385     visl = current_range;
2386     visr = current_range;
2387     while ( (visl > 0) && (win.left < ranges[visl].extents.left) ) --visl;
2388     while ( (visr < last_range) && (ranges[visr].extents.right < win.right) ) ++visr;
2389   }
2390 }
2391 
find_range(float x,int r)2392 int din::find_range (float x, int r) {
2393   while (1) {
2394     range& curr = ranges [r];
2395     float deltax = x - curr.extents.left;
2396     if (deltax > curr.extents.width) {
2397       if (++r < num_ranges); else {
2398         r = last_range;
2399         break; // drone in last range
2400       }
2401     }
2402     else if (deltax < 0) {
2403       if (--r < 0) {
2404         r = 0; // drone in first range
2405         break;
2406       }
2407     }
2408     else
2409       break; // drone in current range
2410   }
2411   return r;
2412 }
2413 
find_tone_and_volume()2414 int din::find_tone_and_volume () {
2415 
2416   // locate current tone
2417   range* curr = &ranges [current_range];
2418   int deltax = tonex - curr->extents.left;
2419   if (deltax >= curr->extents.width) { // tone in range to the right
2420     ++current_range;
2421     if (current_range == num_ranges) { // snap to last range
2422       current_range = last_range;
2423       curr = lastr;
2424     } else {
2425       curr = &ranges [current_range];
2426     }
2427   } else if (deltax < 0) { // tone in range to the left
2428     --current_range;
2429     if (current_range < 0) { // snap to first range
2430       curr = firstr;
2431       current_range = 0;
2432     } else {
2433       curr = &ranges [current_range];
2434     }
2435   }
2436 
2437   // located tone so find frequency
2438   //
2439   deltax = tonex - curr->extents.left;
2440   delta = warp_pitch (deltax * curr->extents.width_1);
2441   step = curr->notes[0].step + delta * curr->delta_step; // step determines frequency see note.h
2442 
2443 	// find VOLUME
2444 	static const int if_uniq = 1;
2445 	int dv = toney - BOTTOM;
2446 	float iv = dv * 1.0f / ranges[current_range].extents.height;
2447 	float fin_vol = 1.0f;
2448   if (dv < 0) { // below keyboard, silence voice
2449 		fin_vol = 0.0f;
2450 		wavplay.set_interpolated_pitch_volume (step, fin_vol, if_uniq);
2451 		am_vol = 0;
2452 		VOLUME = -warp_vol (-iv);
2453   } else {
2454 		VOLUME = warp_vol (iv);
2455 		float fdr_vol = uis.fdr_voice.amount * VOLUME;
2456 		fin_vol = fdr_vol * VOICE_VOLUME;
2457 		wavplay.set_interpolated_pitch_volume (step, fin_vol, if_uniq);
2458 		am_vol = fdr_vol * am_depth;
2459   }
2460 
2461 	if (dinfo.voice_is_voice == 0) {
2462 		nsr.set_spread (fin_vol);
2463 		nsr.set_samples (1.0f / step);
2464 	}
2465 
2466   Tcl_UpdateLinkedVar (interpreter.interp, "volume"); // VOLUME is accessible in Tcl interpreter as variable volume
2467 
2468 	if (dinfo.show_pitch_volume.board) {
2469 		sprintf (BUFFER, "%0.3f @ %03d%%", (step * SAMPLE_RATE), int(VOLUME * 100));
2470 		pitch_volume_info = BUFFER;
2471 	}
2472 
2473   return 1;
2474 
2475 }
2476 
draw()2477 void din::draw () {
2478 
2479   glMatrixMode (GL_PROJECTION);
2480   glLoadIdentity ();
2481   glOrtho (win.left, win.right, win.bottom, win.top, -1, 1);
2482 
2483   glMatrixMode (GL_MODELVIEW);
2484   glLoadIdentity ();
2485 
2486   draw_drones (); // draw drones
2487 
2488 	if (UI_OFF == 0) {
2489 
2490 	  if (dinfo.dist.vol) draw_vol_dist ();
2491 	  if (dinfo.dist.pitch) draw_pitch_dist ();
2492 
2493 		// mark selected range?
2494   	if (dinfo.mark_sel_range && (dinfo.sel_range >= visl && dinfo.sel_range <= visr)) {
2495     	range& cr = ranges[dinfo.sel_range];
2496     	box<int>& cre = cr.extents;
2497     	glLineWidth (3);
2498 			glEnable (GL_LINE_STIPPLE);
2499 			glLineStipple (1, 0xf0f0);
2500     	glColor3f (0.5f, 0.75f, 1.0f);
2501     	gl_pts[0]=cre.left; gl_pts[1]=cre.bottom;
2502     	gl_pts[2]=cre.right; gl_pts[3]=cre.bottom;
2503     	gl_pts[4]=cre.right; gl_pts[5]=cre.top;
2504     	gl_pts[6]=cre.left; gl_pts[7]=cre.top;
2505 			glVertexPointer (2, GL_INT, 0, gl_pts);
2506     	glDrawArrays (GL_LINE_LOOP, 0, 4);
2507     	glLineWidth (1);
2508 			glDisable (GL_LINE_STIPPLE);
2509   	}
2510 
2511   	// label visible ranges
2512   	for (int i = visl; i < visr; ++i) ranges[i].draw_labels (range::LEFT, dinfo.show_pitch_volume.board);
2513   	ranges[visr].draw_labels (range::BOTH, dinfo.show_pitch_volume.board);
2514 
2515   	// phrasor markers
2516   	phrasor0.draw ();
2517 
2518   	// draw cursor info
2519   	int cursorx = tonex + 8, cursory = toney;
2520   	if (dinfo.show_pitch_volume.board && !basic_editor::hide_cursor) {
2521 			glColor3f (0.9f, 0.9f, 1.0f);
2522     	draw_string (pitch_volume_info, cursorx, cursory);
2523       if (rising || falling) {
2524     	  cursory += line_height;
2525         draw_string (num_drones_info, cursorx, cursory);
2526       }
2527   	}
2528 
2529     // drones xform center
2530     dinfo.cen.draw ();
2531 
2532   	// draw guide for positioning drones
2533   	if (dinfo.voice == 0) {
2534     	glColor3f (0.25, 0.25, 0.25);
2535     	gl_pts[0]=tonex;gl_pts[1]=toney;
2536     	gl_pts[2]=tonex;gl_pts[3]=BOTTOM;
2537     	glVertexPointer (2, GL_INT, 0, gl_pts);
2538     	glDrawArrays (GL_LINES, 0, 2);
2539   	}
2540 
2541     // draw selector
2542 		mkb_selector.draw (rgn);
2543 
2544 	}
2545 
2546 
2547 
2548 }
2549 
enter()2550 void din::enter () {
2551   if (phrasor0.state == phrasor::playing)
2552 		return;
2553 	else {
2554     ui::enter ();
2555 		win_mousex = win.left + mousex;
2556 		win_mousey = win.bottom + mouseyy;
2557   }
2558 }
2559 
window_resized(int w,int h)2560 void din::window_resized (int w, int h) {
2561 	clear_all_phrases ();
2562 	win (win.left, win.bottom, win.left + w, win.bottom + h);
2563 	warp_mouse (prev_mousex, prev_mousey);
2564   dinfo.gravity.forcetrack = 1;
2565 	win_mousex = win.left + mousex;
2566 	win_mousey = win.bottom + mouseyy;
2567 	find_current_range ();
2568 }
2569 
change_depth(int i,float d)2570 void din::change_depth (int i, float d) {
2571 
2572   if (i == 1) {
2573     fm_depth += d;
2574     hz2step (fm_depth, fm_step);
2575     cons << YELLOW << "Voice FM depth = " << fm_depth << eol;
2576     MENU.sp_fm_depth.set_value (fm_depth);
2577   } else {
2578     am_depth += d;
2579     cons << YELLOW << "Voice AM depth = " << am_depth << eol;
2580     MENU.sp_am_depth.set_value (am_depth);
2581   }
2582 }
2583 
change_bpm(beat2value & which,float amt)2584 void din::change_bpm (beat2value& which, float amt) {
2585   float bpm = which.bpm + amt;
2586   bpm = which.set_bpm (bpm);
2587   cons << YELLOW << which.name << " bpm: " << bpm << eol;
2588   MENU.update_bpm (which.name, bpm);
2589 }
2590 
calc_am_fm_gater()2591 int din::calc_am_fm_gater () {
2592 	int ret = 0;
2593 	memcpy (aout.bufL, wavplay.pvol, aout.samples_channel_size);
2594 	multiply (aout.bufL, aout.samples_per_channel, am_depth);
2595 	ret += am.modulate_and_mix (aout.ams, aout.mix, aout.mixa, aout.samples_per_channel, aout.bufL);
2596 	ret += fm.modulate_and_mix (aout.fms, aout.mix, aout.mixa, aout.samples_per_channel, fm_step);
2597   ret += gatr.gen_and_mix (aout.gatr, aout.mix, aout.mixa, aout.samples_per_channel);
2598 	return ret;
2599 }
2600 
modulate_drones()2601 void din::modulate_drones () {
2602 
2603   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
2604     drone& di = *(*i);
2605 		if (di.frozen == 0) {
2606 			modulator& dm = di.mod;
2607 			dm.calc ();
2608       di.autorot.calc (dm.dt);
2609       // AM along a direction vector, FM along a direction vector
2610       float x = di.cx + dm.fm.result * (*dm.fm.dirx) + dm.am.result * (*dm.am.dirx);
2611       float y = di.cy + dm.fm.result * (*dm.fm.diry) + dm.am.result * (*dm.am.diry);
2612       if (di.autorot.v.yes) rotate_vector (di.vx, di.vy, di.autorot.v.angle.theta);
2613       if (di.autorot.a.yes) rotate_vector (di.ax, di.ay, di.autorot.a.angle.theta);
2614       di.set_pos (x, y);
2615       // di.set_pos (di.cx + dm.fm.result, di.cy + dm.am.result);
2616 		}
2617 	}
2618 }
2619 
setvelaccel(int w,int id,int neg)2620 void din::setvelaccel (int w, int id, int neg) {
2621 	if (num_selected_drones) {
2622     float xx[5], yy[5];
2623     int negs[2] = {1, -1};
2624     xx[0] = 0; xx[1] = 1;
2625     yy[0] = 1; yy[1] = 0;
2626     xx[4] = 0; yy[4] = 0;
2627 		for (int i = 0; i < num_selected_drones; ++i) {
2628       drone& ds = *selected_drones[i];
2629       xx[2]=ds.vx;
2630       yy[2]=ds.vy;
2631       xx[3]=ds.ax;
2632       yy[3]=ds.ay;
2633       float* wx[2] = {&ds.vx, &ds.ax};
2634       float* wy[2] = {&ds.vy, &ds.ay};
2635       float* aft [2] = {&ds.autorot.v.autoflip.total, &ds.autorot.a.autoflip.total};
2636       alarm_t* art [2] = {&ds.autorot.v.tik, &ds.autorot.a.tik};
2637       int negg = negs[neg];
2638       float xxx = negg * xx[id];
2639       float yyy = negg * yy[id];
2640       if (w == 2) {
2641         ds.vx = ds.ax = xxx;
2642         ds.vy = ds.ay = yyy;
2643         ds.autorot.v.autoflip.total = ds.autorot.a.autoflip.total = 0.0f;
2644         ds.autorot.v.tik.start ();
2645         ds.autorot.a.tik.start ();
2646       } else {
2647         *wx[w] = xxx;
2648         *wy[w] = yyy;
2649         *aft[w] = 0.0f;
2650         art[w]->start ();
2651       }
2652     }
2653   } else cons << RED_PSD << eol;
2654 }
2655 
setmoddir(int w,int id)2656 void din::setmoddir (int w, int id) {
2657 	if (num_selected_drones) {
2658     const char* dirs [] = {"Vertical", "Horizontal", "Velocity", "Acceleration"};
2659     const char* whats [] = {"AM", "FM"};
2660 		for (int i = 0; i < num_selected_drones; ++i) {
2661       drone& ds = *selected_drones[i];
2662       mod_params* modp [] = {&ds.mod.am, &ds.mod.fm};
2663       mod_params* modpw = modp[w];
2664       modpw->id = id;
2665       modpw->calcdir (ds);
2666     }
2667     cons << "Set " << whats[w] << " direction of " << num_selected_drones << " drones to " << dirs[id] << eol;
2668   } else cons << RED_PSD << eol;
2669 }
2670 
setautorot(int what,int state,int tog)2671 void din::setautorot (int what, int state, int tog) {
2672   if (what == menu::autorott::BOTH) {
2673     for (int i = 0; i < num_selected_drones; ++i) {
2674       drone& ds = *selected_drones[i];
2675       int amst [] = {state, !ds.autorot.v.yes};
2676       int fmst [] = {state, !ds.autorot.a.yes};
2677       ds.autorot.v.yes = amst[tog];
2678       ds.autorot.a.yes = fmst[tog];
2679     }
2680   } else {
2681     for (int i = 0; i < num_selected_drones; ++i) {
2682       drone& ds = *selected_drones[i];
2683       int& yes = ds.autorot.arr[what]->yes;
2684       int states[] = {state, !yes};
2685       yes = states[tog];
2686     }
2687   }
2688   TOGGLEMENU
2689 }
2690 
setautoflip(int what,int state,int tog)2691 void din::setautoflip (int what, int state, int tog) {
2692   if (num_selected_drones) {
2693     if (what == menu::autorott::BOTH) {
2694       for (int i = 0; i < num_selected_drones; ++i) {
2695         drone& ds = *selected_drones[i];
2696         int amst [] = {state, !ds.autorot.v.autoflip.yes};
2697         int fmst [] = {state, !ds.autorot.a.autoflip.yes};
2698         ds.autorot.v.autoflip.yes = amst[tog];
2699         ds.autorot.a.autoflip.yes = fmst[tog];
2700         ds.autorot.v.autoflip.total = 0.0f;
2701         ds.autorot.a.autoflip.total = 0.0f;
2702 
2703       }
2704     } else {
2705       for (int i = 0; i < num_selected_drones; ++i) {
2706         drone& ds = *selected_drones[i];
2707         autoflipt& af = ds.autorot.arr[what]->autoflip;
2708         af.total = 0.0f;
2709         int& yes = af.yes;
2710         int states[] = {state, !yes};
2711         yes = states[tog];
2712       }
2713     }
2714     TOGGLEMENU
2715   } else
2716     cons << RED_PSD << eol;
2717 }
2718 
2719 
setautorotparam(int which,int what)2720 void din::setautorotparam (int which, int what) {
2721   if (which == menu::autorott::BOTH) {
2722     for (int i = 0; i < num_selected_drones; ++i) {
2723       drone& ds = *selected_drones[i];
2724       autorotator &var = ds.autorot.v, &aar = ds.autorot.a;
2725       var.yes = aar.yes = 1;
2726       if (what == menu::autorott::RPM) {
2727         var.mov = aar.mov = autorotator::SMOOTH;
2728         var.set_rpm (ds.autorot.v.rpm + MENU.autorotate.rpm());
2729         aar.set_rpm (ds.autorot.a.rpm + MENU.autorotate.rpm());
2730         cons << "Drone : " << i << " Velocity RPM = " << var.rpm << " Acceleration RPM = " << aar.rpm << eol;
2731       } else if (what == menu::autorott::DEG) {
2732         var.mov = aar.mov = autorotator::TICK;
2733         var.chgdeg (MENU.autorotate.deg());
2734         aar.chgdeg (MENU.autorotate.deg());
2735         cons << "Drone : " << i << " Velocity Degrees / Second = " << var.deg << ", Acceleration Degrees / Second = " << aar.deg << eol;
2736       } else if (what == menu::autorott::TPS) {
2737         var.mov = aar.mov = autorotator::TICK;
2738         var.chgtps (MENU.autorotate.tps());
2739         aar.chgtps (MENU.autorotate.tps());
2740         cons << "Drone : " << i << " Velocity Ticks / Second = " << var.tps << ", Acceleration Ticks / Second = " << aar.tps << eol;
2741       } else {
2742         var.mov = aar.mov = MENU.autorotate.mov.id;
2743         if (MENU.autorotate.mov.id == autorotator::SMOOTH) {
2744           var.set_rpm (var.rpm);
2745           aar.set_rpm (aar.rpm);
2746         } else {
2747           var.settps (var.tps);
2748           var.setdeg (var.deg);
2749           aar.settps (aar.tps);
2750           aar.setdeg (aar.deg);
2751         }
2752       }
2753     }
2754   } else {
2755     const char* strs[2] = {" Velocity", " Acceleration"};
2756     for (int i = 0; i < num_selected_drones; ++i) {
2757       drone& ds = *selected_drones[i];
2758       autorotator& ar = *ds.autorot.arr[which];
2759       ar.yes = 1;
2760       if (what == menu::autorott::RPM) {
2761         ar.mov = autorotator::SMOOTH;
2762         ar.set_rpm (ar.rpm + MENU.autorotate.rpm());
2763         cons << "Drone : " << i << strs[which] << " RPM = " << ar.rpm << eol;
2764       } else if (what == menu::autorott::DEG) {
2765         ar.mov = autorotator::TICK;
2766         ar.chgdeg (MENU.autorotate.deg());
2767         cons << "Drone : " << i << strs[which] << " Degrees / Second = " << ar.deg << spc << ", Ticks / Second = " << ar.tps << eol;
2768       } else if (what == menu::autorott::TPS) {
2769         ar.mov = autorotator::TICK;
2770         ar.chgtps (MENU.autorotate.tps());
2771         cons << "Drone : " << i << strs[which] << " Degrees / Second = " << ar.deg << spc << ", Ticks / Second = " << ar.tps << eol;
2772       } else {
2773         ar.mov = MENU.autorotate.mov.id;
2774         if (MENU.autorotate.mov.id == autorotator::SMOOTH) {
2775           ar.set_rpm (ar.rpm);
2776         } else {
2777           ar.settps (ar.tps);
2778           ar.setdeg (ar.deg);
2779         }
2780       }
2781     }
2782   }
2783 }
2784 
setautorotdir(int what,int dir)2785 void din::setautorotdir (int what, int dir) {
2786   if (num_selected_drones) {
2787     if (what == menu::autorott::BOTH) {
2788 		  for (int i = 0; i < num_selected_drones; ++i) {
2789 			  drone& ds = *selected_drones[i];
2790         ds.autorot.v.dir = dir;
2791         ds.autorot.a.dir = dir;
2792       }
2793     } else {
2794       for (int i = 0; i < num_selected_drones; ++i) {
2795         drone& ds = *selected_drones[i];
2796         ds.autorot.arr[what]->dir = dir;
2797       }
2798     }
2799     TOGGLEMENU
2800   } else
2801     cons << RED_PSD << eol;
2802 }
2803 
2804 
setautoflipangle(int what)2805 void din::setautoflipangle (int what) {
2806   if (what == menu::autorott::BOTH) {
2807     for (int i = 0; i < num_selected_drones; ++i) {
2808       drone& ds = *selected_drones[i];
2809       autoflipt &amaf = ds.autorot.v.autoflip, &fmaf = ds.autorot.a.autoflip;
2810       amaf.total = fmaf.total = 0.0f;
2811       amaf.set (amaf.angle.deg + MENU.autorotate.autoflip.angle());
2812       fmaf.set (fmaf.angle.deg + MENU.autorotate.autoflip.angle());
2813       cons << "Drone : " << i << " Velocity Auto flip angle = " << amaf.angle.deg << " Acceleration Auto flip angle = " << fmaf.angle.deg << eol;
2814     }
2815   } else {
2816     const char* strs[2] = {" Velocity", " Acceleration"};
2817     for (int i = 0; i < num_selected_drones; ++i) {
2818       drone& ds = *selected_drones[i];
2819       autoflipt& af = ds.autorot.arr[what]->autoflip;
2820       af.total = 0.0f;
2821       af.set (af.angle.deg + MENU.autorotate.autoflip.angle());
2822       cons << "Drone : " << i << strs[what] << " Auto flip angle = " << af.angle.deg << eol;
2823     }
2824   }
2825 }
2826 
render_audio(float * out0,float * out1)2827 int din::render_audio (float* out0, float* out1) {
2828 
2829 	int ret = 0;
2830 
2831   ret = calc_am_fm_gater (); // compute voice AM & FM & gater over bpm
2832 
2833 	find_tone_and_volume ();
2834 	float *lout = out0, *rout = out1;
2835 
2836 	if (dinfo.voice_is_voice) {
2837 		wavplay.gen_wav_fm_am_mix (lout, aout.samples_per_channel);
2838 		ret += wavplay.mixer.active;
2839 	} else { // voice is noise
2840 		nsr (lout, rout, aout.samples_per_channel, 1.0f);
2841 		ret = 1;
2842 	}
2843 
2844   // gater on voice
2845   lout = out0;
2846   rout = out1;
2847   if (uis.fdr_gater.on) {
2848     memcpy (aout.result, lout, aout.samples_channel_size); // voice
2849     multiply (lout, aout.gatr, aout.samples_per_channel); // voice * gater
2850 		fill (aout.bufR, fdr_gater_prev_amount, uis.fdr_gater.amount, aout.samples_per_channel);
2851 		fdr_gater_prev_amount = uis.fdr_gater.amount;
2852 		tween (lout, aout.result, aout.samples_per_channel, aout.bufR); // voice > voice*gater
2853   } else {
2854     if (dinfo.gater) multiply (lout, aout.gatr, aout.samples_per_channel); // voice * gater
2855   }
2856   memcpy (rout, lout, aout.samples_channel_size); // copy left -> right
2857 
2858   // render drones
2859   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
2860     drone& di = *(*i);
2861     float* lout = out0, *rout = out1;
2862     if (di.update_pv) di.update_pitch_volume ();
2863 		if (di.is == drone::DRONE) {
2864 			play& dp = di.player;
2865 			dp.master (lout, rout, aout.result, aout.samples_per_channel, dp.pvol);
2866 			ret += dp.mixer.active;
2867 		} else {
2868 			di.nsr (lout, rout, aout.samples_per_channel, di.fdr.amount * di.gab.amount * drone::mastervolume);
2869 		}
2870   }
2871 
2872 	return ret;
2873 
2874 }
2875 
rise_drones()2876 void din::rise_drones () {
2877   if (rising) {
2878     for (drone_iterator i = risers.begin(), j = risers.end (); i != j;) {
2879 			drone* pdi = *i;
2880       drone& di = *pdi;
2881       di.fdr.eval ();
2882       if (di.fdr.reached) {
2883         di.state = drone::ACTIVE;
2884 				di.update_pv = drone::EMPLACE;
2885         i = risers.erase (i);
2886         j = risers.end ();
2887         --rising;
2888       } else {
2889         di.update_pv = drone::INTERPOLATE;
2890 				++i;
2891 			}
2892     }
2893   }
2894 }
2895 
fall_drones()2896 void din::fall_drones () {
2897   if (falling) {
2898     for (drone_iterator i = fallers.begin(), j = fallers.end (); i != j;) {
2899       drone* pdi = *i;
2900       drone& di = *pdi;
2901       if (!di.frozen) {
2902         di.fdr.eval ();
2903         if (di.fdr.reached) {
2904 
2905           i = fallers.erase (i);
2906           j = fallers.end ();
2907           --falling;
2908 
2909           if (pdi->reincarnate) {
2910             di.life = MENU.lifetime();
2911             di.state = drone::RISING;
2912             risers.push_back (pdi);
2913             ++rising;
2914             di.fdr.set (0.0f, 1.0f, 1, MENU.riset());
2915             di.birth = ui_clk ();
2916           } else {
2917             remove_attractee (pdi);
2918             remove_tracker (pdi);
2919             if (dinfo.gravity.tracked_drone == pdi) dinfo.gravity.tracked_drone = 0;
2920             if (di.launcher) erase (launchers, pdi);
2921             if (di.attractor) {
2922               erase (attractors, pdi);
2923               list<attractee>& lae = di.attractees;
2924               for (list<attractee>::iterator iter = lae.begin (), jter = lae.end(); iter != jter; ++iter) {
2925                 attractee& ae = *iter;
2926                 drone& de = *ae.d;
2927                 de.orbiting = 0;
2928               }
2929             }
2930             if (di.gravity) {
2931               erase (gravitated, pdi);
2932               erase (satellites, pdi);
2933             }
2934             remove_drone_from_targets (pdi);
2935             remove_drone_from_selection (pdi);
2936             remove_drone_from_pre_mesh (pdi);
2937             remove_drone_from_mesh (pdi);
2938 
2939             remove_connections (pdi);
2940 
2941             remove_from_groups (pdi);
2942 
2943             if (ec == pdi) ec = 0;
2944 
2945             gab.erase (pdi);
2946 
2947             --num_drones;
2948             print_num_drones ();
2949 
2950             if (num_drones == 0) prep_modulate (MODULATE_VOICE);
2951 
2952             if (pdi->chuck.yes) pdi->chuck.de ();
2953 
2954             erase (drones, pdi);
2955             delete pdi;
2956 
2957           }
2958 
2959         } else {
2960           ++i;
2961           di.update_pv = drone::INTERPOLATE;
2962         }
2963       }
2964       else
2965         ++i;
2966     }
2967   }
2968 }
2969 
2970 
height_changed(int r,int dh)2971 void din::height_changed (int r, int dh) {
2972 	if (r == -1) {
2973   	for (int i = 0; i < num_ranges; ++i) ranges[i].change_height (dh);
2974 		refresh_all_drones ();
2975 	} else {
2976 		ranges[r].change_height (dh);
2977 		refresh_drones (r);
2978 	}
2979 }
2980 
toggle_this(int & what,checkbutton & cb)2981 void din::toggle_this (int& what, checkbutton& cb) {
2982   what = !what;
2983   cb.set_state (what);
2984 }
2985 
switch_modulation()2986 void din::switch_modulation () { // switch modulation target
2987   static const char* swhat [] = {"Modulating drones", "Modulating voice"};
2988   modulate_what = !modulate_what;
2989 	prep_modulate (modulate_what);
2990   cons << YELLOW << swhat[modulate_what] << eol;
2991 }
2992 
prep_modulate(int op)2993 void din::prep_modulate (int op) {
2994   modulate_what = op;
2995 	delta_t* pdt [] = {&dam_delta, &am_delta};
2996 	p_am_delta = pdt [modulate_what];
2997 	MENU.init_modulation ();
2998 }
2999 
change__bpm(int type,beat2value & bv2,float amount)3000 void din::change__bpm (int type, beat2value& bv2, float amount) {
3001   if (modulate_what == MODULATE_DRONES)
3002     change_drone_bpm (type, amount);
3003   else
3004     change_bpm (bv2, amount);
3005 }
3006 
change__depth(int drone_arg1,float amount1,int voice_arg2,float amount2)3007 void din::change__depth (int drone_arg1, float amount1, int voice_arg2, float amount2) {
3008   if (modulate_what == MODULATE_DRONES)
3009     change_drone_depth (drone_arg1, amount1);
3010   else
3011     change_depth (voice_arg2, amount2);
3012 }
3013 
change_am_depth(float d)3014 void din::change_am_depth (float d) {
3015   change__depth (modulator::AM, d, 0, d);
3016 }
3017 
change_fm_depth(float d)3018 void din::change_fm_depth (float d) {
3019   change__depth (modulator::FM, d, 1, d);
3020 }
3021 
change_am_bpm(float d)3022 void din::change_am_bpm (float d) {
3023   change__bpm (modulator::AM, am, d);
3024 }
3025 
change_fm_bpm(float d)3026 void din::change_fm_bpm (float d) {
3027   change__bpm (modulator::FM, fm, d);
3028 }
3029 
change_drone_depth(int what,float delta)3030 void din::change_drone_depth (int what, float delta) {
3031 	if (num_selected_drones) {
3032 		for (int i = 0; i < num_selected_drones; ++i) {
3033 			drone& ds = *selected_drones[i];
3034 			ds.change_depth (i, what, delta);
3035 		}
3036 	} else cons << RED_PSD << eol;
3037 }
3038 
change_drone_bpm(int what,float delta)3039 void din::change_drone_bpm (int what, float delta) {
3040 	if (num_selected_drones) {
3041 		for (int i = 0; i < num_selected_drones; ++i) {
3042 			drone& ds = *selected_drones[i];
3043 			ds.change_bpm (i, what, delta);
3044 		}
3045 	} else cons << RED_PSD << eol;
3046 }
3047 
change_drone_depth(int what,spinner<float> & s)3048 void din::change_drone_depth (int what, spinner<float>& s) {
3049 	if (num_selected_drones) {
3050 		for (int i = 0; i < num_selected_drones; ++i) {
3051 			drone& ds = *selected_drones[i];
3052 			float dv = s ();
3053 			ds.change_depth (i, what, dv);
3054 		}
3055 	} else cons << RED_PSD << eol;
3056 }
3057 
change_drone_bpm(int what,spinner<float> & s)3058 void din::change_drone_bpm (int what, spinner<float>& s) {
3059 	if (num_selected_drones) {
3060 		for (int i = 0; i < num_selected_drones; ++i) {
3061 			drone& ds = *selected_drones[i];
3062 			float dv = s ();
3063 			ds.change_bpm (i, what, dv);
3064 		}
3065 	} else cons << RED_PSD << eol;
3066 }
3067 
toggle_adding_drones()3068 void din::toggle_adding_drones () {
3069   adding = !adding;
3070   if (adding) {
3071 		cons << GREEN << "Click to add drones. ESC to stop" << eol;
3072   } else {
3073 		cons << RED << "Stopped adding drones!" << eol;
3074 		uis.add (this, &mkb_selector);
3075   }
3076 }
3077 
start_moving_drones()3078 void din::start_moving_drones () {
3079   if (num_selected_drones) set_moving_drones (1); else cons << RED_PSD << eol;
3080 }
3081 
toggle_moving_drones()3082 void din::toggle_moving_drones () {
3083   if (moving_drones == 0) {
3084     start_moving_drones ();
3085   } else set_moving_drones (0);
3086 }
3087 
set_moving_drones(int md)3088 void din::set_moving_drones (int md) {
3089   moving_drones = md;
3090   if (moving_drones)
3091     cons << GREEN << "Just move mouse to move drones, ESC or Click to stop!" << eol;
3092   else
3093     cons << YELLOW << "@ " << name << eol;
3094 }
3095 
finish_phrase_recording()3096 int din::finish_phrase_recording () {
3097   if (phrasor0.state == phrasor::recording) {
3098     if (phrasor0.validate ()) {
3099       phrasor0.play ();
3100       cons << GREEN << "Phrasor has stopped recording and started playing!" << eol;
3101       return 1;
3102     }
3103   }
3104   return 0;
3105 }
3106 
do_phrase_recording()3107 void din::do_phrase_recording () {
3108   if (!finish_phrase_recording()) {
3109     phrasor0.clear ();
3110     phrasor0.state = phrasor::recording;
3111     cons << GREEN << "Phrasor is recording. Click or press f to finish!" << eol;
3112   }
3113 }
3114 
clear_all_phrases()3115 void din::clear_all_phrases () {
3116 	if (phrasor0.size != 0) {
3117 		phrasor0.clear ();
3118 		if (MENU.show == 0) find_current_range ();
3119 		MENU.s_phrase_position.set_val (0);
3120     wanding = 0;
3121 		cons << RED << "Phrase cleared!" << eol;
3122 	}
3123 }
3124 
3125 
set_key_to_pitch_at_cursor()3126 void din::set_key_to_pitch_at_cursor () {
3127 	float hz = step * SAMPLE_RATE;
3128 	set_tonic (this, hz);
3129 }
3130 
change_drone_accel(spinner<float> & s)3131 void din::change_drone_accel (spinner<float>& s) {
3132 	if (num_selected_drones) {
3133 		cons << YELLOW;
3134     int gt0 = MENU.accelgt0.state;
3135 		for (int i = 0; i < num_selected_drones; ++i) {
3136 			drone& di = *selected_drones[i];
3137 			di.A += s ();
3138       if (gt0) {if (di.A < 0.0f) di.A = 0.0f;}
3139 			cons << "Drone: " << i << ", Acceleration = " << di.A << eol;
3140 		}
3141 	} else cons << RED_PSD << eol;
3142 }
3143 
change_drone_vel(spinner<float> & s)3144 void din::change_drone_vel (spinner<float>& s) {
3145 	if (num_selected_drones) {
3146 		cons << YELLOW;
3147     int gt0 = MENU.velgt0.state;
3148 		for (int i = 0; i < num_selected_drones; ++i) {
3149 			drone& di = *selected_drones[i];
3150       di.V += s ();
3151       if (gt0) {if (di.V < 0.0f) di.V = 0.0f;}
3152 			cons << "Drone: " << i << ", Velocity = " << di.V << eol;
3153 		}
3154 	} else cons << RED_PSD << eol;
3155 }
3156 
rotate_drone_vel(spinner<float> & s)3157 void din::rotate_drone_vel (spinner<float>& s) {
3158 	if (num_selected_drones) {
3159 		cons << YELLOW;
3160 		for (int i = 0; i < num_selected_drones; ++i) {
3161 			drone& di = *selected_drones[i];
3162 			float deg = -s(), rad = deg * PI_BY_180;
3163 			rotate_vector (di.vx, di.vy, rad);
3164 			cons << "Drone: " << i << ", Rotated Velocity by " << deg << " degrees." << eol;
3165 		}
3166 	} else cons << RED_PSD << eol;
3167 }
3168 
calc_xform_vectors(vector<point<float>> & V,int n)3169 void din::calc_xform_vectors (vector<point <float> >& V, int n) {
3170 	V.resize (n);
3171 	for (int i = 0; i < n; ++i) {
3172 		drone& di = *selected_drones [i];
3173 		point<float>& vv = V[i];
3174     if (di.chuck.yes && di.chuck.sun) {
3175 		  direction<float> (vv.x, vv.y, di.chuck.sun->cx, di.chuck.sun->cy, di.cx, di.cy);
3176     } else
3177 		  direction<float> (vv.x, vv.y, dinfo.cen.x, dinfo.cen.y, di.cx, di.cy);
3178 	}
3179 }
3180 
calc_xform_vectors()3181 void din::calc_xform_vectors () {
3182   if (xforming == SCALE) calc_xform_vectors (svec, num_selected_drones); else
3183   if (xforming == ROTATE) calc_xform_vectors (rvec, num_selected_drones);
3184 }
3185 
resize_xform_vectors()3186 void din::resize_xform_vectors () {
3187 	if (xforming == SCALE) svec.resize (num_selected_drones); else rvec.resize (num_selected_drones);
3188 }
3189 
calc_drones_centroid()3190 void din::calc_drones_centroid () {
3191   startagain:
3192   if (num_selected_drones) {
3193     dinfo.cen.x = dinfo.cen.y = 0.0f;
3194     for (int i = 0; i < num_selected_drones; ++i) {
3195       drone& di = *selected_drones [i];
3196       dinfo.cen.x += di.cx; dinfo.cen.y += di.cy;
3197     }
3198     dinfo.cen.x /= num_selected_drones;
3199     dinfo.cen.y /= num_selected_drones;
3200   } else {
3201     select_all_drones ();
3202     if (num_selected_drones) goto startagain; else cons << RED_PSD << eol;
3203   }
3204 }
3205 
prep_scale_drones()3206 int din::prep_scale_drones () {
3207 	int n = num_selected_drones;
3208 	if (n) {
3209 		calc_xform_vectors (svec, n);
3210 		scl = 1.0f;
3211 		xforming = SCALE;
3212 		return n;
3213 	}
3214 	return 0;
3215 }
3216 
prep_rotate_drones()3217 int din::prep_rotate_drones () {
3218 	int n = num_selected_drones;
3219 	if (n) {
3220 		calc_xform_vectors (rvec, n);
3221 		angle = 0.0f;
3222 		xforming = ROTATE;
3223 		return n;
3224 	}
3225 	return 0;
3226 }
3227 
rotate_drones()3228 void din::rotate_drones () {
3229 	float dx, dy, cx, cy;
3230 	for (int i = 0; i < num_selected_drones; ++i) {
3231 		drone& di = *selected_drones[i];
3232 		point<float> rv = rvec[i];
3233     rotate_vector (rv.x, rv.y, angle);
3234     if (!di.chuck.yes) {
3235       cx = dinfo.cen.x;
3236       cy = dinfo.cen.y;
3237       dx = cx + rv.x;
3238       dy = cy + rv.y;
3239       di.set_center (dx, dy);
3240     } else cons << RED << "Wont rotate chucked drone!" << eol;
3241     /*if (di.chuck.yes && di.chuck.sun) {
3242       cx = di.chuck.sun->cx;
3243       cy = di.chuck.sun->cy;
3244       di.chuck.len = unit_vector (di.chuck.ux, di.chuck.uy, rv.x, rv.y);
3245       dx = cx + rv.x;
3246       dy = cy + rv.y;
3247       di.set_center (dx, dy);
3248       if (di.chuck.sat) di.chuck.sat->chuck.re (*di.chuck.sat);
3249     } else {
3250       cx = dinfo.cen.x;
3251       cy = dinfo.cen.y;
3252       dx = cx + rv.x;
3253       dy = cy + rv.y;
3254       di.set_center (dx, dy);
3255     }*/
3256 	}
3257 }
3258 
scale_drones()3259 void din::scale_drones () {
3260   list<drone*> rm;
3261   int nrm = 0;
3262 	for (int i = 0; i < num_selected_drones; ++i) {
3263     drone* pdi = selected_drones[i];
3264 		drone& di = *pdi;
3265     if (!di.chuck.yes) {
3266       point<float> sv = svec[i];
3267       sv *= scl;
3268       di.set_center (dinfo.cen.x + sv.x, dinfo.cen.y + sv.y, 0);
3269       if (di.nconn) {
3270         rm.push_back (pdi);
3271         for (drone_iterator p = di.connections.begin (), q = di.connections.end (); p != q; ++p) rm.push_back (*p);
3272         nrm = nrm + di.nconn + 1;
3273       }
3274     } else cons << RED << "Wont scale chucked drone!" << eol;
3275 	}
3276   if (nrm) for (drone_iterator p = rm.begin (), q = rm.end (); p != q; ++p) (*p)->remagconns ();
3277 }
3278 
scale_drones(float ds)3279 void din::scale_drones (float ds) {
3280 	if (CTRL) scl.x += ds;
3281 	else if (SHIFT) scl.y += ds;
3282 	else scl += ds;
3283 }
3284 
change_drones_per_min(spinner<float> & s)3285 void din::change_drones_per_min (spinner<float>& s) {
3286 	if (num_selected_drones) {
3287 		cons << YELLOW;
3288 		float dpm;
3289 		for (int i = 0; i < num_selected_drones; ++i) {
3290 			drone* pds = selected_drones[i];
3291 			drone& ds = *pds;
3292 			dpm = ds.dpm + s ();
3293 			if (dpm > 0.0f) {
3294 				ds.dpm = dpm;
3295 				ds.launch_every.triggert = 60.0 / ds.dpm;
3296 			}
3297 			cons << "Drone: " << i << ", drones per minute = " << ds.dpm << eol;
3298 		}
3299 	} else cons << RED_PSD << eol;
3300 }
3301 
select_attractees()3302 void din::select_attractees () { // select the attractees of the selected drones or all drones
3303 
3304 	if (num_selected_drones == 0) {
3305     if (num_drones) {
3306       select_all_drones ();
3307     } else {
3308       cons << RED << "No drones, so no attractees" << eol;
3309       return;
3310     }
3311 	}
3312 
3313 	vector<drone*> new_selected_drones;
3314 	for (int i = 0; i < num_selected_drones; ++i) {
3315     drone& di = *selected_drones[i];
3316 		if (di.attractor) {
3317 			list<attractee>& lae = di.attractees;
3318 			for (list<attractee>::iterator iter = lae.begin (), jter = lae.end(); iter != jter; ++iter) {
3319 				attractee& ae = *iter;
3320 				new_selected_drones.push_back (ae.d);
3321 			}
3322 		}
3323 	}
3324 
3325   int ns = new_selected_drones.size ();
3326   if (ns) {
3327 		CLEAR_SELECTED_DRONES
3328     for (int i = 0; i < ns; ++i) {
3329       drone* pd = new_selected_drones[i];
3330       add_drone_to_selection (pd);
3331     }
3332 	  print_selected_drones ();
3333   } else {
3334     cons << RED << "Sorry, no attractees found!" << eol;
3335   }
3336 
3337 }
3338 
select_attractors()3339 void din::select_attractors () { // select the attractors of selected drones
3340 	if (num_selected_drones) {
3341 		vector<drone*> selv (selected_drones);
3342 		int q = num_selected_drones;
3343 		CLEAR_SELECTED_DRONES
3344 		for (drone_iterator i = attractors.begin(), j = attractors.end(); i != j; ++i) {
3345 			drone* pdi = *i;
3346 			drone& di = *pdi;
3347 			list<attractee>& lae = di.attractees;
3348 			for (list<attractee>::iterator iter = lae.begin (), jter = lae.end(); iter != jter; ++iter) {
3349 				attractee& ae = *iter;
3350 				for (int p = 0; p < q; ++p) {
3351 					drone* sd = selv [p];
3352 					if (sd == ae.d) {
3353 						add_drone_to_selection (pdi);
3354 						goto next_attractor;
3355 					}
3356 				}
3357 			}
3358 			next_attractor:
3359 				;
3360 		}
3361 	} else {
3362 		for (drone_iterator i = attractors.begin(), j = attractors.end(); i != j; ++i) {
3363 			drone* pdi = *i;
3364 			pdi->sel = 1;
3365 			selected_drones.push_back (pdi);
3366 		}
3367 	}
3368 	print_selected_drones ();
3369 }
3370 
trail_drones()3371 void din::trail_drones () {
3372   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
3373     drone& di = *(*i);
3374 		di.trail.add (di.sx, di.y);
3375 	}
3376 }
3377 
toggle_create_this()3378 void din::toggle_create_this () {
3379 	if (dinfo.create_this) {
3380 		toggle_create_drone_pendulum ();
3381 	} else {
3382 		toggle_create_mesh ();
3383 	}
3384 }
3385 
toggle_create_drone_pendulum()3386 void din::toggle_create_drone_pendulum () {
3387 	if (create_drone_pend) ;
3388 	else {
3389 		cons << GREEN << "Click and drag a box to make a drone pendulum, ESC to cancel" << eol;
3390 		create_drone_pend = 1;
3391 	}
3392 }
3393 
toggle_create_mesh()3394 void din::toggle_create_mesh () {
3395 
3396 	if (amd.active) {
3397 		cons << RED << "Already making a mesh, please wait for it to finish :)" << eol;
3398 		return;
3399 	}
3400 
3401   if (meshh.create) {
3402 		create_drone_mesh ();
3403 		meshh.create = 0;
3404 	} else {
3405 		cons << GREEN << "Click and drag a box to preview drone mesh, ESC to cancel" << eol;
3406   	meshh.create = 1;
3407 	}
3408 
3409 }
3410 
stop_creating_mesh()3411 void din::stop_creating_mesh () {
3412 	meshh.create = 0;
3413 	mkb_selector.mesh = 0;
3414 	cons << RED << "Stopped creating mesh" << eol;
3415 }
3416 
stop_creating_drone_pendulum()3417 void din::stop_creating_drone_pendulum () {
3418 	create_drone_pend = 0;
3419 	cons << RED << "Stopped making drone pendulum" << eol;
3420 }
3421 
bg()3422 void din::bg () {
3423 
3424 	drone::proc_conn.clear ();
3425 	if (ec && !xforming) ec = ec->eval_conns ();
3426 
3427 	if (phrasor0.state == phrasor::playing) {
3428 		phrasor0.get (tonex, toney);
3429 		phrasor0.next ();
3430 	}
3431 
3432   if (wanding) {
3433     if ((wand.x != tonex) || (wand.y != toney)) {
3434       if (magnitude2 (wand.x, wand.y, tonex, toney) >= drone::wand.dist2) {
3435         wand.x = tonex;
3436         wand.y = toney;
3437 
3438         /*if (CTRL) {
3439           if (wand0.x == -1) {
3440             wand0.y = wand.y;
3441           }
3442           wand.y = wand0.y;
3443         } else if (ALT) {
3444           if (wand0.y == -1) {
3445             wand0.x = wand.x;
3446           }
3447           wand.x = wand0.x;
3448         }*/
3449 
3450         if (SHIFT)
3451           ;
3452         else
3453           add_drone (wand.x, wand.y);
3454       }
3455     }
3456   }
3457 
3458 	if (amd.active && !amd.drop && amd (ui_clk())) {
3459 		create_drone:
3460 		if (amd.i < mkb_selector.rowcol) {
3461 				amd.p = mkb_selector.order [amd.i];
3462 				int p = 2 * amd.p;
3463 				int x = mkb_selector.meshp [p];
3464 				int y = mkb_selector.meshp [p + 1];
3465 				drone* d = add_drone (x, y);
3466 				mkb_selector.meshd[amd.p] = d;
3467 				if (dinfo.mesh_vars.apply_to.active) {
3468 					float a = ((amd.i % dinfo.mesh_vars.dpp) + 1) * 1. / dinfo.mesh_vars.dpp;
3469 					float bpm = a * dinfo.drone_pend.bpm;
3470 					d->mod.active = 1;
3471 					if (dinfo.mesh_vars.apply_to.am) d->mod.am.bv.set_bpm (bpm);
3472 					if (dinfo.mesh_vars.apply_to.fm) d->mod.fm.bv.set_bpm (bpm);
3473 				}
3474         if (!dinfo.seloncre) {
3475           d->sel = 1;
3476           selected_drones.push_back (d);
3477         }
3478 				amd.i++;
3479 				if (amd.triggert == 0.0) goto create_drone;
3480 		} else {
3481 			// assign drones to polygons of the mesh
3482 			mesh a_mesh;
3483       a_mesh.r = rndr ();
3484       a_mesh.g = rndg ();
3485       a_mesh.b = rndb ();
3486 			for (int i = 0, j = mkb_selector.rows - 1; i < j; ++i) {
3487 				int ic = i * mkb_selector.cols;
3488 				for (int k = 0, l = mkb_selector.cols - 1; k < l; ++k) {
3489 					int d0i = ic + k, d1i = d0i + 1;
3490 					int d2i = d0i + mkb_selector.cols, d3i = d2i + 1;
3491 					drone* d0 = mkb_selector.get_mesh_drone(d0i), *d1 = mkb_selector.get_mesh_drone(d1i);
3492 					drone* d2 = mkb_selector.get_mesh_drone(d2i), *d3 = mkb_selector.get_mesh_drone(d3i);
3493 					a_mesh.add_poly (d0, d1, d3, d2); // each poly has 4 drones
3494 				}
3495 			}
3496 
3497 			meshes.push_back (a_mesh);
3498 			++meshh.num;
3499       if (!dinfo.seloncre) print_selected_drones ();
3500 			cons << GREEN << "Created a " << dinfo.rows << " x " << dinfo.cols << " drone mesh with " << mkb_selector.rowcol << " drones" << eol;
3501 			amd.reset ();
3502 			mkb_selector.clear ();
3503 		}
3504 	} else {
3505 		if (amd.drop) {
3506 			cons << RED << "Aborted drone mesh" << eol;
3507 			amd.reset ();
3508 		}
3509 	}
3510 
3511   fall_drones ();
3512 	rise_drones ();
3513 	if (quit == DONT) launch_drones ();
3514 	carry_satellites_to_orbit ();
3515 	attract_drones ();
3516   track_drones ();
3517   evalgravity ();
3518   evalchuck ();
3519   modulate_drones ();
3520   move_drones_under_gravity ();
3521 	trail_drones ();
3522 	kill_old_drones ();
3523 	modulate_ranges ();
3524   gab.eval ();
3525 
3526 }
3527 
drawchuck()3528 void din::drawchuck () {
3529   if (MENU.choutline.state) {
3530     for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
3531       drone& di = *(*i);
3532       drone* sat = di.chuck.sat;
3533       if (di.chuck.yes && sat) {
3534         glBegin (GL_LINES);
3535           glColor3f (di.r, di.g, di.b);
3536           glVertex2f (di.sx, di.y);
3537           glColor3f (sat->r, sat->g, sat->b);
3538           glVertex2f (sat->sx, sat->y);
3539         glEnd ();
3540       }
3541     }
3542   }
3543 }
3544 
evalchuck()3545 void din::evalchuck () {
3546 
3547   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
3548     drone& di = *(*i);
3549     if (di.chuck.yes) {
3550       di.chuck.cx = di.cx;
3551       di.chuck.cy = di.cy;
3552     }
3553   }
3554 
3555   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
3556     drone& di = *(*i);
3557     if (di.chuck.yes && di.chuck.sun) {
3558       if (di.frozen) {
3559         di.chuck.len = unit_vector (di.chuck.ux, di.chuck.uy, di.chuck.sun->chuck.cx, di.chuck.sun->chuck.cy, di.cx, di.cy);
3560       } else {
3561         rotate_vector (di.chuck.ux, di.chuck.uy, di.chuck.dir * di.chuck.speed * drone::chuckt::apt.rad);
3562         di.set_center (di.chuck.sun->chuck.cx + di.chuck.len * di.chuck.ux, di.chuck.sun->chuck.cy + di.chuck.len * di.chuck.uy);
3563       }
3564     }
3565   }
3566 
3567 }
3568 
changechuckspeed(spinner<float> & sp)3569 void din::changechuckspeed (spinner<float>& sp) {
3570 	if (num_selected_drones) {
3571     for (int i = 0; i < num_selected_drones; ++i) {
3572       drone& di = *selected_drones[i];
3573       if (di.chuck.yes) {
3574         float& speed = di.chuck.speed;
3575         speed += sp ();
3576         if (speed < 0.0f) speed = 0.0f;
3577         cons << YELLOW << "Drone " << i << ", speed = " << speed << eol;
3578         RESETCHUCKTRAILS(di)
3579       }
3580     }
3581   } else {
3582     cons << RED_PSD << eol;
3583   }
3584 }
3585 
changechucklength(spinner<float> & sp)3586 void din::changechucklength (spinner<float>& sp) {
3587 	if (num_selected_drones) {
3588     for (int i = 0; i < num_selected_drones; ++i) {
3589       drone& di = *selected_drones[i];
3590       if (di.chuck.yes) {
3591         float& len = di.chuck.len;
3592         len += sp ();
3593         if (len < 0.0f) len = 0.0f;
3594         RESETCHUCKTRAILS(di)
3595         cons << YELLOW << "Drone " << i << ", length = " << len << eol;
3596       }
3597     }
3598   } else {
3599     cons << RED_PSD << eol;
3600   }
3601 }
3602 
flipchuckspeed()3603 void din::flipchuckspeed () {
3604 	if (num_selected_drones) {
3605     for (int i = 0; i < num_selected_drones; ++i) {
3606       drone& di = *selected_drones[i];
3607       if (di.chuck.yes) di.chuck.dir = -di.chuck.dir;
3608       RESETCHUCKTRAILS(di)
3609     }
3610   } else {
3611     cons << RED_PSD << eol;
3612   }
3613 }
3614 
togchuckspeed()3615 void din::togchuckspeed () {
3616 	if (num_selected_drones) {
3617     for (int i = 0; i < num_selected_drones; ++i) {
3618       drone& di = *selected_drones[i];
3619       if (di.chuck.yes) swap (di.chuck.speed, di.chuck.speed0);
3620       RESETCHUCKTRAILS(di)
3621     }
3622   } else {
3623     cons << RED_PSD << eol;
3624   }
3625 }
3626 
resetchucktrails(drone & d)3627 void din::resetchucktrails (drone& d) {
3628   d.trail.reset ();
3629   if (d.chuck.sat) resetchucktrails (*d.chuck.sat);
3630 }
3631 
resetallchucktrails()3632 void din::resetallchucktrails () {
3633   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
3634     drone& di = *(*i);
3635     if (di.chuck.yes) di.trail.reset ();
3636   }
3637 }
3638 
update_drone_pendulum(drone_pendulum_group & g)3639 void din::update_drone_pendulum (drone_pendulum_group& g) {
3640 	float a = 0.0f, da = 1.0 / (g.n - 1);
3641 	for (int i = 0, j = g.n; i < j; ++i) {
3642 		drone* pd = g.drones[i];
3643 		drone& d = *pd;
3644 		mod_params* mods [] = {&d.mod.am, &d.mod.fm};
3645 		mod_params& mod = *mods[g.orient];
3646 		mod.depth = warp_depth (a) * float (uis.dpeu.depth.f_value);
3647 		mod.bv.set_bpm (warp_bpm (a)* float (uis.dpeu.bpm.f_value));
3648 		a += da;
3649 	}
3650 }
3651 
update_drone_pendulums()3652 void din::update_drone_pendulums () {
3653 	map<group*, bool> updated;
3654 	for (int i = 0, j = drone_pendulums.size (); i < j; ++i) {
3655 		drone_pendulum_group* g = drone_pendulums[i];
3656 		drone_pendulum_group& gr = *g;
3657 		for (int m = 0, n = num_selected_drones; m < n; ++m) {
3658 			drone* ds = selected_drones[m];
3659 			if ((updated[g] == false) && gr.member (ds)) {
3660 				updated[g] = true;
3661 				update_drone_pendulum (gr);
3662 			}
3663 		}
3664 	}
3665 }
3666 
remove_from_groups(drone * d)3667 void din::remove_from_groups (drone* d) {
3668 	for (vector<drone_pendulum_group*>::iterator i = drone_pendulums.begin (), j = drone_pendulums.end (); i < j;) {
3669 		drone_pendulum_group& gi = *(*i);
3670 		if (gi.remove (d)) {
3671 			if (gi.n == 0) {
3672 				i = drone_pendulums.erase (i);
3673 				j = drone_pendulums.end ();
3674 			} else ++i;
3675 		} else ++i;
3676 	}
3677 }
3678 
remove_drone_from_mesh(drone * pd)3679 void din::remove_drone_from_mesh (drone* pd) {
3680   if (meshh.num == 0) return;
3681   for (mesh_iterator i = meshes.begin (); i != meshes.end ();) {
3682     mesh& mi = *i;
3683     mi.remove_poly (pd);
3684     if (mi.num_polys == 0) {
3685       i = meshes.erase (i);
3686       --meshh.num;
3687     } else ++i;
3688   }
3689 }
3690 
remove_drone_from_pre_mesh(drone * d)3691 void din::remove_drone_from_pre_mesh (drone* d) {
3692 	if (erase (mkb_selector.meshd, d)) amd.drop = 1;
3693 }
3694 
get_drone(int id)3695 drone* din::get_drone (int id) { // get drone given its unique id
3696   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
3697     drone* pd = *i;
3698     if (pd->id == id) return pd;
3699   }
3700   return 0;
3701 }
3702 
load_selected_drones(ifstream & f)3703 void din::load_selected_drones (ifstream& f) {
3704 	string ignore;
3705 	int n;
3706 	f >> ignore >> n;
3707 	if (n) {
3708 		int did;
3709 		selected_drones.resize (n);
3710 		for (int m = 0; m < n; ++m) {
3711 			f >> did;
3712 			drone* sd = get_drone (did);
3713       sd->sel = 1;
3714       selected_drones[m] = sd;
3715 		}
3716 		print_selected_drones ();
3717 	}
3718 	num_selected_drones = n;
3719 }
3720 
save_selected_drones(ofstream & f)3721 void din::save_selected_drones (ofstream& f) {
3722 	f << "selected_drones " << num_selected_drones << spc;
3723 	if (num_selected_drones) {
3724 		for (int i = 0; i < num_selected_drones; ++i) {
3725 			drone* pd = selected_drones[i];
3726 			f << pd->id << spc;
3727 		}
3728 	}
3729 	f << endl;
3730 }
3731 
3732 
make_trackers()3733 void din::make_trackers () {
3734   if (num_selected_drones < 1) {
3735     cons << RED_A2D << eol;
3736 
3737     return;
3738   } else if (num_selected_drones == 1) { // toggle tracker
3739 		drone* pd = selected_drones[0];
3740 		if (pd->tracking) {
3741 			remove_tracker (pd);
3742 			cons << GREEN << "Selected drone no longer tracks another drone" << eol;
3743 			return;
3744 		}
3745 		cons << RED << "Drone is not tracking any other drone!" << eol;
3746 		return;
3747 	}
3748   int last = num_selected_drones - 1;
3749   drone* p_tracked_drone = selected_drones [last];
3750   int nl = 0;
3751   for (int i = 0; i < last; ++i) {
3752     drone* pdi = selected_drones [i];
3753     push_back (trackers, pdi);
3754     pdi->tracking = 1;
3755     pdi->tracked_drone = p_tracked_drone;
3756     ++nl;
3757   }
3758   if (nl) cons << GREEN << "Number of drones tracking another drone = " << nl << eol;
3759 }
3760 
track_drones()3761 void din::track_drones () {
3762 
3763   for (drone_iterator i = trackers.begin (), j = trackers.end (); i != j; ++i) {
3764     drone* pdi = *i;
3765     drone& di = *pdi;
3766     drone& td = *di.tracked_drone;
3767 		if (di.tracking == drone::POINT) {
3768 			unit_vector (di.vx, di.vy, di.x, di.y, td.x, td.y);
3769       di.ax = di.vy;
3770       di.ay = -di.vx;
3771 		} else { // USE
3772 			di.vx = td.vx;
3773 			di.vy = td.vy;
3774       di.ax = td.ax;
3775       di.ay = td.ay;
3776 		}
3777   }
3778 
3779 
3780 }
3781 
evalgravity()3782 void din::evalgravity () {
3783 
3784   gravity_t& grav = dinfo.gravity;
3785   grav.modulate ();
3786   if (grav.mouse.state) {
3787     if (delta_mousex || delta_mousey || grav.forcetrack) grav.track (mousex, mouseyy);
3788   } else {
3789     if (grav.dron.state) {
3790       if (grav.tracked_drone) {
3791         int dwx = grav.tracked_drone->sx, dwy = grav.tracked_drone->y; // in window space
3792         if (dwx != grav.ldwx || dwy != grav.ldwy) {
3793           float xr = (dwx - win.left) * win.width_1;
3794           float yr = (dwy - win.bottom) * win.height_1;
3795           int dvx = (int) (xr * view.xmax);
3796           int dvy = (int) (yr * view.ymax); // in view space
3797           grav.track (dvx, dvy);
3798           grav.ldwx = dwx;
3799           grav.ldwy = dwy;
3800         }
3801       } else {
3802         if (num_selected_drones) {
3803           grav.tracked_drone = selected_drones[0];
3804         }
3805       }
3806     } else {
3807       grav.tracked_drone = 0;
3808     }
3809   }
3810 }
3811 
select_tracked_drones()3812 void din::select_tracked_drones () {
3813 	CLEAR_SELECTED_DRONES
3814   for (drone_iterator i = trackers.begin (), j = trackers.end (); i != j; ++i) {
3815     drone* pdi = *i;
3816 		drone* ptd = pdi->tracked_drone;
3817 		if (ptd->sel == 0) {
3818 			ptd->sel = 1;
3819 			selected_drones.push_back (ptd);
3820 		}
3821   }
3822 	print_selected_drones ();
3823 }
3824 
remove_tracker(drone * ptd)3825 void din::remove_tracker (drone* ptd) {
3826   for (drone_iterator i = trackers.begin (), j = trackers.end (); i != j;) {
3827     drone* pdi = *i;
3828     drone& di = *pdi;
3829     if (pdi == ptd || di.tracked_drone == ptd) {
3830 			di.tracking = 0;
3831 			di.tracked_drone = 0;
3832 			i = trackers.erase (i);
3833 			j = trackers.end ();
3834 		} else ++i;
3835   }
3836 }
3837 
sync_drones()3838 void din::sync_drones () {
3839   for (int i = 0; i < num_selected_drones; ++i) {
3840     drone& ds = *selected_drones[i];
3841 		ds.player.x = ds.mod.am.bv.now = ds.mod.fm.bv.now = 0.0f;
3842   }
3843 }
3844 
toggle_freeze_drones()3845 void din::toggle_freeze_drones () {
3846 	if (num_selected_drones) {
3847 		int nf = 0, nt = 0;
3848 		for (int i = 0; i < num_selected_drones; ++i) {
3849 			drone& ds = *selected_drones[i];
3850 			if (ds.frozen) nt += ds.thaw (); else nf += ds.freeze ();
3851 		}
3852 		cons << GREEN << "Froze " << nf << " drones, Thawed " << nt << s_drones << eol;
3853 	}
3854 }
3855 
freeze_drones()3856 int din::freeze_drones () {
3857 	if (num_selected_drones) {
3858 		int nf = 0;
3859 		for (int i = 0; i < num_selected_drones; ++i) {
3860 			drone& ds = *selected_drones[i];
3861 			nf += ds.freeze ();
3862 		}
3863 		cons << GREEN << "Froze " << nf << s_drones << eol;
3864 		return nf;
3865 	} else cons << RED_PSD << eol;
3866 	return 0;
3867 }
3868 
thaw_drones()3869 int din::thaw_drones () {
3870 	if (num_selected_drones) {
3871 		int nt = 0;
3872 		for (int i = 0; i < num_selected_drones; ++i) {
3873 			drone& ds = *selected_drones[i];
3874 			if (ds.thaw ()) ++nt;
3875 		}
3876 		cons << GREEN << "Thawed " << nt << s_drones << eol;
3877 		return nt;
3878 	} else cons << RED_PSD << eol;
3879 	return 0;
3880 }
3881 
freeze_orbiters()3882 int din::freeze_orbiters () {
3883 	if (num_selected_drones) {
3884 		int nf = 0;
3885 		for (int i = 0; i < num_selected_drones; ++i) {
3886 			drone& ds = *selected_drones[i];
3887 			if (ds.orbiting) nf += ds.freeze ();
3888 		}
3889 		return nf;
3890 	}
3891 	return 0;
3892 }
3893 
thaw_orbiters()3894 int din::thaw_orbiters () {
3895 	xforming = NONE;
3896 	if (num_selected_drones) {
3897 		int nt = 0;
3898 		for (int i = 0; i < num_selected_drones; ++i) {
3899 			drone& ds = *selected_drones[i];
3900 			if (ds.orbiting) nt += ds.thaw ();
3901 		}
3902 		return nt;
3903 	}
3904 	return 0;
3905 }
3906 
lower_delta(float & d,float v,const string & mesg,float minn)3907 void din::lower_delta (float& d, float v, const string& mesg, float minn) {
3908 	d += v;
3909 	if (d < minn) d = minn;
3910 	cons << YELLOW << mesg << d << eol;
3911 }
3912 
raise_delta(float & d,float v,const string & mesg)3913 void din::raise_delta (float& d, float v, const string& mesg) {
3914 	d += v;
3915 	cons << YELLOW << mesg << d << eol;
3916 }
3917 
delta_t(float _depth,float _bpm)3918 din::delta_t::delta_t (float _depth, float _bpm) {
3919 	depth = _depth;
3920 	bpm = _bpm;
3921 	min_depth = 0.0f;
3922 }
3923 
region_begin()3924 void din::region_begin () {
3925 	rgn.left = rgn.right = win_mousex;
3926 	rgn.bottom = rgn.top = win_mousey;
3927 	if (meshh.create) mkb_selector.set_mesh (meshh.create, dinfo.rows, dinfo.cols);
3928 }
3929 
region_update()3930 const box<float>& din::region_update () {
3931 	rgn.right = win_mousex;
3932 	rgn.top = win_mousey;
3933 	if (mkb_selector.mesh) {
3934 		int s = SHIFT, c = CTRL, sc = s|c;
3935 		if (sc) { // equalise width/height
3936 			float w = rgn.right - rgn.left, h = rgn.top - rgn.bottom;
3937 			float aw = abs(w), ah = abs(h);
3938 			if (s) { // equalise to smaller of width, height
3939 				if (aw > ah) {
3940 					float dw = aw - ah;
3941 					int _ve = w < 0? 1:-1;
3942 					rgn.right += (_ve * dw);
3943 				} else {
3944 					float dh = ah - aw;
3945 					int _ve = h < 0? 1:-1;
3946 					rgn.top += (_ve * dh);
3947 				}
3948 			} else { // equalise to larger of width, height
3949 				if (aw > ah) {
3950 					float dw = aw - ah;
3951 					int _ve = h < 0? -1:1;
3952 					rgn.top += (_ve * dw);
3953 				} else {
3954 					float dh = ah - aw;
3955 					int _ve = w < 0? -1:1;
3956 					rgn.right += (_ve * dh);
3957 				}
3958 			}
3959 		}
3960 		mkb_selector.gen_mesh_pts (rgn);
3961 	}
3962 	return rgn;
3963 }
3964 
region_end()3965 void din::region_end () {
3966 	int swp = rgn.calc ();
3967 	if (meshh.create) {
3968 		if (swp) mkb_selector.gen_mesh_pts (rgn);
3969 		create_drone_mesh ();
3970 		meshh.create = 0;
3971 	} else if (create_drone_pend) {
3972 		create_drone_pendulum ();
3973 		create_drone_pend = 0;
3974 	}
3975 	else
3976 		find_selected_drones (rgn);
3977 }
3978 
region_abort()3979 void din::region_abort () {
3980 	if (meshh.create) stop_creating_mesh ();
3981 	if (create_drone_pend) stop_creating_drone_pendulum ();
3982 }
3983 
modulate_ranges()3984 void din::modulate_ranges () {
3985 	int nw, nw_2, center, nl, nr, dl, dr, z;
3986 	nw = nw_2 = center = nl = nr = dl = dr = z = 0;
3987 	for (int i = 0; i < num_ranges; ++i) {
3988 		range& ri = ranges[i];
3989 		if (ri.mod.active > 0) {
3990 			ri.mod.calc ();
3991 			// width modulation
3992 			nw = ri.mod.fm.initial + ri.mod.fm.result;
3993 			switch (ri.fixed) {
3994 				case range::LEFT:
3995 					dr = nw - ri.extents.width;
3996 					range_right_changed (i, dr, 0);
3997 					break;
3998 				case range::RIGHT:
3999 					dl = ri.extents.width - nw;
4000 					range_left_changed (i, dl, 0);
4001 					break;
4002 				default:
4003 					nw_2 = nw / 2;
4004 					center = (ri.extents.left + ri.extents.right) / 2;
4005 					nl = center - nw_2, nr = center + nw_2;
4006 					dl = nl - ri.extents.left;
4007 					dr = nr - ri.extents.right;
4008 					range_left_changed (i, dl, 0);
4009 					range_right_changed (i, dr, 0);
4010 					break;
4011 			}
4012 			// height modulation
4013 			int nh = ri.mod.am.initial + ri.mod.am.result;
4014 			if (nh < 1) nh = 1;
4015 			ri.extents.top = BOTTOM + nh;
4016 			ri.extents.calc ();
4017 
4018 			z = 1;
4019 		}
4020 	}
4021 	if (z) {
4022 		refresh_all_drones ();
4023 		find_visible_ranges ();
4024 	}
4025 }
4026 
set_ran_mod(int w)4027 void din::set_ran_mod (int w) {
4028 	for (int i = 0; i < num_ranges; ++i) {
4029 		range& ri = ranges[i];
4030 		ri.mod.active = w;
4031 	}
4032 	MENU.cb_mod_ran.set_state (ranges[dinfo.sel_range].mod.active, 0);
4033 }
4034 
pause_resume_ran_mod()4035 void din::pause_resume_ran_mod () {
4036 	for (int i = 0; i < num_ranges; ++i) {
4037 		range& ri = ranges[i];
4038 		ri.mod.active = -ri.mod.active;
4039 	}
4040 }
4041 
toggle_ran_mod()4042 void din::toggle_ran_mod () {
4043 	for (int i = 0; i < num_ranges; ++i) {
4044 		range& ri = ranges[i];
4045 		ri.mod.active = !ri.mod.active;
4046 	}
4047 	MENU.cb_mod_ran.set_state (ranges[dinfo.sel_range].mod.active, 0);
4048 }
4049 
update_drone_mod_solvers(int w,multi_curve & mx)4050 void din::update_drone_mod_solvers (int w, multi_curve& mx) {
4051 	if (w == modulator::AM) {
4052 		for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
4053 			modulator& dm = (*i)->mod;
4054 			dm.am.bv.sol.update ();
4055 		}
4056 	} else {
4057 		for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
4058 			modulator& dm = (*i)->mod;
4059 			dm.fm.bv.sol.update ();
4060 		}
4061 	}
4062 }
4063 
update_range_mod_solvers(int w,multi_curve & mx)4064 void din::update_range_mod_solvers (int w, multi_curve& mx) {
4065 	if (w == modulator::AM) {
4066 		for (int i = 0; i < num_ranges; ++i) {
4067 			modulator& rm = ranges[i].mod;
4068 			rm.am.bv.sol.update (); // am for width
4069 		}
4070 	} else {
4071 		for (int i = 0; i < num_ranges; ++i) {
4072 			modulator& rm = ranges[i].mod;
4073 			rm.fm.bv.sol.update (); // fm for height
4074 		}
4075 	}
4076 }
4077 
snap_drones(int v)4078 void din::snap_drones (int v) {
4079 	if (num_selected_drones) {
4080 		int nt[2] = {0};
4081 		static const char* what_str1 [] = {"Unsnapped ", "Snapped "};
4082 		if (v == -1) { // toggle
4083 			for (int i = 0; i < num_selected_drones; ++i) {
4084 				drone* pdi = selected_drones[i];
4085 				pdi->snap = !pdi->snap;
4086 				++nt[pdi->snap];
4087 			}
4088 			cons << "Snapped " << nt[1] << " drones, Unsnapped " << nt[0] << s_drones << eol;
4089 
4090 		} else { // set
4091 			for (int i = 0; i < num_selected_drones; ++i) {
4092 				drone* pdi = selected_drones[i];
4093 				pdi->snap = v;
4094 			}
4095 			cons << GREEN << what_str1[v] << num_selected_drones << " drones" << eol;
4096 		}
4097 
4098 	} else {
4099 		cons << RED_PSD << eol;
4100 	}
4101 }
4102 
pos_afx_vel(int v)4103 void din::pos_afx_vel (int v) {
4104 	int nm [2] = {0};
4105 	if (num_selected_drones) {
4106 		if (v == -1) { // toggle
4107 			for (int i = 0; i < num_selected_drones; ++i) {
4108 				drone* pdi = selected_drones[i];
4109 				pdi->posafxvel.yes = !pdi->posafxvel.yes;
4110 				++nm[pdi->posafxvel.yes];
4111 			}
4112 			cons << GREEN << "Position affects velocity for " << nm[1] << " drones, Unset for " << nm[0] << s_drones << eol;
4113 		} else { // set
4114 			for (int i = 0; i < num_selected_drones; ++i) {
4115 				drone* pdi = selected_drones[i];
4116 				pdi->posafxvel.yes = v;
4117 			}
4118 			static const char* strs[] = {"Unset", "Set"};
4119 			cons << GREEN << strs[v] << " Position affects velocity for " << num_selected_drones << s_drones << eol;
4120 
4121 		}
4122 	} else {
4123 		cons << RED_PSD << eol;
4124 	}
4125 }
4126 
select_all_browsed_drones(int bd)4127 void din::select_all_browsed_drones (int bd) {
4128 	selected_drones.resize (num_browsed_drones);
4129 	for (int i = 0; i < num_browsed_drones; ++i) {
4130 		drone* pdb = browsed_drones[i];
4131 		pdb->sel = 1;
4132 		selected_drones[i] = pdb;
4133 	}
4134 	print_selected_drones ();
4135 	browsed_drone = bd;
4136 	MENU.sp_browse_drone.set_value (browsed_drone);
4137 }
4138 
browse_drone(int db)4139 void din::browse_drone (int db) {
4140 	if (num_browsed_drones) {
4141 		clear_selected_drones ();
4142 		browsed_drone += db;
4143 		if (browsed_drone > last_browseable_drone) { // select all browsed drones
4144 			select_all_browsed_drones (-1);
4145 			return;
4146 		} else if (browsed_drone < 0) {
4147 			select_all_browsed_drones (num_browsed_drones);
4148 			return;
4149 		}
4150 		drone* pdb = browsed_drones [browsed_drone];
4151 		pdb->sel = 1;
4152 		num_selected_drones = 1;
4153 		selected_drones.resize (num_selected_drones);
4154 		selected_drones[0] = pdb;
4155     sprintf (BUFFER, "Browsed drone %d of %d", browsed_drone+1, num_browsed_drones);
4156     cons << GREEN << BUFFER;
4157       drone::chuckt& chuck = pdb->chuck;
4158       if (chuck.yes) chuck.print ();
4159     cons << eol;
4160     MENU.sp_browse_drone.set_value (browsed_drone);
4161 	} else {
4162 		cons << RED << "No drones to browse, make a new selection" << eol;
4163 	}
4164 }
4165 
browse_range(int dr)4166 void din::browse_range (int dr) {
4167 	dinfo.sel_range += dr;
4168 	clamp (0, dinfo.sel_range, last_range);
4169 	MENU.load_range (dinfo.sel_range);
4170 }
4171 
all_ranges_width_changed()4172 void din::all_ranges_width_changed () {
4173 	float a = 0.0f, da = 1.0f / last_range;
4174 	extern solver sol_ran_width;
4175 	int w = 0;
4176 	float s = 0.0f;
4177 	for (int i = 0; i < num_ranges; ++i) {
4178 		s = sol_ran_width (a);
4179 		w = s * WIDTH;
4180 		if (w < 1) w = 1;
4181 		set_range_width (i, w);
4182 		a += da;
4183 	}
4184 }
4185 
all_ranges_height_changed()4186 void din::all_ranges_height_changed () {
4187 	float a = 0.0f, da = 1.0f / last_range;
4188 	extern solver sol_ran_height;
4189 	int h = 0;
4190 	float s = 0.0f;
4191 	for (int i = 0; i < num_ranges; ++i) {
4192 		s = sol_ran_height (a);
4193 		h = s * HEIGHT;
4194 		if (h < 1) h = 1;
4195 		set_range_height (i, h);
4196 		a += da;
4197 	}
4198 }
4199 
draw_vol_dist()4200 void din::draw_vol_dist () {
4201 
4202   glEnable (GL_BLEND);
4203   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4204 
4205 	const float c = 1.0f, b = 0.9f;
4206 	float yb, yt;
4207 	int xl, xr;
4208 	float a, da;
4209 	float v, vc;
4210   for (int i = visl, j = visr + 1; i < j; ++i) {
4211     range& R = ranges[i];
4212 		const int dy = min (dinfo.dist.pix, R.extents.height);
4213 		yb = R.extents.bottom; yt = R.extents.top;
4214 		xl = R.extents.left; xr = R.extents.right;
4215 		a = 0.0f; da = dy * R.extents.height_1;
4216 		v = vc = 0.0f;
4217 		glBegin (GL_QUAD_STRIP);
4218 			while (yb < yt) {
4219 				v = warp_vol (a);
4220 				vc = v * c;
4221 				glColor4f (vc, 0, vc, b);
4222 				glVertex2f (xl, yb);
4223 				glVertex2f (xr, yb);
4224 				yb += dy;
4225 				a += da;
4226 			}
4227 			a = 1.0f;
4228 			v = warp_vol (a);
4229 			vc = v * c;
4230 			glColor4f (vc, 0, vc, b);
4231 			glVertex2f (xl, yt);
4232 			glVertex2f (xr, yt);
4233 		glEnd ();
4234 	}
4235   glDisable (GL_BLEND);
4236 }
4237 
draw_pitch_dist()4238 void din::draw_pitch_dist () {
4239 
4240   glEnable (GL_BLEND);
4241   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4242 
4243 	const float c = 1.0f, b = 0.5f;
4244 	float yb, yt;
4245 	int xl, xr;
4246 	float a, da;
4247 	float p, pc;
4248   for (int i = visl, j = visr + 1; i < j; ++i) {
4249     range& R = ranges[i];
4250 		const int dx = min (dinfo.dist.pix, R.extents.width);
4251 		yb = R.extents.bottom; yt = R.extents.top;
4252 		xl = R.extents.left; xr = R.extents.right;
4253 		a = 0.0f; da = dx * R.extents.width_1;
4254 		p = pc = 0.0f;
4255 		glBegin (GL_QUAD_STRIP);
4256 			while (xl < xr) {
4257 				p = warp_pitch (a);
4258 				pc = p * c;
4259 				glColor4f (0, pc, pc, b);
4260 				glVertex2f (xl, yb);
4261 				glVertex2f (xl, yt);
4262 				xl += dx;
4263 				a += da;
4264 			}
4265 			a = 1.0f;
4266 			p = warp_pitch (a);
4267 			pc = p * c;
4268 			glColor4f (0, pc, pc, b);
4269 			glVertex2f (xr, yb);
4270 			glVertex2f (xr, yt);
4271 		glEnd ();
4272 	}
4273 
4274   glDisable (GL_BLEND);
4275 }
4276 
noise_interpolator_changed()4277 void din::noise_interpolator_changed () {
4278   for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) {
4279     drone& di = *(*i);
4280 		di.nsr.warp (&noiser::interp);
4281 	}
4282 }
4283 
can_connect(drone * d1,drone * d2)4284 int din::can_connect (drone* d1, drone* d2) {
4285 	if (d1 == d2) return 0; // no self connection
4286 	if (d2->nconn)
4287 		for (drone_iterator p = d2->connections.begin (), q = d2->connections.end(); p != q; ++p)
4288 			if (d1 == *p) return 0; // already connected
4289 	return 1;
4290 }
4291 
calc_stepz(const string & fld)4292 void din::calc_stepz (const string& fld) {
4293 	nstepz = 0;
4294 	stepz.clear ();
4295 	int p;
4296 	map<int, bool> exists;
4297 	string str;
4298 	stringstream ss1 (fld);
4299 	while (ss1.eof() == 0) {
4300 		ss1 >> str;
4301 		stringstream ss2 (str);
4302 		ss2 >> p;
4303 		if (p > 0 && (exists[p] == false)) {
4304 			stepz.push_back (p);
4305 			++nstepz;
4306 			exists[p] = true;
4307 		}
4308 	}
4309 }
4310 
alloc_conns()4311 void din::alloc_conns () {
4312 	if (totcon > con_size) {
4313 		if (con_pts) delete[] con_pts;
4314 		if (con_clr) delete[] con_clr;
4315 		con_pts = new float [totcon * 2 * 2];
4316 		con_clr = new float [totcon * 2 * 3];
4317 		con_size = totcon;
4318 	}
4319 }
4320 
disconnect_drones()4321 int din::disconnect_drones () {
4322 	if (num_selected_drones) {
4323     if (MENU.trackcon.state == 0) {
4324 		  for (int i = 0; i < num_selected_drones; ++i) {
4325         drone* pd = selected_drones[i];
4326         remove_connections (pd);
4327         if (pd->tracking) {
4328           erase (trackers, pd);
4329           pd->tracking = 0;
4330           pd->tracked_drone = 0;
4331         }
4332       }
4333 
4334     } else {
4335 		  for (int i = 0; i < num_selected_drones; ++i) remove_connections (selected_drones[i]);
4336     }
4337 		return 1;
4338 	} else cons << RED_PSD << eol;
4339 	return 0;
4340 }
4341 
remove_connections(drone * pd)4342 void din::remove_connections (drone* pd) {
4343 
4344 	// remove connections to pd
4345 	for (drone_iterator i = drones.begin (), j = drones.end (); i != j; ++i) {
4346 		drone* pdi = *i;
4347 		drone& di = *pdi;
4348 		if (di.nconn && pdi != pd) {
4349 			list<double>::iterator mi = di.mags.begin ();
4350 			for (drone_iterator p = di.connections.begin (), q = di.connections.end(); p != q;) {
4351 				drone* pdp = *p;
4352 				if (pdp == pd) {
4353 					p = di.connections.erase (p);
4354 					q = di.connections.end ();
4355 					mi = di.mags.erase (mi);
4356 					--di.nconn;
4357 					--totcon;
4358 				} else {
4359 					++p;
4360 					++mi;
4361 				}
4362 			}
4363 		}
4364 	}
4365 
4366 	// remove connections from pd
4367 	if (pd->nconn) {
4368 		totcon -= pd->nconn;
4369 		pd->nconn = 0;
4370 		pd->connections.clear ();
4371 		pd->mags.clear ();
4372 	}
4373 
4374 	_2totcon = 2 * totcon;
4375 
4376 	/*for (vector<connect>::iterator i = conns.begin (), j = conns.end (); i != j;) {
4377 		connect& ci = *i;
4378 		if (ci.d1 == pd || ci.d2 == pd) {
4379 			i = conns.erase (i);
4380 			j = conns.end ();
4381 		} else
4382 		++i;
4383 	}*/
4384 
4385 }
4386 
4387 /*void din::dirty_connection (drone* d) {
4388 	for (int i = 0, j = conns.size (); i < j; ++i) {
4389 		connect& ci = conns[i];
4390 		if (ci.d1 == d || ci.d2 == d) ci.dirty = 1;
4391 	}
4392 }
4393 
4394 void din::dirty_connections () {
4395 	for (int i = 0; i < num_selected_drones; ++i) {
4396 		drone* pdi = selected_drones[i];
4397 		dirty_connection (pdi);
4398 	}
4399 }*/
4400 
draw_connections()4401 void din::draw_connections () {
4402 
4403 	if (totcon == 0) return;
4404 
4405 	int p = 0, q = 0;
4406 
4407 	map<drone*, bool> drawn;
4408 	for (drone_iterator i = drones.begin (), j = drones.end (); i != j; ++i) {
4409 		drone& di = *(*i);
4410 		if (di.nconn) {
4411 			for (drone_iterator s = di.connections.begin (), t = di.connections.end(); s != t; ++s) {
4412 				con_clr[q++] = di.r;
4413 				con_clr[q++] = di.g;
4414 				con_clr[q++] = di.b;
4415 				drone& dj = *(*s);
4416 				con_clr[q++] = dj.r;
4417 				con_clr[q++] = dj.g;
4418 				con_clr[q++] = dj.b;
4419 				con_pts[p++]=di.sx;
4420 				con_pts[p++]=di.y;
4421 				con_pts[p++]=dj.sx;
4422 				con_pts[p++]=dj.y;
4423 			}
4424 		}
4425 	}
4426 
4427 	glEnableClientState (GL_COLOR_ARRAY);
4428 	glColorPointer (3, GL_FLOAT, 0, con_clr);
4429 	glVertexPointer (2, GL_FLOAT, 0, con_pts);
4430 	glDrawArrays (GL_LINES, 0, _2totcon);
4431 	glDisableClientState (GL_COLOR_ARRAY);
4432 
4433 	//for (int i = 0, j = conns.size (); i < j; ++i) conns[i].draw ();
4434 
4435 }
4436 
reset_drone_arrows()4437 void din::reset_drone_arrows () {
4438 	if (num_selected_drones) {
4439 		for (int i = 0; i < num_selected_drones; ++i) {
4440 			drone& ds = *selected_drones[i];
4441 			ds.arrow.reset ();
4442 		}
4443 	} else cons << RED_PSD << eol;
4444 }
4445 
abort()4446 void din::gabber::abort () {
4447   for (drone_iterator i = drones.begin (), j = drones.end (); i != j; ++i) {
4448     drone& di = *(*i);
4449     di.tovol = di.gab.amount;
4450   }
4451   drones.clear ();
4452   n = 0;
4453   cons << RED << "Aborted " << what << eol;
4454 }
4455 
set(din * dd,float t,const string & w,float tdiv,int fid)4456 void din::gabber::set (din* dd, float t, const string& w, float tdiv, int fid) {
4457   int ns = dd->num_selected_drones;
4458 	if (ns) {
4459     if (n) abort ();
4460 		for (int i = 0; i < ns; ++i) {
4461       drone* pds = dd->selected_drones[i];
4462 			drone& ds = *pds;
4463       if (!equals (ds.gab.amount, t)) {
4464         ds.gab.set (ds.gab.amount, t * ds.tovol, 1, max (0.0f, MENU.gabt()) / tdiv);
4465         ds.finl = drone::fins[fid];
4466         drones.push_back (pds);
4467         ++n;
4468       }
4469     }
4470     if (n) {
4471       what = w;
4472       cons << YELLOW << "Started " << what << spc << n << TOGO << eol;
4473     }
4474   } else {
4475     cons << RED_PSD << eol;
4476   }
4477 }
4478 
eval()4479 void din::gabber::eval () {
4480   if (n) {
4481     for (drone_iterator i = drones.begin (), j = drones.end (); i != j;) {
4482       drone* pdi = *i;
4483       drone& di = *pdi;
4484       di.update_pv = drone::INTERPOLATE;
4485       if (di.gab.eval () == 0) {
4486         di.tovol = di.gab.start;
4487         i = drones.erase (i);
4488         j = drones.end ();
4489         if (di.finl) di.finl->finished (din0, pdi);
4490         if (--n == 0) cons << GREEN << "Finished " << what << eol; else cons << YELLOW << what << spc << n << TOGO << eol;
4491       } else {
4492         ++i;
4493       }
4494     }
4495   }
4496 }
4497 
erase(drone * d)4498 void din::gabber::erase (drone* d) {
4499   if (::erase (drones, d)) --n;
4500 }
4501 
setgabt()4502 void din::gabber::setgabt () {
4503   if (n)
4504     for (drone_iterator i = drones.begin (), j = drones.end (); i != j; ++i)
4505       (*i)->gab.delta_time = MENU.gabt();
4506 }
4507 
setdronevol(spinner<float> & s)4508 void din::setdronevol (spinner<float>& s) {
4509   if (num_selected_drones) {
4510     for (int i = 0; i < num_selected_drones; ++i) {
4511       drone& ds = *selected_drones[i];
4512       ds.gab.amount += s();
4513       ds.tovol = ds.gab.amount;
4514       ds.update_pv = drone::EMPLACE;
4515       cons << "Drone " << i << " volume = " << ds.gab.amount << eol;
4516     }
4517   }
4518 }
4519 
drone2noise()4520 void din::drone2noise () {
4521   gab.set (this, 0.0f, "Drone > Noise", 2.0f, 1);
4522 }
4523 
noise2drone()4524 void din::noise2drone () {
4525   gab.set (this, 0.0f, "Noise > Drone", 2.0f, 2);
4526 }
4527 
finished(din & mkb,drone * pdi)4528 void drone::drone2noise::finished (din& mkb, drone* pdi) {
4529   drone& di = *pdi;
4530   di.is = drone::NOISE;
4531   di.setnoise ();
4532   di.r = di.g = di.b = 1.0f;
4533   di.gab.set (di.gab.amount, 1.0f * di.tovol, 1, MENU.gabt() / 2.0f);
4534   di.finl = 0;
4535   mkb.gab.drones.push_back (pdi);
4536   ++mkb.gab.n;
4537 }
4538 
finished(din & mkb,drone * pdi)4539 void drone::noise2drone::finished (din& mkb, drone* pdi) {
4540   drone& di = *pdi;
4541   di.is = drone::DRONE;
4542   di.setcolor ();
4543   di.gab.set (di.gab.amount, 1.0f * di.tovol, 1, MENU.gabt() / 2.0f);
4544   di.finl = 0;
4545   mkb.gab.drones.push_back (pdi);
4546   ++mkb.gab.n;
4547 }
4548 
4549 
set_random_color()4550 void din::set_random_color () {
4551   rndr.set (MENU.s_red_min (), MENU.s_red_max());
4552   rndg.set (MENU.s_green_min (), MENU.s_green_max());
4553   rndb.set (MENU.s_blue_min (), MENU.s_blue_max());
4554 }
4555 
gotpoint()4556 void din::gotpoint () {
4557   dinfo.cen.x = win_mousex;
4558   dinfo.cen.y = win_mousey;
4559 }
4560 
ranchkdro()4561 void din::ranchkdro () {
4562   for (drone_iterator i = drones.begin (), j = drones.end (); i != j; ++i) {
4563     drone& di = *(*i);
4564     clamp (0, di.range, last_range);
4565   }
4566 }
4567 
delselran()4568 void din::delselran () {
4569   // delete selected range
4570   if (num_ranges == 1) {
4571     cons << RED << "Will not delete the only range!" << eol;
4572     return;
4573   }
4574 
4575   int& sr = dinfo.sel_range;
4576   vector<range>::iterator rb = ranges.begin();
4577   if (sr == 0 || sr == last_range)
4578     ;
4579   else {
4580     int p = sr - 1, q = sr + 1;
4581     range& rp = ranges[p];
4582     range& rq = ranges[q];
4583     range& rs = ranges[sr];
4584     rp.notes[1] = rq.notes[0];
4585     rp.intervals[1] = rq.intervals[0];
4586     for (int i = sr + 1; i < num_ranges; ++i) {
4587       range& ri = ranges[i];
4588       ri.extents.move (-rs.extents.width, 0);
4589     }
4590   }
4591 
4592   ranges.erase (rb + sr);
4593 
4594   initranpar (num_ranges - 1);
4595   ranchkdro ();
4596   refresh_all_drones ();
4597   find_current_range ();
4598 
4599 }
4600 
initranpar(int n)4601 void din::initranpar (int n) {
4602 	num_ranges = n;
4603 	last_range = num_ranges - 1;
4604 	firstr = &ranges [0];
4605 	lastr = &ranges [last_range];
4606 	clamp<int> (0, dinfo.sel_range, last_range);
4607 	MENU.sp_range.set_limits (0, last_range);
4608 }
4609 
4610 
mkb_selector_t()4611 mkb_selector_t::mkb_selector_t () : of_prox_far (proximity_orderer::FARTHEST) {
4612 	orderers[0]=&of_asc;
4613 	orderers[1]=&of_desc;
4614 	orderers[2]=&of_asc_cols;
4615 	orderers[3]=&of_desc_cols;
4616 	orderers[4]=&of_rnd;
4617 	orderers[5]=&of_prox_near;
4618 	orderers[6]=&of_prox_far;
4619 }
4620 
draw(const box<float> & region)4621 void mkb_selector_t::draw (const box<float>& region) {
4622   if (din0.dinfo.cen.op) din0.dinfo.cen.draw ();
4623   else {
4624     if (mesh) {
4625       glPointSize (4);
4626       glVertexPointer (2, GL_FLOAT, 0, meshp);
4627       glColor3f (1, 1, 1);
4628       glDrawArrays (GL_POINTS, 0, rowcol);
4629       glPointSize (1);
4630     }
4631     cross = din0.create_drone_pend | din0.meshh.create;
4632     box_selector::draw (region);
4633   }
4634 }
4635 
handle_input()4636 int mkb_selector_t::handle_input () {
4637   if (lmb) {
4638     if (lmb_clicked == 0) {
4639       if (din0.wanding || din0.moving_drones) { // || din0.phrasor0.state) {
4640         lmb_clicked = 1;
4641         return 1;
4642       }
4643     } else
4644       return 1;
4645   } else {
4646     if (lmb_clicked) {
4647       lmb_clicked = 0;
4648       if (din0.moving_drones) din0.set_moving_drones (0);
4649       din0.stopwanding ();
4650       if (din0.phrasor0.state == phrasor::recording) din0.finish_phrase_recording ();
4651       return 1;
4652     }
4653   }
4654   int r = din0.dinfo.cen.handle_input();
4655   if (!r) return box_selector::handle_input (); else return r;
4656 }
4657 
setcolor()4658 void drone::setcolor () {
4659   if (is == drone::NOISE)
4660     r = g = b = 1;
4661   else {
4662     color& gc = MENU.colorer ();
4663     r = gc.r;
4664     g = gc.g;
4665     b = gc.b;
4666   }
4667 }
4668 
stopwanding()4669 int din::stopwanding () {
4670   if (wanding) {// && (phrasor0.state != phrasor::playing)) {
4671     wanding = 0;
4672     cons << RED << "Stopped wanding drones!" << eol;
4673     return 1;
4674   }
4675   return 0;
4676 }
4677 
4678 /*void din::eval_conns () {
4679 	for (drone_iterator i = drones.begin (), j = drones.end (); i != j; ++i) {
4680 		drone& di = *(*i);
4681 		if (di.conn) {
4682 			list<double>::iterator mi = di.mags.begin ();
4683 			for (drone_iterator s = di.connections.begin (), t = di.connections.end(); s != t; ++s) {
4684 				drone& dc = *(*s);
4685 				double now = magnitude (dc.cx, dc.cy, di.cx, di.cy);
4686 				double org = *mi;
4687 				if (equals (now, org))
4688 					;
4689 				else if (now > org) {
4690 					double lead = 0.01 * (now - org);
4691 					float ux, uy; unit_vector<float, int> (ux, uy, dc.cx, dc.cy, di.cx, di.cy);
4692 					dc.set_center (dc.cx + float (lead * ux), dc.cy + float(lead * uy), &di);
4693 				}
4694 			}
4695 		}
4696 	}
4697 }*/
4698 
4699 /*void din::butt_drones () {
4700 	if ((win_mousex == prev_win_mousex) && (win_mousey == prev_win_mousey)) return;
4701 	double mag;
4702 	float ux, uy;
4703 	for (int i = 0; i < num_selected_drones; ++i) {
4704 		drone& di = *selected_drones[i];
4705 		mag = unit_vector<float, int> (ux, uy, win_mousex, win_mousey, di.cx, di.cy);
4706 		if (mag < butt) {
4707 			double lead = drone::STIFFNESS * (butt - mag);
4708 			float nx = di.cx + lead * ux, ny = di.cy + lead * uy;
4709 			if (magnitude (nx, ny, ring.x, ring.y) < ring.r) {
4710 				di.set_center (nx, ny);
4711 				for (int j = 0; j < num_selected_drones; ++j) {
4712 					if (i != j) {
4713 						drone& dj = *selected_drones[j];
4714 						mag = unit_vector<float, int> (ux, uy, dj.cx, dj.cy, di.cx, di.cy);
4715 						if (mag < inter_butt) {
4716 							double lead = drone::STIFFNESS * (inter_butt - mag);
4717 							float nx = di.cx + lead * ux, ny = di.cy + lead * uy;
4718 							if (magnitude (nx, ny, ring.x, ring.y) < ring.r) {
4719 								di.set_center (nx, ny);
4720 							}
4721 						}
4722 					}
4723 				}
4724 			}
4725 		}
4726 	}
4727 }*/
4728 
4729 
4730 /*void din::orbit_reciprocal () { // attach selected drones to attractor
4731   int n = selected_drones.size ();
4732 	if (n) {
4733 		for (int i = 0, j = 1; i < n; ++i) {
4734 			drone* di = selected_drones[i];
4735 			drone* dj = selected_drones[j];
4736 			list<attractee>& lae = dj->attractees;
4737 			if (!di->orbiting) {
4738 				push_back (attractors, dj);
4739 				attractee ae (di->id, di);
4740 				if (push_back (lae, ae)) {
4741 					(*dj).attractor++;
4742 					di->orbiting = 1;
4743 				}
4744 			}
4745 			if (++j == n) j = 0;
4746 		}
4747 	} else cons << RED << "Please select at least 2 drones!" << eol;
4748 }*/
4749 
4750 
4751 	/*if (butting) {
4752 		float r [] = {ring.r, butt, inter_butt};
4753 		float cx [] = {ring.x, win_mousex, win_mousex};
4754 		float cy [] = {ring.y, win_mousey, win_mousey};
4755 
4756 		glColor3f (0.25f, 0.25f, 0.25f);
4757 		extern const float TWO_PI;
4758 		int npts = 33;
4759 		for (int p = 0; p < 3; ++p) {
4760 			float R = r[p];
4761 			float a = 0, da = TWO_PI / (npts - 1);
4762 			glBegin (GL_LINE_LOOP);
4763 			for (int i = 0; i < npts; ++i, a += da) {
4764 				glVertex2f (cx[p] + R * cos(a), cy[p] + R * sin (a));
4765 			}
4766 			glEnd ();
4767 		}
4768 	}*/
4769