Subversion Repositories DIN Is Noise

Rev

Rev 1479 | Rev 1556 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
* sine_mixer.cc
* DIN Is Noise is copyright (c) 2006-2020 Jagannathan Sampath
* For more information, please visit https://dinisnoise.org/
*/



#include "dingl.h"
#include "input.h"
#include "viewwin.h"
#include "sine_mixer.h"
#include "ui_list.h"
#include "viewwin.h"
#include "vector2d.h"
#include "circler.h"
#include "log.h"
#include "console.h"
#include "container.h"
#include <math.h>
using namespace std;

extern ui_list uis;
extern viewport view;
extern const float PI;
extern const float TWO_PI;
extern int MILLION;
extern curve_library sin_lib;
extern int line_height;
extern const char SPC;

sine_mixer::sine_mixer () : cp_sin ("sine_mixer_sin.crv"), sin_ed ("sine_mixer_sin.ed"), sine_levels ("sine_levels") {
  plugin::name = "Sine_Mixer";
  mouse_slider_listener::name = "Harmonics";
  shapeform = 0;
  type = 0;
  orient = mouse_slider_listener::X;
  sin_ed.add (&cp_sin.crv, this);
  sin_ed.attach_library (&sin_lib);
}

void sine_mixer::load_params () {
  ifstream f (make_fname().c_str(), ios::in);
  string ignore;
  f >> ignore >> num_points >> ignore >> make_shapeform >> ignore >> type >> ignore >> auto_apply;
  NUM_SINE_SAMPLES = num_points + 1;

  // harmonics bookmarks
  int nb;
  f >> ignore >> nb;
  if (nb) {
    hlba.resize (nb);
    for (int i = 0; i < nb; ++i) {
      harmonics_list_button* b = new harmonics_list_button ();
      minus.add_child (b);
      hlba[i] = b;
      int nh;
      f >> nh;
      vector<int>& hs = b->harmonics;
      hs.resize (nh);
      for (int m = 0; m < nh; ++m) f >> hs[m];
    }
  }
}

void sine_mixer::save_params () {
  ofstream f (make_fname().c_str(), ios::out);
  string ignore;
  f << "num_points " << int (sp_points.f_value) << " make_shapeform " << cb_make_shapeform.state << " type " << type << " auto_apply " << cb_auto_apply.state << endl;

  int j = hlba.size ();
  f << "harmonics_bookmarks " << j << SPC;
  for (int i = 0; i < j; ++i) {
    harmonics_list_button* hlb = hlba[i];
    vector<int>& hs = hlb->harmonics;
    int n = hs.size ();
    f << n << SPC;
    for (int m = 0; m < n; ++m) {
      f << hs[m] << SPC;
    }
  }
}

sine_mixer::~sine_mixer () {
  save_params ();
  rem_all_bookmarks ();
  widget_save ("d_sine_mixer", ctrls);
  dlog << "--- destroyed sine mixer ---" << endl;
}

void sine_mixer::num_harmonics (int h) {
  nharmonics = h;
  if (nharmonics < 1) nharmonics = 1;
  prep_harmonics ();
}

void sine_mixer::prep_harmonics () {
  harmonics.resize (nharmonics);
  float df = TWO_PI / (NUM_SINE_SAMPLES - 1);
  funktion& f_sin = *pf_sin;
  for (int i = 0, j = 1; i < nharmonics; ++i, ++j) {
    vector< point<float> >& harmonic = harmonics[i];
    harmonic.resize (NUM_SINE_SAMPLES);
    float dx = j * df;
    float x = 0;
    for (int p = 0; p < NUM_SINE_SAMPLES; ++p) {
      point<float>& hp = harmonic[p];
      hp.x = cos(x);
      hp.y = f_sin (x, TWO_PI);
      x += dx;
      if (x > TWO_PI) x -= TWO_PI;
    }
  }
  norm.resize (NUM_SINE_SAMPLES);
  mix ();
}

void sine_mixer::mix () {
  for (int p = 0; p < NUM_SINE_SAMPLES; ++p) { point<float>& pi = norm[p]; pi.x = pi.y = 0;}
  ss.str(""); ss << plugin::name;
  for (int i = 0; i < nharmonics; ++i) {
    float lev = sine_levels.values[i];
    if (lev > 0) {
      vector< point<float> >& harmonic = harmonics[i];
      for (int p = 0; p < NUM_SINE_SAMPLES; ++p) {
        point<float>& np = norm[p];
        point<float>& hp = harmonic[p];
        np.x += (lev * hp.x);
        np.y += (lev * hp.y);
      }
      ss << '_' << (i+1);
    }
  }
  normalise ();
}

void sine_mixer::normalise () {
  int n = NUM_SINE_SAMPLES;
  if (n) {
    point<float>& np0 = norm[0];
    float maxy = fabs (np0.y), maxx = fabs (np0.x);
    for (int i = 0; i < n; ++i) {
      point<float>& pi = norm[i];
      float vx = fabs (pi.x), vy = fabs (pi.y);
      if (vx > maxx) maxx = vx;
      if (vy > maxy) maxy = vy;
    }
    if (maxx != 0) for (int p = 0; p < n; ++p) norm[p].x /= maxx;
    if (maxy != 0) for (int p = 0; p < n; ++p) norm[p].y /= maxy;
  }
}

void sine_mixer::render () {

  undo = !cb_auto_apply.state;
  shapeform = cb_make_shapeform.state;

  int ns = norm.size ();
  points.resize (ns);
  if (shapeform) {
    for (int i = 0; i < ns; ++i) {
      point<float>& ni = norm[i];
      point<float>& pi = points[i];
      pi.x = ni.x;
      pi.y = ni.y;
    }
  } else {
    float x = 0;
    float dx = 1.0f / (NUM_SINE_SAMPLES - 1);
    for (int i = 0; i < ns; ++i) {
      point<float>& ni = norm[i];
      point<float>& pi = points[i];
      pi.x = x;
      pi.y = ni.y;
      x += dx;
    }
  }

  gen_pts ();

}

void sine_mixer::setup () {

  plugin::setup ();
  widget* _ctrls [] = {&sine_levels, &sp_points, &cb_make_shapeform, &ol_sin, &b_edit, &cb_paint_harmonics, &fb_mover, &b_lshift, &b_rshift, &b_slide, &cb_wrap, &b_all, &b_inv, &b_non, &plus, &minus, &cross};

  num_ctrls = 19;
  ctrls.resize (num_ctrls);

  for (int i = 0, j = 2; j < num_ctrls; ++i, ++j) {
    ctrls[j] = _ctrls[i];
    //_ctrls[i]->set_moveable(1);
  }

  load_params ();

  sp_points.set ("Points", 1, 1, MILLION, this, 0);
  sp_points.set_value (num_points);

  sine_levels.set_listener (this);
  cb_make_shapeform.set_text ("Make shapeform");
  cb_make_shapeform.set_state (make_shapeform);
  cb_make_shapeform.set_listener (this);
  cb_paint_harmonics.set_text ("Paint harmonics");
  cb_paint_harmonics.set_listener (this);
  if (auto_apply) {
    cb_auto_apply.set_state (1, 0);
    plugin::mix = undo = 0;
  }

  ol_sin.set_listener (this);
  fb_mover.movlis = this;
  widget_load ("d_sine_mixer", ctrls);

  fb_mover.set_pos (sine_levels.extents.right + sine_levels.elem_width, sine_levels.extents.bottom);
  fb_mover.set_moveable (1);

  b_edit.set_text ("Edit");
  b_lshift.set_pos (fb_mover.extents.left, b_lshift.extents.bottom);
  b_lshift.set_text ("<<");
  b_rshift.set_text (">>");
  b_slide.set_text ("Slide");

  cb_wrap.set_text ("Wrap");
  cb_wrap.set_state (sine_levels.wrap);
  cb_wrap.set_listener (this);

  b_all.set_text ("All");
  b_inv.set_text ("Invert");
  b_non.set_text ("None");

  button* bhl [] = {&plus, &minus, &cross};
  click_listener* cl [] = {&pll, &mil, &crl};
  for (int i = 0; i < 3; ++i) bhl[i]->set_listener (cl[i]);

  button* bw [] = {&b_edit, &b_lshift, &b_rshift, &b_slide, &b_all, &b_inv, &b_non};
  for (int i = 0; i < 7; ++i) {
    button* bwi = bw[i];
    bwi->set_listener (this);
  }
  b_lshift.click_repeat = b_rshift.click_repeat = 1;


  set_type ();
  num_harmonics (sine_levels.nlev);
  render ();

  for (int i = 0, j = hlba.size (), y = minus.extents.bottom - state_button::SIZE2; i < j; ++i) {
    harmonics_list_button* hlb = hlba[i];
    hlb->set_pos (minus.extents.left, y);
    hlb->set_listener (&hal);
    y -= state_button::SIZE2;
    ctrls.push_back (hlb);
    ++num_ctrls;
  }

}

void sine_mixer::set_type () {
  if (type) {
    pf_sin = &cp_sin;
    ol_sin.option.set_text (" Custom sin");
    b_edit.set_color (clr.r, clr.g, clr.b);
    b_edit.set_listener (this);
  } else {
    pf_sin = &st_sin;
    ol_sin.option.set_text (" Standard sin");
    b_edit.set_color (0.25f, 0.25f, 0.25f);
    b_edit.set_listener (0);
  }
  int spacer = 10; b_edit.set_pos (ol_sin.option.extents.right + spacer, ol_sin.option.extents.bottom);
}

void sine_mixer::changed (field& f) {
  if (&f == &sp_points.f_value) {
    set_samples (f);
    do_render ();
  }
}

void sine_mixer::changed (levels& l) {
  mix ();
  do_render ();
}

void sine_mixer::changed (checkbutton& cb) {
  if (&cb == &cb_make_shapeform) {
    render ();
    apply_not_auto_apply ();
  } else if (&cb == &cb_paint_harmonics) {
    sine_levels.paint = cb_paint_harmonics.state;
  } else if (&cb == &cb_wrap) {
    sine_levels.wrap = cb_wrap.state;
  } else plugin::changed (cb);
}

void sine_mixer::set_samples (int s) {
  NUM_SINE_SAMPLES = s + 1;
  if (NUM_SINE_SAMPLES < MIN_SINE_SAMPLES) NUM_SINE_SAMPLES = MIN_SINE_SAMPLES;
  prep_harmonics ();
}


void sine_mixer::apply_not_auto_apply () {
  if (cb_auto_apply.state) {
    plugin::mix = undo = 1;
    uis.crved->apply_plugin (this);
    plugin::mix = undo = 0;
  } else uis.crved->apply_plugin (this);
}

void sine_mixer::picked (label& lbl, int dir) {
  type = !type;
  set_type ();
  prep_harmonics ();
  render ();
}

void sine_mixer::shift_apply () {
  mix ();
  render ();
  apply_not_auto_apply ();
}

void sine_mixer::sel_all_harms () {
  for (int i = 0; i < sine_levels.nlev; ++i) {
    if (sine_levels.heights[i]) sine_levels.selection[i] = 1;
  }
  sine_levels.nsel += sine_levels.nlev;
  clear_bookmarks ();
}

void sine_mixer::desel_all_harms () {
  for (int i = 0; i < sine_levels.nlev; ++i) sine_levels.selection[i] = 0;
  sine_levels.nsel = 0;
  clear_bookmarks ();
}

void sine_mixer::inv_sel_harms () {
  for (int i = 0; i < sine_levels.nlev; ++i) {
    bool& si = sine_levels.selection[i];
    int& nsel = sine_levels.nsel;

    if (si) {
      si = 0;
      --nsel;
    }
    else if (sine_levels.heights[i]) {
      si = 1;
      ++nsel;
    }
  }
  clear_bookmarks ();
}

void sine_mixer::clicked (button& b) {
  if (&b == &b_lshift) {
    if (sine_levels.lshift ()) shift_apply ();
  } else if (&b == &b_rshift) {
    if (sine_levels.rshift ()) shift_apply ();
  } else if (&b == &b_all) {
    sel_all_harms ();
  } else if (&b == &b_inv) {
    inv_sel_harms ();
  } else if (&b == &b_non) {
    desel_all_harms ();
  } else if (&b == &b_slide) {
    extern mouse_slider mouse_slider0;
    if (mouse_slider_active ())
      return;
    else {
      mouse_slider0.add (this);
      activate_mouse_slider ();
    }
  } else if (&b == &b_edit) {
    uis.set_current (&sin_ed);
    return;
  } else plugin::clicked (b);
}

void sine_mixer::edited (curve_editor* e, int i) {
  cp_sin.sol.update ();
  curve_listener::edited (e, i);
  prep_harmonics ();
  render ();
}

void sine_mixer::moved () {
  if (sine_levels.extents.top > fb_mover.extents.bottom) {
    sine_levels.height = sine_levels.extents.height = sine_levels.extents.top - fb_mover.extents.bottom;
    sine_levels.set_pos (sine_levels.posx, fb_mover.posy);
    sine_levels.reheight ();
  }
  fb_mover.set_pos (sine_levels.extents.right + sine_levels.elem_width, fb_mover.extents.bottom);
}

void sine_mixer::moused (int dx) {
  if (dx > 0) sine_levels.rshift (); else sine_levels.lshift ();
  shift_apply ();
}

void sine_mixer::bookmark_harmonics () {
  if (sine_levels.nsel) {
    harmonics_list_button* hlb = new harmonics_list_button ();
    int n = hlba.size ();
    if (n) {
      int l = n - 1;
      harmonics_list_button* lb = hlba[l];
      hlb->set_pos (minus.extents.left, lb->extents.bottom - state_button::SIZE2);
    } else {
      hlb->set_pos (minus.extents.left, minus.extents.bottom - state_button::SIZE2);
    }

    for (int i = 0; i < sine_levels.nlev; ++i) if (sine_levels.selection[i]) hlb->harmonics.push_back (i);

    clear_bookmarks ();

    hlb->set_state (1, 0);
    hlb->set_listener (&hal);

    minus.add_child (hlb);
     
    hlba.push_back (hlb);

    ctrls.push_back (hlb);
    ++num_ctrls;

  } else {
    cons << RED << "No harmonics selected to bookmark. SHIFT+click a harmonic to select" << eol;
  }
}

void sine_mixer::rem_all_bookmarks () {
  for (int i = 0, j = hlba.size (); i < j; ++i) {
    harmonics_list_button* hlb = hlba[i];
    erase (ctrls, hlb);
    --num_ctrls;
    delete hlb;
  }
  hlba.clear ();
  minus.children.clear ();
}


void sine_mixer::rem_bookmarks () {
  for (vector<harmonics_list_button*>::iterator i = hlba.begin (), j = hlba.end (); i != j; ) {
    harmonics_list_button* hlb = *i;
    if (hlb->state) {
      i = hlba.erase (i);
      j = hlba.end ();
      minus.remove_child (hlb);
      erase (ctrls, hlb);
      --num_ctrls;
      delete hlb;
    } else {
      ++i;
    }
  }
}

void sine_mixer::clear_bookmarks () {
  for (int i = 0, j = hlba.size (); i < j; ++i) {
    harmonics_list_button* hlb = hlba[i];
    hlb->set_state (0, 0);
  }
}

CLICKED_BUTTON (sine_mixer, plus_lis) {
  sinemixer.bookmark_harmonics ();
}

CLICKED_BUTTON (sine_mixer, minus_lis) {
  sinemixer.rem_bookmarks ();
}

CLICKED_BUTTON (sine_mixer, cross_lis) {
  sinemixer.rem_all_bookmarks ();
}

CLICKED_CHECKBUTTON (sine_mixer, harm_lis) {
  harmonics_list_button& hlb = dynamic_cast<harmonics_list_button&>(cb);
  int s = hlb.state;
  if (SHIFT)
    ;
  else {
    sinemixer.desel_all_harms ();
    if (s == 0) s = 1;
    hlb.set_state (s, 0);
  }
  vector<harmonics_list_button*>& hlba = sinemixer.hlba;
  for (int i = 0, j = hlba.size (); i < j; ++i) {
    if (&hlb == hlba[i]) {
      vector<int>& hs = hlb.harmonics;
      int n = hs.size ();
      for (int m = 0; m < n; ++m) sinemixer.sine_levels.selection [hs[m]] = s;
      sinemixer.sine_levels.nsel += (n * s);
    }
  }
}