/* * din.cc * DIN Is Noise is copyright (c) 2006-2021 Jagannathan Sampath * DIN Is Noise is released under GNU Public License 2.0 * For more information, please visit https://dinisnoise.org/ */ #include "main.h" #include "din.h" #include "console.h" #include "solver.h" #include "container.h" #include "utils.h" #include "input.h" #include "color.h" #include "random.h" #include "command.h" #include "delay.h" #include "chrono.h" #include "delay.h" #include "tcl_interp.h" #include "font.h" #include "scale_info.h" #include "ui_list.h" #include "vector2d.h" #include "keyboard_keyboard.h" #include "defvelaccel.h" #include "log.h" #include #include #define ENDER -1 extern string user_data_dir; // user data directory extern console cons; // console extern viewport view; // viewport extern int mousex, mousey, mouseyy; // mouse pos extern int lmb, rmb, mmb; // mouse button state extern int LEFT, BOTTOM, RIGHT, TOP; // microtonal keyboard extents extern int HEIGHT; // default number of volumes on the microtonal keyboard extern int WIDTH; // default number of microtones in a range extern int NUM_OCTAVES; // number of octaves the board spans extern map NOTE_POS; // interval name -> value, 1 - 1, 1# - 2, 2 - 3 etc extern int SAMPLE_RATE; // sampling rate extern map INTERVALS; // interval name -> value extern audio_out aout; // audio output extern tcl_interp interpreter; // integrated tcl interpreter extern int TRAILSIZE; // drone trail size (== number of trail points) extern audio_clock clk; // audio clock extern din din0; // microtonal-keyboard extern float VOLUME; // volume of voice on microtonal-keyboard extern curve_library wav_lib; // waveform library extern float FRAME_TIME; // time per frame in seconds extern int quit; // user wants to quit? extern int line_height; // of text extern keyboard_keyboard keybd2; // keyboard-keyboard extern int IPS; // inputs per second extern beat2value octave_shift; // octave shift over bpm extern const float PI_BY_180; extern const float PI; extern mouse_slider mouse_slider0; extern const char* s_drones; extern float VOICE_VOLUME; typedef std::list::iterator mesh_iterator; // din::din () in eval.cc void din::setup () { droneed.add (&drone_wave, &dronelis); droneed.attach_library (&wav_lib); wavsol (&wave); wavplay.set_wave (&wavsol); waved.add (&wave, &wavlis); waved.attach_library (&wav_lib); gatr.setup (); gated.attach_library (&gatlib); gated.add (gatr.crv, &gatrlis); gated.bv.push_back (&gatr); am_depth = 0; fm_depth = 0; fm.setup (); am.setup (); moded.add (fm.crv, &fmlis); moded.add (am.crv, &amlis); moded.bv.push_back (&fm); moded.bv.push_back (&am); fmlis.set (&fm); amlis.set (&am); gatrlis.set (&gatr); dinfo.gravity.calc (); } void din::scale_loaded () { int load_drones_too = 1, load_ranges_too = 1; load_scale (load_drones_too, load_ranges_too); } void din::scale_changed () { reset_all_ranges (); } void din::load_scale (int _load_drones_, int _load_ranges_) { setup_ranges (NUM_OCTAVES, _load_ranges_); if (_load_drones_) load_drones (); refresh_all_drones (); } int din::load_ranges () { string fname = user_data_dir + scaleinfo.name + ".ranges"; dlog << "<< loading ranges from: " << fname; ifstream file (fname.c_str(), ios::in); if (!file) { dlog << "!!! couldnt load range pos from " << fname << ", will use defaults +++" << endl; return 0; } string ignore; file >> ignore >> NUM_OCTAVES; int n; file >> ignore >> n; create_ranges (n); int l = LEFT, r, w, h; for (int i = 0; i < num_ranges; ++i) { range& R = ranges[i]; file >> w >> h; r = l + w; R.extents (l, BOTTOM, r, BOTTOM + h); l = r; file >> R.mod.active >> R.fixed >> R.mod.am.depth >> R.mod.am.bv.bpm >> R.mod.am.bv.now >> R.mod.am.bv.bps >> R.mod.am.initial >> R.mod.fm.depth >> R.mod.fm.bv.bpm >> R.mod.fm.bv.now >> R.mod.fm.bv.bps >> R.mod.fm.initial; R.notes[0].load (file) >> R.intervals[0]; R.notes[1].load (file) >> R.intervals[1]; R.fixed = range::CENTER; } dlog << ", done >>>" << endl; return 1; } void din::save_ranges () { string fname = user_data_dir + scaleinfo.name + ".ranges"; ofstream file (fname.c_str(), ios::out); if (file) { file << "num_octaves " << NUM_OCTAVES << endl; file << "num_ranges " << num_ranges << endl; for (int i = 0; i < num_ranges; ++i) { range& r = ranges[i]; file << r.extents.width << spc << r.extents.height << spc << r.mod.active << spc << r.fixed << spc << 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 << 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; r.notes[0].save (file) << r.intervals[0] << spc; r.notes[1].save (file) << r.intervals[1] << spc; } dlog << "+++ saved ranges in " << fname << " +++" << endl; } } void din::create_ranges (int n) { ranges.resize (n); initranpar (n); } void din::setup_ranges (int last_num_octaves, int load) { if (load) { load_ranges (); } else { int last_num_ranges = num_ranges; create_ranges (NUM_OCTAVES * scaleinfo.num_ranges); set_range_width (last_num_ranges, last_range, WIDTH); set_range_height (last_num_ranges, last_range, HEIGHT); init_range_mod (last_num_ranges, last_range); if (last_num_octaves < NUM_OCTAVES) calc_added_range_notes (last_num_octaves, last_num_ranges); } find_current_range (); } void din::reset_all_ranges () { create_ranges (NUM_OCTAVES * scaleinfo.num_ranges); set_range_width (0, last_range, WIDTH); set_range_height (0, last_range, HEIGHT); init_range_mod (0, last_range); calc_added_range_notes (0, 0); refresh_all_drones (); } void din::calc_added_range_notes (int p, int r) { int rn = r; for (; p < NUM_OCTAVES; ++p) { for (int i = 0, j = 1; i < scaleinfo.num_ranges; ++i, ++j) { range& R = ranges[r++]; note& n0 = R.notes[0]; note& n1 = R.notes[1]; n0.scale_pos = i; n1.scale_pos = j; n0.octave = n1.octave = p; string& i0 = R.intervals[0]; string& i1 = R.intervals[1]; i0 = scaleinfo.notes[i]; i1 = scaleinfo.notes[j]; R.calc (scaleinfo); n0.set_name (i0, scaleinfo.western); n1.set_name (i1, scaleinfo.western); } } if (rn) { range &R1 = ranges[rn-1], &R = ranges[rn]; // last note of existing ranges should be = to first note of first new range if (!equals (R.notes[0].hz, R1.notes[1].hz)) { R.notes[0]=R1.notes[1]; R.intervals[0]=R1.intervals[1]; R.delta_step = R.notes[1].step - R.notes[0].step; } } } void din::init_range_mod (int s, int t) { for (int i = s; i <= t; ++i) ranges[i].init_mod (); } void din::set_range_width (int ran, int sz) { range& R = ranges[ran]; int delta = sz - R.extents.width; R.extents (R.extents.left, R.extents.bottom, R.extents.left + sz, R.extents.top); R.mod.fm.initial = R.extents.width; R.mod.fm.bv.now = 0; for (int i = ran + 1; i < num_ranges; ++i) { range& Ri = ranges[i]; Ri.extents (Ri.extents.left + delta, Ri.extents.bottom, Ri.extents.right + delta, Ri.extents.top); } refresh_drones (ran, last_range); find_visible_ranges (); } void din::set_range_width (int s, int t, int sz) { int r, l; if (s < 1) r = LEFT; else r = ranges[s-1].extents.right; for (int i = s; i <= t; ++i) { l = r; r = l + sz; range& R = ranges[i]; R.extents (l, R.extents.bottom, r, R.extents.top); R.mod.fm.initial = R.extents.width; R.mod.fm.bv.now = 0; } refresh_drones (s, t); find_visible_ranges (); } void din::set_range_height (int s, int t, int h) { for (int i = s; i <= t; ++i) { range& R = ranges[i]; R.extents (R.extents.left, BOTTOM, R.extents.right, BOTTOM+h); R.mod.am.initial = h; R.mod.am.bv.now = 0; } refresh_drones (s, t); } void din::set_range_height (int r, int h) { range& R = ranges[r]; R.extents (R.extents.left, BOTTOM, R.extents.right, BOTTOM + h); R.mod.am.initial = h; R.mod.am.bv.now = 0; refresh_drones (r); } void din::default_range_to_all (int h) { extern multi_curve ran_width_crv, ran_height_crv; if (h) { set_range_height (0, last_range, HEIGHT); ran_height_crv.load ("range-height.crv.default"); } else { set_range_width (0, last_range, WIDTH); ran_width_crv.load ("range-width.crv.default"); } } void din::selected_range_to_all (int h) { if (h) set_range_height (0, last_range, ranges[dinfo.sel_range].extents.height); else set_range_width (0, last_range, ranges[dinfo.sel_range].extents.width); } void din::default_range_to_selected (int h) { if (h) set_range_height (dinfo.sel_range, HEIGHT); else set_range_width (dinfo.sel_range, WIDTH); } int din::range_left_changed (int r, int dx, int mr) { int valid = 0; range& R = ranges [r]; int oldleft = R.extents.left; if (dx != 0) { int newleft = oldleft + dx; valid = newleft < R.extents.right ? 1 : 0; if (valid) { if (adjustranges.others) { R.extents (newleft, R.extents.bottom, R.extents.right, R.extents.top); for (int i = 0; i < r; ++i) { range& ir = ranges [i]; ir.extents (ir.extents.left + dx, ir.extents.bottom, ir.extents.right + dx, ir.extents.top); } } else { int j = r - 1; if (j > -1) { range& rl = ranges[j]; box& rle = rl.extents; if (rle.left < newleft) { R.extents (newleft, R.extents.bottom, R.extents.right, R.extents.top); rle (rle.left, rle.bottom, R.extents.left, rle.top); } } else { R.extents (newleft, R.extents.bottom, R.extents.right, R.extents.top); } } if (mr) { // reset modulation R.mod.fm.initial = R.extents.width; R.mod.fm.bv.now = 0; } if (R.mod.active == 0) R.print_hz_per_pixel (); } LEFT = ranges[0].extents.left; } return valid; } int din::range_right_changed (int r, int dx, int mr) { int valid = 0; range& R = ranges [r]; int oldright = R.extents.right; if (dx != 0) { int newright = oldright + dx; valid = newright > R.extents.left ? 1 : 0; if (valid) { if (adjustranges.others) { R.extents (R.extents.left, R.extents.bottom, newright, R.extents.top); for (int i = r + 1; i < num_ranges; ++i) { range& ir = ranges [i]; ir.extents (ir.extents.left + dx, ir.extents.bottom, ir.extents.right + dx, ir.extents.top); } } else { int j = r + 1; if (j < num_ranges) { range& rr = ranges[j]; box& rre = rr.extents; if (newright < rre.right) { R.extents (R.extents.left, R.extents.bottom, newright, R.extents.top); rre (newright, rre.bottom, rre.right, rre.top); } } else { R.extents (R.extents.left, R.extents.bottom, newright, R.extents.top); } } if (mr) { // reset modulation R.mod.fm.initial = R.extents.width; R.mod.fm.bv.now = 0; } if (R.mod.active == 0) R.print_hz_per_pixel (); } } return valid; } void din::calc_all_range_notes () { int r = 0; for (int i = 0; i < num_ranges; ++i) ranges[r++].calc (scaleinfo); } void din::tonic_changed () { all_notes.set_tonic (scaleinfo.tonic); calc_all_range_notes (); refresh_all_drones (); notate_all_ranges (); } void din::notate_all_ranges () { extern int NOTATION; int western = scaleinfo.western; switch (NOTATION) { case WESTERN: extern const char* WESTERN_FLAT []; for (int i = 0; i < num_ranges; ++i) { range& ri = ranges [i]; string i0 = ri.intervals[0], i1 = ri.intervals[1]; int ii0 = NOTE_POS[i0], ii1 = NOTE_POS[i1]; int kii0 = (western + ii0) % 12; int kii1 = (western + ii1) % 12; ri.notes[0].set_name (WESTERN_FLAT[kii0]); ri.notes[1].set_name (WESTERN_FLAT[kii1]); } break; case NUMERIC: for (int i = 0; i < num_ranges; ++i) { range& ri = ranges [i]; ri.notes[0].set_name (ri.intervals[0]); ri.notes[1].set_name (ri.intervals[1]); } break; default: extern map INT2IND; for (int i = 0; i < num_ranges; ++i) { range& ri = ranges [i]; ri.notes[0].set_name (INT2IND[ri.intervals[0]]); ri.notes[1].set_name (INT2IND[ri.intervals[1]]); } } } void din::mouse2tonic () { // set mouse at tonic range& r = ranges[scaleinfo.notes.size () - 1]; // range of middle tonic int wx = r.extents.left; if (wx >= 0 && wx <= view.xmax) { warp_mouse (wx, mousey); dinfo.gravity.forcetrack = 1; MENU.screen_mousex = wx; MENU.screen_mousey = mousey; } } float din::get_note_value (const string& s) { return scaleinfo.intervals[s]; } void din::tuning_changed () { scaleinfo.intervals = INTERVALS; calc_all_range_notes (); refresh_all_drones (); } void din::save_scale () { save_ranges (); save_drones (); wave.save ("microtonal-keyboard-waveform.crv"); scaleinfo.save_scale (); } din::~din () { if (dvap) delete[] dvap; if (dap) delete[] dap; if (dcol) delete[] dcol; if (con_pts) delete[] con_pts; if (con_clr) delete[] con_clr; for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) delete *i; for (int i = 0, j = drone_pendulums.size (); i < j; ++i) { group* grp = drone_pendulums[i]; if (grp) delete grp; } dlog << "--- destroyed microtonal-keyboard ---" << endl; } void din::sample_rate_changed () { for (int i = 0; i < num_ranges; ++i) ranges[i].sample_rate_changed (); beat2value* bv [] = {&fm, &am, &gatr, &octave_shift}; for (int i = 0; i < 4; ++i) bv[i]->set_bpm (bv[i]->bpm); select_all_drones (); change_drone_bpm (modulator::FM, 0); change_drone_bpm (modulator::AM, 0); update_drone_tone (); } void din::samples_per_channel_changed () { wavplay.realloc (); for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); di.player.realloc (); di.update_pv = drone::EMPLACE; } } void din::load_drones () { string fdrone = user_data_dir + scaleinfo.name + ".drone"; ifstream file (fdrone.c_str(), ios::in); drones.clear (); rising = falling = 0; if (!file) return; else { string ignore; num_drones = 0; file >> ignore >> drone::UID; file >> ignore >> num_drones; print_num_drones (); file >> ignore >> drone::mastervolume; dlog << "<<< loading " << num_drones << " drones from: " << fdrone; int T = 0; for (int i = 0; i < num_drones; ++i) { drone* pdi = new drone; drone& di = *pdi; file >> ignore >> di.id; file >> ignore >> di.is; file >> ignore >> di.cx >> di.cy >> di.posafxvel.pt.x >> di.posafxvel.pt.y >> di.posafxvel.yes; file >> ignore >> di.player.x >> di.vol; file >> ignore >> di.r >> di.g >> di.b; //file >> ignore >> di.arrow.u >> di.arrow.v; file >> ignore >> di.arrow; 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; di.mod.am.calcdir (di); di.mod.fm.calcdir (di); file >> ignore >> di.trail.total; if (T < di.trail.total) T = di.trail.total; file >> di.handle_size; file >> ignore >> di.orbiting; file >> ignore >> di.V >> di.A >> di.vx >> di.vy >> di.v_mult >> di.ax >> di.ay; file >> ignore >> di.attractor; if (di.attractor) { int n = di.attractor; for (int i = 0; i < n; ++i) { attractee ae; file >> ae.id; di.attractees.push_back (ae); } attractors.push_back (pdi); } file >> ignore >> di.launcher; if (di.launcher) { float tt, dt; file >> tt >> dt >> di.dpm; di.launch_every.triggert = tt; di.launch_every.startt = ui_clk () - dt; launchers.push_back (pdi); } file >> ignore >> di.num_targets; if (di.num_targets) { file >> ignore >> di.cur_target; vector& targets = di.targets; targets.clear (); for (int i = 0; i < di.num_targets; ++i) { uintptr_t pt; file >> pt; targets.push_back ((drone*) pt); } } file >> ignore >> di.tracking; if (di.tracking) { uintptr_t id; file >> id; di.tracked_drone = (drone *) id; trackers.push_back (pdi); } file >> ignore >> di.gravity; if (di.gravity) gravitated.push_back (pdi); uintptr_t pt; file >> ignore >> pt; di.target = (drone *) pt; if (di.target) satellites.push_back (pdi); file >> ignore >> di.reincarnate; file >> ignore >> di.birth; if (di.birth != -1) { float elapsed = di.birth; di.birth = ui_clk () - elapsed; } file >> ignore >> di.life; file >> ignore >> di.insert; file >> ignore >> di.snap; file >> ignore >> di.frozen; if (di.frozen) { di.frozen = 1; di.froze_at = ui_clk (); di.set_pos (di.cx + di.mod.fm.result, di.cy + di.mod.am.result); } else { di.set_pos (di.cx, di.cy); di.froze_at = -1; } di.state = drone::RISING; di.fdr.set (0.0f, 1.0f, 1, MENU.riset()); risers.push_back (pdi); ++rising; drones.push_back (pdi); float smp, spr; file >> ignore >> smp >> spr; di.nsr.set_samples (smp); di.nsr.set_spread (spr); file >> ignore; drone::proc_conn [pdi] = false; long long cd; double mag; while (file.eof () == 0) { file >> cd; if (cd == ENDER) break; else { di.connections.push_back ((drone *)cd); file >> mag; di.mags.push_back (mag); ++di.nconn; ++totcon; } } { float start, end, amount; file >> ignore >> start >> end >> amount; di.gab.set (start, end); di.gab.amount = amount; } { file >> ignore >> di.chuck.yes; if (di.chuck.yes) file >> di.chuck; } } // load complete trail_t::alloc (T); _2totcon = 2 * totcon; alloc_conns (); // load the meshes // map dmap; file >> ignore >> meshh.num; if (meshh.num) { for (int m = 0; m < meshh.num; ++m) { mesh a_mesh; file >> ignore >> a_mesh.r >> a_mesh.g >> a_mesh.b; int num_polys; file >> ignore >> num_polys; for (int i = 0; i < num_polys; ++i) { drone* drones[4] = {0}; // 4 drones to a poly file >> ignore; for (int p = 0; p < 4; ++p) { int id; file >> id; drone* did = dmap [id]; if (did == 0) { did = get_drone (id); dmap[id] = did; } drones[p] = did; } a_mesh.add_poly (drones[0], drones[1], drones[2], drones[3]); } meshes.push_back (a_mesh); } } file >> ignore >> meshh.draw; // load drone tracked by gravity int tid = 0; file >> ignore >> tid; if (tid) dinfo.gravity.tracked_drone = get_drone (tid); load_selected_drones (file); load_drone_pendulum_groups (file); // convert attractees for (drone_iterator i = attractors.begin (), j = attractors.end(); i != j; ++i) { drone& di = *(*i); for (list::iterator iter = di.attractees.begin (), jter = di.attractees.end (); iter != jter; ++iter) { attractee& ae = *iter; ae.d = get_drone (ae.id); } } // convert tracked drone for (drone_iterator i = trackers.begin (), j = trackers.end(); i != j; ++i) { drone& di = *(*i); di.tracked_drone = get_drone ((uintptr_t) di.tracked_drone); } // convert targets and connections for (drone_iterator i = drones.begin (), j = drones.end (); i != j; ++i) { drone& di = *(*i); if (di.num_targets) for (int i = 0; i < di.num_targets; ++i) di.targets[i] = get_drone ((uintptr_t) di.targets[i]); if (di.nconn) for (drone_iterator p = di.connections.begin (), q = di.connections.end (); p != q; ++p) *p = get_drone ((uintptr_t) *p); if (di.chuck.yes) { if (di.chuck.sun) di.chuck.sun = get_drone ((uintptr_t) di.chuck.sun); if (di.chuck.sat) di.chuck.sat = get_drone ((uintptr_t) di.chuck.sat); } } // convert satellites for (drone_iterator i = satellites.begin (), j = satellites.end (); i != j; ++i) { drone& di = *(*i); di.target = get_drone ((uintptr_t) di.target); } update_drone_players (); if (num_drones) prep_modulate (MODULATE_DRONES); else prep_modulate (MODULATE_VOICE); dlog << ", done. >>>" << endl; } } void din::save_drones () { drone_wave.save ("drone.crv"); string drone_file = user_data_dir + scaleinfo.name + ".drone"; ofstream file (drone_file.c_str(), ios::out); if (file) { file << "uid " << drone::UID << endl; file << "num_drones " << num_drones << endl; file << "master_volume " << drone::mastervolume << endl; for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); file << "id " << di.id << endl; file << "is " << di.is << endl; file << "positon " << di.cx << spc << di.cy << spc << di.posafxvel.pt.x << spc << di.posafxvel.pt.y << spc << di.posafxvel.yes << endl; file << "wavepos " << di.player.x << spc << di.vol << endl; file << "color " << di.r << spc << di.g << spc << di.b << endl; file << "arrow " << di.arrow << endl; 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; file << "trail+handle " << di.trail.total << spc << di.handle_size << endl; file << "orbiting " << di.orbiting << endl; 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; file << "attractor " << di.attractor; if (di.attractor) { // save attractees for (list::iterator iter = di.attractees.begin (), jter = di.attractees.end (); iter != jter; ++iter) { attractee& ae = *iter; file << spc << ae.id; // only save unique id, rebuild on load } } file << endl; file << "launcher " << di.launcher; if (di.launcher) file << spc << di.launch_every.triggert << spc << (ui_clk()-di.launch_every.startt) << spc << di.dpm << spc << endl; else file << endl; file << "launcher_targets " << di.num_targets << endl; if (di.num_targets) { file << "cur_target " << di.cur_target; for (int t = 0; t < di.num_targets; ++t) { drone* pdt = di.targets[t]; file << spc << pdt->id; } file << endl; } file << "tracking " << di.tracking; if (di.tracking) file << spc << di.tracked_drone->id << endl; else file << endl; file << "gravity " << di.gravity << endl; if (di.target) { file << "satellite_target " << di.target->id << endl; } else file << "satellite_target 0" << endl; file << "reincarnate " << di.reincarnate << endl; if (di.birth != -1) file << "birth " << (ui_clk() - di.birth) << endl; else file << "birth -1" << endl; file << "life-time " << di.life << endl; file << "insert-time " << di.insert << endl; file << "snap " << di.snap << endl; file << "frozen " << di.frozen << endl; file << "noiser "; file << di.nsr << endl; file << "connections "; if (di.nconn) { list::iterator mi = di.mags.begin (); for (drone_iterator p = di.connections.begin(), q = di.connections.end(); p != q; ++p, ++mi) { file << (*p)->id << spc << *mi << spc; } } file << ENDER << endl; file << "gab " << di.gab.start << spc << di.gab.end << spc << di.gab.amount << endl; file << "chuck " << di.chuck.yes << spc; if (di.chuck.yes) file << di.chuck << endl; else file << endl; } file << "num_meshes " << meshh.num << endl; if (meshh.num) { for (mesh_iterator m = meshes.begin (), n = meshes.end(); m != n; ++m) { // save meshes mesh& mi = *m; file << "color " << mi.r << spc << mi.g << spc << mi.b << endl; file << "num_polys " << mi.num_polys << endl; for (poly_iterator p = mi.polys.begin (), q = mi.polys.end (); p != q; ++p) { // save polys poly& pp = *p; file << "poly"; for (int r = 0; r < 4; ++r) file << spc << pp.drones[r]->id; // save drone id, on reload we will point to right drone file << endl; } } } file << "draw_meshes " << meshh.draw << endl; file << "drone_tracked_by_gravity "; if (dinfo.gravity.tracked_drone) { file << dinfo.gravity.tracked_drone->id << endl; } else file << '0' << endl; save_selected_drones (file); save_drone_pendulum_groups (file); dlog << "+++ saved " << num_drones << " drones in: " << drone_file << " +++" << endl; } } void din::save_drone_pendulum_groups (ofstream& file) { int ng = drone_pendulums.size (); file << "groups " << ng << spc; for (int i = 0; i < ng; ++i) { drone_pendulum_group& dpg = *drone_pendulums[i]; file << dpg.n << spc << dpg.orient << spc << dpg.depth << spc; vector dpgd = dpg.drones; for (int j = 0, k = dpg.n; j < k; ++j) { drone* dj = dpgd[j]; file << dj->id << spc; } } file << endl; } void din::load_drone_pendulum_groups (ifstream& file) { string ignore; int ng; file >> ignore >> ng; if (ng) { drone_pendulums.resize (ng); for (int i = 0; i < ng; ++i) { drone_pendulum_group* pdpg = new drone_pendulum_group (); drone_pendulum_group& dpg = *pdpg; drone_pendulums[i] = pdpg; file >> dpg.n >> dpg.orient >> dpg.depth; vector& dpgd = dpg.drones; dpgd.resize (dpg.n); int did; for (int j = 0, k = dpg.n; j < k; ++j) { file >> did; dpgd[j] = get_drone (did); } } } } void din::update_drone_tone () { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); range& r = ranges[di.range]; di.step = (1 - di.pos) * r.notes[0].step + di.pos * r.notes[1].step; di.update_pv = drone::EMPLACE; } } void din::refresh_all_drones () { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); di.set_pos (di.x, di.y); } } void din::refresh_drones (int r1, int r2) { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); if ((di.range >= r1) && (di.range <= r2)) di.set_pos (di.x, di.y); } } void din::refresh_drones (int r) { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); if (di.range == r) di.set_pos (di.x, di.y); } } void din::update_drone_x (int s, int t) { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); if ((di.range >= s) && (di.range <= t)) di.set_pos (di.x, di.y); } } void din::update_drone_anchors () { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); di.calc_handle (); } } void din::update_drone_ranges () { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); if (di.range > last_range) di.range = last_range; } } void din::set_drone (drone& dd, float wx, float wy) { // create drone at position dd.cx = dd.posafxvel.pt.x = wx; dd.cy = dd.posafxvel.pt.y = wy; // install waveform, pitch and volume dd.sol (&drone_wave); dd.player.set_wave (&dd.sol); // prep to rise the drones dd.fdr.set (0.0f, 1.0f, 1, MENU.riset()); dd.set_pos (dd.cx, dd.cy); dd.state = drone::RISING; risers.push_back (&dd); ++rising; drone::proc_conn [&dd] = false; dd.setcolor (); } void din::movedrone (drone& dd) { float cx = dd.cx, cy = dd.cy; if (!SHIFT) cx += delta_mousex; if (!CTRL) cy -= delta_mousey; dd.set_center (cx, cy); dd.update_pv = drone::EMPLACE; if (dd.chuck.yes) RESETCHUCKTRAILS(dd) ec = ⅆ } void din::color_selected_drones () { if (num_selected_drones) { int last = num_selected_drones - 1; float _1bylast = 1.0f / last; for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; get_color::data.p = i * _1bylast; ds.setcolor (); } } else cons << RED_PSD << eol; } void din::mortalize_drones (int reincarnate) { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; ds.birth = ui_clk (); ds.reincarnate = reincarnate; } } else cons << RED_PSD << eol; } void din::immortalize_drones () { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; ds.birth = -1; ds.reincarnate = 0; } } else cons << RED_PSD << eol; } void din::delete_selected_drones () { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; if (ds.reincarnate) ds.reincarnate = 0; if (ds.state == drone::FALLING) ds.fdr.retime (MENU.fallt()); else delete_drone (ds); } clear_selected_drones (); } else cons << RED_PSD << eol; } int din::delete_all_drones () { select_all_drones (); delete_selected_drones (); return 1; } void din::delete_drone (drone& ds) { drone* pds = &ds; if (ds.state == drone::RISING) if (erase (risers, pds)) --rising; if (push_back (fallers, pds)) { ++falling; ds.state = drone::FALLING; ds.fdr.set (ds.fdr.alpha, 0.0f, 1, MENU.fallt()); } } int din::select_all_drones () { clear_selected_drones (); for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone* pdi = *i; pdi->sel = 1; selected_drones.push_back (pdi); } print_selected_drones (); return 1; } int din::select_launchers () { CLEAR_SELECTED_DRONES for (drone_iterator i = launchers.begin(), j = launchers.end(); i != j; ++i) { drone* pdi = *i; add_drone_to_selection (pdi); } print_selected_drones (); return 1; } void din::clear_selected_drones () { for (int i = 0; i < num_selected_drones; ++i) selected_drones[i]->sel = 0; selected_drones.clear (); num_selected_drones = 0; } void din::orbit_selected_drones () { // attach selected drones to attractor if (num_selected_drones > 1) { int last = num_selected_drones - 1; drone* p_att = selected_drones [last]; // last selected drone is attractor push_back (attractors, p_att); drone& att = *p_att; list& lae = att.attractees; for (int i = 0; i < last; ++i) { // other drones are attractees drone* pae = selected_drones [i]; if (!pae->orbiting) { attractee ae (pae->id, pae); if (push_back (lae, ae)) { ++att.attractor; pae->orbiting = 1; } } else { cons << RED << "Drone orbits already, ignored!" << eol; } } } else cons << RED_A2D << ". Drones will orbit around the last drone!" << eol; } void din::remove_attractee (drone* d) { for (drone_iterator i = attractors.begin(); i != attractors.end();) { // run thru list of attractors drone* p_att = *i; drone& att = *p_att; list& lae = att.attractees; int erased = 0; for (list::iterator iter = lae.begin (); iter != lae.end();) { // run thru list of attractees attractee& ae = *iter; if (ae.d != d) ++iter; else { // remove attractee lae.erase (iter); if (--att.attractor == 0) { i = attractors.erase (i); erased = 1; } break; } } if (!erased) ++i; } } void din::set_drones_under_gravity () { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone* pdg = selected_drones[i]; if (pdg->y < BOTTOM) pdg->gravity = -1; else pdg->gravity = 1; push_back (gravitated, pdg); pdg->birth = ui_clk (); } } else cons << RED_PSD << eol; } void din::move_drones_under_gravity () { for (drone_iterator i = gravitated.begin(), j = gravitated.end(); i != j; ++i) { // run thru list of drones driven by gravity drone* pdi = *i; drone& di = *pdi; // get the ith drone if (di.frozen == 0) { // current position di.xi = di.x; di.yi = di.y; // calculate new position along its velocity di.set_pos (di.x + di.V * di.vx, di.y + di.V * di.vy); // acceleration is due to gravity! di.ax = dinfo.gravity.gx; di.ay = di.gravity * dinfo.gravity.gy; // reverse gravity effect if drone launched below 0 volume line // update velocity ie we accelerate di.vx += di.ax; di.vy += di.ay; // bounce when reached bottom line of microtonal keyboard if ((di.target == 0) && ((di.gravity == 1 && di.y <= BOTTOM) || (di.gravity == -1 && di.y >= BOTTOM))) { if (di.bounces.n++ >= di.bounces.max) { delete_drone (di); } else { float dx = di.x - di.xi; if (dx == 0.0f) { // slope is infinite di.set_pos (di.x, BOTTOM); } else { // slope is available float dy = di.y - di.yi; if (dy == 0.0f) di.set_pos (di.x, BOTTOM); else { float m = dy * 1.0f / dx; di.set_pos (di.xi + (BOTTOM - di.yi) / m, BOTTOM); } } float reduction = MENU.sp_rebound() / 100.0; int style = dinfo.bounce.style; if (style == din_info::bouncet::RANDOM) style = get_rand_bit (); if (style == din_info::bouncet::BACK) di.vx *= -reduction; di.vy = reduction * -di.vy; } } di.move_center (); } } } void din::set_targets () { if (num_selected_drones == 0) { cons << RED << "Select a launcher and drones to target" << eol; return; } drone* pd0 = selected_drones[0]; if (pd0->launcher == 0) make_launcher (pd0); // first drone is launcher pd0->clear_targets (); if (num_selected_drones == 1) { pd0->targets.push_back (pd0); pd0->num_targets = pd0->targets.size (); cons << GREEN << "Selected drone is a launcher and also the target" << eol; return; } for (int i = 1; i < num_selected_drones; ++i) { // make other drones in selection the targets drone* pdi = selected_drones[i]; vector targets = pd0->targets; vector::iterator te = targets.end (), f = find (targets.begin (), targets.end (), pdi); if (f == te) pd0->targets.push_back (pdi); } pd0->num_targets = pd0->targets.size (); cons << GREEN << "First drone is launcher, it targets " << pd0->num_targets << " other drones" << eol; } void din::remove_drone_from_targets (drone* T) { for (drone_iterator i = satellites.begin(), j = satellites.end(); i != j;) { // remove satellites going towards T drone* pdi = *i; drone& di = *pdi; if (di.target == T) { di.target = 0; i = satellites.erase (i); j = satellites.end (); } else ++i; } for (drone_iterator i = launchers.begin(), j = launchers.end (); i != j; ++i) { // remove target from launcher drone* pdi = *i; vector& targets = pdi->targets; vector::iterator te = targets.end (), f = find (targets.begin (), te, T); if (f != te) { targets.erase (f); pdi->num_targets = targets.size (); clamp (0, pdi->cur_target, pdi->num_targets - 1); } } } void din::clear_targets () { int n = 0; for (int i = 0; i < num_selected_drones; ++i) { drone* pdi = selected_drones[i]; if (pdi->num_targets) { pdi->clear_targets (); ++n; } } if (n) cons << GREEN << "Cleared targets of " << n << s_drones << eol; else cons << RED << "No targets found!" << eol; } void din::kill_old_drones () { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); if (!di.frozen && (di.birth != -1) && (di.state != drone::FALLING)) { double elapsed = ui_clk() - di.birth; if (elapsed >= di.life) delete_drone (di); } } } void din::carry_satellites_to_orbit () { // satellites is a bunch of drones to be inserted into orbit around another drone for (drone_iterator i = satellites.begin(), j = satellites.end(); i != j;) { // run thru satellites to be inserted into circular orbit drone* pdi = *i; drone& di = *pdi; if (di.frozen == 0) { drone& dt = *di.target; // the target we want the satellite to orbit unit_vector (di.ax, di.ay, dt.x - di.x, dt.y - di.y); // centripetal acceleration ie unit vector joining satellite & target float pvx = -di.ay, pvy = di.ax; // velocity to insert into orbit (just perpendicular to centripetal acceleration so its centrifugal velocity) double now = ui_clk(), delta = now - di.birth; 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! if (alpha >= 1.0f) { // insert drone into orbit now! list& lae = dt.attractees; lae.push_back (attractee (pdi->id, pdi)); push_back (attractors, di.target); di.target = 0; // inserted into orbit, so clear ++dt.attractor; i = satellites.erase (i); j = satellites.end (); // no longer a satellite we need to insert } else { // continue carrying satellites into orbit float dot = di.vx * pvx + di.vy * pvy; // dot product current velocity and insertion velocity to see if they are facing the same direction if (dot < 0) { // no so flip insertion velocity so it faces the same direction as current velocity pvx = -pvx; pvy = -pvy; di.v_mult = -1; // see attract_drones () } else di.v_mult = 1; // set interpolated velocity as current satellite velocity float ivx, ivy; unit_vector (ivx, ivy, di.vx + alpha * (pvx - di.vx), di.vy + alpha * (pvy - di.vy)); // interpolate current velocity and insertion velocity di.vx = ivx; di.vy = ivy; 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 di.xi = di.x; di.yi = di.y; di.set_pos (newx, newy); di.move_center (); ++i; } } else ++i; } } void din::toggle_launchers () { if (num_selected_drones == 0) { cons << RED_PSD << eol; return; } double startt = ui_clk(); int nl = 0, nd = 0; for (int i = 0; i < num_selected_drones; ++i) { drone* pdi = selected_drones[i]; drone& di = *pdi; di.launcher = !di.launcher; if (di.launcher) { di.launch_every.startt = startt - di.launch_every.triggert; // for immediate launch launchers.push_back (pdi); ++nl; } else { erase (launchers, pdi); ++nd; } } cons << GREEN << "Launching from " << nl << " drones, Stopped Launching from " << nd << s_drones << eol; } void din::make_launcher (drone* pl) { double startt = ui_clk(); pl->launcher = 1; pl->launch_every.startt = startt - pl->launch_every.triggert; launchers.push_back (pl); } void din::make_launchers () { if (num_selected_drones == 0) { cons << RED_PSD << eol; return; } int nl = 0; for (int i = 0; i < num_selected_drones; ++i) { drone* pdi = selected_drones[i]; if (pdi->launcher == 0) { make_launcher (pdi); ++nl; } } if (nl) cons << GREEN << "Made " << nl << " launchers" << eol; else cons << RED << "All selected drones are launchers!" << eol; } void din::destroy_launchers () { if (num_selected_drones == 0) { cons << RED_PSD << eol; return; } int nl = 0; for (int i = 0; i < num_selected_drones; ++i) { drone* pdi = selected_drones[i]; drone& di = *pdi; if (di.launcher) { di.launcher = 0; erase (launchers, pdi); if (di.tracking) { di.tracking = 0; di.tracked_drone = 0; erase (trackers, pdi); } ++nl; } } if (nl) cons << GREEN << "Stopped launching from " << nl << s_drones << eol; else cons << RED << "No drone launchers found!" << eol; } void din::seloncre (drone* d) { if (dinfo.seloncre) { d->sel = 1; selected_drones.push_back (d); print_selected_drones (); } } drone* din::add_drone (float wx, float wy, int fromlauncher) { drone* newdrone = new drone (wy); seloncre (newdrone); drones.push_back (newdrone); ++num_drones; print_num_drones (); set_drone (*newdrone, wx, wy); if (!fromlauncher && !drone::anchored) balloon (newdrone); return newdrone; } void din::balloon (drone* d) { d->reincarnate = 0; if (d->y < BOTTOM) d->gravity = -1; else d->gravity = 1; gravitated.push_back (d); d->birth = ui_clk (); } void din::launch_drones () { for (drone_iterator i = launchers.begin(); i != launchers.end(); ++i) { drone* pdi = *i; drone& di = *pdi; if (di.frozen == 0 && di.launch_every (ui_clk())) { // time to launch a drone #define CALLEDFROMLAUNCHER 1 drone* newdronep = add_drone (di.x, di.y, CALLEDFROMLAUNCHER); drone& newdrone = *newdronep; if (newdrone.y < BOTTOM) newdrone.gravity = -1; else newdrone.gravity = 1; // reverse gravity vector if launched below microtonal keyboard // newdrone.is = di.is; newdrone.setcolor (); /*newdrone.r = di.r; newdrone.g = di.g; newdrone.b = di.b;*/ newdrone.V = di.V; newdrone.vx = di.vx; newdrone.vy = di.vy; if (drone::v0.rndrot) rotate_vector (newdrone.vx, newdrone.vy, drone::v0.rotrd()); newdrone.A = di.A; newdrone.ax = di.ax; newdrone.ay = di.ay; if (drone::a0.rndrot) rotate_vector (newdrone.ax, newdrone.ay, drone::a0.rotrd()); /*newdrone.autorot.v = di.autorot.v; newdrone.autorot.a = di.autorot.a; newdrone.handle_size = di.handle_size; newdrone.trail.total = di.trail.total; newdrone.life = di.life; */ newdrone.launched_by = pdi; newdrone.snap = di.snap; newdrone.gab = di.gab; newdrone.arrow = di.arrow; int num_targets = di.num_targets; if (num_targets) { // launch a satellite newdrone.insert = di.insert; int& cur_target = di.cur_target; newdrone.target = di.targets [cur_target]; if (++cur_target >= num_targets) cur_target = 0; satellites.push_back (newdronep); newdrone.orbiting = 1; } else { gravitated.push_back (newdronep); } spinner2& lifet = MENU.lifetime; spinner2::variancet& vart = lifet.variance; if (vart.cb.state) { newdrone.life = vart.rd () * di.life; } else { newdrone.life = di.life; } newdrone.birth = ui_clk(); newdrone.reincarnate = 0; } } } void din::attract_drones () { // attract drones that orbit other drones // for (drone_iterator i = attractors.begin(), j = attractors.end(); i != j; ++i) { drone* pda = *i; drone& da = *pda; list& lae = da.attractees; for (list::iterator iter = lae.begin (), jter = lae.end(); iter != jter; ++iter) { // run thru list of attractees attractee& ae = *iter; drone& de = *ae.d; unit_vector (de.ax, de.ay, (float)(da.sx - de.x), (float)(da.y - de.y)); // centripetal acceleration de.vx = -de.ay; de.vy = de.ax; // centrifugal velocity is just perpendacular to centripetal acceleration de.vx *= de.v_mult; de.vy *= de.v_mult; // flip if necessary - see carry_satellites_to_orbit () if (de.frozen == 0) { // calculate position of the drones de.xi = de.x; de.yi = de.y; de.x = de.xi + de.V * de.vx + de.A * de.ax; de.y = de.yi + de.V * de.vy + de.A * de.ay; de.move_center (); de.set_pos (de.x, de.y); } } } } void din::add_drone_to_selection (drone* pd) { int& sel = pd->sel; if (CTRL) { if (sel) { remove_drone_from_selection (pd); return; } } if (sel) ; else { pd->sel = 1; selected_drones.push_back (pd); } } int din::get_selected_drone_id (drone* d) { for (int i = 0; i < num_selected_drones; ++i) { if (selected_drones[i] == d) return i; } return -1; } void din::remove_drone_from_selection (drone* pd) { pd->sel = 0; if (xforming) { int id = get_selected_drone_id (pd); if (id != -1) { if (xforming == SCALE) erase_id (svec, id); else erase_id (rvec, id); } } if (erase (selected_drones, pd)) --num_selected_drones; if (erase (browsed_drones, pd)) { --num_browsed_drones; last_browseable_drone = num_browsed_drones - 1; } } void din::update_drone_players () { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); di.sol (&drone_wave); di.player.set_wave (&di.sol); } } 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) { // make arrow // float ak2, ak3, ak2t, ak3t; // base to neck A[k]=x; A[k+1]=y; A[k+2] = ak2 = x + ux; A[k+3] = ak3 = y + uy; ak2t = x + t * ux; ak3t = y + t * uy; float arx = x + u * ux, ary = y + u * uy; float vvx = v * vx, vvy = v * vy; // flank1 to neck float ak4, ak5; ak4 = A[k+4] = arx + vvx; ak5 = A[k+5] = ary + vvy; A[k+6] = ak2t; A[k+7] = ak3t; // flank2 to neck float ak8, ak9; ak8 = A[k+8]= arx - vvx; ak9 = A[k+9]= ary - vvy; A[k+10]= ak2t; A[k+11]= ak3t; if (cap) { A[k+12]=ak4; A[k+13]=ak5; A[k+14]=ak2; A[k+15]=ak3; A[k+16]=ak2; A[k+17]=ak3; A[k+18]=ak8; A[k+19]=ak9; n = 20; } else n = 12; } void din::draw_drones () { glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); draw_connections (); drawchuck (); // draw drone mesh if (meshh.num && meshh.draw) { for (mesh_iterator i = meshes.begin (), j = meshes.end(); i != j; ++i) (*i).draw (); } // draw drone trails for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); if (di.range >= visl && di.range <= visr) { glColor4f (di.r * di.gab.amount, di.g * di.gab.amount, di.b * di.gab.amount, di.fdr.amount); di.trail.draw (); } } // hilite browsed drone int dhp [12] = {0}; glVertexPointer (2, GL_INT, 0, dhp); if (num_selected_drones == 1 && num_browsed_drones) { drone& ds = *selected_drones[0]; glEnable (GL_LINE_STIPPLE); glLineStipple (1, 0xf0f0); glColor3f (ds.r, ds.g, ds.b); dhp[0]=ds.handle.midx;dhp[1]=win.top; dhp[2]=ds.handle.midx;dhp[3]=win.bottom; dhp[4]=win.left;dhp[5]=ds.handle.midy; dhp[6]=win.right;dhp[7]=ds.handle.midy; glDrawArrays (GL_LINES, 0, 4); glDisable (GL_LINE_STIPPLE); } // draw drone handles and pitch/volume info if (dinfo.show_pitch_volume.drones) tb_hz_vol.clear (); for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); if (inbox (win, di.x, di.y)) { glColor4f (di.r * di.gab.amount, di.g * di.gab.amount, di.b * di.gab.amount, di.fdr.amount); if (dinfo.show_pitch_volume.drones && di.sel) { sprintf (BUFFER, " %0.3f @ %d%%", di.step * SAMPLE_RATE, int(di.vol*di.gab.amount*100.0+0.5)); // draw pitch/volume tb_hz_vol.add (text (BUFFER, di.handle.right, di.handle.bottom, di.r, di.g, di.b, text::temporary, text::normal, di.handle.right - win.left + fnt.spacing.word, di.handle.top - win.bottom - fnt.spacing.ch)); } glRecti (di.handle.left, di.handle.bottom, di.handle.right, di.handle.top); // fill handle if (di.sel) glColor4f (0, 1, 0, di.fdr.amount); else glColor4f (1, 1, 1, di.fdr.amount); dhp[0]=di.handle.left; dhp[1] = di.handle.bottom; dhp[2]=di.handle.right; dhp[3]=di.handle.bottom; dhp[4]=di.handle.right; dhp[5]=di.handle.top; dhp[6]=di.handle.left; dhp[7]=di.handle.top; glDrawArrays (GL_LINE_LOOP, 0, 4); // draw handle outline with selection status if (di.attractor) { // mark + on attractor dhp[0]=di.handle.midx; dhp[1] = di.handle.top; dhp[2]=di.handle.midx; dhp[3]=di.handle.bottom; dhp[4]=di.handle.left; dhp[5]=di.handle.midy; dhp[6]=di.handle.right; dhp[7]=di.handle.midy; glDrawArrays (GL_LINES, 0, 4); } if (di.launcher) { // mark x on launcher dhp[0]=di.handle.left; dhp[1] = di.handle.top; dhp[2]=di.handle.right; dhp[3]=di.handle.bottom; dhp[4]=di.handle.left; dhp[5]=di.handle.bottom; dhp[6]=di.handle.right; dhp[7]=di.handle.top; glDrawArrays (GL_LINES, 0, 4); } } } if (dinfo.anchor) { // draw drone anchors if (n_dap < num_drones) { if (dap) delete[] dap; dap = new float [4 * num_drones]; n_dap = num_drones; } glVertexPointer (2, GL_FLOAT, 0, dap); int ai = 0, ad = 0; for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); if (di.range >= visl && di.range <= visr) { dap[ai++] = di.sx; dap[ai++] = di.y; dap[ai++] = di.sx; dap[ai++] = BOTTOM; ++ad; } } glColor3f (0.25, 0.25, 0.25); glDrawArrays (GL_LINES, 0, 2 * ad); } // draw velocity and acceleration vectors if (num_drones && (dinfo.vel || dinfo.accel)) { static const int v_size = 4, a_size = 8 * v_size; int nn_dvap = 20 * num_drones; if (n_dvap < nn_dvap) { if (dvap) delete[] dvap; if (dcol) delete[] dcol; dvap = new float [nn_dvap]; dcol = new float [2 * nn_dvap]; n_dvap = nn_dvap; } int v = 0, nv = 0; if (dinfo.vel) { int ci = 0; for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); if (di.range >= visl && di.range <= visr) { float vl = di.V * v_size, vdx = vl * di.vx, vdy = vl * di.vy, pvdx = -vdy, pvdy = vdx; int dv = 12; 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); di.xv = di.sx + vdx; di.yv = di.y + vdy; v += dv; color dic (di.r * di.gab.amount, di.g * di.gab.amount, di.b * di.gab.amount); for (int s = 0, t = dv / 2; s < t; ++s) { dcol[ci++] = dic.r; dcol[ci++] = dic.g; dcol[ci++] = dic.b; dcol[ci++] = 1.0f; } ++nv; } } if (nv) { glEnableClientState (GL_COLOR_ARRAY); glColorPointer (4, GL_FLOAT, 0, dcol); glVertexPointer (2, GL_FLOAT, 0, dvap); glDrawArrays (GL_LINES, 0, v / 2); glDisableClientState (GL_COLOR_ARRAY); } } if (dinfo.accel) { int a = 0, na = 0; for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); if (di.range >= visl && di.range <= visr) { float al = di.A * a_size, adx = al * di.ax, ady = al * di.ay, padx = -ady, pady = adx; int da = 12; 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); di.xa = di.sx + adx; di.ya = di.y + ady; a += da; ++na; } } if (na) { glColor4f (1, 0.25, 0.5, 1); glVertexPointer (2, GL_FLOAT, 0, dvap); glDrawArrays (GL_LINES, 0, a / 2); } } } if (dinfo.show_pitch_volume.drones) tb_hz_vol.draw (); glDisable (GL_BLEND); } void din::setdronemastervolume (float d) { drone::mastervolume = d; for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); di.update_pv = drone::EMPLACE; } MENU.sp_drone_master_vol.set_value (d); sprintf (BUFFER, "Drone master volume = %0.3f", d); cons << YELLOW << BUFFER << eol; } void din::update_drone_solvers (multi_curve& crv) { static const char* dw = "drone-waveform"; for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); di.sol.update (); if (crv.num_vertices) di.player.set_mix (crv, dw); } } string din::get_selected_drones () { stringstream ss; for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); if (di.sel) ss << di.id << spc; } return ss.str(); } void din::set_drone_volume (int i, float v) { drone* pd = get_drone (i); if (pd) { pd->xi = pd->x; pd->yi = pd->y; int x = pd->x, y = (int) (BOTTOM + v * HEIGHT + 0.5f); pd->set_pos (x, y); pd->move_center (); } } void din::calc_win_mouse () { if (MENU.show == 0) { delta_mousex = mousex - prev_mousex; delta_mousey = mousey - prev_mousey; prev_mousex = mousex; prev_mousey = mousey; prev_win_mousex = win_mousex; prev_win_mousey = win_mousey; win_mousex += delta_mousex; win_mousey -= delta_mousey; tonex = win_mousex; toney = win_mousey; } } int din::is_drone_hit (drone& di, const box& rgn) { float x [] = {di.handle.midx, di.handle.left, di.handle.right}; float y [] = {di.handle.midy, di.handle.bottom, di.handle.top}; for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) if (inbox (rgn, x[i], y[j])) return 1; return 0; } void din::calc_selector_range (const box& rgn, int& left, int& right) { float xl = rgn.left, xr = rgn.right; left = right = 0; for (int i = 0; i < num_ranges; ++i) { range& ri = ranges[i]; if (xl >= ri.extents.left) left = max (0, i - 1); if (xr >= ri.extents.right) right = min (last_range, i + 1); } } void din::find_selected_drones (const box& rgn) { // select drones that lie inside selected region // supports ctrl & shift keys int sell, selr; calc_selector_range (rgn, sell, selr); CLEAR_SELECTED_DRONES for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone* pdi = *i; drone& di = *pdi; if ((di.state > drone::DEAD) && (di.range >= sell) && (di.range <= selr) && is_drone_hit (di, rgn)) add_drone_to_selection (pdi); } print_selected_drones (); } void din::invert_selected_drones () { selected_drones.clear (); for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone* pdi = *i; drone& di = *pdi; if (di.sel) di.sel = 0; else { di.sel = 1; selected_drones.push_back (pdi); } } print_selected_drones (); } void din::print_selected_drones () { num_selected_drones = selected_drones.size (); if (num_selected_drones) { if (num_selected_drones != 1) { browsed_drones = selected_drones; num_browsed_drones = num_selected_drones; last_browseable_drone = num_browsed_drones - 1; browsed_drone = -1; MENU.sp_browse_drone.set_listener (MENUP.brwdl); MENU.sp_browse_drone.set_value (browsed_drone); } else { MENU.sp_browse_drone.set_listener (0); ec = selected_drones[0]; } cons << GREEN; prep_modulate (MODULATE_DRONES); MENU.next_tab = MENUP.cb_mkb_drone_params; MENU.next_tab_instr = this; if (xforming) resize_xform_vectors (); } else { cons << RED; browsed_drones.clear (); num_browsed_drones = 0; browsed_drone = last_browseable_drone = -1; ec = 0; } cons << "Selected " << num_selected_drones << s_drones << eol; } int din::handle_input () { // if (butting) butt_drones (); static const double reptf = 1./7, repts = 1./64.; static const double first_repeat_time = 0.3, other_repeat_time = 0.05; static double start_time, repeat_time = first_repeat_time; static int lmb_clicked = 0; // mov if (keypressedd (SDLK_a, dinfo.scroll.rept, dinfo.scroll.rept)) scroll (-dinfo.scroll.dx, 0); else if (keypressedd (SDLK_d, dinfo.scroll.rept, dinfo.scroll.rept)) scroll (+dinfo.scroll.dx, 0); else if (keypressedd (SDLK_w, dinfo.scroll.rept, dinfo.scroll.rept)) scroll (0, +dinfo.scroll.dy); else if (keypressedd (SDLK_s, dinfo.scroll.rept, dinfo.scroll.rept)) scroll (0, -dinfo.scroll.dy); if (wheel && !MENU.show && !mouse_slider0.active) { if (SHIFT) scroll (0, wheel * dinfo.scroll.dy); else scroll (-wheel * dinfo.scroll.dx, 0); } if (lmb) { if (lmb_clicked == 0) { lmb_clicked = 1; if (adding) { add_drone (win_mousex, win_mousey); start_time = ui_clk(); } } else { if (adding) { // for spraying drones double delta_time = ui_clk() - start_time; if (delta_time >= repeat_time) { // click repeat lmb_clicked = 0; repeat_time = other_repeat_time; } } } } else { lmb_clicked = 0; repeat_time = first_repeat_time; } if (phrasor0.state == phrasor::recording) { // record mouse pos for playback l8r static point pt; pt.x = win_mousex; pt.y = win_mousey; phrasor0.add (pt); ++phrasor0.size; } // octave shift if (keypressed (SDLK_z)) modulate_down (); else if (keypressed (SDLK_x)) modulate_up (); else if (keypressed (SDLK_e)) { if (!mouse_slider0.active) { if (SHIFT) MENU.bsdl.clicked (MENU.b_scale_drones); else if (CTRL) MENU.brdl.clicked (MENU.b_rotate_drones); else { // move drones if (moving_drones) set_moving_drones (0); // stop moving else if (mouse_slider0.deactivate()) ; // bcos scale or rotate else if (!MENU.show) start_moving_drones (); // start moving } } } else if (moving_drones) { if (num_selected_drones) { if (prev_win_mousex != win_mousex || prev_win_mousey != win_mousey) { for (int i = 0; i < num_selected_drones; ++i) { drone& di = *selected_drones[i]; movedrone (di); } } return 1; } else { cons << RED_PSD << eol; } } else if (keypressed (SDLK_f)) { if (SHIFT) { dinfo.sel_range = current_range; MENU.load_range (current_range); MENU.next_tab = MENUP.cb_mkb_ranges; MENU.next_tab_instr = this; } else if (CTRL) { MENU.cnol.picked (MENU.ol_change_note.option, 0); print_range_info (ranges[dinfo.sel_range]); } else { do_phrase_recording (); } } else if (keypressed (SDLK_v)) { if (SHIFT) { MENU.rwl.clicked (MENU.b_adjust_range_both); // adjust range left and right } else if (CTRL) { MENU.cnb.clicked (MENU.b_change_note_both); // change both notes of range } else { // phrase play/pause if (phrasor0.state == phrasor::playing) { if (MENU.show == 0) { phrasor0.state = phrasor::paused; find_current_range (); cons << YELLOW << "phrasor has PAUSED." << eol; } else cons << RED << "Close menu!" << eol; } else { if (phrasor0.validate ()) { phrasor0.play (); if (phrasor0.state == phrasor::playing) cons << GREEN << "Phrasor is PLAYING" << eol; } else { pos_afx_vel (-1); } } } } else if (keypressed (SDLK_g)) { // phrase clear if (SHIFT) { MENU.rwl.clicked (MENU.b_adjust_range_left); // adjust range left } else if (CTRL) { MENU.cnl.clicked (MENU.b_change_note_left); // change range left note } else { clear_all_phrases (); } } else if (keypressed (SDLK_h)) { if (SHIFT) { MENU.rwl.clicked (MENU.b_adjust_range_right); // adjust range right } else if (CTRL) { MENU.cnr.clicked (MENU.b_change_note_right); // change range right note } else toggle_launchers (); } else if (keypressedd (SDLK_n)) --MENU.sp_drones_per_min; else if (keypressedd (SDLK_m)) ++MENU.sp_drones_per_min; else if (keypressed (SDLK_b)) { if (SHIFT) { MENU.rhl.clicked (MENU.b_adjust_range_height); } else if (CTRL) { MENU.bhl.clicked (MENU.b_adjust_board_height); } else uis.cb_gater.toggle (); } // drones // else if (keypressedd (SDLK_q)) { if (!mouse_slider0.active) { if (SHIFT) { MENU.picked (MENU.ol_drone_is.option, 0); } else { if (dinfo.wand) { if (wanding) stopwanding (); else MENU.dcl.startwanding (); } else add_drone (win_mousex, win_mousey); } } } else if (keypressedd (SDLK_c)) { if (SHIFT) set_drones_under_gravity (); else delete_selected_drones (); } else if (keypressedd (SDLK_LEFTBRACKET, reptf, repts)) { if (SHIFT) --MENU.sp_rotate_drone_vel; else --MENU.sp_change_drone_vel; } else if (keypressedd (SDLK_RIGHTBRACKET, reptf, repts)) { if (SHIFT) ++MENU.sp_rotate_drone_vel; else if (CTRL) toggle_this (dinfo.vel, MENU.cb_show_vel); else ++MENU.sp_change_drone_vel; } else if (keypressed (SDLK_l)) { if (SHIFT) select_launchers (); else select_all_drones (); } else if (keypressed (SDLK_i)) { if (SHIFT) { dinfo.show_pitch_volume.board = !dinfo.show_pitch_volume.board; dont_call_listener (uis.cb_show_pitch_volume_board, dinfo.show_pitch_volume.board); } else invert_selected_drones (); } else if (keypressedd (SDLK_LEFT)) { if (SHIFT) browse_range (-1); else browse_drone (-1); } else if (keypressedd (SDLK_RIGHT)) { if (SHIFT) browse_range (+1); else browse_drone (+1); } else if (keypressed (SDLK_j)) { if (SHIFT) { dinfo.show_pitch_volume.drones = !dinfo.show_pitch_volume.drones; dont_call_listener (uis.cb_show_pitch_volume_drones, dinfo.show_pitch_volume.drones); } else toggle_freeze_drones (); } else if (keypressed (SDLK_k)) { if (SHIFT) snap_drones (1); else if (CTRL) snap_drones (0); else snap_drones (-1); // toggle } else if (keypressedd (SDLK_o, reptf, repts)) --MENU.sp_change_drone_accel; else if (keypressedd (SDLK_p, reptf, repts)) { if (CTRL) toggle_this (dinfo.accel, MENU.cb_show_accel); else ++MENU.sp_change_drone_accel; } /*else if (keypressed (SDLK_F3)) { butting = !butting; } else if (keypressed (SDLK_F4)) { ring.x = win_mousex; ring.y = win_mousey; }*/ else if (keypressed (SDLK_SEMICOLON)) select_attractors (); else if (keypressed (SDLK_QUOTE)) select_attractees (); else if (keypressedd (SDLK_COMMA, reptf, repts)) { if (SHIFT) gab.set (this, 0.0f, "muting drones"); else if (CTRL) noise2drone (); else setdronemastervolume (drone::mastervolume - float(MENU.sp_drone_master_vol.f_delta)); } else if (keypressedd (SDLK_PERIOD, reptf, repts)) { if (SHIFT) gab.set (this, 1.0f, "unmuting drones"); else if (CTRL) drone2noise (); else setdronemastervolume (drone::mastervolume + float(MENU.sp_drone_master_vol.f_delta)); } else if (keypressed (SDLK_F4)) switch_modulation (); else if (keypressed (SDLK_BACKSLASH)) set_key_to_pitch_at_cursor (); else if (keypressed (SDLK_SPACE)) { if (adjustranges.active) { adjustranges.others = !adjustranges.others; if (adjustranges.others) cons << GREEN << "Adjust other ranges too" << eol; else cons << YELLOW << "Adjusting this range only" << eol; } else uis.cb_voice.toggle (); // toggle lead voice } else if (keypressed (SDLK_F1)) helptext(); // bpms if (keypressedd (SDLK_F5)) { // decrease gater bpm upto limit if (SHIFT) lower_delta (gater_delta.bpm, -1, "delta_gater_bpm = "); else if (CTRL) { gatr.min_bpm = gatr.bpm; cons << YELLOW << "set minimum gater bpm to " << gatr.bpm << eol; } else change_bpm (gatr, -gater_delta.bpm); //-(float)MENU.sp_gater_bpm.f_delta); } else if (keypressedd (SDLK_F6)) { // increase gater bpm if (SHIFT) raise_delta (gater_delta.bpm, +1, "delta_gater_bpm = "); else if (CTRL) { gatr.min_bpm = 0; cons << YELLOW << "set minimum gater bpm to " << gatr.min_bpm << eol; } else change_bpm (gatr, gater_delta.bpm); //MENU.sp_gater_bpm.f_delta); } else if (keypressedd (SDLK_F7)) { // decrease fm bpm if (SHIFT) lower_delta (fm_delta.bpm, -1, "delta_fm_bpm = "); else change__bpm (modulator::FM, fm, -fm_delta.bpm); //-(float)MENU.sp_fm_bpm.f_delta); } else if (keypressedd (SDLK_F8)) { // increase fm bpm if (SHIFT) raise_delta (fm_delta.bpm, +1, "delta_fm_bpm = "); else change__bpm (modulator::FM, fm, fm_delta.bpm); //MENU.sp_fm_bpm.f_delta); } else if (keypressedd (SDLK_F9)) { // decrease am bpm if (SHIFT) lower_delta (am_delta.bpm, -1, "delta_am_bpm = "); else change__bpm (modulator::AM, am, -am_delta.bpm); //-(float)MENU.sp_am_bpm.f_delta); } else if (keypressedd (SDLK_F10)) { // increase am bpm if (SHIFT) raise_delta (am_delta.bpm, 1, "delta_am_bpm = "); else change__bpm (modulator::AM, am, am_delta.bpm); //MENU.sp_am_bpm.f_delta); } else if (keypressedd (SDLK_F11)) { // decrease octave shift bpm if (SHIFT) lower_delta (os_delta.bpm, -1, "delta_octave_shift_bpm = "); else change_bpm (octave_shift, -os_delta.bpm); //-(float)MENU.sp_octave_shift_bpm.f_delta); } else if (keypressedd (SDLK_F12)) { // increase octave shift bpm if (SHIFT) raise_delta (os_delta.bpm, +1, "delta_octave_shift_bpm = "); else change_bpm (octave_shift, os_delta.bpm); //MENU.sp_octave_shift_bpm.f_delta); } // depths else if (keypressedd (SDLK_r)) { // decrease am depth if (SHIFT) lower_delta (p_am_delta->depth, -float(MENU.sp_am_depth.f_delta), "delta_am_depth = ", 0.0f); else change__depth (modulator::AM, -dam_delta.depth, 0, -am_delta.depth); } else if (keypressedd (SDLK_t)) { // increase am depth if (SHIFT) raise_delta (p_am_delta->depth, float(MENU.sp_am_depth.f_delta), "delta_am_depth = "); else change__depth (modulator::AM, dam_delta.depth, 0, am_delta.depth); } else if (keypressedd (SDLK_y)) { // decrease fm depth if (SHIFT) lower_delta (fm_delta.depth, -float (MENU.sp_fm_depth.f_delta), "delta_fm_depth = "); else change__depth (modulator::FM, -fm_delta.depth, 1, -fm_delta.depth); } else if (keypressedd (SDLK_u)) { // increase fm depth if (SHIFT) raise_delta (fm_delta.depth, float (MENU.sp_fm_depth.f_delta), "delta_fm_depth = "); else change__depth (modulator::FM, fm_delta.depth, 1, fm_delta.depth); } else if (keypressedd (SDLK_MINUS)) { --MENU.sp_change_drone_trail_length; } else if (keypressedd (SDLK_EQUALS)) { ++MENU.sp_change_drone_trail_length; } else if (keypressedd (SDLK_9)) { if (!mouse_slider0.active) --MENU.sp_change_drone_handle_size; } else if (keypressedd (SDLK_0)) { if (!mouse_slider0.active) ++MENU.sp_change_drone_handle_size; } else if (keypressed (SDLK_INSERT)) { dinfo.dist.vol = !dinfo.dist.vol; MENU.cb_vol_dis.set_state (dinfo.dist.vol); } else if (keypressed (SDLK_DELETE)) { dinfo.dist.pitch = !dinfo.dist.pitch; MENU.cb_pitch_dis.set_state (dinfo.dist.pitch); } /*else if (keypressedd (SDLK_INSERT, reptf, repts)){ if (SHIFT) ++inter_butt; else if (CTRL) ring.r += 10; else ++butt; } else if (keypressedd (SDLK_DELETE, reptf, repts)) { if (SHIFT) --inter_butt; else if (CTRL) ring.r -= 10; else --butt; if (inter_butt < 0) inter_butt = 0; if (butt < 0) butt = 0; if (ring.r < 0) ring.r = 0; }*/ return 1; } #ifdef __SVG__ void din::write_trail () { dlog << "" << endl; for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; ds.trail.write (); } dlog << "" << endl; } #endif void din::change_drone_lifetime (spinner& s) { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; ds.life += s (); if (ds.life < 0) ds.life = 0; cons << GREEN << "Drone: " << i << ", lifetime = " << ds.life << " secs" << eol; } } else { cons << RED_PSD << eol; } } void din::change_orbit_insertion_time (spinner& s) { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; if (ds.launcher) { ds.insert += s (); if (ds.insert < 0) ds.insert = 0; cons << "Drone: " << i << ", orbit insertion time = " << ds.insert << " secs" << eol; } } } else { cons << RED_PSD << eol; } } void din::change_drone_trail_points (spinner& s) { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; ds.trail.change (s()); cons << GREEN << "Drone: " << i << ", trail points = " << ds.trail.total << eol; } } else cons << RED_PSD << eol; } void din::change_drone_handle_size (spinner& s) { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; ds.handle_size += s(); if (ds.handle_size < 0) ds.handle_size = 0; else cons << GREEN << "Drone " << i << ", handle size = " << ds.handle_size << eol; } update_drone_anchors (); } else cons << RED_PSD << eol; } /*void din::change_drone_label_offset (int w, int sz) { rnd rd (-1.0f, +1.0f); if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; float* xy [2] = {&ds.lbloff.x, &ds.lbloff.y}; *xy[w] += (sz + rd()); } } else cons << RED_PSD << eol; }*/ void din::change_drone_arrow (spinner& s, int w) { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; drone::arrowt& ar = ds.arrow; float* wa [] = {&ar.u, &ar.v, &ar.t}; *wa[w] += s (); } } else cons << RED_PSD << eol; } void din::capdronearrows (int c) { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; ds.arrow.cap = c; } } else cons << RED_PSD << eol; } void din::scroll (int dx, int dy, int warp_mouse) { mousex -= dx; prev_mousex -= dx; mousey += dy; prev_mousey += dy; win (win.left + dx, win.bottom + dy, win.right + dx, win.top + dy); find_visible_ranges (dx); if (warp_mouse) { if ((mousex > 0 && mousex < view.width) && (mousey > 0 && mousey < view.height)) SDL_WarpMouse (mousex, mousey); dinfo.gravity.forcetrack = 1; } dinfo.gravity.ldwx = dinfo.gravity.ldwy = -1; // see din::evalgravity () } void din::find_current_range () { // find the range where mouse is found if (win_mousex <= ranges[0].extents.left) current_range = 0; else if (win_mousex >= ranges[last_range].extents.right) current_range = last_range; else for (int i = 0; i < num_ranges; ++i) { range& curr = ranges[i]; box& ext = curr.extents; if ( (win_mousex >= ext.left) && (win_mousex <= ext.right)) { current_range = i; break; } } find_visible_ranges (); } void din::find_visible_ranges (int dir) { // we only draw visible ranges if (dir > 0) { while ((visr < last_range) && (ranges[visr].extents.right < win.right)) ++visr; while ((visl < last_range) && (ranges[visl].extents.right < win.left)) ++visl; } else if (dir < 0) { while ((visl > 0) && (ranges[visl].extents.left > win.left)) --visl; while ((visr > 0) && (ranges[visr].extents.left > win.right)) --visr; } else { visl = current_range; visr = current_range; while ( (visl > 0) && (win.left < ranges[visl].extents.left) ) --visl; while ( (visr < last_range) && (ranges[visr].extents.right < win.right) ) ++visr; } } int din::find_range (float x, int r) { while (1) { range& curr = ranges [r]; float deltax = x - curr.extents.left; if (deltax > curr.extents.width) { if (++r < num_ranges); else { r = last_range; break; // drone in last range } } else if (deltax < 0) { if (--r < 0) { r = 0; // drone in first range break; } } else break; // drone in current range } return r; } int din::find_tone_and_volume () { // locate current tone range* curr = &ranges [current_range]; int deltax = tonex - curr->extents.left; if (deltax >= curr->extents.width) { // tone in range to the right ++current_range; if (current_range == num_ranges) { // snap to last range current_range = last_range; curr = lastr; } else { curr = &ranges [current_range]; } } else if (deltax < 0) { // tone in range to the left --current_range; if (current_range < 0) { // snap to first range curr = firstr; current_range = 0; } else { curr = &ranges [current_range]; } } // located tone so find frequency // deltax = tonex - curr->extents.left; delta = warp_pitch (deltax * curr->extents.width_1); step = curr->notes[0].step + delta * curr->delta_step; // step determines frequency see note.h // find VOLUME static const int if_uniq = 1; int dv = toney - BOTTOM; float iv = dv * 1.0f / ranges[current_range].extents.height; float fin_vol = 1.0f; if (dv < 0) { // below keyboard, silence voice fin_vol = 0.0f; wavplay.set_interpolated_pitch_volume (step, fin_vol, if_uniq); am_vol = 0; VOLUME = -warp_vol (-iv); } else { VOLUME = warp_vol (iv); float fdr_vol = uis.fdr_voice.amount * VOLUME; fin_vol = fdr_vol * VOICE_VOLUME; wavplay.set_interpolated_pitch_volume (step, fin_vol, if_uniq); am_vol = fdr_vol * am_depth; } if (dinfo.voice_is_voice == 0) { nsr.set_spread (fin_vol); nsr.set_samples (1.0f / step); } Tcl_UpdateLinkedVar (interpreter.interp, "volume"); // VOLUME is accessible in Tcl interpreter as variable volume if (dinfo.show_pitch_volume.board) { sprintf (BUFFER, "%0.3f @ %03d%%", (step * SAMPLE_RATE), int(VOLUME * 100)); pitch_volume_info = BUFFER; } return 1; } void din::draw () { glMatrixMode (GL_PROJECTION); glLoadIdentity (); glOrtho (win.left, win.right, win.bottom, win.top, -1, 1); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); draw_drones (); // draw drones if (UI_OFF == 0) { if (dinfo.dist.vol) draw_vol_dist (); if (dinfo.dist.pitch) draw_pitch_dist (); // mark selected range? if (dinfo.mark_sel_range && (dinfo.sel_range >= visl && dinfo.sel_range <= visr)) { range& cr = ranges[dinfo.sel_range]; box& cre = cr.extents; glLineWidth (3); glEnable (GL_LINE_STIPPLE); glLineStipple (1, 0xf0f0); glColor3f (0.5f, 0.75f, 1.0f); gl_pts[0]=cre.left; gl_pts[1]=cre.bottom; gl_pts[2]=cre.right; gl_pts[3]=cre.bottom; gl_pts[4]=cre.right; gl_pts[5]=cre.top; gl_pts[6]=cre.left; gl_pts[7]=cre.top; glVertexPointer (2, GL_INT, 0, gl_pts); glDrawArrays (GL_LINE_LOOP, 0, 4); glLineWidth (1); glDisable (GL_LINE_STIPPLE); } // label visible ranges for (int i = visl; i < visr; ++i) ranges[i].draw_labels (range::LEFT, dinfo.show_pitch_volume.board); ranges[visr].draw_labels (range::BOTH, dinfo.show_pitch_volume.board); // phrasor markers phrasor0.draw (); // draw cursor info int cursorx = tonex + 8, cursory = toney; if (dinfo.show_pitch_volume.board && !basic_editor::hide_cursor) { glColor3f (0.9f, 0.9f, 1.0f); draw_string (pitch_volume_info, cursorx, cursory); if (rising || falling) { cursory += line_height; draw_string (num_drones_info, cursorx, cursory); } } // drones xform center dinfo.cen.draw (); // draw guide for positioning drones if (dinfo.voice == 0) { glColor3f (0.25, 0.25, 0.25); gl_pts[0]=tonex;gl_pts[1]=toney; gl_pts[2]=tonex;gl_pts[3]=BOTTOM; glVertexPointer (2, GL_INT, 0, gl_pts); glDrawArrays (GL_LINES, 0, 2); } // draw selector mkb_selector.draw (rgn); } } void din::enter () { if (phrasor0.state == phrasor::playing) return; else { ui::enter (); win_mousex = win.left + mousex; win_mousey = win.bottom + mouseyy; } } void din::window_resized (int w, int h) { clear_all_phrases (); win (win.left, win.bottom, win.left + w, win.bottom + h); warp_mouse (prev_mousex, prev_mousey); dinfo.gravity.forcetrack = 1; win_mousex = win.left + mousex; win_mousey = win.bottom + mouseyy; find_current_range (); } void din::change_depth (int i, float d) { if (i == 1) { fm_depth += d; hz2step (fm_depth, fm_step); cons << YELLOW << "Voice FM depth = " << fm_depth << eol; MENU.sp_fm_depth.set_value (fm_depth); } else { am_depth += d; cons << YELLOW << "Voice AM depth = " << am_depth << eol; MENU.sp_am_depth.set_value (am_depth); } } void din::change_bpm (beat2value& which, float amt) { float bpm = which.bpm + amt; bpm = which.set_bpm (bpm); cons << YELLOW << which.name << " bpm: " << bpm << eol; MENU.update_bpm (which.name, bpm); } int din::calc_am_fm_gater () { int ret = 0; memcpy (aout.bufL, wavplay.pvol, aout.samples_channel_size); multiply (aout.bufL, aout.samples_per_channel, am_depth); ret += am.modulate_and_mix (aout.ams, aout.mix, aout.mixa, aout.samples_per_channel, aout.bufL); ret += fm.modulate_and_mix (aout.fms, aout.mix, aout.mixa, aout.samples_per_channel, fm_step); ret += gatr.gen_and_mix (aout.gatr, aout.mix, aout.mixa, aout.samples_per_channel); return ret; } void din::modulate_drones () { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); if (di.frozen == 0) { modulator& dm = di.mod; dm.calc (); di.autorot.calc (dm.dt); // AM along a direction vector, FM along a direction vector float x = di.cx + dm.fm.result * (*dm.fm.dirx) + dm.am.result * (*dm.am.dirx); float y = di.cy + dm.fm.result * (*dm.fm.diry) + dm.am.result * (*dm.am.diry); if (di.autorot.v.yes) rotate_vector (di.vx, di.vy, di.autorot.v.angle.theta); if (di.autorot.a.yes) rotate_vector (di.ax, di.ay, di.autorot.a.angle.theta); di.set_pos (x, y); // di.set_pos (di.cx + dm.fm.result, di.cy + dm.am.result); } } } void din::setvelaccel (int w, int id, int neg) { if (num_selected_drones) { float xx[5], yy[5]; int negs[2] = {1, -1}; xx[0] = 0; xx[1] = 1; yy[0] = 1; yy[1] = 0; xx[4] = 0; yy[4] = 0; for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; xx[2]=ds.vx; yy[2]=ds.vy; xx[3]=ds.ax; yy[3]=ds.ay; float* wx[2] = {&ds.vx, &ds.ax}; float* wy[2] = {&ds.vy, &ds.ay}; float* aft [2] = {&ds.autorot.v.autoflip.total, &ds.autorot.a.autoflip.total}; alarm_t* art [2] = {&ds.autorot.v.tik, &ds.autorot.a.tik}; int negg = negs[neg]; float xxx = negg * xx[id]; float yyy = negg * yy[id]; if (w == 2) { ds.vx = ds.ax = xxx; ds.vy = ds.ay = yyy; ds.autorot.v.autoflip.total = ds.autorot.a.autoflip.total = 0.0f; ds.autorot.v.tik.start (); ds.autorot.a.tik.start (); } else { *wx[w] = xxx; *wy[w] = yyy; *aft[w] = 0.0f; art[w]->start (); } } } else cons << RED_PSD << eol; } void din::setmoddir (int w, int id) { if (num_selected_drones) { const char* dirs [] = {"Vertical", "Horizontal", "Velocity", "Acceleration"}; const char* whats [] = {"AM", "FM"}; for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; mod_params* modp [] = {&ds.mod.am, &ds.mod.fm}; mod_params* modpw = modp[w]; modpw->id = id; modpw->calcdir (ds); } cons << "Set " << whats[w] << " direction of " << num_selected_drones << " drones to " << dirs[id] << eol; } else cons << RED_PSD << eol; } void din::setautorot (int what, int state, int tog) { if (what == menu::autorott::BOTH) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; int amst [] = {state, !ds.autorot.v.yes}; int fmst [] = {state, !ds.autorot.a.yes}; ds.autorot.v.yes = amst[tog]; ds.autorot.a.yes = fmst[tog]; } } else { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; int& yes = ds.autorot.arr[what]->yes; int states[] = {state, !yes}; yes = states[tog]; } } TOGGLEMENU } void din::setautoflip (int what, int state, int tog) { if (num_selected_drones) { if (what == menu::autorott::BOTH) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; int amst [] = {state, !ds.autorot.v.autoflip.yes}; int fmst [] = {state, !ds.autorot.a.autoflip.yes}; ds.autorot.v.autoflip.yes = amst[tog]; ds.autorot.a.autoflip.yes = fmst[tog]; ds.autorot.v.autoflip.total = 0.0f; ds.autorot.a.autoflip.total = 0.0f; } } else { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; autoflipt& af = ds.autorot.arr[what]->autoflip; af.total = 0.0f; int& yes = af.yes; int states[] = {state, !yes}; yes = states[tog]; } } TOGGLEMENU } else cons << RED_PSD << eol; } void din::setautorotparam (int which, int what) { if (which == menu::autorott::BOTH) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; autorotator &var = ds.autorot.v, &aar = ds.autorot.a; var.yes = aar.yes = 1; if (what == menu::autorott::RPM) { var.mov = aar.mov = autorotator::SMOOTH; var.set_rpm (ds.autorot.v.rpm + MENU.autorotate.rpm()); aar.set_rpm (ds.autorot.a.rpm + MENU.autorotate.rpm()); cons << "Drone : " << i << " Velocity RPM = " << var.rpm << " Acceleration RPM = " << aar.rpm << eol; } else if (what == menu::autorott::DEG) { var.mov = aar.mov = autorotator::TICK; var.chgdeg (MENU.autorotate.deg()); aar.chgdeg (MENU.autorotate.deg()); cons << "Drone : " << i << " Velocity Degrees / Second = " << var.deg << ", Acceleration Degrees / Second = " << aar.deg << eol; } else if (what == menu::autorott::TPS) { var.mov = aar.mov = autorotator::TICK; var.chgtps (MENU.autorotate.tps()); aar.chgtps (MENU.autorotate.tps()); cons << "Drone : " << i << " Velocity Ticks / Second = " << var.tps << ", Acceleration Ticks / Second = " << aar.tps << eol; } else { var.mov = aar.mov = MENU.autorotate.mov.id; if (MENU.autorotate.mov.id == autorotator::SMOOTH) { var.set_rpm (var.rpm); aar.set_rpm (aar.rpm); } else { var.settps (var.tps); var.setdeg (var.deg); aar.settps (aar.tps); aar.setdeg (aar.deg); } } } } else { const char* strs[2] = {" Velocity", " Acceleration"}; for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; autorotator& ar = *ds.autorot.arr[which]; ar.yes = 1; if (what == menu::autorott::RPM) { ar.mov = autorotator::SMOOTH; ar.set_rpm (ar.rpm + MENU.autorotate.rpm()); cons << "Drone : " << i << strs[which] << " RPM = " << ar.rpm << eol; } else if (what == menu::autorott::DEG) { ar.mov = autorotator::TICK; ar.chgdeg (MENU.autorotate.deg()); cons << "Drone : " << i << strs[which] << " Degrees / Second = " << ar.deg << spc << ", Ticks / Second = " << ar.tps << eol; } else if (what == menu::autorott::TPS) { ar.mov = autorotator::TICK; ar.chgtps (MENU.autorotate.tps()); cons << "Drone : " << i << strs[which] << " Degrees / Second = " << ar.deg << spc << ", Ticks / Second = " << ar.tps << eol; } else { ar.mov = MENU.autorotate.mov.id; if (MENU.autorotate.mov.id == autorotator::SMOOTH) { ar.set_rpm (ar.rpm); } else { ar.settps (ar.tps); ar.setdeg (ar.deg); } } } } } void din::setautorotdir (int what, int dir) { if (num_selected_drones) { if (what == menu::autorott::BOTH) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; ds.autorot.v.dir = dir; ds.autorot.a.dir = dir; } } else { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; ds.autorot.arr[what]->dir = dir; } } TOGGLEMENU } else cons << RED_PSD << eol; } void din::setautoflipangle (int what) { if (what == menu::autorott::BOTH) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; autoflipt &amaf = ds.autorot.v.autoflip, &fmaf = ds.autorot.a.autoflip; amaf.total = fmaf.total = 0.0f; amaf.set (amaf.angle.deg + MENU.autorotate.autoflip.angle()); fmaf.set (fmaf.angle.deg + MENU.autorotate.autoflip.angle()); cons << "Drone : " << i << " Velocity Auto flip angle = " << amaf.angle.deg << " Acceleration Auto flip angle = " << fmaf.angle.deg << eol; } } else { const char* strs[2] = {" Velocity", " Acceleration"}; for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; autoflipt& af = ds.autorot.arr[what]->autoflip; af.total = 0.0f; af.set (af.angle.deg + MENU.autorotate.autoflip.angle()); cons << "Drone : " << i << strs[what] << " Auto flip angle = " << af.angle.deg << eol; } } } int din::render_audio (float* out0, float* out1) { int ret = 0; ret = calc_am_fm_gater (); // compute voice AM & FM & gater over bpm find_tone_and_volume (); float *lout = out0, *rout = out1; if (dinfo.voice_is_voice) { wavplay.gen_wav_fm_am_mix (lout, aout.samples_per_channel); ret += wavplay.mixer.active; } else { // voice is noise nsr (lout, rout, aout.samples_per_channel, 1.0f); ret = 1; } // gater on voice lout = out0; rout = out1; if (uis.fdr_gater.on) { memcpy (aout.result, lout, aout.samples_channel_size); // voice multiply (lout, aout.gatr, aout.samples_per_channel); // voice * gater fill (aout.bufR, fdr_gater_prev_amount, uis.fdr_gater.amount, aout.samples_per_channel); fdr_gater_prev_amount = uis.fdr_gater.amount; tween (lout, aout.result, aout.samples_per_channel, aout.bufR); // voice > voice*gater } else { if (dinfo.gater) multiply (lout, aout.gatr, aout.samples_per_channel); // voice * gater } memcpy (rout, lout, aout.samples_channel_size); // copy left -> right // render drones for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); float* lout = out0, *rout = out1; if (di.update_pv) di.update_pitch_volume (); if (di.is == drone::DRONE) { play& dp = di.player; dp.master (lout, rout, aout.result, aout.samples_per_channel, dp.pvol); ret += dp.mixer.active; } else { di.nsr (lout, rout, aout.samples_per_channel, di.fdr.amount * di.gab.amount * drone::mastervolume); } } return ret; } void din::rise_drones () { if (rising) { for (drone_iterator i = risers.begin(), j = risers.end (); i != j;) { drone* pdi = *i; drone& di = *pdi; di.fdr.eval (); if (di.fdr.reached) { di.state = drone::ACTIVE; di.update_pv = drone::EMPLACE; i = risers.erase (i); j = risers.end (); --rising; } else { di.update_pv = drone::INTERPOLATE; ++i; } } } } void din::fall_drones () { if (falling) { for (drone_iterator i = fallers.begin(), j = fallers.end (); i != j;) { drone* pdi = *i; drone& di = *pdi; if (!di.frozen) { di.fdr.eval (); if (di.fdr.reached) { i = fallers.erase (i); j = fallers.end (); --falling; if (pdi->reincarnate) { di.life = MENU.lifetime(); di.state = drone::RISING; risers.push_back (pdi); ++rising; di.fdr.set (0.0f, 1.0f, 1, MENU.riset()); di.birth = ui_clk (); } else { remove_attractee (pdi); remove_tracker (pdi); if (dinfo.gravity.tracked_drone == pdi) dinfo.gravity.tracked_drone = 0; if (di.launcher) erase (launchers, pdi); if (di.attractor) { erase (attractors, pdi); list& lae = di.attractees; for (list::iterator iter = lae.begin (), jter = lae.end(); iter != jter; ++iter) { attractee& ae = *iter; drone& de = *ae.d; de.orbiting = 0; } } if (di.gravity) { erase (gravitated, pdi); erase (satellites, pdi); } remove_drone_from_targets (pdi); remove_drone_from_selection (pdi); remove_drone_from_pre_mesh (pdi); remove_drone_from_mesh (pdi); remove_connections (pdi); remove_from_groups (pdi); if (ec == pdi) ec = 0; gab.erase (pdi); --num_drones; print_num_drones (); if (num_drones == 0) prep_modulate (MODULATE_VOICE); if (pdi->chuck.yes) pdi->chuck.de (); erase (drones, pdi); delete pdi; } } else { ++i; di.update_pv = drone::INTERPOLATE; } } else ++i; } } } void din::height_changed (int r, int dh) { if (r == -1) { for (int i = 0; i < num_ranges; ++i) ranges[i].change_height (dh); refresh_all_drones (); } else { ranges[r].change_height (dh); refresh_drones (r); } } void din::toggle_this (int& what, checkbutton& cb) { what = !what; cb.set_state (what); } void din::switch_modulation () { // switch modulation target static const char* swhat [] = {"Modulating drones", "Modulating voice"}; modulate_what = !modulate_what; prep_modulate (modulate_what); cons << YELLOW << swhat[modulate_what] << eol; } void din::prep_modulate (int op) { modulate_what = op; delta_t* pdt [] = {&dam_delta, &am_delta}; p_am_delta = pdt [modulate_what]; MENU.init_modulation (); } void din::change__bpm (int type, beat2value& bv2, float amount) { if (modulate_what == MODULATE_DRONES) change_drone_bpm (type, amount); else change_bpm (bv2, amount); } void din::change__depth (int drone_arg1, float amount1, int voice_arg2, float amount2) { if (modulate_what == MODULATE_DRONES) change_drone_depth (drone_arg1, amount1); else change_depth (voice_arg2, amount2); } void din::change_am_depth (float d) { change__depth (modulator::AM, d, 0, d); } void din::change_fm_depth (float d) { change__depth (modulator::FM, d, 1, d); } void din::change_am_bpm (float d) { change__bpm (modulator::AM, am, d); } void din::change_fm_bpm (float d) { change__bpm (modulator::FM, fm, d); } void din::change_drone_depth (int what, float delta) { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; ds.change_depth (i, what, delta); } } else cons << RED_PSD << eol; } void din::change_drone_bpm (int what, float delta) { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; ds.change_bpm (i, what, delta); } } else cons << RED_PSD << eol; } void din::change_drone_depth (int what, spinner& s) { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; float dv = s (); ds.change_depth (i, what, dv); } } else cons << RED_PSD << eol; } void din::change_drone_bpm (int what, spinner& s) { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; float dv = s (); ds.change_bpm (i, what, dv); } } else cons << RED_PSD << eol; } void din::toggle_adding_drones () { adding = !adding; if (adding) { cons << GREEN << "Click to add drones. ESC to stop" << eol; } else { cons << RED << "Stopped adding drones!" << eol; uis.add (this, &mkb_selector); } } void din::start_moving_drones () { if (num_selected_drones) set_moving_drones (1); else cons << RED_PSD << eol; } void din::toggle_moving_drones () { if (moving_drones == 0) { start_moving_drones (); } else set_moving_drones (0); } void din::set_moving_drones (int md) { moving_drones = md; if (moving_drones) cons << GREEN << "Just move mouse to move drones, ESC or Click to stop!" << eol; else cons << YELLOW << "@ " << name << eol; } int din::finish_phrase_recording () { if (phrasor0.state == phrasor::recording) { if (phrasor0.validate ()) { phrasor0.play (); cons << GREEN << "Phrasor has stopped recording and started playing!" << eol; return 1; } } return 0; } void din::do_phrase_recording () { if (!finish_phrase_recording()) { phrasor0.clear (); phrasor0.state = phrasor::recording; cons << GREEN << "Phrasor is recording. Click or press f to finish!" << eol; } } void din::clear_all_phrases () { if (phrasor0.size != 0) { phrasor0.clear (); if (MENU.show == 0) find_current_range (); MENU.s_phrase_position.set_val (0); wanding = 0; cons << RED << "Phrase cleared!" << eol; } } void din::set_key_to_pitch_at_cursor () { float hz = step * SAMPLE_RATE; set_tonic (this, hz); } void din::change_drone_accel (spinner& s) { if (num_selected_drones) { cons << YELLOW; int gt0 = MENU.accelgt0.state; for (int i = 0; i < num_selected_drones; ++i) { drone& di = *selected_drones[i]; di.A += s (); if (gt0) {if (di.A < 0.0f) di.A = 0.0f;} cons << "Drone: " << i << ", Acceleration = " << di.A << eol; } } else cons << RED_PSD << eol; } void din::change_drone_vel (spinner& s) { if (num_selected_drones) { cons << YELLOW; int gt0 = MENU.velgt0.state; for (int i = 0; i < num_selected_drones; ++i) { drone& di = *selected_drones[i]; di.V += s (); if (gt0) {if (di.V < 0.0f) di.V = 0.0f;} cons << "Drone: " << i << ", Velocity = " << di.V << eol; } } else cons << RED_PSD << eol; } void din::rotate_drone_vel (spinner& s) { if (num_selected_drones) { cons << YELLOW; for (int i = 0; i < num_selected_drones; ++i) { drone& di = *selected_drones[i]; float deg = -s(), rad = deg * PI_BY_180; rotate_vector (di.vx, di.vy, rad); cons << "Drone: " << i << ", Rotated Velocity by " << deg << " degrees." << eol; } } else cons << RED_PSD << eol; } void din::calc_xform_vectors (vector >& V, int n) { V.resize (n); for (int i = 0; i < n; ++i) { drone& di = *selected_drones [i]; point& vv = V[i]; if (di.chuck.yes && di.chuck.sun) { direction (vv.x, vv.y, di.chuck.sun->cx, di.chuck.sun->cy, di.cx, di.cy); } else direction (vv.x, vv.y, dinfo.cen.x, dinfo.cen.y, di.cx, di.cy); } } void din::calc_xform_vectors () { if (xforming == SCALE) calc_xform_vectors (svec, num_selected_drones); else if (xforming == ROTATE) calc_xform_vectors (rvec, num_selected_drones); } void din::resize_xform_vectors () { if (xforming == SCALE) svec.resize (num_selected_drones); else rvec.resize (num_selected_drones); } void din::calc_drones_centroid () { startagain: if (num_selected_drones) { dinfo.cen.x = dinfo.cen.y = 0.0f; for (int i = 0; i < num_selected_drones; ++i) { drone& di = *selected_drones [i]; dinfo.cen.x += di.cx; dinfo.cen.y += di.cy; } dinfo.cen.x /= num_selected_drones; dinfo.cen.y /= num_selected_drones; } else { select_all_drones (); if (num_selected_drones) goto startagain; else cons << RED_PSD << eol; } } int din::prep_scale_drones () { int n = num_selected_drones; if (n) { calc_xform_vectors (svec, n); scl = 1.0f; xforming = SCALE; return n; } return 0; } int din::prep_rotate_drones () { int n = num_selected_drones; if (n) { calc_xform_vectors (rvec, n); angle = 0.0f; xforming = ROTATE; return n; } return 0; } void din::rotate_drones () { float dx, dy, cx, cy; for (int i = 0; i < num_selected_drones; ++i) { drone& di = *selected_drones[i]; point rv = rvec[i]; rotate_vector (rv.x, rv.y, angle); if (!di.chuck.yes) { cx = dinfo.cen.x; cy = dinfo.cen.y; dx = cx + rv.x; dy = cy + rv.y; di.set_center (dx, dy); } else cons << RED << "Wont rotate chucked drone!" << eol; /*if (di.chuck.yes && di.chuck.sun) { cx = di.chuck.sun->cx; cy = di.chuck.sun->cy; di.chuck.len = unit_vector (di.chuck.ux, di.chuck.uy, rv.x, rv.y); dx = cx + rv.x; dy = cy + rv.y; di.set_center (dx, dy); if (di.chuck.sat) di.chuck.sat->chuck.re (*di.chuck.sat); } else { cx = dinfo.cen.x; cy = dinfo.cen.y; dx = cx + rv.x; dy = cy + rv.y; di.set_center (dx, dy); }*/ } } void din::scale_drones () { list rm; int nrm = 0; for (int i = 0; i < num_selected_drones; ++i) { drone* pdi = selected_drones[i]; drone& di = *pdi; if (!di.chuck.yes) { point sv = svec[i]; sv *= scl; di.set_center (dinfo.cen.x + sv.x, dinfo.cen.y + sv.y, 0); if (di.nconn) { rm.push_back (pdi); for (drone_iterator p = di.connections.begin (), q = di.connections.end (); p != q; ++p) rm.push_back (*p); nrm = nrm + di.nconn + 1; } } else cons << RED << "Wont scale chucked drone!" << eol; } if (nrm) for (drone_iterator p = rm.begin (), q = rm.end (); p != q; ++p) (*p)->remagconns (); } void din::scale_drones (float ds) { if (CTRL) scl.x += ds; else if (SHIFT) scl.y += ds; else scl += ds; } void din::change_drones_per_min (spinner& s) { if (num_selected_drones) { cons << YELLOW; float dpm; for (int i = 0; i < num_selected_drones; ++i) { drone* pds = selected_drones[i]; drone& ds = *pds; dpm = ds.dpm + s (); if (dpm > 0.0f) { ds.dpm = dpm; ds.launch_every.triggert = 60.0 / ds.dpm; } cons << "Drone: " << i << ", drones per minute = " << ds.dpm << eol; } } else cons << RED_PSD << eol; } void din::select_attractees () { // select the attractees of the selected drones or all drones if (num_selected_drones == 0) { if (num_drones) { select_all_drones (); } else { cons << RED << "No drones, so no attractees" << eol; return; } } vector new_selected_drones; for (int i = 0; i < num_selected_drones; ++i) { drone& di = *selected_drones[i]; if (di.attractor) { list& lae = di.attractees; for (list::iterator iter = lae.begin (), jter = lae.end(); iter != jter; ++iter) { attractee& ae = *iter; new_selected_drones.push_back (ae.d); } } } int ns = new_selected_drones.size (); if (ns) { CLEAR_SELECTED_DRONES for (int i = 0; i < ns; ++i) { drone* pd = new_selected_drones[i]; add_drone_to_selection (pd); } print_selected_drones (); } else { cons << RED << "Sorry, no attractees found!" << eol; } } void din::select_attractors () { // select the attractors of selected drones if (num_selected_drones) { vector selv (selected_drones); int q = num_selected_drones; CLEAR_SELECTED_DRONES for (drone_iterator i = attractors.begin(), j = attractors.end(); i != j; ++i) { drone* pdi = *i; drone& di = *pdi; list& lae = di.attractees; for (list::iterator iter = lae.begin (), jter = lae.end(); iter != jter; ++iter) { attractee& ae = *iter; for (int p = 0; p < q; ++p) { drone* sd = selv [p]; if (sd == ae.d) { add_drone_to_selection (pdi); goto next_attractor; } } } next_attractor: ; } } else { for (drone_iterator i = attractors.begin(), j = attractors.end(); i != j; ++i) { drone* pdi = *i; pdi->sel = 1; selected_drones.push_back (pdi); } } print_selected_drones (); } void din::trail_drones () { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); di.trail.add (di.sx, di.y); } } void din::toggle_create_this () { if (dinfo.create_this) { toggle_create_drone_pendulum (); } else { toggle_create_mesh (); } } void din::toggle_create_drone_pendulum () { if (create_drone_pend) ; else { cons << GREEN << "Click and drag a box to make a drone pendulum, ESC to cancel" << eol; create_drone_pend = 1; } } void din::toggle_create_mesh () { if (amd.active) { cons << RED << "Already making a mesh, please wait for it to finish :)" << eol; return; } if (meshh.create) { create_drone_mesh (); meshh.create = 0; } else { cons << GREEN << "Click and drag a box to preview drone mesh, ESC to cancel" << eol; meshh.create = 1; } } void din::stop_creating_mesh () { meshh.create = 0; mkb_selector.mesh = 0; cons << RED << "Stopped creating mesh" << eol; } void din::stop_creating_drone_pendulum () { create_drone_pend = 0; cons << RED << "Stopped making drone pendulum" << eol; } void din::bg () { drone::proc_conn.clear (); if (ec && !xforming) ec = ec->eval_conns (); if (phrasor0.state == phrasor::playing) { phrasor0.get (tonex, toney); phrasor0.next (); } if (wanding) { if ((wand.x != tonex) || (wand.y != toney)) { if (magnitude2 (wand.x, wand.y, tonex, toney) >= drone::wand.dist2) { wand.x = tonex; wand.y = toney; /*if (CTRL) { if (wand0.x == -1) { wand0.y = wand.y; } wand.y = wand0.y; } else if (ALT) { if (wand0.y == -1) { wand0.x = wand.x; } wand.x = wand0.x; }*/ if (SHIFT) ; else add_drone (wand.x, wand.y); } } } if (amd.active && !amd.drop && amd (ui_clk())) { create_drone: if (amd.i < mkb_selector.rowcol) { amd.p = mkb_selector.order [amd.i]; int p = 2 * amd.p; int x = mkb_selector.meshp [p]; int y = mkb_selector.meshp [p + 1]; drone* d = add_drone (x, y); mkb_selector.meshd[amd.p] = d; if (dinfo.mesh_vars.apply_to.active) { float a = ((amd.i % dinfo.mesh_vars.dpp) + 1) * 1. / dinfo.mesh_vars.dpp; float bpm = a * dinfo.drone_pend.bpm; d->mod.active = 1; if (dinfo.mesh_vars.apply_to.am) d->mod.am.bv.set_bpm (bpm); if (dinfo.mesh_vars.apply_to.fm) d->mod.fm.bv.set_bpm (bpm); } if (!dinfo.seloncre) { d->sel = 1; selected_drones.push_back (d); } amd.i++; if (amd.triggert == 0.0) goto create_drone; } else { // assign drones to polygons of the mesh mesh a_mesh; a_mesh.r = rndr (); a_mesh.g = rndg (); a_mesh.b = rndb (); for (int i = 0, j = mkb_selector.rows - 1; i < j; ++i) { int ic = i * mkb_selector.cols; for (int k = 0, l = mkb_selector.cols - 1; k < l; ++k) { int d0i = ic + k, d1i = d0i + 1; int d2i = d0i + mkb_selector.cols, d3i = d2i + 1; drone* d0 = mkb_selector.get_mesh_drone(d0i), *d1 = mkb_selector.get_mesh_drone(d1i); drone* d2 = mkb_selector.get_mesh_drone(d2i), *d3 = mkb_selector.get_mesh_drone(d3i); a_mesh.add_poly (d0, d1, d3, d2); // each poly has 4 drones } } meshes.push_back (a_mesh); ++meshh.num; if (!dinfo.seloncre) print_selected_drones (); cons << GREEN << "Created a " << dinfo.rows << " x " << dinfo.cols << " drone mesh with " << mkb_selector.rowcol << " drones" << eol; amd.reset (); mkb_selector.clear (); } } else { if (amd.drop) { cons << RED << "Aborted drone mesh" << eol; amd.reset (); } } fall_drones (); rise_drones (); if (quit == DONT) launch_drones (); carry_satellites_to_orbit (); attract_drones (); track_drones (); evalgravity (); evalchuck (); modulate_drones (); move_drones_under_gravity (); trail_drones (); kill_old_drones (); modulate_ranges (); gab.eval (); } void din::drawchuck () { if (MENU.choutline.state) { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); drone* sat = di.chuck.sat; if (di.chuck.yes && sat) { glBegin (GL_LINES); glColor3f (di.r, di.g, di.b); glVertex2f (di.sx, di.y); glColor3f (sat->r, sat->g, sat->b); glVertex2f (sat->sx, sat->y); glEnd (); } } } } void din::evalchuck () { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); if (di.chuck.yes) { di.chuck.cx = di.cx; di.chuck.cy = di.cy; } } for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); if (di.chuck.yes && di.chuck.sun) { if (di.frozen) { 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); } else { rotate_vector (di.chuck.ux, di.chuck.uy, di.chuck.dir * di.chuck.speed * drone::chuckt::apt.rad); 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); } } } } void din::changechuckspeed (spinner& sp) { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& di = *selected_drones[i]; if (di.chuck.yes) { float& speed = di.chuck.speed; speed += sp (); if (speed < 0.0f) speed = 0.0f; cons << YELLOW << "Drone " << i << ", speed = " << speed << eol; RESETCHUCKTRAILS(di) } } } else { cons << RED_PSD << eol; } } void din::changechucklength (spinner& sp) { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& di = *selected_drones[i]; if (di.chuck.yes) { float& len = di.chuck.len; len += sp (); if (len < 0.0f) len = 0.0f; RESETCHUCKTRAILS(di) cons << YELLOW << "Drone " << i << ", length = " << len << eol; } } } else { cons << RED_PSD << eol; } } void din::flipchuckspeed () { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& di = *selected_drones[i]; if (di.chuck.yes) di.chuck.dir = -di.chuck.dir; RESETCHUCKTRAILS(di) } } else { cons << RED_PSD << eol; } } void din::togchuckspeed () { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& di = *selected_drones[i]; if (di.chuck.yes) swap (di.chuck.speed, di.chuck.speed0); RESETCHUCKTRAILS(di) } } else { cons << RED_PSD << eol; } } void din::resetchucktrails (drone& d) { d.trail.reset (); if (d.chuck.sat) resetchucktrails (*d.chuck.sat); } void din::resetallchucktrails () { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); if (di.chuck.yes) di.trail.reset (); } } void din::update_drone_pendulum (drone_pendulum_group& g) { float a = 0.0f, da = 1.0 / (g.n - 1); for (int i = 0, j = g.n; i < j; ++i) { drone* pd = g.drones[i]; drone& d = *pd; mod_params* mods [] = {&d.mod.am, &d.mod.fm}; mod_params& mod = *mods[g.orient]; mod.depth = warp_depth (a) * float (uis.dpeu.depth.f_value); mod.bv.set_bpm (warp_bpm (a)* float (uis.dpeu.bpm.f_value)); a += da; } } void din::update_drone_pendulums () { map updated; for (int i = 0, j = drone_pendulums.size (); i < j; ++i) { drone_pendulum_group* g = drone_pendulums[i]; drone_pendulum_group& gr = *g; for (int m = 0, n = num_selected_drones; m < n; ++m) { drone* ds = selected_drones[m]; if ((updated[g] == false) && gr.member (ds)) { updated[g] = true; update_drone_pendulum (gr); } } } } void din::remove_from_groups (drone* d) { for (vector::iterator i = drone_pendulums.begin (), j = drone_pendulums.end (); i < j;) { drone_pendulum_group& gi = *(*i); if (gi.remove (d)) { if (gi.n == 0) { i = drone_pendulums.erase (i); j = drone_pendulums.end (); } else ++i; } else ++i; } } void din::remove_drone_from_mesh (drone* pd) { if (meshh.num == 0) return; for (mesh_iterator i = meshes.begin (); i != meshes.end ();) { mesh& mi = *i; mi.remove_poly (pd); if (mi.num_polys == 0) { i = meshes.erase (i); --meshh.num; } else ++i; } } void din::remove_drone_from_pre_mesh (drone* d) { if (erase (mkb_selector.meshd, d)) amd.drop = 1; } drone* din::get_drone (int id) { // get drone given its unique id for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone* pd = *i; if (pd->id == id) return pd; } return 0; } void din::load_selected_drones (ifstream& f) { string ignore; int n; f >> ignore >> n; if (n) { int did; selected_drones.resize (n); for (int m = 0; m < n; ++m) { f >> did; drone* sd = get_drone (did); sd->sel = 1; selected_drones[m] = sd; } print_selected_drones (); } num_selected_drones = n; } void din::save_selected_drones (ofstream& f) { f << "selected_drones " << num_selected_drones << spc; if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone* pd = selected_drones[i]; f << pd->id << spc; } } f << endl; } void din::make_trackers () { if (num_selected_drones < 1) { cons << RED_A2D << eol; return; } else if (num_selected_drones == 1) { // toggle tracker drone* pd = selected_drones[0]; if (pd->tracking) { remove_tracker (pd); cons << GREEN << "Selected drone no longer tracks another drone" << eol; return; } cons << RED << "Drone is not tracking any other drone!" << eol; return; } int last = num_selected_drones - 1; drone* p_tracked_drone = selected_drones [last]; int nl = 0; for (int i = 0; i < last; ++i) { drone* pdi = selected_drones [i]; push_back (trackers, pdi); pdi->tracking = 1; pdi->tracked_drone = p_tracked_drone; ++nl; } if (nl) cons << GREEN << "Number of drones tracking another drone = " << nl << eol; } void din::track_drones () { for (drone_iterator i = trackers.begin (), j = trackers.end (); i != j; ++i) { drone* pdi = *i; drone& di = *pdi; drone& td = *di.tracked_drone; if (di.tracking == drone::POINT) { unit_vector (di.vx, di.vy, di.x, di.y, td.x, td.y); di.ax = di.vy; di.ay = -di.vx; } else { // USE di.vx = td.vx; di.vy = td.vy; di.ax = td.ax; di.ay = td.ay; } } } void din::evalgravity () { gravity_t& grav = dinfo.gravity; grav.modulate (); if (grav.mouse.state) { if (delta_mousex || delta_mousey || grav.forcetrack) grav.track (mousex, mouseyy); } else { if (grav.dron.state) { if (grav.tracked_drone) { int dwx = grav.tracked_drone->sx, dwy = grav.tracked_drone->y; // in window space if (dwx != grav.ldwx || dwy != grav.ldwy) { float xr = (dwx - win.left) * win.width_1; float yr = (dwy - win.bottom) * win.height_1; int dvx = (int) (xr * view.xmax); int dvy = (int) (yr * view.ymax); // in view space grav.track (dvx, dvy); grav.ldwx = dwx; grav.ldwy = dwy; } } else { if (num_selected_drones) { grav.tracked_drone = selected_drones[0]; } } } else { grav.tracked_drone = 0; } } } void din::select_tracked_drones () { CLEAR_SELECTED_DRONES for (drone_iterator i = trackers.begin (), j = trackers.end (); i != j; ++i) { drone* pdi = *i; drone* ptd = pdi->tracked_drone; if (ptd->sel == 0) { ptd->sel = 1; selected_drones.push_back (ptd); } } print_selected_drones (); } void din::remove_tracker (drone* ptd) { for (drone_iterator i = trackers.begin (), j = trackers.end (); i != j;) { drone* pdi = *i; drone& di = *pdi; if (pdi == ptd || di.tracked_drone == ptd) { di.tracking = 0; di.tracked_drone = 0; i = trackers.erase (i); j = trackers.end (); } else ++i; } } void din::sync_drones () { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; ds.player.x = ds.mod.am.bv.now = ds.mod.fm.bv.now = 0.0f; } } void din::toggle_freeze_drones () { if (num_selected_drones) { int nf = 0, nt = 0; for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; if (ds.frozen) nt += ds.thaw (); else nf += ds.freeze (); } cons << GREEN << "Froze " << nf << " drones, Thawed " << nt << s_drones << eol; } } int din::freeze_drones () { if (num_selected_drones) { int nf = 0; for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; nf += ds.freeze (); } cons << GREEN << "Froze " << nf << s_drones << eol; return nf; } else cons << RED_PSD << eol; return 0; } int din::thaw_drones () { if (num_selected_drones) { int nt = 0; for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; if (ds.thaw ()) ++nt; } cons << GREEN << "Thawed " << nt << s_drones << eol; return nt; } else cons << RED_PSD << eol; return 0; } int din::freeze_orbiters () { if (num_selected_drones) { int nf = 0; for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; if (ds.orbiting) nf += ds.freeze (); } return nf; } return 0; } int din::thaw_orbiters () { xforming = NONE; if (num_selected_drones) { int nt = 0; for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; if (ds.orbiting) nt += ds.thaw (); } return nt; } return 0; } void din::lower_delta (float& d, float v, const string& mesg, float minn) { d += v; if (d < minn) d = minn; cons << YELLOW << mesg << d << eol; } void din::raise_delta (float& d, float v, const string& mesg) { d += v; cons << YELLOW << mesg << d << eol; } din::delta_t::delta_t (float _depth, float _bpm) { depth = _depth; bpm = _bpm; min_depth = 0.0f; } void din::region_begin () { rgn.left = rgn.right = win_mousex; rgn.bottom = rgn.top = win_mousey; if (meshh.create) mkb_selector.set_mesh (meshh.create, dinfo.rows, dinfo.cols); } const box& din::region_update () { rgn.right = win_mousex; rgn.top = win_mousey; if (mkb_selector.mesh) { int s = SHIFT, c = CTRL, sc = s|c; if (sc) { // equalise width/height float w = rgn.right - rgn.left, h = rgn.top - rgn.bottom; float aw = abs(w), ah = abs(h); if (s) { // equalise to smaller of width, height if (aw > ah) { float dw = aw - ah; int _ve = w < 0? 1:-1; rgn.right += (_ve * dw); } else { float dh = ah - aw; int _ve = h < 0? 1:-1; rgn.top += (_ve * dh); } } else { // equalise to larger of width, height if (aw > ah) { float dw = aw - ah; int _ve = h < 0? -1:1; rgn.top += (_ve * dw); } else { float dh = ah - aw; int _ve = w < 0? -1:1; rgn.right += (_ve * dh); } } } mkb_selector.gen_mesh_pts (rgn); } return rgn; } void din::region_end () { int swp = rgn.calc (); if (meshh.create) { if (swp) mkb_selector.gen_mesh_pts (rgn); create_drone_mesh (); meshh.create = 0; } else if (create_drone_pend) { create_drone_pendulum (); create_drone_pend = 0; } else find_selected_drones (rgn); } void din::region_abort () { if (meshh.create) stop_creating_mesh (); if (create_drone_pend) stop_creating_drone_pendulum (); } void din::modulate_ranges () { int nw, nw_2, center, nl, nr, dl, dr, z; nw = nw_2 = center = nl = nr = dl = dr = z = 0; for (int i = 0; i < num_ranges; ++i) { range& ri = ranges[i]; if (ri.mod.active > 0) { ri.mod.calc (); // width modulation nw = ri.mod.fm.initial + ri.mod.fm.result; switch (ri.fixed) { case range::LEFT: dr = nw - ri.extents.width; range_right_changed (i, dr, 0); break; case range::RIGHT: dl = ri.extents.width - nw; range_left_changed (i, dl, 0); break; default: nw_2 = nw / 2; center = (ri.extents.left + ri.extents.right) / 2; nl = center - nw_2, nr = center + nw_2; dl = nl - ri.extents.left; dr = nr - ri.extents.right; range_left_changed (i, dl, 0); range_right_changed (i, dr, 0); break; } // height modulation int nh = ri.mod.am.initial + ri.mod.am.result; if (nh < 1) nh = 1; ri.extents.top = BOTTOM + nh; ri.extents.calc (); z = 1; } } if (z) { refresh_all_drones (); find_visible_ranges (); } } void din::set_ran_mod (int w) { for (int i = 0; i < num_ranges; ++i) { range& ri = ranges[i]; ri.mod.active = w; } MENU.cb_mod_ran.set_state (ranges[dinfo.sel_range].mod.active, 0); } void din::pause_resume_ran_mod () { for (int i = 0; i < num_ranges; ++i) { range& ri = ranges[i]; ri.mod.active = -ri.mod.active; } } void din::toggle_ran_mod () { for (int i = 0; i < num_ranges; ++i) { range& ri = ranges[i]; ri.mod.active = !ri.mod.active; } MENU.cb_mod_ran.set_state (ranges[dinfo.sel_range].mod.active, 0); } void din::update_drone_mod_solvers (int w, multi_curve& mx) { if (w == modulator::AM) { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { modulator& dm = (*i)->mod; dm.am.bv.sol.update (); } } else { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { modulator& dm = (*i)->mod; dm.fm.bv.sol.update (); } } } void din::update_range_mod_solvers (int w, multi_curve& mx) { if (w == modulator::AM) { for (int i = 0; i < num_ranges; ++i) { modulator& rm = ranges[i].mod; rm.am.bv.sol.update (); // am for width } } else { for (int i = 0; i < num_ranges; ++i) { modulator& rm = ranges[i].mod; rm.fm.bv.sol.update (); // fm for height } } } void din::snap_drones (int v) { if (num_selected_drones) { int nt[2] = {0}; static const char* what_str1 [] = {"Unsnapped ", "Snapped "}; if (v == -1) { // toggle for (int i = 0; i < num_selected_drones; ++i) { drone* pdi = selected_drones[i]; pdi->snap = !pdi->snap; ++nt[pdi->snap]; } cons << "Snapped " << nt[1] << " drones, Unsnapped " << nt[0] << s_drones << eol; } else { // set for (int i = 0; i < num_selected_drones; ++i) { drone* pdi = selected_drones[i]; pdi->snap = v; } cons << GREEN << what_str1[v] << num_selected_drones << " drones" << eol; } } else { cons << RED_PSD << eol; } } void din::pos_afx_vel (int v) { int nm [2] = {0}; if (num_selected_drones) { if (v == -1) { // toggle for (int i = 0; i < num_selected_drones; ++i) { drone* pdi = selected_drones[i]; pdi->posafxvel.yes = !pdi->posafxvel.yes; ++nm[pdi->posafxvel.yes]; } cons << GREEN << "Position affects velocity for " << nm[1] << " drones, Unset for " << nm[0] << s_drones << eol; } else { // set for (int i = 0; i < num_selected_drones; ++i) { drone* pdi = selected_drones[i]; pdi->posafxvel.yes = v; } static const char* strs[] = {"Unset", "Set"}; cons << GREEN << strs[v] << " Position affects velocity for " << num_selected_drones << s_drones << eol; } } else { cons << RED_PSD << eol; } } void din::select_all_browsed_drones (int bd) { selected_drones.resize (num_browsed_drones); for (int i = 0; i < num_browsed_drones; ++i) { drone* pdb = browsed_drones[i]; pdb->sel = 1; selected_drones[i] = pdb; } print_selected_drones (); browsed_drone = bd; MENU.sp_browse_drone.set_value (browsed_drone); } void din::browse_drone (int db) { if (num_browsed_drones) { clear_selected_drones (); browsed_drone += db; if (browsed_drone > last_browseable_drone) { // select all browsed drones select_all_browsed_drones (-1); return; } else if (browsed_drone < 0) { select_all_browsed_drones (num_browsed_drones); return; } drone* pdb = browsed_drones [browsed_drone]; pdb->sel = 1; num_selected_drones = 1; selected_drones.resize (num_selected_drones); selected_drones[0] = pdb; sprintf (BUFFER, "Browsed drone %d of %d", browsed_drone+1, num_browsed_drones); cons << GREEN << BUFFER; drone::chuckt& chuck = pdb->chuck; if (chuck.yes) chuck.print (); cons << eol; MENU.sp_browse_drone.set_value (browsed_drone); } else { cons << RED << "No drones to browse, make a new selection" << eol; } } void din::browse_range (int dr) { dinfo.sel_range += dr; clamp (0, dinfo.sel_range, last_range); MENU.load_range (dinfo.sel_range); } void din::all_ranges_width_changed () { float a = 0.0f, da = 1.0f / last_range; extern solver sol_ran_width; int w = 0; float s = 0.0f; for (int i = 0; i < num_ranges; ++i) { s = sol_ran_width (a); w = s * WIDTH; if (w < 1) w = 1; set_range_width (i, w); a += da; } } void din::all_ranges_height_changed () { float a = 0.0f, da = 1.0f / last_range; extern solver sol_ran_height; int h = 0; float s = 0.0f; for (int i = 0; i < num_ranges; ++i) { s = sol_ran_height (a); h = s * HEIGHT; if (h < 1) h = 1; set_range_height (i, h); a += da; } } void din::draw_vol_dist () { glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); const float c = 1.0f, b = 0.9f; float yb, yt; int xl, xr; float a, da; float v, vc; for (int i = visl, j = visr + 1; i < j; ++i) { range& R = ranges[i]; const int dy = min (dinfo.dist.pix, R.extents.height); yb = R.extents.bottom; yt = R.extents.top; xl = R.extents.left; xr = R.extents.right; a = 0.0f; da = dy * R.extents.height_1; v = vc = 0.0f; glBegin (GL_QUAD_STRIP); while (yb < yt) { v = warp_vol (a); vc = v * c; glColor4f (vc, 0, vc, b); glVertex2f (xl, yb); glVertex2f (xr, yb); yb += dy; a += da; } a = 1.0f; v = warp_vol (a); vc = v * c; glColor4f (vc, 0, vc, b); glVertex2f (xl, yt); glVertex2f (xr, yt); glEnd (); } glDisable (GL_BLEND); } void din::draw_pitch_dist () { glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); const float c = 1.0f, b = 0.5f; float yb, yt; int xl, xr; float a, da; float p, pc; for (int i = visl, j = visr + 1; i < j; ++i) { range& R = ranges[i]; const int dx = min (dinfo.dist.pix, R.extents.width); yb = R.extents.bottom; yt = R.extents.top; xl = R.extents.left; xr = R.extents.right; a = 0.0f; da = dx * R.extents.width_1; p = pc = 0.0f; glBegin (GL_QUAD_STRIP); while (xl < xr) { p = warp_pitch (a); pc = p * c; glColor4f (0, pc, pc, b); glVertex2f (xl, yb); glVertex2f (xl, yt); xl += dx; a += da; } a = 1.0f; p = warp_pitch (a); pc = p * c; glColor4f (0, pc, pc, b); glVertex2f (xr, yb); glVertex2f (xr, yt); glEnd (); } glDisable (GL_BLEND); } void din::noise_interpolator_changed () { for (drone_iterator i = drones.begin(), j = drones.end(); i != j; ++i) { drone& di = *(*i); di.nsr.warp (&noiser::interp); } } int din::can_connect (drone* d1, drone* d2) { if (d1 == d2) return 0; // no self connection if (d2->nconn) for (drone_iterator p = d2->connections.begin (), q = d2->connections.end(); p != q; ++p) if (d1 == *p) return 0; // already connected return 1; } void din::calc_stepz (const string& fld) { nstepz = 0; stepz.clear (); int p; map exists; string str; stringstream ss1 (fld); while (ss1.eof() == 0) { ss1 >> str; stringstream ss2 (str); ss2 >> p; if (p > 0 && (exists[p] == false)) { stepz.push_back (p); ++nstepz; exists[p] = true; } } } void din::alloc_conns () { if (totcon > con_size) { if (con_pts) delete[] con_pts; if (con_clr) delete[] con_clr; con_pts = new float [totcon * 2 * 2]; con_clr = new float [totcon * 2 * 3]; con_size = totcon; } } int din::disconnect_drones () { if (num_selected_drones) { if (MENU.trackcon.state == 0) { for (int i = 0; i < num_selected_drones; ++i) { drone* pd = selected_drones[i]; remove_connections (pd); if (pd->tracking) { erase (trackers, pd); pd->tracking = 0; pd->tracked_drone = 0; } } } else { for (int i = 0; i < num_selected_drones; ++i) remove_connections (selected_drones[i]); } return 1; } else cons << RED_PSD << eol; return 0; } void din::remove_connections (drone* pd) { // remove connections to pd for (drone_iterator i = drones.begin (), j = drones.end (); i != j; ++i) { drone* pdi = *i; drone& di = *pdi; if (di.nconn && pdi != pd) { list::iterator mi = di.mags.begin (); for (drone_iterator p = di.connections.begin (), q = di.connections.end(); p != q;) { drone* pdp = *p; if (pdp == pd) { p = di.connections.erase (p); q = di.connections.end (); mi = di.mags.erase (mi); --di.nconn; --totcon; } else { ++p; ++mi; } } } } // remove connections from pd if (pd->nconn) { totcon -= pd->nconn; pd->nconn = 0; pd->connections.clear (); pd->mags.clear (); } _2totcon = 2 * totcon; /*for (vector::iterator i = conns.begin (), j = conns.end (); i != j;) { connect& ci = *i; if (ci.d1 == pd || ci.d2 == pd) { i = conns.erase (i); j = conns.end (); } else ++i; }*/ } /*void din::dirty_connection (drone* d) { for (int i = 0, j = conns.size (); i < j; ++i) { connect& ci = conns[i]; if (ci.d1 == d || ci.d2 == d) ci.dirty = 1; } } void din::dirty_connections () { for (int i = 0; i < num_selected_drones; ++i) { drone* pdi = selected_drones[i]; dirty_connection (pdi); } }*/ void din::draw_connections () { if (totcon == 0) return; int p = 0, q = 0; map drawn; for (drone_iterator i = drones.begin (), j = drones.end (); i != j; ++i) { drone& di = *(*i); if (di.nconn) { for (drone_iterator s = di.connections.begin (), t = di.connections.end(); s != t; ++s) { con_clr[q++] = di.r; con_clr[q++] = di.g; con_clr[q++] = di.b; drone& dj = *(*s); con_clr[q++] = dj.r; con_clr[q++] = dj.g; con_clr[q++] = dj.b; con_pts[p++]=di.sx; con_pts[p++]=di.y; con_pts[p++]=dj.sx; con_pts[p++]=dj.y; } } } glEnableClientState (GL_COLOR_ARRAY); glColorPointer (3, GL_FLOAT, 0, con_clr); glVertexPointer (2, GL_FLOAT, 0, con_pts); glDrawArrays (GL_LINES, 0, _2totcon); glDisableClientState (GL_COLOR_ARRAY); //for (int i = 0, j = conns.size (); i < j; ++i) conns[i].draw (); } void din::reset_drone_arrows () { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; ds.arrow.reset (); } } else cons << RED_PSD << eol; } void din::gabber::abort () { for (drone_iterator i = drones.begin (), j = drones.end (); i != j; ++i) { drone& di = *(*i); di.tovol = di.gab.amount; } drones.clear (); n = 0; cons << RED << "Aborted " << what << eol; } void din::gabber::set (din* dd, float t, const string& w, float tdiv, int fid) { int ns = dd->num_selected_drones; if (ns) { if (n) abort (); for (int i = 0; i < ns; ++i) { drone* pds = dd->selected_drones[i]; drone& ds = *pds; if (!equals (ds.gab.amount, t)) { ds.gab.set (ds.gab.amount, t * ds.tovol, 1, max (0.0f, MENU.gabt()) / tdiv); ds.finl = drone::fins[fid]; drones.push_back (pds); ++n; } } if (n) { what = w; cons << YELLOW << "Started " << what << spc << n << TOGO << eol; } } else { cons << RED_PSD << eol; } } void din::gabber::eval () { if (n) { for (drone_iterator i = drones.begin (), j = drones.end (); i != j;) { drone* pdi = *i; drone& di = *pdi; di.update_pv = drone::INTERPOLATE; if (di.gab.eval () == 0) { di.tovol = di.gab.start; i = drones.erase (i); j = drones.end (); if (di.finl) di.finl->finished (din0, pdi); if (--n == 0) cons << GREEN << "Finished " << what << eol; else cons << YELLOW << what << spc << n << TOGO << eol; } else { ++i; } } } } void din::gabber::erase (drone* d) { if (::erase (drones, d)) --n; } void din::gabber::setgabt () { if (n) for (drone_iterator i = drones.begin (), j = drones.end (); i != j; ++i) (*i)->gab.delta_time = MENU.gabt(); } void din::setdronevol (spinner& s) { if (num_selected_drones) { for (int i = 0; i < num_selected_drones; ++i) { drone& ds = *selected_drones[i]; ds.gab.amount += s(); ds.tovol = ds.gab.amount; ds.update_pv = drone::EMPLACE; cons << "Drone " << i << " volume = " << ds.gab.amount << eol; } } } void din::drone2noise () { gab.set (this, 0.0f, "Drone > Noise", 2.0f, 1); } void din::noise2drone () { gab.set (this, 0.0f, "Noise > Drone", 2.0f, 2); } void drone::drone2noise::finished (din& mkb, drone* pdi) { drone& di = *pdi; di.is = drone::NOISE; di.setnoise (); di.r = di.g = di.b = 1.0f; di.gab.set (di.gab.amount, 1.0f * di.tovol, 1, MENU.gabt() / 2.0f); di.finl = 0; mkb.gab.drones.push_back (pdi); ++mkb.gab.n; } void drone::noise2drone::finished (din& mkb, drone* pdi) { drone& di = *pdi; di.is = drone::DRONE; di.setcolor (); di.gab.set (di.gab.amount, 1.0f * di.tovol, 1, MENU.gabt() / 2.0f); di.finl = 0; mkb.gab.drones.push_back (pdi); ++mkb.gab.n; } void din::set_random_color () { rndr.set (MENU.s_red_min (), MENU.s_red_max()); rndg.set (MENU.s_green_min (), MENU.s_green_max()); rndb.set (MENU.s_blue_min (), MENU.s_blue_max()); } void din::gotpoint () { dinfo.cen.x = win_mousex; dinfo.cen.y = win_mousey; } void din::ranchkdro () { for (drone_iterator i = drones.begin (), j = drones.end (); i != j; ++i) { drone& di = *(*i); clamp (0, di.range, last_range); } } void din::delselran () { // delete selected range if (num_ranges == 1) { cons << RED << "Will not delete the only range!" << eol; return; } int& sr = dinfo.sel_range; vector::iterator rb = ranges.begin(); if (sr == 0 || sr == last_range) ; else { int p = sr - 1, q = sr + 1; range& rp = ranges[p]; range& rq = ranges[q]; range& rs = ranges[sr]; rp.notes[1] = rq.notes[0]; rp.intervals[1] = rq.intervals[0]; for (int i = sr + 1; i < num_ranges; ++i) { range& ri = ranges[i]; ri.extents.move (-rs.extents.width, 0); } } ranges.erase (rb + sr); initranpar (num_ranges - 1); ranchkdro (); refresh_all_drones (); find_current_range (); } void din::initranpar (int n) { num_ranges = n; last_range = num_ranges - 1; firstr = &ranges [0]; lastr = &ranges [last_range]; clamp (0, dinfo.sel_range, last_range); MENU.sp_range.set_limits (0, last_range); } mkb_selector_t::mkb_selector_t () : of_prox_far (proximity_orderer::FARTHEST) { orderers[0]=&of_asc; orderers[1]=&of_desc; orderers[2]=&of_asc_cols; orderers[3]=&of_desc_cols; orderers[4]=&of_rnd; orderers[5]=&of_prox_near; orderers[6]=&of_prox_far; } void mkb_selector_t::draw (const box& region) { if (din0.dinfo.cen.op) din0.dinfo.cen.draw (); else { if (mesh) { glPointSize (4); glVertexPointer (2, GL_FLOAT, 0, meshp); glColor3f (1, 1, 1); glDrawArrays (GL_POINTS, 0, rowcol); glPointSize (1); } cross = din0.create_drone_pend | din0.meshh.create; box_selector::draw (region); } } int mkb_selector_t::handle_input () { if (lmb) { if (lmb_clicked == 0) { if (din0.wanding || din0.moving_drones) { // || din0.phrasor0.state) { lmb_clicked = 1; return 1; } } else return 1; } else { if (lmb_clicked) { lmb_clicked = 0; if (din0.moving_drones) din0.set_moving_drones (0); din0.stopwanding (); if (din0.phrasor0.state == phrasor::recording) din0.finish_phrase_recording (); return 1; } } int r = din0.dinfo.cen.handle_input(); if (!r) return box_selector::handle_input (); else return r; } void drone::setcolor () { if (is == drone::NOISE) r = g = b = 1; else { color& gc = MENU.colorer (); r = gc.r; g = gc.g; b = gc.b; } } int din::stopwanding () { if (wanding) {// && (phrasor0.state != phrasor::playing)) { wanding = 0; cons << RED << "Stopped wanding drones!" << eol; return 1; } return 0; } /*void din::eval_conns () { for (drone_iterator i = drones.begin (), j = drones.end (); i != j; ++i) { drone& di = *(*i); if (di.conn) { list::iterator mi = di.mags.begin (); for (drone_iterator s = di.connections.begin (), t = di.connections.end(); s != t; ++s) { drone& dc = *(*s); double now = magnitude (dc.cx, dc.cy, di.cx, di.cy); double org = *mi; if (equals (now, org)) ; else if (now > org) { double lead = 0.01 * (now - org); float ux, uy; unit_vector (ux, uy, dc.cx, dc.cy, di.cx, di.cy); dc.set_center (dc.cx + float (lead * ux), dc.cy + float(lead * uy), &di); } } } } }*/ /*void din::butt_drones () { if ((win_mousex == prev_win_mousex) && (win_mousey == prev_win_mousey)) return; double mag; float ux, uy; for (int i = 0; i < num_selected_drones; ++i) { drone& di = *selected_drones[i]; mag = unit_vector (ux, uy, win_mousex, win_mousey, di.cx, di.cy); if (mag < butt) { double lead = drone::STIFFNESS * (butt - mag); float nx = di.cx + lead * ux, ny = di.cy + lead * uy; if (magnitude (nx, ny, ring.x, ring.y) < ring.r) { di.set_center (nx, ny); for (int j = 0; j < num_selected_drones; ++j) { if (i != j) { drone& dj = *selected_drones[j]; mag = unit_vector (ux, uy, dj.cx, dj.cy, di.cx, di.cy); if (mag < inter_butt) { double lead = drone::STIFFNESS * (inter_butt - mag); float nx = di.cx + lead * ux, ny = di.cy + lead * uy; if (magnitude (nx, ny, ring.x, ring.y) < ring.r) { di.set_center (nx, ny); } } } } } } } }*/ /*void din::orbit_reciprocal () { // attach selected drones to attractor int n = selected_drones.size (); if (n) { for (int i = 0, j = 1; i < n; ++i) { drone* di = selected_drones[i]; drone* dj = selected_drones[j]; list& lae = dj->attractees; if (!di->orbiting) { push_back (attractors, dj); attractee ae (di->id, di); if (push_back (lae, ae)) { (*dj).attractor++; di->orbiting = 1; } } if (++j == n) j = 0; } } else cons << RED << "Please select at least 2 drones!" << eol; }*/ /*if (butting) { float r [] = {ring.r, butt, inter_butt}; float cx [] = {ring.x, win_mousex, win_mousex}; float cy [] = {ring.y, win_mousey, win_mousey}; glColor3f (0.25f, 0.25f, 0.25f); extern const float TWO_PI; int npts = 33; for (int p = 0; p < 3; ++p) { float R = r[p]; float a = 0, da = TWO_PI / (npts - 1); glBegin (GL_LINE_LOOP); for (int i = 0; i < npts; ++i, a += da) { glVertex2f (cx[p] + R * cos(a), cy[p] + R * sin (a)); } glEnd (); } }*/