Rev 2310 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* main.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 <SDL/SDL.h>
#include <string>
#include <map>
#include <vector>
#include <iostream>
#include <fstream>
#include <list>
#include <algorithm>
#include <tcl.h>
#include "dingl.h"
#include "main.h"
#include "box.h"
#include "utils.h"
#include "font.h"
#include "ui_list.h"
#include "console.h"
#include "input.h"
#include "viewwin.h"
#include "curve.h"
#include "multi_curve.h"
#include "solver.h"
#include "chrono.h"
#include "curve_editor.h"
#include "font_editor.h"
#include "din.h"
#include "curve_library.h"
#include "console_iterator.h"
#include "delay.h"
#include "random.h"
#include "globals.h"
#include "command.h"
#include "scalelist.h"
#include "morse_code.h"
#include "sine_mixer.h"
#include "tcl_interp.h"
#include "compressor.h"
#include "oscilloscope.h"
#include "keyboard_keyboard.h"
#include "authors_note.h"
#include "midi_in.h"
#include "menu.h"
#include "curve_picker.h"
#include "fractaliser.h"
#include "rose_milker.h"
#include "circler.h"
#include "spiraler.h"
#include "starrer.h"
#include "lissajous.h"
#include "superformula.h"
#include "warper.h"
#include "recorder.h"
#include "mondrian.h"
#include "instrument.h"
#include "countries.h"
#include "morpher.h"
#include "number.h"
#include "binaural_drones.h"
#include "fft.h"
#include "capturer.h"
#include "noiser.h"
#include "defvelaccel.h"
#include "just.h"
using namespace std;
#if defined __GPL20__
string home = getenv ("HOME");
string user_data_dir (home + "/.din/"); // contains defaults, user savings and prefs
string country_data_dir (user_data_dir + "country/"); // contains country data used by countries plugin (see countries.cc)
#elif defined (__MACOSX_CORE__) || defined (__LINUX_BIN__)
string user_data_dir = "user/";
string country_data_dir = "user/country/";
#elif __WINDOWS_DS__
string user_data_dir = "user\\";
string country_data_dir = "user\\country\\";
#endif
ofstream dlog ("log", ios::out); // DIN Is Noise log
extern const float GOLDEN_RATIO = 1.618033;
extern const float PI = 3.1415961;
extern const float TWO_PI = 2 * PI;
extern const float PI_BY_180 = PI / 180.;
extern const char spc = ' ';
char tokenizer::delim = spc;
// for attack, decay and deltas [see keyboard-keyboard.cc, mondrian.cc, triggered_note.cc]
extern const float MIN_TIME = 0.01f; // seconds
tcl_interp interpreter; // integrated TCL interpreter
int quit = DONT;
struct startup_shutdown {
startup_shutdown () {
dlog << "!!! started DIN Is Noise @ " << interpreter ("clock format [clock seconds]").result << " !!!" << endl;
time_t t0 = time(0);
seed_rand_gen (t0);
dlog << "+++ initialised random number generator @ seed = " << t0 << " +++" << endl;
}
~startup_shutdown () {
SDL_Quit ();
dlog << "!!! cleaned up SDL !!!" << endl;
dlog << "*** [Mondrian] box count = " << rect::ref << " ***" << endl;
dlog << "*** [Mondrian] ball count = " << ball::ref << " ***" << endl;
dlog << "*** [Mondrian] slit count = " << slit::ref << " ***" << endl;
dlog << "*** [Microtonal-Keyboard] drone count = " << drone::ref << " ***" << endl;
dlog << "\\o/ DIN Is Noise was up for " << interpreter ("uptime 0").result << " \\o/" << endl;
dlog << "DIN Is Noise shutdown @ " << interpreter ("clock format [clock seconds]").result << endl;
}
} SS ;
help curve_editor::helptext ("curve_editor.hlp");
// DIN clocks
double TIME_NOW = 0; // in seconds on the audio clock stored in variable timenow on TCL interpreter
audio_clock clk; // audio clock
ui_clock ui_clk; // UI clock
// keyboard and mouse state
keyboard keybd;
int mousex = 0, mousey = 0, mouseyy = 0; // absolute mouse x, y & main viewport y
int lmb = 0, mmb = 0, rmb = 0; // left & right mouse buttons
int wheel = 0; // mouse wheel
int wheely = -60; // for moving menu, settings widgets
int SHIFT = 0; // shift button
int CTRL = 0; // ctrl button
int ALT = 0; // alt button
is_lmb_t is_lmb; // for acquiring lmb
// UI
int UI_OFF = 0;
int widget::HOVER = 0; // mouse hovering on any widget?
widget* widget::focus = 0; // widget that has focus
widget* widget::next_focus = 0; // widget waiting to have focus
// see spinner.h, spinner2.h
int SPACING = 6;
int VAR_MIN = -100, VAR_MAX = 100; // for variance @ spinner.h
int VAR_MIN2 = 0, VAR_MAX2 = 100; // for variance @ spinner2.h
string VARSTR, VARSTR2;
// widget defaults
// loaded from globals file (see globals.cc)
float widget::R, widget::G, widget::B; // default widget color
int widget::bb [16] = {0}; // widget bounding box
color checkbutton::on_color, checkbutton::off_color; // checkbutton on/off colors
const char* field::fmts [] = {"%0.3f", "%0.4f", "%0.6f", "%f"}; // precision formats for field
int FPS = 0; // requested frames per second
double TIME_PER_FRAME; // in seconds, calc @ command.cc
double LAST_FRAME_TIME = 0.0;
double FPSNOW = 0.0;
int IPS; // requested keyboard/mouse inputs per second
double TIME_PER_INPUT; // in seconds
double LAST_INPUT_TIME = 0.0;
double IPSNOW = 0.0;
int basic_editor::hide_cursor = 0; // to hide cursor when mouse is on a ui control
float* basic_editor::gl_pts = 0;
float* basic_editor::gl_clr = 0;
int basic_editor::n_pts = 0;
int basic_editor::ref = 0;
const char* basic_editor::drawt::snapss[2] = {"Not drawing snapping guides", "Drawing snapping guides"};
const char* basic_editor::drawt::guides[2] = {"Not drawing cursor guide", "Drawing cursor guide"};
int plugin::change_curve_name = 1; // when applying plugin?
int capturer_t::ref = 0; // see capturer.h
int point_modulator::ref = 0; // see point_modulator.h
list<crvpt> LIST_OF_POINTS; // list of points (see curve.h/cc)
// binaurality
//
int DIN_IS_BINAURAL = 0; // default no (for now :)
int JUSTIFICATION = just::RANDOM;
float SEPARATION = 4.0f;
// see drone.h/cc
int drone::UID = 0; // unique id for drones
int drone::ref = 0; // for ref counting drones
map<drone*, bool> drone::proc_conn; // drone connections
float drone::STIFFNESS = 1.0f; // stiffness of inter-drone connections
double drone::LIFETIME = 3; // for launched drones (seconds)
int drone::HANDLESIZE = 3; // default drone handle size
double drone::INSERTTIME = 3; // for launched drones to get into orbit (seconds)
double drone::gabt = 1.0f; // for mute/unmute drones
float drone::MASTERVOLUME = 0.0f; // for all drones
point<float> mod_params::horizontal (1.0f,0.0f), mod_params::vertical (0.0f,1.0f); // drone modulation directions
int drone::IS = drone::DRONE;
drone::wandt drone::wand (5.0); // for wandded drones
anglet drone::chuckt::apt; // angle per turn (degrees) for chuck rotation
int drone::chuckt::outline = 1; // draw chuck outlines?
int drone::chuckt::autoresettrails = 1; // when chuck params changed?
int drone::ARE = drone::IMMORTAL; // type of drone
int drone::anchored = 0;
float drone::arrowt::U = 0.25, drone::arrowt::V = 0.25, drone::arrowt::K = 1.0f, drone::arrowt::CAP = 1;
defvelaccel drone::v0 (" Velocity"), drone::a0 (" Acceleration");
const char* menu::defvelaccelui::autopauset::tars[] = {" Target is Auto rotate", " Target is Auto flip"};
multi_curve drone::modvt::crv ("modv.crv");
float drone::anchoropacity = 0.5;
// for drone <> noise conversion
drone::drone2noise drone::dnl;
drone::noise2drone drone::ndl;
drone::fin* drone::fins[3] = {0, &drone::dnl, &drone::ndl};
double drone::posafxvelt::minmag = 3.0f;
// for trails on drones and mondrian
float* trail_t::tpts = 0;
int trail_t::n_tpts = 0;
// drone mesh, see mesh.h/cc
int* mesh::gl_pts = 0;
float* mesh::clr = 0;
int mesh::n_glpts = 0;
int proximity_orderer::ROW = 0, proximity_orderer::COL = 0;
double fader::TIME; // loaded from din_info
// see curve_mixer.h/cc
float curve_mixer::TIME = 1.0f; // curve (waveform/envelope) mixing time in seconds
int curve_mixer::SAMPLES = 1024; // curve mixing time in samples, change one, changes the other
double curve_mixer::ELAPSEDT = 0.0;
// for sprintf
const int BUFFER_SIZE = 1 << 15;
char BUFFER [BUFFER_SIZE] = {0};
// music constants
//
int NUM_NOTES = 13;
// notations
int NOTATION = WESTERN;
const char* notation_types [] = {"numeric", "western", "indian"};
const char* WESTERN_SHARP [] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "C"};
const char* WESTERN_FLAT [] = {"C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B", "C"};
const char* INDIAN_SWAR [] = {"s", "r", "R", "g", "G", "m", "M", "P", "d", "D", "n", "N", "S"};
//const char* SOLFEGE [] = {"Do", "re", "Re", "mi", "Mi", "fa", "Fa", "So", "la", "La", "ti", "Ti", "Do"};
// for the octave of Middle-C; from wikipedia - piano key frequencies page.
float WIKIPEDIA_KEY_FREQUENCIES [] = {
261.626f, 277.183f, 293.665f, 311.127f, 329.628f, 349.228f, 369.994f, 391.995f, 415.305f, 440.0f, 466.164f, 493.883f, 523.251f
};
string NEAREST_NOTE; // note nearest to key of DIN
float NEAREST_NOTE_DISTANCE; // distance in Hz of the nearest note from the key of DIN
float NEAREST_NOTE_FREQUENCY; // frequency in Hz of the nearest note to the key of DIN
int SAMPLE_RATE; // sample rate of DIN
float SAMPLE_DURATION; // duration of an audio sample in seconds
string SCALE; // current scale
string TUNING; // current tuning
int NUM_INTERVALS; // number of intervals in tuning
string INTERVALS_FILE; // file name that contains interval info
map <string, float> INTERVALS; // interval name -> value
map <string, string> INT2IND;
vector<string> INTERVAL_NAMES; // sequential interval names (eg., 1 2b 2 3b 3 ... 7b 7 8)
vector<float> INTERVAL_VALUES; // sequential interval values (eg., value of 1 2b 3 3b ... 7b 7 8)
map <string, int> NOTE_POS; // interval name -> note number (eg., 1 => 0, 2b => 1, 3 => 2, etc)
scale_info all_notes; // used by change left/right note on range to move to any note
//
// microtonal keyboard
//
const char* s_drones = " drones";
int LEFT = 0, BOTTOM, TOP;
int WIDTH, HEIGHT;
int TRAILSIZE = 0; // default drone trail size (== number of trail points), mondrian ball trail size
int NUM_OCTAVES = 3; // number of octaves
// random bpm init see range::init_mod()
// limits loaded from globals file, see globals.cc
rnd<int> RAN_MOD_BPM;
const char* din_info::cnn_opts [] = {" to scale note", " to any note"};
const char* din_info::cnno [] = {"Octave", "Note"};
// see curve_samples in curve_editor.h
float curve_samples::dm = 0.0f;
float curve_samples::nsec = 1.0f;
// screens - 1 is instrument; 2 - 8 are editors
//
const Uint8 ui_list::key [] = {SDLK_2, SDLK_3, SDLK_4, SDLK_5, SDLK_6, SDLK_7, SDLK_8}; // keys 2 - 8
ui* ui_list::ed [] = {0};
ui* ui::over = 0;
// solver xhandlers; see solver.cc
atmin _atmin;
atmax _atmax;
tomin _tomin;
tomax _tomax;
loopmin _loopmin;
loopmax _loopmax;
pongmin _pongmin;
pongmax _pongmax;
// see multi_curve.cc
multi_curve curve_editor::copy;
multi_curve mix;
color curve_editor::vtxlbl; // vertex label color
int hit_t::name_only = 0;
// see sine_mixer.cc
int sine_mixer::NUM_SINE_SAMPLES = 100;
const int sine_mixer::MIN_SINE_SAMPLES = 4;
// program info
string APP_NAME;
string VERSION_NUMBER;
//
// display
//
int FULL_SCREEN = 0; // full screen?
const int SCREEN_DEPTH = 24; // fixed color depth
// see viewwin.cc
viewport view; // display - using OpenGL
int viewport::handle_radius;
float viewport::handle_factor;
int window::PAN_RATE = 100, window::ZOOM_RATE = 100;
double window::PAN_REPEAT = 1.0 / PAN_RATE, window::ZOOM_REPEAT = 1.0 / ZOOM_RATE;
float window::PAN_AMOUNT = 0.1f, window::ZOOM_AMOUNT = 0.1f;
load_globals lg;
// 0 init correct for oscilloscope; see oscilloscope.cc
float oscilloscope::sample_t::lmin = 0, oscilloscope::sample_t::lmax = 0;
float oscilloscope::sample_t::rmin = 0, oscilloscope::sample_t::rmax = 0;
oscilloscope scope ("scope.osc");
// custom vector font
#ifdef __SVG_FNT__
font fnt ("laser.fnt");
#elif __PLOTTER_FNT__
font fnt ("plotter.fnt");
#else
font fnt ("jag.fnt");
#endif
int line_height; // of text
// console
//
console cons;
// possible text colors
const float cc = 0.75f;
const color console::yellow (1, 1, cc);
const color console::green (cc, 1, cc);
const color console::red (1, cc, cc);
const color console::cyan (cc, 1, 1);
const color console::white (1, 1, 1);
const char* console::precision = "%.3f";
void set_window_caption () {
make_app_name ();
SDL_WM_SetCaption (APP_NAME.c_str(), APP_NAME.c_str());
}
string CHARSET [] = { // list of input chars
// US layout
"abcdefghijklmnopqrstuvwxyz0123456789 .=-/;\\,[]'`", // normal
"ABCDEFGHIJKLMNOPQRSTUVWXYZ)!@#$%^&*( >+_?:|<{}\"~", // shift
};
const int CHARSET_LENGTH = CHARSET[0].length ();
char get_typed_char () { // get char typed on an input area
const string& norm = CHARSET[0];
const string& shift = CHARSET[1];
for (int i = 0; i < CHARSET_LENGTH; ++i) {
if (keypressedd (norm[i])) {
if (SHIFT || keydown (SDLK_CAPSLOCK))
return shift[i];
else
return norm[i];
}
}
return 0;
}
// audio output
//
audio_out aout;
// list of scales
scalelist scalelst;
//
// L and R delays
//
delay left_delay (1000, "feedback-l.crv", "volume-l.crv"), right_delay (1000, "feedback-r.crv", "volume-r.crv");
curve_editor delayed ("delay.ed");
font_editor fed (fnt, "font.ed", "font.hlp");
multi_curve dummy ("dummy.crv");
// vars in Tcl interpreter
//
// midi bpm from external midi clock
double MIDI_BPM = 0;
// tap bpm from computer keyboard
double TAP_BPM = 0;
// microtonal-keyboard height (0 to 1)
float VOLUME = 0;
fft fft0; // FFT of waveform in waveform editors
cmdlist cmdlst; // list of din commands
// 1 oscillator / waveform for lead
//
float VOICE_VOLUME = 0.2f;
//
// curve libraries
//
curve_library wav_lib ("waveforms.lib"); // waveforms
curve_library sin_lib ("sin.lib"); // custom sine curves
curve_library cos_lib ("cos.lib"); // custom cosine curves
curve_library attack_lib ("attack.lib", 1); // attack curves [1 = has_sustain]
curve_library decay_lib ("decay.lib"); // decay curves
// compressor
compressor coml ("coml.crv"), comr ("comr.crv");
curve_editor comed ("compressor.ed");
// octave shift
//
beat2value octave_shift ("os", "octave-shift.crv");
curve_editor octed ("octave-shift.ed");
curve_library octlib ("octave-shift-patterns.lib");
beat2value_listener octlis;
// drone modulation
//
multi_curve drone_mod_am_crv ("drone-mod-am.crv");
multi_curve drone_mod_fm_crv ("drone-mod-fm.crv");
curve_editor drone_mod_ed ("drone-modulation.ed");
drone_mod_lis dmlis;
// range modulation
multi_curve ran_mod_width_crv ("range-mod-width.crv");
multi_curve ran_mod_height_crv ("range-mod-height.crv");
curve_editor ran_mod_ed ("range-modulation.ed");
// point modulation
curve_editor pomo_ed ("point-modulation.ed");
multi_curve pomo_x_crv ("pomo-x.crv");
multi_curve pomo_y_crv ("pomo-y.crv");
pomo_lis pol;
// range width/height set
multi_curve ran_width_crv ("range-width.crv"), ran_height_crv ("range-height.crv");
solver sol_ran_width (&ran_width_crv), sol_ran_height (&ran_height_crv);
curve_editor ran_wh_ed ("range-width-height.ed");
range_wh_lis rwhl;
// pitch / volume distribution
multi_curve pitch_crv ("pitch.crv"), vol_crv ("vol.crv");
curve_editor pitch_vol_ed ("pitch-vol.ed");
solver warp_pitch (&pitch_crv), warp_vol (&vol_crv);
multi_curve* warcrv [] = {&pitch_crv, &vol_crv};
solver* warsol_pv [] = {&warp_pitch, &warp_vol};
pitch_vol_lis pvl;
// noise interpolation
multi_curve noiser::interp ("noiser.crv");
curve_editor noiser::ed ("noiser.ed");
noise_interp_lis noiser::lis;
// drone pendulum depth & bpm
multi_curve dp_depth ("dp_depth.crv"), dp_bpm ("dp_bpm.crv");
curve_editor drone_pend_ed ("drone-pend.ed");
solver warp_depth (&dp_depth), warp_bpm (&dp_bpm);
solver* warsol_dp [] = {&warp_depth, &warp_bpm};
multi_curve* dp_crv [] = {&dp_depth, &dp_bpm};
drone_pend_ed_lis dpel;
recorder recorder0; // for recording sounds made in DIN
// microtonal-keyboard see din.cc/.h
//
const string din::PSD = "Please select some drones!";
const string din::A2D = "Please select at least 2 drones.";
const char* ol_fixed_lbls [] = {" with left fixed", " with center fixed", " with right fixed"};
const char* voice_is_lbls [] = {"Noise", "Voice"};
din din0 (cmdlst);
int BEATER = 0; // beater editor id init in din::setup
// mondrian (see mondrian.cc/h)
//
unsigned char mondrian::patbuf [1024] = {0};
string mondrian::patstr = "din is noise";
int mondrian::patstep = 1, mondrian::patlen = mondrian::patstr.length ();
rnd<float> rect::rd (0.0f, 1.0f); // to make box color
int rect::ref = 0, ball::ref = 0, slit::ref = 0;
const float mondrian::gutter = 2;
const float mondrian::gutter2 = mondrian::gutter * mondrian::gutter;
float mondrian::min_split_size = 16;
float slit::HALF_SIZE = 20;
float slit::MIN_HALF_SIZE = 1;
float slit::MIN_SIZE = 2 * slit::MIN_HALF_SIZE;
const char* ball::types_str [4] = {" bouncer", " wrecker", " healer", " bouncer or wrecker or healer"};
const char* ball::trigstr [2] = {"note", "noise"};
float ball::recent_attack_time = 0.01f; // secs
float ball::recent_decay_time = 2.0f; // secs
float ball::recent_pitch_mult = 1.0f; // modulation
const char* mondrian_listener::split_types [3] = {" into 2 boxes", " at notes", " into N boxes"};
const char* mondrian_listener::selection_targets [2] = {"Selection target = slits", "Selection target = balls"};
const char* mondrian_listener::pick_box_types [5] = {" Pick the oldest box", " Pick a random box", " Pick the biggest box", " Pick the youngest box", " Pick a box that has a ball"};
const char* mondrian_listener::auto_split_orient_types [4] = { "", " Split horizontally", " Split vertically", " Split horizontally & vertically"};
const char* mondrian_listener::auto_split_at_types [2] = {" Split at notes", " Split anywhere"};
const double slit::INITIAL_OPEN_CLOSE_TIME = 2.0;
// ball operations
const char* ball_op::names [] = {"All Ops", "Turn", "Speed", "Teleport", "Clone"};
float ball_op::TRIGGERT = 0.1; // seconds
float turn::CLOCKWISE = 60.0f, turn::ANTI_CLOCKWISE = 60.0f; // degrees
float speed::BRAKE = 1, speed::ACCELERATE = 1;
float teleport::MAX_RADIUS = 300.0f;
int Clone::max_balls = 64;
int Transform::rules [3] = {ball::WRECKER, ball::HEALER, ball::BOUNCER};
mondrian mondrian0;
// binaural drones see binaural_drones.cc/h)
//
i_binaural_drones binaural_drones0;
const char* binaural_drones_listener::justs [] = {" Justification = Left", " Justification = Right", " Justification = Center"};
gotog _gotomax (1, &mondrian0.attacked);
// keyboard-keyboard
//
float NOTE_VOLUME = 0.75f * VOICE_VOLUME;
int PITCH_BEND; // in Hz
float PITCH_BEND_PER_PIXEL;
// in seconds
float ATTACK_TIME = 0.05f;
float DECAY_TIME = 5.0f;
float DELTA_TIME = 0.025f;
keyboard_keyboard keybd2;
gotog _gotog (1, &keybd2.attacked); // default sustain (see keyboard-keyboard.cc)
// available instruments
const char* INSTRUMENTS [] = {"keyboard_keyboard", "microtonal_keyboard", "mondrian", "binaural_drones"};
const char* INSTRUMENTS_SHORT [] = {"kkb", "mkb", "mon", "bd"};
extern const int NUM_INSTRUMENTS = 4, LAST_INSTRUMENT = NUM_INSTRUMENTS - 1;
int CURRENT_INSTRUMENT = 0;
string INSTRUMENT = INSTRUMENTS [CURRENT_INSTRUMENT];
instrument* INSTRUMENT_PTR [] = {&keybd2, &din0, &mondrian0, &binaural_drones0};
checkbutton* LAST_TABS [NUM_INSTRUMENTS] = {0, 0, 0, 0};
mkb_selector_t mkb_selector; // selector for microtonal keyboard with drone mesh preview
box_selector mon_selector; // selector for mondrian
string style_listener::styles [] = {"loop", "pong"};
vector<multi_curve*> curve_list;
void setup_curve_list () {
multi_curve* lst [] = {
&din0.wave,
&keybd2.wave,
din0.fm.crv,
din0.am.crv,
din0.gatr.crv,
octave_shift.crv,
&din0.drone_wave,
&left_delay.fbk_crv,
&left_delay.vol_crv,
&right_delay.fbk_crv,
&right_delay.vol_crv
};
for (int i = 0; i < 11; ++i) curve_list.push_back (lst[i]);
}
const char* bpm_com::str [bpm_com::NUM] = {"os", "gr", "am", "fm"};
beat2value* bpm_com::bv [] = {&octave_shift, &din0.gatr, &din0.am, &din0.fm};
#define DEFINE_TCL_FUNC(X) inline int (X) (ClientData cd, Tcl_Interp* ti, int objc, Tcl_Obj* CONST objv[]) { return tcl_run (cd, ti, objc, objv);}
DEFINE_TCL_FUNC(tcl_key)
DEFINE_TCL_FUNC(tcl_setv)
DEFINE_TCL_FUNC(tcl_getv)
DEFINE_TCL_FUNC(tcl_set_delay)
DEFINE_TCL_FUNC(tcl_get_delay)
DEFINE_TCL_FUNC(tcl_set_bpm)
DEFINE_TCL_FUNC(tcl_get_bpm)
DEFINE_TCL_FUNC (tcl_set_beat);
DEFINE_TCL_FUNC (tcl_get_beat);
DEFINE_TCL_FUNC(tcl_set_style)
DEFINE_TCL_FUNC(tcl_get_style)
DEFINE_TCL_FUNC(tcl_set_kern)
DEFINE_TCL_FUNC(tcl_get_kern)
DEFINE_TCL_FUNC(tcl_set_font_size)
DEFINE_TCL_FUNC(tcl_get_font_size)
DEFINE_TCL_FUNC(tcl_note_distance)
DEFINE_TCL_FUNC(tcl_chord)
DEFINE_TCL_FUNC(tcl_notation)
DEFINE_TCL_FUNC(tcl_echo)
DEFINE_TCL_FUNC(tcl_curve_value)
DEFINE_TCL_FUNC(tcl_curve_name)
DEFINE_TCL_FUNC(tcl_curve_library)
DEFINE_TCL_FUNC(tcl_morse_code)
DEFINE_TCL_FUNC (tcl_set_editor);
DEFINE_TCL_FUNC (tcl_set_kb_layout);
DEFINE_TCL_FUNC (tcl_set_scope);
DEFINE_TCL_FUNC (tcl_get_scope);
DEFINE_TCL_FUNC (tcl_get_drone);
DEFINE_TCL_FUNC (tcl_set_drone);
DEFINE_TCL_FUNC (tcl_text_color);
DEFINE_TCL_FUNC (tcl_paste_gater);
DEFINE_TCL_FUNC (tcl_get_intervals);
DEFINE_TCL_FUNC (tcl_num_octaves);
DEFINE_TCL_FUNC (tcl_set_audio);
DEFINE_TCL_FUNC (tcl_load_scale);
DEFINE_TCL_FUNC (tcl_scale_curve);
DEFINE_TCL_FUNC (tcl_binaural_drone);
DEFINE_TCL_FUNC (tcl_set_sine_mixer);
DEFINE_TCL_FUNC (tcl_change_sine_mixer);
DEFINE_TCL_FUNC (tcl_update_sine_mixer);
DEFINE_TCL_FUNC (tcl_write_svg);
DEFINE_TCL_FUNC (tcl_write_trail);
// din commands
//
// format: long name, short name
// for L and R delays
set_delay sd (&left_delay, &right_delay, "set-delay", "sd");
get_delay gd (&left_delay, &right_delay, "get-delay", "gd");
// to load the scale
load_scale los (&din0, "load-scale", "los");
// set and get din variables
set_var sv (&din0, "set-var", "sv");
get_var gv (&din0, "get-var", "gv");
// bpm commands
//
set_bpm sb ("set-bpm", "sb");
get_bpm gb ("get-bpm", "gb");
set_beat sn ("set-beat", "sbt");
get_beat gn ("get-beat", "gbt");
set_style ss ("set-style", "ss");
get_style gs ("get-style", "gs");
int doublebpm = 0;
float BPM_MULT = 2.0f;
// set key/tonic
key ky (&din0, "key", "key");
// display notation on the keyboard
notation no (&din0, "notation", "no");
// music utils
note_distance nd ("note-distance", "nd");
chord ch ("chord", "ch");
// font cmds
set_font_size sfs ("set-font-size", "sfs");
get_font_size gfs ("get-font-size", "gfs");
set_kern sk ("set-kern", "sk");
get_kern gk ("get-kern", "gk");
// curve cmds
curve_name cn ("curve-name", "cn");
curve_value cv ("curve-value", "cv");
curve__library cl ("curve-library", "cl");
set_curve_editor sced ("set-curve-editor", "sced");
paste_gater pasg ("paste-gater", "paste-gater");
scale_curve scrv ("scale-curve", "scrv");
// morse code
morse_code mc ("morse-code", "mc");
// to replace curves in a multi curve with a seed curve
fractaliser fractaliser_;
// to generate curve from polar equation R = sin (K * theta)
rose_milker rosemilker;
// to generate a regular polygon
circler circler_;
// to generate a spiral with R = A * theta
spiraler spiraler_;
// to connect dots to make star polygons
starrer starrer_;
// to generate lissajous curve
lissajous lissajous_;
// to generate superformula curve
superformula superformula_;
// to warp XY of segments of a curve
warper warper_;
// to turn country outlines into curves
countries countries_;
// to morph one curve into another
morpher morpher_;
// to convert a number into a curve
number number_;
// sine mixer for waveform edit
sine_mixer sinemixer;
// plugin browser
const int plugin_browser::num_plugins = 12;
plugin* plugin_browser::plugins [] = {
&circler_,
&sinemixer,
&rosemilker,
&spiraler_,
&lissajous_,
&number_,
&fractaliser_,
&countries_,
&warper_,
&morpher_,
&superformula_,
&starrer_,
};
// unix like echo
echo ech ("echo", ".");
set_kb_layout kbl ("set-kb-layout", "kbl");
// oscilloscope
set_scope ssco ("set-scope", "ssco", &din0, &binaural_drones0);
get_scope gsco ("get-scope", "gsco", &din0);
// drone
get_drone gdro ("get-drone", "gdro", din0);
set_drone sdro ("set-drone", "sdro", din0);
// console
set_text_color stc ("set-text-color", "stc");
// get scale intervals
get_intervals gint ("get-intervals", "gint");
// set number of octaves
num_octaves noct ("num-octaves", "noct", din0);
// set audio
set_audio sau ("set-audio", "sa");
#ifdef __SVG__
write_svg wsvg ("write-svg", "wsvg"); // write curve into svg file
write_trail wtrl ("write-trail", "wtrl"); // write drone trails into svg file
#endif
#ifdef __HPGL__
write_hpgl whpgl ("write-hpgl", "hpgl"); // write curve into hp-gl file for output on graphtec plotters
#endif
// used by binaural drones instrument
cmd_binaural_drone snd ("binaural-drone", "bd");
set_sine_mixer ssm ("set-sine-mixer", "ssm");
change_sine_mixer csm ("change-sine-mixer", "csm");
update_sine_mixer usm ("update-sine-mixer", "usm");
void add_commands (Tcl_Interp* interp) { // add din commands to Tcl interpreter
unsigned int ncmds = 42;
tclcmd cmd_funcs [] = {
tcl_key,
tcl_setv,
tcl_getv,
tcl_set_delay,
tcl_get_delay,
tcl_set_bpm,
tcl_get_bpm,
tcl_set_beat,
tcl_get_beat,
tcl_set_style,
tcl_get_style,
tcl_set_kern,
tcl_get_kern,
tcl_set_font_size,
tcl_get_font_size,
tcl_note_distance,
tcl_chord,
tcl_notation,
tcl_echo,
tcl_curve_value,
tcl_curve_name,
tcl_curve_library,
tcl_morse_code,
tcl_set_editor,
tcl_set_scope,
tcl_get_scope,
tcl_get_drone,
tcl_set_drone,
tcl_text_color,
tcl_paste_gater,
tcl_get_intervals,
tcl_num_octaves,
tcl_set_kb_layout,
tcl_set_audio,
tcl_load_scale,
tcl_scale_curve,
tcl_binaural_drone,
tcl_set_sine_mixer,
tcl_change_sine_mixer,
tcl_update_sine_mixer,
tcl_write_svg,
tcl_write_trail,
};
command* cmds [] = {
&ky,
&sv,
&gv,
&sd,
&gd,
&sb,
&gb,
&sn,
&gn,
&ss,
&gs,
&sk,
&gk,
&sfs,
&gfs,
&nd,
&ch,
&no,
&ech,
&cv,
&cn,
&cl,
&mc,
&sced,
&ssco,
&gsco,
&gdro,
&sdro,
&stc,
&pasg,
&gint,
&noct,
&kbl,
&sau,
&los,
&scrv,
&snd,
&ssm,
&csm,
&usm,
&wsvg,
&wtrl,
};
extern cmdlist cmdlst;
for (unsigned int i = 0; i < ncmds; ++i) {
command* cmdp = cmds [i];
cmdlst.add (cmdp);
Tcl_CreateObjCommand (interp, cmdp->longname.c_str(), cmd_funcs[i], (ClientData) i, 0);
Tcl_CreateObjCommand (interp, cmdp->shortname.c_str(), cmd_funcs[i], (ClientData) i, 0);
}
dlog << "+++ added " << ncmds << " din commands to the Tcl interpreter +++" << endl;
}
authors_note anote;
curve_picker_t curve_picker;
mouse_slider mouse_slider0;
int mouse_slider::warp = 1;
ui_list uis;
curve_editor drone::modvt::ed ("modv.ed");
modv_lis drone::modvt::lis;
void modulate_down () {
instrument* instr = get_current_instrument ();
if (instr->osd.active == 0) {
static const string down = "down";
start_octave_shift (instr, 0, down);
}
}
void modulate_up () {
instrument* instr = get_current_instrument ();
if (instr->osd.active == 0) {
static const string up = "up";
start_octave_shift (instr, 1, up);
}
}
void start_octave_shift (instrument* instr, int idir, const string& sdir) {
octave_shift_data& osd = instr->osd;
osd.tonic = instr->scaleinfo.tonic;
osd.dir = idir;
osd.active = 1;
osd.now = octave_shift.sol.firstx;
}
void do_octave_shift () {
for (int i = 0; i < NUM_INSTRUMENTS; ++i) {
instrument* instr = INSTRUMENT_PTR [i];
octave_shift_data& osd = instr->osd;
if (osd.active) {
osd.now += (octave_shift.delta * aout.samples_per_channel);
static const string octave_shift_str = "Octave Shift ", percent = "%";
float now = osd.now - octave_shift.sol.firstx;
float delta = octave_shift.sol.lastx - octave_shift.sol.firstx;
osd.percent_complete = (int) (now / delta * 100);
stringstream ss; ss << octave_shift_str << osd.percent_complete << percent;
string txt (ss.str());
MENU.l_octave_shift.set_text (txt);
uis.l_octave_shift.set_text (txt);
if (osd.now > octave_shift.sol.lastx) { // finished
osd.now = octave_shift.sol.lastx;
osd.active = 0;
MENU.l_octave_shift.set_text (octave_shift_str);
uis.l_octave_shift.set_text (octave_shift_str);
}
float shift = octave_shift.sol (osd.now);
if (shift != 0) {
if (osd.dir) set_tonic (instr, osd.tonic * shift); // go up
else set_tonic (instr, osd.tonic / shift); // go down
}
if (!osd.active) {
cons << GREEN;
cons ("key");
}
}
}
}
int abort_octave_shift (instrument* inst) {
octave_shift_data& osd = inst->osd;
if (osd.active) {
osd.active = 0;
cons << GREEN;
cons ("key");
static const char* oss = "Octave Shift";
MENU.l_octave_shift.set_text (oss);
uis.l_octave_shift.set_text (oss);
return 1;
} else cons << RED << "No octave shift in progress!" << eol;
return 0;
}
int esc_octave_shift (instrument* inst) {
if (SHIFT)
return abort_octave_shift (inst);
return 0;
}
void setup_screens () {
dlog << "*** setting up screens ***" << endl;
left_delay.setup ();
right_delay.setup ();
coml.apply (&coml.crv);
comr.apply (&comr.crv);
// in delay editor load feedback & volume curves
delayed.add (&left_delay.fbk_crv, &left_delay.fbk_lis);
delayed.add (&left_delay.vol_crv, &left_delay.vol_lis);
delayed.add (&right_delay.fbk_crv, &right_delay.fbk_lis);
delayed.add (&right_delay.vol_crv, &right_delay.vol_lis);
dlog << "+++ added curves to delay editor +++ " << endl;
// add L & R compressor curves to compressor editor
comed.add (&coml.crv, &coml.lis);
comed.add (&comr.crv, &comr.lis);
// octave shift
octave_shift.setup ();
octlis.set (&octave_shift);
octave_shift.xmin = &_atmin;
octave_shift.xmax = &_atmax;
octed.add (octave_shift.crv, &octlis);
octed.attach_library (&octlib);
// drone modulation
drone_mod_ed.add (&drone_mod_am_crv, &dmlis);
drone_mod_ed.add (&drone_mod_fm_crv, &dmlis);
drone_mod_ed.attach_library (&wav_lib);
// range modulation
ran_mod_ed.add (&ran_mod_width_crv, MENUP.rml);
ran_mod_ed.add (&ran_mod_height_crv, MENUP.rml);
ran_mod_ed.attach_library (&wav_lib);
// range width+height
ran_wh_ed.add (&ran_width_crv, &rwhl);
ran_wh_ed.add (&ran_height_crv, &rwhl);
// range volume & pitch
pitch_vol_ed.add (warcrv[0], &pvl);
pitch_vol_ed.add (warcrv[1], &pvl);
// drone pendulum amplitude & bpm
drone_pend_ed.add (dp_crv[0], &dpel);
drone_pend_ed.add (dp_crv[1], &dpel);
// point modulation
pomo_ed.add (&pomo_x_crv, &pol);
pomo_ed.add (&pomo_y_crv, &pol);
// noise interpolator
noiser::ed.add (&noiser::interp, &noiser::lis);
// drone speed modulation
drone::modvt::init ();
// font editor
fed.add (&dummy, 0);
// setup geometry > sound plugins of curve editor
for (int i = 0; i < plugin_browser::num_plugins; ++i) {
plugin* pi = plugin_browser::plugins[i];
dlog << "setting up plugin: " << pi->name << endl;
pi->setup ();
dlog << pi->name << " setup complete." << endl;
}
din0.setup ();
keybd2.setup ();
mondrian0.setup ();
uis.add_widgets ();
uis.setup ();
curve_picker.setup ();
fft0.setup ();
dlog << "+++ setup screens complete +++" << endl;
}
void setup_plugin_labels () {
fractaliser_.b_edit.set_text ("Edit");
warper_.b_edit.set_text ("Edit");
}
void goto_next_instrument () {
scope.save_current_instrument ();
++CURRENT_INSTRUMENT;
if (CURRENT_INSTRUMENT >= NUM_INSTRUMENTS) CURRENT_INSTRUMENT = 0;
}
void find_instrument () {
for (int i = 0; i < NUM_INSTRUMENTS; ++i) {
if (INSTRUMENT == INSTRUMENTS[i]) {
CURRENT_INSTRUMENT = i;
break;
}
}
}
int is_instrument (ui* u) {
for (int i = 0; i < NUM_INSTRUMENTS; ++i) if ((void *) u == (void *) INSTRUMENT_PTR[i]) return 1;
return 0;
}
instrument* find_instrument (const string& inst) {
for (int i = 0; i < NUM_INSTRUMENTS; ++i) if (inst == INSTRUMENTS[i] || inst == INSTRUMENTS_SHORT[i]) return INSTRUMENT_PTR[i];
return get_current_instrument ();
}
instrument* get_current_instrument () {
return INSTRUMENT_PTR [CURRENT_INSTRUMENT];
}
void update_window (int w, int h, int wp, int hp) { // called when main window resized
glViewport (0, 0, w, h);
view (w, h);
int w1 = w - 1, h1 = h - 1;
cons.set_window (box<int>(0, 0, w1, h1));
uis.update_widgets (w, h, wp, hp);
keybd2.calc_visual_params ();
din0.window_resized (w1, h1);
mondrian0.calc_visual_params ();
if (uis.crved)
uis.crved->calc_visual_params ();
dlog << "+++ update window complete ++" << endl;
}
void setup_sdl_surface (SDL_Surface* surface, int w, int h, int fs = 0) {
if (surface) SDL_FreeSurface (surface);
if (fs) {
surface = SDL_SetVideoMode (w, h, SCREEN_DEPTH, SDL_OPENGL | SDL_FULLSCREEN);
} else {
char* sdl_pos = (char *) "SDL_VIDEO_CENTERED=center";
SDL_putenv (sdl_pos);
surface = SDL_SetVideoMode (w, h, SCREEN_DEPTH, SDL_OPENGL | SDL_RESIZABLE);
}
if (surface) {
dlog << "+++ setup video mode " << w << ' ' << h << ' ' << SCREEN_DEPTH << " +++" << endl;
} else {
dlog << "!!! couldnt set video mode: " << w << ' ' << h << ' ' << SCREEN_DEPTH << endl;
exit (1);
}
/*
// for diagnostics
GLint vwh [2];
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, vwh);
dlog << "max viewport: " << vwh[0] << spc << vwh[1] << endl;
*/
}
void save_window () {
string fname = user_data_dir + "window";
ofstream file (fname.c_str(), ios::out);
extern viewport view;
if (file) {
file << "view " << view.width << spc << view.height << endl;
file << "fs " << FULL_SCREEN << endl;
file << "mode " << uis.settings_scr.imode << endl;
file << "win " << din0.win.left << spc << din0.win.bottom << endl;
} else {
dlog << "!!! couldnt save window in " << fname << " !!!" << endl;
return;
}
dlog << "+++ saved window in " << fname << " +++" << endl;
}
void restore_last_window () {
dlog << "*** reading last window ***" << endl;
int width = 0, height = 0;
string fname (user_data_dir + "window");
ifstream file (fname.c_str(), ios::in);
string ignore;
// last window size
file >> ignore >> width >> height;
file >> ignore >> FULL_SCREEN;
file >> ignore >> uis.settings_scr.imode;
if (FULL_SCREEN == 0) {
uis.settings_scr.add_display_mode (width, height);
uis.settings_scr.imode = uis.settings_scr.num_modes - 1;
} else
uis.settings_scr.add_display_mode (800, 600); // one windowed mode for sanity
// last microtonal board position
file >> ignore >> din0.win.left >> din0.win.bottom;
view (width, height);
din0.prev_mousey = view.ymax;
}
SDL_Surface* surface = 0;
void setup_video_mode (int w, int h, int vw, int vh, int fs) {
setup_sdl_surface (surface, w, h, fs);
update_window (w, h, vw, vh);
glEnableClientState (GL_VERTEX_ARRAY);
}
void try_quit () {
if (uis.cb_record.state) {
cons << RED << "Recording in progress. Will not exit!" << eol;
return;
}
dlog << "*** started to quit DIN Is Noise ***" << endl;
din0.save ();
keybd2.scaleinfo.save_scale ();
mondrian0.scaleinfo.save_scale ();
binaural_drones0.scaleinfo.save_scale ();
save_window ();
interpreter ("src save_settings");
dlog << "+++ saved DIN settings +++ " << endl;
uis.cb_voice.turn_off ();
uis.cb_delay.turn_off ();
din0.delete_all_drones ();
binaural_drones0.save ();
MENU.bdl.clicked (MENU.bbd_select_all);
MENU.bdl.clicked (MENU.bbd_delete);
scope.save_current_instrument ();
quit = SOON;
dlog << "!!! Quitting SOON !!!" << endl;
}
int read_input () {
// handle window events
wheel = 0;
widget::HOVER = 0;
static SDL_Event event;
while (SDL_PollEvent(&event)) {
switch(event.type) {
case SDL_VIDEORESIZE:
if (FULL_SCREEN == 0) {
setup_video_mode (event.resize.w, event.resize.h, view.width, view.height, FULL_SCREEN);
uis.settings_scr.update_windowed_mode (event.resize.w, event.resize.h);
}
break;
case SDL_MOUSEBUTTONUP:
switch (event.button.button) {
case SDL_BUTTON_WHEELUP:
wheel = 1;
break;
case SDL_BUTTON_WHEELDOWN:
wheel = -1;
break;
}
break;
case SDL_QUIT:
quit = IMMEDIATE;
break;
}
}
// read keyboard
keybd.read ();
SHIFT = shift_down ();
CTRL = ctrl_down ();
ALT = alt_down ();
// read mouse
int buttons = SDL_GetMouseState (&mousex, &mousey);
mouseyy = view.ymax - mousey;
lmb = buttons & SDL_BUTTON_LMASK;
mmb = buttons & SDL_BUTTON_MMASK;
rmb = buttons & SDL_BUTTON_RMASK;
return 1;
}
midi_in midiin;
void applyfx (float* out0, float* out1, int do_delay, int do_compress) {
//
// apply delays
//
float fdr = uis.fdr_delay.amount;
float* outl = out0; left_delay (outl, aout.samples_per_channel, fdr);
float* outr = out1; right_delay (outr, aout.samples_per_channel, fdr);
// apply compression
//
if (do_compress) {
float* outl = out0, *outr = out1;
coml.apply (outl, aout.samples_per_channel);
comr.apply (outr, aout.samples_per_channel);
}
}
int n_pomo_eds = 35;
curve_editor* pomo_eds [] = {
&din0.waved,
&din0.moded,
&din0.gated,
&delayed,
&octed,
&din0.droneed,
&keybd2.waved,
&keybd2.attacked,
&keybd2.decayed,
&keybd2.veled,
&comed,
&mc.ed,
&drone_mod_ed,
&fed,
&fractaliser_.ed,
&warper_.ed,
&mondrian0.waved,
&mondrian0.attacked,
&mondrian0.decayed,
&binaural_drones0.waved,
&spiraler_.scr.sin_ed,
&spiraler_.scr.cos_ed,
&spiraler_.scr.rad_ed,
&rosemilker.scr.sin_ed,
&rosemilker.scr.cos_ed,
&circler_.scr.sin_ed,
&circler_.scr.cos_ed,
&circler_.scr.rad_ed,
&sinemixer.sin_ed,
&ran_mod_ed,
&ran_wh_ed,
&pitch_vol_ed,
&pomo_ed,
&noiser::ed,
&drone_pend_ed,
};
const char* keys_trig_what [] = {" Keys trigger notes", " Keys trigger noise"};
const char* colorer_t::s_schemes [] = {" Top", " Bottom", " Blend", " Random"};
color_data_t get_color::data;
int main (int argc, char** argv) {
dlog << "*** Starting DIN Is Noise " << VERSION_NUMBER << " ***" << endl;
// bring up OpenGL window
//
if (SDL_Init (SDL_INIT_VIDEO) < 0) {
dlog << "!!! couldnt initialise SDL video !!!" << endl;
exit (1);
} else {
dlog << "+++ initialised SDL video +++" << endl;
}
uis.settings_scr.load_fullscreen_modes ();
if (SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) < 0) {
dlog << "!!! couldnt setup SDL/OpenGL double buffer !!!" << endl;
exit(1);
} else {
dlog << "+++ setup SDL/OpenGL double buffer +++" << endl;
}
restore_last_window ();
interpreter.add_din_specific ();
interpreter ("src init");
dlog << "+++ loaded DIN scripts (init.tcl) +++ " << interpreter.result << endl;
setup_screens ();
setup_curve_list ();
MENU.riset.set_value (din0.dinfo.drone_rise_time);
MENU.fallt.set_value (din0.dinfo.drone_fall_time);
MENU.ddpm.set_value (din0.dinfo.dpm);
MENU.ddpl.set_value (din0.dinfo.dpl);
interpreter ("src settings");
dlog << "+++ loaded DIN settings (settings.tcl) +++ " << interpreter.result << endl;
all_notes.load_scale ("all_notes");
midiin.open ();
binaural_drones0.load ();
// init menu items
uis.sp_attack_time.set_value (ATTACK_TIME);
uis.sp_decay_time.set_value (DECAY_TIME);
uis.sp_voices.set_value ((int)(1.0f / NOTE_VOLUME + 0.5f));
uis.sp_pitch_bend.set_value (PITCH_BEND_PER_PIXEL);
uis.cb_show_nearby_notes.set_state (keybd2.show_nearby_notes);
float obpm = octave_shift.bpm;
MENU.sp_octave_shift_bpm.set_value (obpm);
uis.sp_octave_shift_bpm.set_value (obpm);
MENU.sp_gater_bpm.set_value (din0.gatr.bpm);
MENU.sp_voice_volume.set_value (VOICE_VOLUME);
MENU.cb_show_anchors.set_state (din0.dinfo.anchor);
MENU.cb_show_vel.set_state (din0.dinfo.vel);
MENU.cb_show_accel.set_state (din0.dinfo.accel);
MENU.cb_mark_ran.set_state (din0.dinfo.mark_sel_range, 0);
MENU.sp_drone_master_vol.set_value (drone::MASTERVOLUME);
MENU.td_tap_display.set_bpm (din0.gatr.bpm);
MENU.mark_tap_target ();
MENU.sp_mesh_rows.set_value (din0.dinfo.rows);
MENU.sp_mesh_cols.set_value (din0.dinfo.cols);
MENU.sp_bounces.set_value (din0.dinfo.bounce.n);
MENU.sp_rebound.set_value (din0.dinfo.bounce.speed);
MENU.picked (MENU.ol_bounce_style.option, 0);
MENU.picked (MENU.ol_drone_is.option, 0);
MENU.sp_snap_left.set_value (din0.dinfo.snap.left);
MENU.sp_snap_right.set_value (din0.dinfo.snap.right);
MENU.sdl.picked (MENU.ol_snap_style.option, 0);
MENU.sp_mondrian_min_voices.set_value (mondrian0.min_voices);
MENU.sp_mondrian_change_attack_time.set_value (0);
MENU.sp_mondrian_change_decay_time.set_value (0);
MENU.sp_mondrian_change_speed.set_delta (mondrian0.delta_speed);
MENU.sp_mondrian_change_note_poly_points.set_value (mondrian0.poly.points);
MENU.sp_mondrian_change_note_poly_radius.set_value (mondrian0.poly.radius);
MENU.sp_mondrian_change_note_poly_radius.set_delta (mondrian0.poly.delta_radius);
MENU.cb_mondrian_auto_adjust_voices.set_state (mondrian0.auto_adjust_voices);
MENU.cb_draw_ball_position.set_state (mondrian0.draw_ball.position);
MENU.cb_draw_ball_heading.set_state (mondrian0.draw_ball.heading);
MENU.cb_draw_ball_trails.set_state (mondrian0.draw_ball.trails);
MENU.cb_draw_boxes.set_state (mondrian0.draw__boxes);
MENU.cb_fill_boxes.set_state (mondrian0.fill_boxes);
MENU.cb_draw_notes.set_state (mondrian0.draw__notes);
MENU.cb_label_hz_vol.set_state (mondrian0.label_hz_vol);
MENU.cb_label_notes.set_state (mondrian0.label_notes);
MENU.ol_ball_types.set_text (ball::types_str[mondrian0.added_ball_type]);
MENU.sp_mondrian_num_boxes.set_value (mondrian0.num_boxes);
MENU.sp_auto_split_time.set_value (mondrian0.auto_split_rect.triggert);
MENU.sp_auto_delete_time.set_value (mondrian0.auto_del_rect.triggert);
MENU.ol_auto_split_at.set_text (mondrian_listener::auto_split_at_types [mondrian0.auto_split_at]);
MENU.ol_auto_split_orient.set_text (mondrian_listener::auto_split_orient_types [mondrian0.auto_split_orient]);
MENU.ol_auto_pick_box_split.set_text (mondrian_listener::pick_box_types [mondrian0.split_leaf]);
MENU.ol_auto_pick_box_delete.set_text (mondrian_listener::pick_box_types [mondrian0.delete_leaf]);
MENU.cb_auto_split_box.set_state (mondrian0.auto_split_rect.active);
MENU.cb_auto_delete_box.set_state (mondrian0.auto_del_rect.active);
MENU.sp_min_split_size.set_value (mondrian::min_split_size);
MENU.text_ure.set_text (mondrian::patstr);
MENU.texstep.set_value (mondrian::patstep);
mondrian0.fillpatbuf ();
uis.cb_show_pitch_volume_drones.set_state (din0.dinfo.show_pitch_volume.drones);
uis.cb_show_pitch_volume_board.set_state (din0.dinfo.show_pitch_volume.board);
MENU.lf_master_volume.fld.set_text (int (binaural_drones0.master_volume * 100.0f));
MENU.lf_bd_start_pitch.fld.set_text (binaural_drones0.starting_pitch);
MENU.sp_bd_separation.set_value (binaural_drones0.separation);
MENU.sp_bd_pairs.set_value (binaural_drones0.pairs);
MENU.lf_bd_spacing.fld.set_text (binaural_drones0.spacing);
MENU.cb_close_octave.set_state (binaural_drones0.close_octave);
MENU.cb_resize_separation.set_state (binaural_drones0.resize_separation);
MENU.bdl.picked (MENU.ol_key_note.option, 0);
MENU.bdl.picked (MENU.ol_justification.option, 0);
MENU.lf_vol_fade_time.fld.set_text (binaural_drones0.vol_fader.duration);
MENU.lf_pitch_fade_time.fld.set_text (binaural_drones0.pitch_fader.duration);
MENU.lf_modulation_amount.fld.set_text (binaural_drones0.modulation_amount);
MENU.bdl.picked (MENU.ol_select_what.option, 0);
MENU.update_binaurals_list ();
MENU.load_range (din0.dinfo.sel_range);
MENU.sral.picked (MENU.ol_set_range.option, 0);
MENU.sp_default_width.set_value (WIDTH);
MENU.sp_default_height.set_value (HEIGHT);
MENU.cnsl.set (MENU.ol_change_note_style.option, din0.dinfo.change_note_style);
MENU.picked (MENU.ol_set_unset_toggle.option, 0);
MENU.picked (MENU.ol_drone_order.option, 0);
MENU.picked (MENU.ol_mesh_point.option, 0);
MENU.sp_mesh_dur.set_value (din0.dinfo.mesh_vars.duration);
MENU.cb_sync_rows_cols.set_state (din0.dinfo.mesh_vars.sync);
MENU.cb_am_bpm.set_state (din0.dinfo.mesh_vars.apply_to.am);
MENU.cb_fm_bpm.set_state (din0.dinfo.mesh_vars.apply_to.fm);
MENU.sp_drones_per_pend.set_value (din0.dinfo.mesh_vars.dpp);
MENU.picked (MENU.ol_create_this.option, 0);
MENU.dp_numdrones.set_value (din0.dinfo.drone_pend.n);
MENU.dp_bpm1.set_value (din0.dinfo.drone_pend.bpm);
MENU.picked (MENU.dp_orient.option, 0);
MENU.cb_pitch_dis.set_state (din0.dinfo.dist.pitch);
MENU.cb_vol_dis.set_state (din0.dinfo.dist.vol);
MENU.sp_lev_sz.set_value (din0.dinfo.dist.pix);
MENU.s_phrase_position.set_right (din0.dinfo.phrasor.right);
justset (MENU.track_phrase_position, din0.dinfo.phrasor.track);
MENU.seloncre.set_state (din0.dinfo.seloncre);
MENU.cnol.picked (MENU.ol_change_note.option, 0);
set_label (uis.ol_trig_what.option, keys_trig_what, keybd2.trig_what);
MENU.cb_draw_mesh.set_state (din0.meshh.draw, 0);
MENU.cmod.changed (MENU.cb_modulation);
MENU.sp_stiff.set_value (drone::STIFFNESS);
MENU.gabt.set_value (drone::gabt);
uis.dpeu.depth.set_value (50);
uis.dpeu.bpm.set_value (din0.dinfo.drone_pend.bpm);
din0.set_random_color ();
get_color::update_data ();
MENU.ol_color.set_text (MENU.colorer.get_scheme_name());
MENU.handlesize.set_value (drone::HANDLESIZE);
MENU.trailsize.set_value (TRAILSIZE);
din0.dinfo.wand = !din0.dinfo.wand;
MENU.awdl.picked (MENU.ol_add_wand.option, 0); // flipped back here
MENU.sp_wand_dist.set_value (drone::wand.dist);
MENU.darl.picked (MENU.ol_drones_are.option, 0);
MENU.lifetime.set_value (drone::LIFETIME);
MENU.chapt.set_value (drone::chuckt::apt.deg);
MENU.dva.which = din0.dinfo.menu.dva.which;
MENU.dva.load ();
MENU.cb_show_gravity.set_state (din0.dinfo.gravity.visible);
MENU.dcl.changed (MENU.cb_show_gravity);
MENU.choutline.set_state (drone::chuckt::outline);
MENU.chautoresettrails.set_state (drone::chuckt::autoresettrails);
MENU.ancl.picked (MENU.anchored.option, 0);
MENU.dronearrowdefaults.cap.set_state (drone::arrowt::CAP, 0);
MENU.gens.set_value (din0.dinfo.gens);
MENU.revl.picked (MENU.revmod.option, 0);
MENU.cb_selection_only.turn_on();
MENU.ancopa.set_value (drone::anchoropacity);
// finish init menu items
const char* viv = voice_is_lbls[din0.dinfo.voice_is_voice];
uis.cb_voice.set_text (viv);
MENU.handle_voice_tab_items (viv);
uis.settings_scr.lf_mixing_time.fld.set_text (curve_mixer::TIME);
uis.settings_scr.sample_rate_changed ();
uis.settings_scr.binaural.is.set_state (DIN_IS_BINAURAL);
uis.settings_scr.binaural.sep.set_value (SEPARATION);
options_list* ol [] = {MENUP.ol_bouncer, MENUP.ol_wrecker, MENUP.ol_healer};
for (int i = 0; i < 3; ++i) {
int j = Transform::rules[i];
sprintf (BUFFER, "%s becomes %s", ball::types_str[i], ball::types_str[j]);
ol[i]->set_text (BUFFER);
}
uis.settings_scr.update_mode_display ();
mondrian0.make_notes ();
curve_picker.widget::hide();
cons.home ();
setup_video_mode (view.width, view.height, view.width, view.height, FULL_SCREEN);
din0.dinfo.gravity.calcui ();
glClearColor(0, 0, 0, 0); // black bg
basic_editor::alloc_gl_pts (16);
nagscr ();
// ui loop
double ft0 = 0;
double it0 = 0;
const string loop ("loop");
const char* timenow = "timenow";
const string s_goodbye ("Goodbye!"), s_drones (" | Drones = "), s_kbkb (" | Keyboard-Keyboard = "), s_mondrian (" | Mondrian = "), s_binaurals (" | Fading Binaurals = ");
const char percent = '%';
aout.start (); // start audio loop in a separate thread. see audio_wanted (..)
it0 = ui_clk ();
ft0 = ui_clk ();
while (1) {
// try to write audio
if (aout.can_write ()) {
float* out0 = aout.writep; // left channel
float* out1 = out0 + aout.samples_per_channel; // right channel
do_octave_shift ();
memset (aout.writep, 0, aout.samples_buffer_size); // silence everything
interpreter (loop); // run loop on tcl proc
// audio from instruments
din0.render_audio (out0, out1);
keybd2.render_audio (out0, out1);
mondrian0.render_audio (out0, out1);
binaural_drones0.render_audio (out0, out1);
// delay and compressor
applyfx (out0, out1, din0.dinfo.delay, din0.dinfo.compress);
// to oscilloscope
if (scope.visible) scope.add_samples (out0, out1, aout.samples_per_channel);
// record?
if (uis.cb_record.state) {
recorder0.add (aout.writep, aout.samples_buffer_size, aout.samples_per_buffer, uis.cb_record, MENU.cb_record);
}
// stream status
aout.available [aout.writei] = 1;
if (++aout.writei >= aout.num_samples_buffers) {
aout.writep = aout.samples_buffers;
aout.writei = 0;
} else aout.writep += aout.samples_per_buffer;
// store timenow in TCL. timenow is seconds on din audio clock
TIME_NOW = clk.secs;
Tcl_UpdateLinkedVar (interpreter.interp, timenow);
}
if (recorder0.saving_started) { // save recording to disk
if (recorder0.save_some (MENU.cb_record) == 0)
MENU.b_save.set_text ("Overwrite");
}
// draw frame
double ft1 = ui_clk ();
LAST_FRAME_TIME = ft1 - ft0;
if (LAST_FRAME_TIME >= TIME_PER_FRAME) {
ft0 = ui_clk ();
FPSNOW = 1.0 / LAST_FRAME_TIME;
uis.bg ();
uis.draw ();
SDL_GL_SwapBuffers ();
}
// handle input [mouse, keys and midi]
double it1 = ui_clk ();
LAST_INPUT_TIME = it1 - it0;
if (LAST_INPUT_TIME > TIME_PER_INPUT) {
it0 = ui_clk ();
IPSNOW = 1.0 / LAST_INPUT_TIME;
read_input ();
if (quit == DONT) ;
else if (quit == SOON) {
cons << console::yellow << s_goodbye << s_drones << din0.num_drones << s_kbkb << keybd2.num_triggered_notes << s_mondrian << mondrian0.num_triggered_notes;
if (binaural_drones0.num_binaural_drones) cons << s_binaurals << int (binaural_drones0.vol_fader.xt*100+0.5) << percent;
cons << eol;
if (
(din0.num_drones == 0) &&
(uis.fdr_voice.on == 0) &&
(uis.fdr_delay.on == 0) &&
(keybd2.num_triggered_notes == 0) &&
(mondrian0.num_triggered_notes == 0) &&
(binaural_drones0.vol_fader.active == 0)
)
break;
}
else if (quit == IMMEDIATE) break;
uis.handle_input ();
for (int i = 0; i < n_pomo_eds; ++i) pomo_eds[i]->pomo.bg (); // update point modulations on curve editors
midiin.handle_input ();
keybd.save ();
}
} // finish
aout.close ();
mesh::destroy ();
trail_t::destroy ();
drone_mod_am_crv.save ("drone-mod-am.crv");
drone_mod_fm_crv.save ("drone-mod-fm.crv");
ran_mod_height_crv.save ("range-mod-height.crv");
ran_mod_width_crv.save ("range-mod-width.crv");
ran_width_crv.save ("range-width.crv");
ran_height_crv.save ("range-height.crv");
vol_crv.save ("vol.crv");
pitch_crv.save ("pitch.crv");
pomo_x_crv.save ("pomo-x.crv");
pomo_y_crv.save ("pomo-y.crv");
noiser::interp.save ("noiser.crv");
dp_depth.save ("dp_depth.crv");
dp_bpm.save ("dp_bpm.crv");
drone::modvt::crv.save ("modv.crv");
#if defined (__SVG_FNT__) || defined (__PLOTTER_FNT__)
ifstream textf ("text.txt", ios::in);
if (textf) {
int x, y;
textf >> x >> y;
string line;
int lh = line_height;
while (!textf.eof()) {
getline (textf, line);
#ifdef __SVG_FNT__
write_string (line, x, y);
y += lh;
#elif __PLOTTER_FNT__
plot_string (line, x, y);
y -= lh;
#endif
}
}
#endif
return 0;
}
void set_tonic (instrument* instr, float f) {
instr->scaleinfo.set_tonic (f);
if (instr == get_current_instrument ()) instr->scaleinfo.update_settings ();
}
float get_tonic (instrument* instr) {
return instr->scaleinfo.tonic;
}
void set_notation (int n) {
NOTATION = n;
din0.notate_all_ranges ();
keybd2.setup_notes (0);
mondrian0.calc_visual_params ();
uis.settings_scr.sn_scale_notes.refresh ();
}
void set_num_octaves (int n) {
int lno = NUM_OCTAVES;
NUM_OCTAVES = n;
#define DONTLOADFROMDISK 0
din0.setup_ranges (lno, DONTLOADFROMDISK);
din0.update_drone_ranges ();
din0.refresh_all_drones ();
}
int hide_menu () {
if (MENU.show) {
MENU.toggle ();
return 1;
}
return 0;
}
void show_menu () {
MENU.show = 0;
MENU.toggle ();
}
void set_snap_drones (int what) {
stringstream ss; ss << "set-var snap_drones " << what;
cons (ss.str());
}
int find_nearest_note (string& note, float& frequency, float& dist) {
float left = WIKIPEDIA_KEY_FREQUENCIES [0] / 2048, right = 2 * left;
float outf = frequency;
if (outf < left) return 0;
// find octave
while (1) {
if ((left <= outf) && (right > outf)) break;
else {
left*=2;
right*=2;
}
}
float oct = left / WIKIPEDIA_KEY_FREQUENCIES[0];
int id = 0;
float tone = 0, newdist = 0;
dist = outf - left;
for (int i = 0; i < 13; ++i) {
tone = WIKIPEDIA_KEY_FREQUENCIES[i] * oct;
newdist = abs(outf - tone);
if (newdist <= dist) {
dist = newdist;
id = i;
} else {
break;
}
}
note = WESTERN_FLAT[id];
frequency = WIKIPEDIA_KEY_FREQUENCIES[id] * oct;
dist = outf - frequency;
return id;
}
void turn_off_ui () {
UI_OFF = 1;
uis.show_hide_widgets (0);
}
void turn_on_ui () {
UI_OFF = 0;
uis.show_hide_widgets (1);
}
void tween (float* buf1, float* buf2, int n, float amount) {// interpolate buf2 -> buf1 and store in buf1
for (int i = 0; i < n; ++i) {
float b1 = buf1 [i], b2 = buf2[i];
buf1[i] = amount * (b1 - b2) + b2;
}
}
void tween (float* buf1, float* buf2, int n, float* amount) {
for (int i = 0; i < n; ++i) {
float b1 = buf1 [i], b2 = buf2[i];
buf1[i] = amount[i] * (b1 - b2) + b2;
}
}
void toggle (int& t, const char** s) {
t = !t;
cons << s[t] << eol;
}
void fill (float* buf, float start, float end, int n) {
float es = end - start;
float da = 1./ n, a = da;
for (int i = 0; i < n; ++i) {
buf[i] = start + a * es;
a += da;
}
}
void multiply (float* out, float* mul, int n) {
for (int i = 0; i < n; ++i) out[i] *= mul[i];
}
void multiply (float* out, int n, float depth) {
for (int i = 0; i < n; ++i) out[i] *= depth;
}
void warp_mouse (int x, int y) {
SDL_WarpMouse (x, y);
mousex = x;
mousey = y;
mouseyy = view.ymax - y;
}
int can_wheel () {
return (wheel && !widget::HOVER && !MENU.show);
}
void range_wh_lis::edited (curve_editor* ed, int i) {
if (i) {
sol_ran_height.update ();
din0.all_ranges_height_changed ();
} else {
sol_ran_width.update ();
din0.all_ranges_width_changed ();
}
}
void pitch_vol_lis::edited (curve_editor* ed, int i) {
warsol_pv[i]->update ();
din0.refresh_all_drones ();
}
void drone_pend_ed_lis::edited (curve_editor* ed, int i) {
warsol_dp[i]->update ();
din0.update_drone_pendulums ();
}
void pomo_lis::edited (curve_editor* ed, int j) {
for (int i = 0; i < n_pomo_eds; ++i) pomo_eds[i]->pomo.update_solvers (j);
}
void noise_interp_lis::edited (curve_editor* ed, int i) {
din0.noise_interpolator_changed ();
update_triggered_noises (keybd2.triggered_notes);
update_triggered_noises (mondrian0.triggered_notes);
}
void modv_lis::edited (curve_editor* ed, int i) {
din0.update_drone_modv_solvers ();
}
void make_good_name (string& name) {
for (int i = 0, j = name.length (); i < j; ++i) {
char& ci = name[i];
if (ci == spc) ci = '_';
}
}
void drone::modvt::init () {
ed.add (&crv, &lis);
}
void hz2step (float& hz, float& step) {
step = hz * 1.0f / SAMPLE_RATE;
}
void step2hz (float& step, float& hz) {
hz = step * SAMPLE_RATE;
}
int is_din_binaural () {
DIN_IS_BINAURAL = uis.settings_scr.binaural.is.state;
return DIN_IS_BINAURAL;
}
float get_binaural_separation_in_hz () {
return uis.settings_scr.binaural.sep ();
}