Subversion Repositories DIN Is Noise

Rev

Rev 2097 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
* binaural_drones.cc
* DIN Is Noise is copyright (c) 2006-2025 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/


#include "binaural_drones.h"
#include "console.h"
#include "curve_listener.h"
#include "audio.h"
#include "input.h"
#include "viewwin.h"
#include "fft.h"
#include "utils.h"
#include "ui_list.h"
#include <algorithm>
#include "log.h"

extern string user_data_dir;
extern int mousex, mousey;
extern atmin _atmin;
extern atmax _atmax;
extern int SAMPLE_RATE;
extern char BUFFER[];
extern const char spc;
extern int FPS;

void waveform_listener::edited (curve_editor* ed, int i) {
  if (fft0.folded () == 0) fft0.go (ed->curveinfo[i].curve);
  sb->update_players (ed->mix);
  curve_listener::edited (ed, i);
}

fade_info::fade_info () {
  xt = dxt = xui = 0.0f;
  active = 0;
  after = 0;
}

void fade_info::start (const string& _name) {
  name = _name;
  xt = xui = 0.0f;
  after = 0;
  active = 1;
}

void fade_info::set_duration (float d) {
  if (d < 0) return;
  duration = d;
  if (equals (d, 0.0f)) d = 0.001f;
  float du = 0.1 * d;
  dxt = SAMPLE_DURATION * 1.0 / d;
  xu = SAMPLE_DURATION * du;
}

int fade_info::eval (float* out) {
  int u = 0;
  if (active) {
    sol (xt, dxt, aout.samples_per_channel, out, _atmin, _atmax);
    if (xt >= 1.0f) {
      complete ();
      u = 1;
    } else {
      if ((xt - xui) >= xu) {
        xui = xt;
        u = 1;
      }
    }
  }
  return u;
}

void fade_info::complete () {
  xt = 1.0f;
  active = 0;
  after = 1;
}

void fade_info::abort () {
  active = 0;
  after = 0;
}

void i_binaural_drones::load () {
  ifstream file ((user_data_dir + "binaural_drones").c_str (), ios::in);
  string ignore;
  file >> ignore >> master_volume;
  file >> ignore >> starting_pitch;
  file >> ignore >> separation;
  file >> ignore >> pairs;
  file >> ignore >> spacing;
  float d;
  file >> ignore >> d; vol_fader.set_duration (d);
  file >> ignore >> d; pitch_fader.set_duration (d);
  file >> ignore >> just;
  file >> ignore >> keynote;
  file >> ignore >> close_octave;
  file >> ignore >> resize_separation;
  file >> ignore >> modulation_amount;
  int n; file >> ignore >> n;
  if (n) {
    for (int i = 0; i < n; ++i) {
      float lhz, rhz, vol, sep, lx, rx;
      int just;
      file >> lhz >> rhz >> vol >> just >> sep >> lx >> rx;
      add (lhz, rhz, vol, just, sep, lx, rx);
    }
    dlog << "+++ loaded " << n << " binaurals +++" << endl;
  }
}

void i_binaural_drones::save () {
  ofstream file ((user_data_dir + "binaural_drones").c_str (), ios::out);
  file << "master_volume " << master_volume << endl;
  file << "starting_pitch " << starting_pitch << endl;
  file << "separation " << separation << endl;
  file << "pairs " << pairs << endl;
  file << "spacing " << spacing << endl;
  file << "volume_fade_duration " << vol_fader.duration << endl;
  file << "pitch_fade_duration " << pitch_fader.duration << endl;
  file << "justification " << just << endl;
  file << "keynote " << keynote << endl;
  file << "close_octave " << close_octave << endl;
  file << "resize_separation " << resize_separation << endl;
  file << "modulation_amount " << modulation_amount << endl;
  file << "num_binaural_drones " << num_binaural_drones << endl;
  for (int i = 0; i < num_binaural_drones; ++i) {
    binaural_drone* bi = binaural_drones[i];
    file << bi->l_hz << spc << bi->r_hz << spc << bi->vol << spc << bi->just << spc << bi->sep << spc << bi->playl.x << spc << bi->playr.x << endl;
  }
  dlog << "+++ saved all binaurals +++" << endl;
}

i_binaural_drones::~i_binaural_drones () {
  for (int i = 0; i < num_binaural_drones; ++i) delete binaural_drones[i];
  wav.save ("binaural-drones-waveform.crv");
  dlog << "--- destroyed binaural_drones ---" << endl;
}

int i_binaural_drones::add (float lhz, float rhz, float vol, int just, float sep, float lx, float rx) {
  binaural_drone* bd = new binaural_drone (&wav, lhz, rhz, vol, just, sep, lx, rx);
  vol_fader.start ("Volume fade-in");
  int id = 0;
  if (num_binaural_drones) { // insert sorted by left hz
    typedef std::vector<binaural_drone*>::iterator binaural_drone_iterator;
    binaural_drone_iterator bd_begin = binaural_drones.begin ();
    for (int i = 0; i < num_binaural_drones; ++i) {
      binaural_drone* bi = binaural_drones [i];
      if (bi->l_hz >= bd->l_hz) {
        binaural_drone_iterator bd_insert = bd_begin + i;
        binaural_drones.insert (bd_insert, bd);
        MENU.il_binaural_drones.insert (i, bd->name);
        ++num_binaural_drones;
        id = i;
        return id;
      }
    }
  }
  binaural_drones.push_back (bd);
  id = num_binaural_drones++;
  MENU.il_binaural_drones.add (bd->name);
  return id;
}

void i_binaural_drones::remove (int which) {
  if (which < num_binaural_drones) {
    binaural_drone* bw = binaural_drones [which];
    binaural_drones.erase (binaural_drones.begin()+which);
    --num_binaural_drones;
    delete bw;
    MENU.il_binaural_drones.remove (which);
  } else cons << RED << "bad binaural drone id: " << which << eol;
}

void i_binaural_drones::sync (int n, const string& lst) {
  if (n == -1) { // sync all
    for (int i = 0; i < num_binaural_drones; ++i) {
      binaural_drone* bi = binaural_drones[i];
      bi->sync ();
    }
  } else { // sync list
    tokenizer tz (lst);
    for (int i = 0; i < n; ++i) {
      int j; tz >> j;
      binaural_drone* bj = binaural_drones[j];
      bj->sync ();
    }
  }
}

void i_binaural_drones::list () {
  cons << YELLOW;
  for (int i = 0; i < num_binaural_drones; ++i) {
    binaural_drone* pbd = binaural_drones[i];
    sprintf (BUFFER, "Pair %d: %s", i, pbd->name.c_str());
    cons << BUFFER << eol;
  }
  sprintf (BUFFER, "%d pairs in total", num_binaural_drones);
  cons << GREEN << BUFFER << eol;
}

string i_binaural_drones::get_sel_vol () {
  stringstream ss;
  for (int i = 0; i < num_binaural_drones; ++i) {
    binaural_drone* bi = binaural_drones[i];
    if (bi->sel) ss << bi->vol << spc;
  }
  return ss.str();
}

int i_binaural_drones::render_audio (float* L0, float* R0) {

  int uv = 0, uh = 0;
  if (vol_fader.active) uv = vol_fader.eval (aout.vol);
  if (pitch_fader.active) uh = pitch_fader.eval (aout.fdr2);
  int uvh = uv | uh;

  for (int i = 0; i < num_binaural_drones; ++i) {
    binaural_drone* bd = binaural_drones[i];
    float* L = L0, *R = R0;
    bd->render (L, R, aout.vol, aout.fdr2, uv, uh, abort);
    if (uvh) MENU.il_binaural_drones.items[i].name = bd->name;
  }

  if (abort) {
    vol_fader.abort ();
    pitch_fader.abort ();
    abort = 0;
    cons << RED << "Aborted" << eol;
  } else {

    if (vol_fader.after) {
      for (int i = 0; i < num_binaural_drones; ++i) binaural_drones[i]->fading.vol = binaural_drone::fade_flags::NONE;
      cons << GREEN << vol_fader.name << " complete." << eol;
      vol_fader.after = 0;
      vol_fader.name = "";
      cons ("after-fade");
    }

    if (pitch_fader.after) {
      for (int i = 0; i < num_binaural_drones; ++i) {
        binaural_drone* bi = binaural_drones[i];
        if (bi->fading.hz) {
          bi->fill_hz ();
          bi->fading.hz = binaural_drone::fade_flags::NONE;
        }
      }
      cons << GREEN << pitch_fader.name << " complete." << eol;
      pitch_fader.after = 0;
      pitch_fader.name = "";
      cons ("after-fade");
    }

  }

  return 1;

}

void i_binaural_drones::update_players (multi_curve& mx) {
  int canmix = mx.num_vertices;
  for (int i = 0; i < num_binaural_drones; ++i) {
    binaural_drone* s = binaural_drones[i];
    s->soll.update ();
    s->solr.update ();
  }
  if (canmix) {
    for (int i = 0; i < num_binaural_drones; ++i) {
      binaural_drone* s = binaural_drones[i];
      s->playl.set_mix (mx, "binaural_drones_waveform");
      s->playr.set_mix (mx, "binaural_drones_waveform");
    }
  }  
}

int i_binaural_drones::handle_input () {
  prev_mousex = mousex;
  prev_mousey = mousey;
  if (keypressed (SDLK_F1)) hlp();
  if (keypressed (SDLK_F3)) aborted ();
  return 1;
}

void i_binaural_drones::enter () {
  extern void show_menu ();
  show_menu ();
}

int i_binaural_drones::change_justification (int d) {
  just += d;
  if (just < binaural_drone::LEFT) just = binaural_drone::CENTER;
  else if (just > binaural_drone::CENTER) just = binaural_drone::LEFT;
  return just;
}

int i_binaural_drones::change_key_note (int d) {
  keynote += d;
  if (keynote < START_PITCH) keynote = FROM_SCALE;
  else if (keynote > FROM_SCALE) keynote = START_PITCH;
  return keynote;
}

int i_binaural_drones::busy () { return vol_fader.active || pitch_fader.active; }

int i_binaural_drones::aborted () {
  if (busy()) abort = 1;
  return abort;
}