Subversion Repositories DIN Is Noise

Rev

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

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


#include "settings.h"
#include "viewwin.h"
#include "console.h"
#include "font.h"
#include "ui_list.h"
#include "tcl_interp.h"
#include "midi_in.h"
#include "audio.h"
#include "delay.h"
#include "main.h"
#include "instrument.h"
#include "curve_mixer.h"
#include <sstream>

#include "log.h"

extern string NEAREST_NOTE;
extern float NEAREST_NOTE_FREQUENCY;
extern float NEAREST_NOTE_DISTANCE;
extern int NUM_OCTAVES;
extern int MILLION;

settings::settings () : ol_display_modes (1) {

  name = "settings";
  //ed = 1; // treat as editor to disable SDLK_1 from switching current instrument

  // assign colors
  b_go_back.set_color (0.5f, 1.0f, 1.0f);

  unsigned char kr1 = 0xeb, kg1 = 0x95, kb1 = 0x60;
  s_key.set_color (kr1, kg1, kb1);
  ol_nearest_note.set_color (kr1, kg1, kb1);

  unsigned char r1 = 0xff, g1 = 0x89, b1 = 0;
  sn_scale_notes.set_color (r1, g1, b1);
  ol_notation.set_color (r1, g1, b1);
  ol_tuning.set_color (r1, g1, b1);
  sp_num_octaves.set_color (r1, g1, b1);

  unsigned char dr1 = 0xa1, dg1 = 0xd6, db1 = 0x36;
  l_delay_dur.set_color (dr1, dg1, db1);
  r_delay_dur.set_color (dr1, dg1, db1);

  unsigned char ar = 0xd2, ag = 0x73, ab = 0xff;
  ol_audio_devices.set_color (ar, ag, ab);
  ol_sample_rates.set_color (ar, ag, ab);
  ol_buffer_sizes.set_color (ar, ag, ab);
  b_refresh_audio_devices.set_color (ar, ag, ab);

  unsigned char mr = 0x40, mg = 0x83, mb = 0xff;
  ol_midi_devices.set_color (mr, mg, mb);
  b_refresh_midi_devices.set_color (mr, mg, mb);

  unsigned char dr2 = 0xaf, dg2 = 0xaf, db2 = 0xff;
  ol_display_modes.set_color (dr2, dg2, db2);
  ol_display_modes.apply.set_listener (this);

  unsigned char sr1 = 0xba, sg1 = 0x00, sb1 = 0x00;
  scroll_up.set_color (sr1, sg1, sb1);
  scroll_down.set_color (sr1, sg1, sb1);

  scroll_up.set_direction (arrow_button::top);
  scroll_down.set_direction (arrow_button::bottom);
  int scroll_arrow_size = 32;
  scroll_up.set_size (scroll_arrow_size);
  scroll_down.set_size (scroll_arrow_size);

  scroll_up.click_repeat = scroll_down.click_repeat = 1;
  scroll_up.first_repeat_time = scroll_down.first_repeat_time = 0.0f;
  scroll_up.subsequent_repeat_time = scroll_down.subsequent_repeat_time = 0.0f;

  imode = -1;
 
  b_factory_reset.set_color (1.0f, 0.5f, 0.5f);

  num_widgets = 0;
 
}

void settings::setup () {

  s_key.set_listener (this);
  s_key.set_limits (0, 1000000); // 0 to 1 million hz

  sp_num_octaves.set_delta (1);
  sp_num_octaves.set_limits (1, 15);
  //sp_num_octaves.set_moveable (1);
  sp_num_octaves.set_listener (this);
  sp_num_octaves.set_label ("Number of Octaves");

  scroll_up.set_listener (this);
  scroll_down.set_listener (this);

  // setup separators
  separator* seps [] = {&h_separator1, &h_separator2, &h_separator3, &h_separator4, &h_separator5, &h_separator6, &h_separator7, &h_separator8};
  for (int i = 0; i < 8; ++i) {
    seps[i]->set_color (0.5f, 0.5f, 0.5f);
    seps[i]->set_extents (480);
  }

  // install into widget array
  widgets.push_back (&b_go_back);
  widgets.push_back (&h_separator1);
  widgets.push_back (&s_key);
  widgets.push_back (&ol_nearest_note);
  widgets.push_back (&h_separator2);
  widgets.push_back (&sn_scale_notes);
  widgets.push_back (&sp_num_octaves);
  widgets.push_back (&ol_notation);
  widgets.push_back (&ol_tuning);
  widgets.push_back (&h_separator3);
  widgets.push_back (&l_delay_dur);
  widgets.push_back (&r_delay_dur);
  widgets.push_back (&h_separator4);
  widgets.push_back (&ol_audio_devices);
  widgets.push_back (&ol_sample_rates);
  widgets.push_back (&ol_buffer_sizes);
  widgets.push_back (&b_refresh_audio_devices);
  widgets.push_back (&h_separator5);
  widgets.push_back (&ol_midi_devices);
  widgets.push_back (&b_refresh_midi_devices);
  widgets.push_back (&cb_show_midi_messages);
  widgets.push_back (&h_separator6);
  widgets.push_back (&ol_display_modes);
  widgets.push_back (&h_separator7);
  widgets.push_back (&b_factory_reset);
  widgets.push_back (&h_separator8);
  widgets.push_back (&sp_fps);
  widgets.push_back (&sp_ips);
  widgets.push_back (&sp_mixing_time);
 
  num_widgets = widgets.size ();

  lnspc.resize (num_widgets);

  // setup widget listeners
  b_go_back.set_listener (this);
  b_factory_reset.set_listener (this);
  ol_notation.set_listener (this);
  ol_tuning.set_listener (this);
  ol_midi_devices.set_listener (this);
  cb_show_midi_messages.set_listener (this);
  b_refresh_midi_devices.set_listener (this);
  ol_audio_devices.set_listener (this);
  ol_sample_rates.set_listener (this);
  ol_buffer_sizes.set_listener (this);
  b_refresh_audio_devices.set_listener (this);
  l_delay_dur.fld.change_lsnr = this;
  r_delay_dur.fld.change_lsnr = this;
  ol_nearest_note.set_listener (this);
  sp_num_octaves.set_listener (this);
  ol_display_modes.set_listener (this);

  spinner<int>* spn[] = {&sp_fps, &sp_ips};
  const char* lspn[] = {"Frames Per Second", "Inputs Per Second"};
  for (int i = 0; i < 2; ++i) {
    spinner<int>* si = spn[i];
    si->set_limits (1, MILLION);
    si->set_delta (1);
    si->set_listener (this);
    si->set_label (lspn[i]);
  }

  sp_mixing_time.set_limits (0, MILLION);
  sp_mixing_time.set_delta (0.1f);
  sp_mixing_time.set_listener (this);
  sp_mixing_time.set_label ("Curve mixing time");

  cb_show_midi_messages.set_state (0);

  i_current_tuning = 0;
  i_current_midi = 0;

  // build audio buffer sizes list
  int bs = 64;
  for (int j = 0; j < 7; ++j) {
    buffer_sizes.push_back (bs);
    bs *= 2;
  }

  i_buffer_size = 0;

}

void settings::enter () {

  // called b4 settings page is displayed
  // refresh settings

  get_current_instrument ()->scaleinfo.update_settings ();

  if (prev_mousex == -1) {
    prev_mousex = view.xmax / 2;
    prev_mousey = view.ymax / 2;
  }
 
  // get current notation
  extern string NOTATION;
  ol_notation.option.set_text (" notation = " + NOTATION);

  // get current tuning
  tunings.clear ();
  interpreter ("tuning list");
  tokenizer tz (interpreter.result);
  while (1) {
    string name; tz >> name;
    if (name == "") break;
    tunings.push_back (name);
  }
  num_tunings = tunings.size ();
  interpreter ("tuning get");
  s_current_tuning = interpreter.result;
  find_current_tuning ();
  ol_tuning.option.set_text (" tuning = " + s_current_tuning + " ");

  // number of octaves
  //

  sp_num_octaves.set_value (NUM_OCTAVES);

  // load l & r delay durations
  const char* const chan [] = {"left", "right"};
  label_field* flds [] = {&l_delay_dur, &r_delay_dur};
  for (int i = 0; i < 2; ++i) {
    stringstream ss_gd;
    ss_gd << "get-delay " << chan[i];
    interpreter (ss_gd.str());
    stringstream ss_res; ss_res << interpreter.result;
    int msecs; ss_res >> msecs;
    flds[i]->fld.set_text (msecs / 1000.0f);
  }

  ui::enter ();

  cons.rollup (1);

}

void settings::update_widgets () {

  int lh = (int)(1.25f * get_line_height ());
  int x1 = (int)(0.25f * view.xmax), y1 = view.ymax - 2.3 * lh;
  int x2 = (int)(0.1f * view.xmax), y2 = view.ymax / 2, sepy = 7;

  scroll_up.set_pos (x2, y2);
  scroll_down.set_pos (x2, y2 - scroll_up.extents.height - sepy);
 
  for (int i = 0; i < num_widgets; ++i) lnspc [i] = lh;
  lnspc[0]=lnspc[3]=lnspc[8]=lnspc[11]=lnspc[16]=lnspc[20]=lnspc[22]=lnspc[24]=10;

  sn_scale_notes.update ();

  b_go_back.set_label ("Go back");
  b_factory_reset.set_label ("Reset to Factory Settings!");
  sp_num_octaves.update ();
  cb_show_midi_messages.set_label ("Show incoming MIDI messages");
  b_refresh_midi_devices.set_label ("Refresh MIDI devices");
  b_refresh_audio_devices.set_label ("Refresh Audio Devices");
  l_delay_dur.lbl.set_text ("L delay duration (seconds) ");
  r_delay_dur.lbl.set_text ("R delay duration (seconds) ");

  sp_fps.update ();
  sp_ips.update ();

  float t = get_tonic (get_current_instrument());
  s_key.set_label ("Key (Hz) ");
  s_key.set_value (t);
  s_key.by.set_text ("by");
  s_key.set_delta (1.0);

  NEAREST_NOTE_FREQUENCY = t;
  find_nearest_note (NEAREST_NOTE, NEAREST_NOTE_FREQUENCY, NEAREST_NOTE_DISTANCE);
  sprintf (sbuf, " nearest note = %s @ %0.3f Hz", NEAREST_NOTE.c_str(), NEAREST_NOTE_FREQUENCY);
  ol_nearest_note.set_text (sbuf);
  ol_nearest_note.set_click_repeat (1);
  for (int i = 0; i < num_widgets; ++i) {
    widgets[i]->set_pos (x1, y1);
    y1 -= lnspc[i];
  }

  i_current_midi = midiin.input_port;
  ol_midi_devices.option.set_text (" midi = " + midiin.get_name (i_current_midi));
  i_current_device = aout.current_device;
  ol_audio_devices.option.set_text (" audio = " + aout.get_name (aout.current_device));
  sprintf (sbuf, " sample rate = %d", aout.sample_rate);
  ol_sample_rates.option.set_text (sbuf);
  set_buffer_size (aout.samples_per_channel);

}

void settings::set_buffer_size (int bs) {
  for (size_t i = 0, j = buffer_sizes.size (); i < j; ++i) {
    if (buffer_sizes[i] == bs) {
      i_buffer_size = i;
      break;
    }
  }
  sprintf (sbuf, " buffer size = %d", buffer_sizes [i_buffer_size]);
  ol_buffer_sizes.option.set_text (sbuf);
}

void settings::find_current_tuning () {
  for (int i = 0; i < num_tunings; ++i) {
    if (s_current_tuning == tunings[i]) {
      i_current_tuning = i;
    }
  }
}

int settings::handle_input () {
  for (int i = 0; i < num_widgets; ++i) if (widgets[i]->handle_input ()) return 1;
  if (scroll_up.handle_input () || scroll_down.handle_input ()) return 1;
  return 0;
}

void settings::draw () {
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  glOrtho (0, view.xmax, 0, view.ymax, -1, 1);
  for (int i = 0; i < num_widgets; ++i) widgets[i]->draw ();
  scroll_up.draw ();
  scroll_down.draw ();
}

void settings::clicked (button& b) {
  static const int delta_height = 7;
  if (&b == &b_factory_reset) {
    cons ("factory-reset");
  } else if (&b == &b_go_back) {
    //uis.set_current (uis.uis[0], 0, 1);
    //uis.set_current (uis.uis[0]);
    uis.set_current (uis.prev);
  } else if (&b == &b_refresh_midi_devices) {
    midiin.probe ();
    ol_midi_devices.option.set_text (" midi = " + midiin.get_name (i_current_midi));
    midiin.open (i_current_midi);
  } else if (&b == &b_refresh_audio_devices) {
    aout.close ();
    aout.probe ();
    aout.open ();
    aout.start ();
    ol_audio_devices.option.set_text (" audio = " + aout.get_name (i_current_device));
    sprintf (sbuf, " sample rate = %d", aout.sample_rate);
    ol_sample_rates.option.set_text (sbuf);
    set_buffer_size (aout.samples_per_channel);
  } else if (&b == &scroll_up) {
    for (int i = 0; i < num_widgets; ++i) widgets[i]->move (0, -delta_height);
  } else if (&b == &scroll_down) {
    for (int i = 0; i < num_widgets; ++i) widgets[i]->move (0, +delta_height);
  } else if (&b == &ol_display_modes.apply) {
    display_mode& dm = display_modes [imode];
    extern int FULL_SCREEN; FULL_SCREEN = dm.fullscreen;
    setup_video_mode (dm.w, dm.h, dm.w, dm.h, dm.fullscreen);
  }
}

void settings::picked (label& l, int d) {
  static const float TWELFTH_ROOT_OF_2 = 1.0594630943f;
  if (&l == &ol_nearest_note.option) {
    float tonic = get_tonic (get_current_instrument ());
    if (d > 0) {
      tonic *= TWELFTH_ROOT_OF_2;
    } else {
      tonic /= TWELFTH_ROOT_OF_2;
    }
    set_tonic (get_current_instrument (), tonic);
  } else if (&l == &ol_notation.option) {
    extern string NOTATION;
    if (NOTATION == "western") {
      set_notation ("numeric");
    } else {
      set_notation ("western");
    }
    ol_notation.option.set_text (" notation = " + NOTATION);
  } else if (&l == &ol_tuning.option) {
    i_current_tuning += d;
    if (i_current_tuning < 0) i_current_tuning = num_tunings - 1; else
    if (i_current_tuning >= num_tunings) i_current_tuning = 0;
    s_current_tuning = tunings[i_current_tuning];
    interpreter ("tuning set " + s_current_tuning);
    ol_tuning.option.set_text (" tuning = " + s_current_tuning + " ");
  } else if (&l == &ol_midi_devices.option) {
    if (midiin.num_ports) {
      i_current_midi += d;
      if (i_current_midi < 0) i_current_midi = midiin.num_ports - 1;
      else if (i_current_midi >= midiin.num_ports) i_current_midi = 0;
      midiin.open (i_current_midi);
      ol_midi_devices.option.set_text (" midi = " + midiin.get_name (i_current_midi));
    }
  } else if (&l == &ol_audio_devices.option) {
    aout.goto_next_device (d);
    sprintf (sbuf, "set-audio device %d", aout.current_device);
    cons (sbuf);
    ol_audio_devices.option.set_text (" audio = " + aout.get_name (aout.current_device));
  } else if (&l == &ol_sample_rates.option) {
    int srate = aout.goto_next_sample_rate_id (d);
    sprintf (sbuf, " sample rate = %d", srate);
    ol_sample_rates.option.set_text (sbuf);
    sprintf (sbuf, "set-audio sample_rate %d", srate);
    cons (sbuf);
  } else if (&l == &ol_buffer_sizes.option) {
    i_buffer_size += d;
    int n = buffer_sizes.size ();
    if (i_buffer_size < 0) i_buffer_size = n - 1; else if (i_buffer_size >= n) i_buffer_size = 0;
    int bs = buffer_sizes [i_buffer_size];
    sprintf (sbuf, " buffer size = %d", bs);
    ol_buffer_sizes.option.set_text (sbuf);
    sprintf (sbuf, "set-audio samples_per_channel %d", bs);
    cons (sbuf);
  } else if (&l == &ol_display_modes.option) {
    imode += d;
    if (imode >= num_modes) imode = 0; else if (imode < 0) imode = num_modes - 1;
    update_mode_display ();
  }

}

void settings::changed (checkbutton& cb) {
  int state = cb_show_midi_messages.state;
  if (state) interpreter ("load-patch midimap 1"); else interpreter ("unload_midimap");
}


void settings::changed (field& f) {
  float value = f;
  if (&f == &l_delay_dur.fld || &f == &r_delay_dur.fld) {
    static float MAX_DURATION = 60; // seconds
    if (value <= 0 || value > MAX_DURATION) {
      if (&f == &l_delay_dur.fld)
        left_delay.get (value);
      else
        right_delay.get (value);
      value /= 1000.0;
      f.set_text (value);
    }
    string cmd ("set-delay ");
    if (&f == &l_delay_dur.fld) cmd += "left "; else cmd += "right ";
    float msecs = value * 1000.0f;
    stringstream ss; ss << msecs;
    cmd += ss.str();
    cons (cmd);
  } else if (&f == &s_key.f_value) {
    set_tonic (get_current_instrument (), value);
  } else if (&f == &sp_num_octaves.f_value) {
    set_num_octaves (f);
  } else if (&f == &sp_fps.f_value) {
    extern int FPS;
    extern double TIME_PER_FRAME;
    FPS = int (f);
    TIME_PER_FRAME = 1.0 / FPS;
  } else if (&f == &sp_ips.f_value) {
    extern int IPS;
    extern double TIME_PER_INPUT;
    IPS = (int) f;
    TIME_PER_INPUT = 1.0 / IPS;
  } else if (&f == &sp_mixing_time.f_value) {
    float mixt = f;
    if (mixt <= 0) {
      cons << console::red << "Bad mix time ie <= 0" << eol;
      return;
    }
    curve_mixer::TIME = f;
  }
}

void settings::load_fullscreen_modes () {

  dlog << "*** loading fullscreen modes ***" << endl;

  SDL_Rect **modes;

  // get available full screen modes
  modes = SDL_ListModes (0, SDL_FULLSCREEN | SDL_OPENGL | SDL_HWSURFACE);

  // Check is there are any modes available
  if (modes == (SDL_Rect **) 0){
    dlog << "No full-screen modes available" << endl;
    return;
  }

  // Check if our resolution is restricted
  if (modes == (SDL_Rect **) -1) {
  } else {
    static const int fullscreen = 1;
    static const int min_width = 1024;
    for(int i =0; modes[i]; ++i) {
      SDL_Rect* moder = modes[i];
      if (moder->w >= min_width) {
        display_modes.push_back (display_mode(moder->w, moder->h, fullscreen));
        dlog << " found mode: " << moder->w << 'x' << moder->h << endl;
      }
    }
  }

  num_modes = display_modes.size ();

  dlog << "number of fullscreen modes = " << num_modes << endl;
  dlog << "+++ loaded all full screen modes +++" << endl;

}

void settings::add_display_mode (int w, int h) {
  display_mode dm (w, h);
  display_modes.push_back (dm);
  num_modes = display_modes.size ();
}

void settings::update_windowed_mode (int w, int h) {
  int last_mode = num_modes - 1;
  display_mode& dm = display_modes [last_mode];
  dm.w = w; dm.h = h;
  if (last_mode == imode) update_mode_display ();
}

void settings::update_mode_display () {
  display_mode& dm = display_modes [imode];
  static const char* const fs_str[] = {"windowed", "full screen"};
  sprintf (sbuf, " display = %d x %d, %s", dm.w, dm.h, fs_str[dm.fullscreen]);
  ol_display_modes.set_text (sbuf);
}