Rev 2302 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* settings.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 "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 "din.h"
#include "just.h"
#include <sstream>
#include "log.h"
extern int NOTATION;
extern string NEAREST_NOTE;
extern float NEAREST_NOTE_FREQUENCY;
extern float NEAREST_NOTE_DISTANCE;
extern int NUM_OCTAVES;
extern char BUFFER [];
extern int wheel, wheely;
extern int line_height;
extern const char* notation_types[];
extern din din0;
settings::settings () : ol_nearest_note (1), ol_display_modes (1) {
name = "settings";
imode = -1;
num_widgets = 0;
i_current_tuning = 0;
}
void settings::setup () {
// setup separators
separator* seps [] = {&hsep1, &hsep2, &hsep3, &hsep4, &hsep5, &hsep6, &hsep7, &hsep8, &hsep9, &hsep10};
for (int i = 0; i < 10; ++i) seps[i]->set_extents (480);
// setup widget array
widget* wa [] = {
&b_go_back,
&hsep1, // 0
&sp_key,
&ol_nearest_note,
&hsep2, // 3
&sn_scale_notes,
&sp_num_octaves,
&ol_notation,
&ol_tuning, // 8
&hsep3,
&l_delay_dur,
&r_delay_dur,
&cb_sync_delay, // 12
&hsep4,
&binaural.is,
&binaural.justs,
&binaural.sep, // 16
&hsep5,
&lf_mixing_time,
&lf_mixing_samples,
&b_set_to_audio_buffer_time, // 20
&hsep6,
&ol_audio_devices,
&ol_sample_rates,
&ol_buffer_sizes,
&b_refresh_audio_devices, // 25
&hsep7,
&ol_midi_devices,
&b_refresh_midi_devices,
&cb_show_midi_messages, // 29
&hsep8,
&ol_display_modes, // 31
&hsep9,
&sp_fps,
&sp_ips, // 34
&hsep10,
&b_factory_reset,
};
int nw = 37;
widgets.resize (nw);
for (int i = 0; i < nw; ++i) widgets[i] = wa[i];
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;
cb_sync_delay.set_listener (this);
ol_nearest_note.set_listener (this);
ol_nearest_note.apply.set_listener (this);
sp_num_octaves.set_listener (this);
ol_display_modes.set_listener (this);
ol_display_modes.apply.set_listener (this);
binaural.justs.set_listener (this);
picked (binaural.justs.option, 0);
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 (lspn[i], 1, 1, MILLION, this, 0);
}
lf_mixing_time.set_listener (this);
lf_mixing_time.fld.fmt = field::inf;
lf_mixing_time.set_label ("Curve mixing time = ");
lf_mixing_samples.set_listener (this);
lf_mixing_samples.set_label ("Curve mixing samples = ");
b_set_to_audio_buffer_time.set_listener (this);
cb_show_midi_messages.set_state (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;
cb_sync_delay.set_text ("Sync");
cb_sync_delay.turn_on ();
interpreter ("tuning list");
tokenizer tz (interpreter.result);
string name;
while (1) {
tz >> name;
if (name == "") break;
tunings.push_back (name);
}
num_tunings = tunings.size ();
binaural.is.set_text ("DIN Is Binaural");
binaural.sep.set ("Separation (Hz)", 0.1f, 0, MILLION, &binsepl, 0);
sp_key.set ("Key (Hz)", 1.0f, 0, MILLION, this, 0);
sp_num_octaves.set ("Number of Octaves", 1, 1, MILLION, this, 0);
}
void settings::enter () {
// called b4 settings page is displayed
// refresh settings
curin = get_current_instrument ();
curin->scaleinfo.update_settings ();
if (prev_mousex == -1) {
prev_mousex = view.xmax / 2;
prev_mousey = view.ymax / 2;
}
sprintf (BUFFER, " notation = %s", notation_types[NOTATION]);
ol_notation.option.set_text (BUFFER);
ol_tuning.option.set_text (" tuning = " + tunings [i_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);
cons << GREEN << "Use mouse wheel to scroll!" << eol;
}
void settings::update_widgets () {
int lh = (int) (1.25f * line_height);
int x1 = (int) (0.25f * view.xmax), y1 = view.ymax - 2.5 * lh;
for (int i = 0; i < num_widgets; ++i) lnspc [i] = lh;
lnspc[0]=lnspc[3]=lnspc[8]=lnspc[12]=lnspc[16]=lnspc[20]=lnspc[25]=lnspc[29]=lnspc[31]=lnspc[34]=14;
sn_scale_notes.update ();
b_go_back.set_text ("Go back");
b_factory_reset.set_text ("Reset to Factory Settings!");
sp_num_octaves.update ();
cb_show_midi_messages.set_text ("Show incoming MIDI messages");
b_refresh_midi_devices.set_text ("Refresh MIDI devices");
b_refresh_audio_devices.set_text ("Refresh Audio Devices");
l_delay_dur.lbl.set_text ("L delay duration");
r_delay_dur.lbl.set_text ("R delay duration");
sp_fps.update ();
sp_ips.update ();
float t = get_tonic (get_current_instrument());
sp_key.set_value (t);
NEAREST_NOTE_FREQUENCY = t;
find_nearest_note (NEAREST_NOTE, NEAREST_NOTE_FREQUENCY, NEAREST_NOTE_DISTANCE);
sprintf (BUFFER, " nearest note = %s @ %0.3f Hz", NEAREST_NOTE.c_str(), NEAREST_NOTE_FREQUENCY);
ol_nearest_note.set_text (BUFFER);
ol_nearest_note.set_click_repeat (1);
ol_nearest_note.apply.set_text ("Set");
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.names [aout.current_device]);
sprintf (BUFFER, " sample rate = %d", aout.sample_rate);
ol_sample_rates.option.set_text (BUFFER);
set_buffer_size (aout.samples_per_channel);
b_set_to_audio_buffer_time.set_text ("Set to Audio Buffer Time");
}
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 (BUFFER, " buffer size = %d", buffer_sizes [i_buffer_size]);
ol_buffer_sizes.option.set_text (BUFFER);
}
int settings::handle_input () {
if (wheel && !widget::HOVER) move_widgets (wheel * wheely);
for (int i = 0; i < num_widgets; ++i) if (widgets[i]->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 ();
}
void settings::move_widgets (int dy) {
for (int i = 0; i < num_widgets; ++i) widgets[i]->move (0, dy);
}
void settings::clicked (button& b) {
if (&b == &ol_nearest_note.apply) {
instrument* i = get_current_instrument ();
scale_info& si = i->scaleinfo;
scale_info::nearest_note_t& nn = si.nearest_note;
find_nearest_note (nn.name, nn.freq, nn.distance);
si.set_tonic (nn.freq);
sp_key.set_value (nn.freq);
} else if (&b == &b_set_to_audio_buffer_time) {
lf_mixing_time.fld.set_text (aout.samples_per_channel * 1.0f / aout.sample_rate);
changed (lf_mixing_time.fld);
} else if (&b == &b_factory_reset) {
cons ("factory-reset");
} else if (&b == &b_go_back) {
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.names [i_current_device]);
sprintf (BUFFER, " sample rate = %d", aout.sample_rate);
ol_sample_rates.option.set_text (BUFFER);
set_buffer_size (aout.samples_per_channel);
} 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;
const static char *bjus [] = {" Justification = Left", " Justification = Right", " Justification = Random"};
if (&l == &binaural.justs.option) {
extern int JUSTIFICATION;
JUSTIFICATION += d;
wrap<int> (just::LEFT, JUSTIFICATION, just::RANDOM);
const char* dj = bjus [JUSTIFICATION];
l.set_text (dj);
} else
if (&l == &ol_nearest_note.option) {
instrument* ci = get_current_instrument ();
float tonic = get_tonic (ci);
if (d > 0) {
tonic *= TWELFTH_ROOT_OF_2;
} else {
tonic /= TWELFTH_ROOT_OF_2;
}
set_tonic (ci, tonic);
ol_nearest_note.set_apply_pos ();
} else if (&l == &ol_notation.option) {
NOTATION += d;
wrap<int> (NUMERIC, NOTATION, INDIAN);
set_notation (NOTATION);
sprintf (BUFFER, " notation = %s", notation_types [NOTATION]);
ol_notation.option.set_text (BUFFER);
} else if (&l == &ol_tuning.option) {
i_current_tuning += d;
wrap (0, i_current_tuning, num_tunings - 1);
s_current_tuning = tunings [i_current_tuning];
ol_tuning.option.set_text (" tuning = " + s_current_tuning);
sprintf (BUFFER, "tuning set %s %d", s_current_tuning.c_str(), i_current_tuning);
interpreter (BUFFER);
} 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) {
if (aout.goto_next_device (d)) {
sprintf (BUFFER, "set-audio device %d", aout.current_device);
cons (BUFFER);
ol_audio_devices.option.set_text (" audio = " + aout.names [aout.current_device]);
}
} else if (&l == &ol_sample_rates.option) {
int srate = aout.goto_next_sample_rate_id (d);
sprintf (BUFFER, " sample rate = %d", srate);
ol_sample_rates.option.set_text (BUFFER);
sprintf (BUFFER, "set-audio sample_rate %d", srate);
cons (BUFFER);
} 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 (BUFFER, " buffer size = %d", bs);
ol_buffer_sizes.option.set_text (BUFFER);
sprintf (BUFFER, "set-audio samples_per_channel %d", bs);
cons (BUFFER);
MENU.sp_scope_samples.set_limits (1, bs);
} 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::do_delay_dur (delay& d, field& f) {
float v = f;
if (v <= 0) {
cons << RED << "bad delay duration" << eol;
d.get (v);
v /= 1000.0;
f.set_text (v);
return;
}
string cmd ("set-delay ");
if (cb_sync_delay.state) {
l_delay_dur.fld.set_text (v);
r_delay_dur.fld.set_text (v);
cmd += "all ";
}
else if (&f == &l_delay_dur.fld) cmd += "left ";
else cmd += "right ";
float msecs = v * 1000.0f;
stringstream ss; ss << msecs;
cmd += ss.str();
cons (cmd);
}
void settings::changed (field& f) {
if (&f == &sp_key.f_value) {
set_tonic (get_current_instrument (), sp_key.value);
} else if (&f == &lf_mixing_time.fld) {
float mixt = f;
if (mixt <= 0.0f) {
cons << RED << "Bad mix time" << eol;
return;
}
curve_mixer::TIME = f;
curve_mixer::SAMPLES = curve_mixer::TIME * SAMPLE_RATE;
lf_mixing_samples.fld.set_text (curve_mixer::SAMPLES);
} else if (&f == &lf_mixing_samples.fld) {
int s = f;
if (s < 1) {
cons << RED << "Bad mix samples" << eol;
return;
}
curve_mixer::SAMPLES = s;
curve_mixer::TIME = curve_mixer::SAMPLES * 1.0f / SAMPLE_RATE;
lf_mixing_time.fld.set_text (curve_mixer::TIME);
} else if (&f == &l_delay_dur.fld) {
do_delay_dur (left_delay, l_delay_dur.fld);
} else if (&f == &r_delay_dur.fld) {
do_delay_dur (right_delay, r_delay_dur.fld);
} else if (&f == &sp_num_octaves.f_value) {
set_num_octaves (sp_num_octaves.value);
} else if (&f == &sp_fps.f_value) {
extern int FPS;
extern double TIME_PER_FRAME;
FPS = sp_fps.value;
TIME_PER_FRAME = 1.0 / FPS;
} else if (&f == &sp_ips.f_value) {
extern int IPS;
extern double TIME_PER_INPUT;
IPS = sp_ips.value;
TIME_PER_INPUT = 1.0 / IPS;
}
}
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 (BUFFER, " display = %d x %d, %s", dm.w, dm.h, fs_str[dm.fullscreen]);
ol_display_modes.set_text (BUFFER);
}
void settings::sample_rate_changed () {
curve_mixer::SAMPLES = curve_mixer::TIME * SAMPLE_RATE;
lf_mixing_samples.fld.set_text (curve_mixer::SAMPLES);
}
settings::~settings () {}
VALUE_CHANGED (settings, bin_sep_lis) {
extern float SEPARATION;
SEPARATION = uis.settings_scr.binaural.sep.value;
cons << GREEN << "Default binaural separation (Hz) = " << SEPARATION << eol;
}