/* * drone.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 "din.h" #include "drone.h" #include "console.h" #include "audio.h" #include "utils.h" #include "vector2d.h" #include using namespace std; extern multi_curve drone_mod_am_crv, drone_mod_fm_crv; extern solver warp_vol, warp_pitch; extern const char spc; extern void get (float& g, float& gx, float& gy, defvelaccel& dva); extern int gethandlesize (); extern int gettrailsize (); extern const float TWO_PI; void drone::setis () { if (IS == DRONE_OR_NOISE) is = get_rand_bit (); else is = IS; } drone::drone (float bottom) : mod (&drone_mod_fm_crv, &drone_mod_am_crv) { setis (); step = vol = 0; range = 0; pos = 0.0f; r = g = b = 0.5f; cx = cy = 0; x = y = 0; dy = 0; xv = x; yv = y; xa = x; ya = y; sx = 0; sel = 0; state = DEAD; frozen = 0; froze_at = 0; handle_size = gethandlesize (); trail.set (gettrailsize()); id = ++UID; get (V, vx, vy, v0); v_mult = 1.0f; get (A, ax, ay, a0); gravity = 0; attractor = 0; orbiting = 0; launcher = 0; tracking = 0; tracked_drone = 0; dpm = 60; ++ref; launched_by = 0; reincarnate = 0; switch (ARE) { case IMMORTAL: birth = -1; break; case MORTAL: birth = ui_clk (); break; case REINCARNATE: birth = ui_clk (); reincarnate = 1; break; } life = LIFETIME; insert = INSERTTIME; target = 0; cur_target = 0; num_targets = 0; update_pv = UNSET; snap = 0; nconn = 0; type = CHAIN; gab.set (1.0f, 0.0f, 0, 1.0f); tovol = 0.0f; finl = 0; note_num = -1; } drone::~drone () { --ref; } void drone::move_center () { cx += (x - xi); cy += (y - yi); } drone* drone::eval_conns () { if (nconn) { int n = 0; proc_conn [this] = true; list::iterator mi = mags.begin(); drone_iterator p = connections.begin (); drone* c0 = *p; for (drone_iterator q = connections.end (); p != q; ++p, ++mi) { drone* pdc = *p; if (proc_conn[pdc] == false) { proc_conn [pdc] = true; drone& dc = *pdc; double now = magnitude (cx, cy, dc.cx, dc.cy); double org = *mi; if (now > org) { double lead = STIFFNESS * (now - org); float ux, uy; unit_vector (ux, uy, dc.cx, dc.cy, cx, cy); dc.set_center (dc.cx + lead * ux, dc.cy + lead * uy); ++n; } } } if (n) return this; else return c0; } return 0; } void drone::remagconns () { list::iterator mi = mags.begin(); drone_iterator p = connections.begin (); for (drone_iterator q = connections.end (); p != q; ++p, ++mi) { drone* pd = *p; *mi = magnitude (cx, cy, pd->cx, pd->cy); } } void drone::set_center (float xx, float yy, int e) { cx = xx; cy = yy; if (frozen) set_pos (cx + mod.fm.result, cy + mod.am.result); if (e) eval_conns (); } void drone::set_pos (float xx, float yy) { // position x = xx; y = yy; // position affects velocity? if (posafxvel.yes && !autorot.v.yes && !gravity && !tracking && !orbiting) { double mag = magnitude (posafxvel.pt.x, posafxvel.pt.y, x, y); if (mag > posafxvelt::minmag) { direction (vx, vy, posafxvel.pt.x, posafxvel.pt.y, x, y); vx /= mag; vy /= mag; posafxvel.pt.x = x; posafxvel.pt.y = y; } } // locate range on microtonal-keyboard range = din0.find_range (x, range); ::range& dr = din0.ranges[range]; // pitch position in range int delta_left = x - dr.extents.left; pos = delta_left * 1.0f / dr.extents.width; if (pos < 0 || pos > 1.0f) ; else pos = warp_pitch (pos); // pitch snap if (snap) { if (pos < din0.dinfo.snap.left) note_num = 0; else if (pos > din0.dinfo.snap.right) note_num = 1; else goto normal; if (note_num) { pos = 1; sx = dr.extents.right; } else { pos = 0; sx = dr.extents.left; } } else { normal: note_num = -1; sx = x; } calc_handle (); update_pv = EMPLACE; // update pitch volume b4 rendering drones } void drone::calc_handle () { //handle (sx - handle_size, round(y) - handle_size, sx + handle_size, round(y) + handle_size); handle (sx - handle_size, y - handle_size, sx + handle_size, y + handle_size); } void drone::update_pitch_volume () { ::range& dr = din0.ranges[range]; dy = y - BOTTOM; float iv = dy * 1.0f / dr.extents.height; if (dy < 0) vol = -warp_vol (-iv); else vol = warp_vol (iv); if (note_num == -1) { float n0step = dr.notes[0].step, n1step = dr.notes[1].step; float nstep = n0step + pos * (n1step - n0step); if (nstep > 0) step = nstep; } else { step = dr.notes[note_num].step; } if (is == DRONE) { float v = fdr.amount * mastervolume * gab.amount * vol; player.set_interpolated_pitch_volume (step, v); } else setnoise (); --update_pv; } void drone::setnoise () { nsr.set_samples (1.0f / step); nsr.set_spread ( fabs(vol) ); } void drone::change_bpm (mod_params& mp, float delta) { mp.bv.set_bpm (mp.bv.bpm + delta); } void drone::change_bpm (int i, int what, float delta) { if (what == modulator::FM) { change_bpm (mod.fm, delta); cons << "drone: " << i << ", FM bpm = " << mod.fm.bv.bpm << eol; } else { change_bpm (mod.am, delta); cons << "drone: " << i << ", AM bpm = " << mod.am.bv.bpm << eol; } } void drone::change_depth (int i, int what, float delta) { if (what == modulator::FM) { mod.fm.depth += delta; cons << "drone: " << i << ", FM depth = " << mod.fm.depth << eol; } else { mod.am.depth += delta; cons << "drone: " << i << ", AM depth = " << mod.am.depth << eol; } } void drone::clear_targets () { targets.clear (); cur_target = 0; num_targets = 0; } void drone::handle_time_pass () { double tp = ui_clk() - froze_at; mod.t += tp; if (autorot.v.autoflip.yes) autorot.v.tik.startt += tp; if (autorot.a.autoflip.yes) autorot.a.tik.startt += tp; fdr.start_time += tp; if (birth != -1) birth += tp; if (launcher) launch_every.startt += tp; } int drone::freeze () { ++frozen; froze_at = ui_clk (); update_pv = drone::EMPLACE; if (chuck.yes && chuckt::autoresettrails && chuck.sat) chuck.resettrail (chuck.sat); return 1; } int drone::thaw () { if (--frozen < 1) { frozen = 0; handle_time_pass (); if (chuck.yes && chuckt::autoresettrails && chuck.sat) chuck.resettrail (chuck.sat); return 1; } return 0; } group::group (std::vector mem, int _n) { n = _n; if (n) { drones.resize (n); for (int i = 0; i < n; ++i) drones[i] = mem[i]; } } std::ostream& operator<< (std::ostream& f, drone::arrowt& aw) { f << aw.u << spc << aw.v << spc << aw.t << spc << aw.cap; return f; } std::istream& operator>> (std::istream& f, drone::arrowt& aw) { f >> aw.u >> aw.v >> aw.t >> aw.cap; return f; } std::ostream& operator<< (std::ostream& f, drone::chuckt& ch) { f << ch.len << spc << ch.speed << spc << ch.dir << spc << ch.ux << spc << ch.uy << spc; if (ch.sun) f << ch.sun->id << spc; else f << 0 << spc; if (ch.sat) f << ch.sat->id; else f << 0; return f; } std::istream& operator>> (std::istream& f, drone::chuckt& ch) { f >> ch.len >> ch.speed >> ch.dir >> ch.ux >> ch.uy; uintptr_t sun; f >> sun; ch.sun = (drone*) sun; uintptr_t sat; f >> sat; ch.sat = (drone*) sat; return f; } void drone::chuckt::re (drone& p) { if (sun) p.chuck.len = unit_vector (p.chuck.ux, p.chuck.uy, sun->cx, sun->cy, p.cx, p.cy); } void drone::chuckt::print () { stringstream ss; ss << " || Speeds: This = " << speed; if (sun) { ss << ", Previous = " << sun->chuck.speed; } else ss << ", Previous = none"; if (sat) { ss << ", Next = " << sat->chuck.speed; } else ss << ", Next = none"; cons << ss.str (); } void drone::chuckt::resettrail (drone* d) { d->trail.reset (); drone* sat = d->chuck.sat; if (sat) sat->chuck.resettrail (sat); } std::ostream& operator<< (std::ostream& f, anglet& a) { f << a.deg; return f; } std::istream& operator>> (std::istream& f, anglet& a) { f >> a.deg; a.torad (); return f; } /*connect::connect (drone* _d1, drone* _d2) { dirty = 1; d1 = _d1; d2 = _d2; mag = magnitude (d1->cx, d1->cy, d2->cx, d2->cy); p1.x = d1->cx; p1.y = d1->cy; p2.x = d2->cx; p2.y = d2->cy; align_vel (); } void connect::align_vel () { unit_vector(d1->vx, d1->vy, d1->cx, d1->cy, d2->cx, d2->cy); //d2->vx = d1->vx; //d2->vy = d1->vy; } int connect::eval (drone** ret) { double magnew = magnitude (d1->cx, d1->cy, d2->cx, d2->cy); if (magnew > mag) { float ux, uy; unit_vector (ux, uy, d1->cx, d1->cy, d2->cx, d2->cy); double lead = magnew - mag; int d1mov = ((p1.x != d1->cx) || (p1.y != d1->cy)); int d2mov = ((p2.x != d2->cx) || (p2.y != d2->cy)); int d12mov = d1mov && d2mov; if (d12mov) { lead /= 2.0; d1->set_center (d1->cx + lead * ux, d1->cy + lead * uy); d2->set_center (d2->cx - lead * ux, d2->cy - lead * uy); ret[0] = d1; ret[1] = d2; } else { if (d1mov) { d2->set_center (d2->cx - lead * ux, d2->cy - lead * uy); ret[0] = d2; ret[1] = 0; } else if (d2mov) { d1->set_center (d1->cx + lead * ux, d1->cy + lead * uy); ret[0] = d1; ret[1] = 0; } } align_vel (); p1.x = d1->cx; p1.y = d1->cy; p2.x = d2->cx; p2.y = d2->cy; dirty = 0; return 1; } dirty = 0; return 0; } void connect::draw () { glBegin (GL_LINES); glColor3f (d1->r, d1->g, d1->b); glVertex2i (d1->cx, d1->cy); glColor3f (d2->r, d2->g, d2->b); glVertex2i (d2->cx, d2->cy); glEnd (); }*/