1 /*
2 * mondrian.h
3 * inspired by the works of Piet Mondrian
4 * DIN Is Noise is released under GNU Public License 2.0
5 * DIN Is Noise is copyright (c) 2006-2021 Jagannathan Sampath
6 * For more information, please visit https://dinisnoise.org/
7 */
8
9 #ifndef __mondrian__
10 #define __mondrian__
11
12 #include "point.h"
13 #include "viewwin.h"
14 #include "ui.h"
15 #include "box_selector.h"
16 #include "textboard.h"
17 #include "triggered_note.h"
18 #include "listeners.h"
19 #include "curve_editor.h"
20 #include "help.h"
21 #include "instrument.h"
22 #include "rect.h"
23 #include "ball.h"
24 #include "slit.h"
25 #include "alarm.h"
26 #include "spinner.h"
27 #include <string>
28 #include <vector>
29
30 typedef std::list<ball*>::iterator balls_iterator;
31
32 struct draw_ball_t {
33 int position;
34 int heading;
35 int trails;
draw_ball_tdraw_ball_t36 draw_ball_t () { position = heading = trails = 1;}
37 };
38
39 struct mondrian : instrument, scale_listener, region_listener, split_listener {
40
41 mondrian ();
42 ~mondrian ();
43
44 void enter ();
45 void leave ();
46
47 multi_curve wave; // waveform shared by all balls
48 curve_editor waved; // waveform editor
49 wave_listener wavlis;
50 void update_waveform (multi_curve& crv);
51
52 multi_curve attack, decay; // attack and decay curves shared by all balls
53 curve_editor attacked, decayed; // attack and decay curve editors
54 attack_listener attacklis;
55 decay_listener decaylis;
56 void update_attack ();
57 void update_decay ();
58 float delta_attack_time, delta_decay_time;
59
60 window win; // edit window
61 // object space <> window space mapping
62 //
63 point<int> win_chunk;
64 point<float> obj_chunk;
65 point<float> win_per_obj;
66 point<float> obj_per_win;
67 float win_resolution;
68 float obj_resolution;
69 void obj2win (const point<float>& p, float& wx, float& wy);
70 void obj2win (const float& ox, const float& oy, float& wx, float& wy);
71 void win2obj (const float& dx, const float& dy, float& cx, float& cy);
72
73 int pan, zoom;
74 void do_panx (int dir);
75 void do_pany (int dir);
76 void do_zoom (int dir);
77
78 void calc_win_mouse ();
79 int lmb_clicked;
80
81 //
82 // file
83 void load_settings ();
84 void load_settings (std::ifstream& file);
85 void save_settings (std::ofstream& file);
86 box_from_disk_t get_box_from_disk (std::list<box_from_disk_t>& boxes, const std::string& id);
87 void load_boxes_and_balls ();
88 void save_boxes (std::ofstream& f, rect* R, std::string& id);
89 void save_balls (std::ofstream& f);
90
91 void setup ();
92
93 int handle_input ();
94
95 // draw
96 //
97
98 int draw__boxes;
99 int fill_boxes;
100 int label_notes;
101 int label_hz_vol;
102 int draw__notes;
103 int draw_slit_cutter;
104 draw_ball_t draw_ball;
105
106 void draw_rect (rect* which);
107 void draw_leaves ();
108 void draw_balls ();
109 void draw_notes ();
110 void draw ();
111
112 // boxes
113 //
114
115 rect* root; // the main box
116 std::list <rect*> leaves; // boxes that dont have children and can bear slits
117 rect* get_sibling (rect* R); // return sibling of R
118 void find (rect* R, float x, float y, finding& f); // find box where x,y is found. starting with R and down
119 rect* box_under_cursor ();
120 finding make_finding (rect* R); // R and its sibling
bad_rectmondrian121 int bad_rect (rect* R) { return R == 0 || R == root; }
122
123 // box splitting
124 //
125
126 rect* split_rect (int type, float where, rect* B = 0); // split box [type = horizontal or vertical]
127 int num_boxes;
128 int get_note_ids (std::pair<int, int>& nids, rect* R, int type);
129 void get_note_ids_from_intervals (std::pair<int, int>& idp, const std::pair<float, float>& ip);
130 int multi_split_rect (split_data& sd);
131 void multi_split_rect (int n, int type, rect* B = 0, std::list<rect*> *pr = 0, split_listener* sl = 0); // split B [or current] into n boxes
132 void multi_split_rect (int type, rect* B = 0, std::list<rect*> *lr = 0, split_listener* sl = 0); // split B [or current] at note intervals
133 int splitting_rects;
134 std::list<split_data> lsd;
135 void split_over (split_data& sd);
136 std::list<rect*> columns;
137 void make_note_grid (); // split the root box both horizontally and vertically at the notes of the scale
138 void make_nxn_grid (); // split the root box into a N x N grid of boxes
139
140 int nleaves;
141 void add_leaf (rect* L); // splitting a box makes 2 leaves
142 void remove_leaf (rect* L);
143
144 rect* earliest_leaf ();
145 rect* latest_leaf ();
146 rect* rnd_leaf ();
147 rect* biggest_leaf ();
148 rect* balled_leaf ();
149 rect* pick_leaf (int& what);
150 int split_leaf, delete_leaf;
151
152 void recreate_slits (rect* b); // to recreate slits of a just deleted box in its two children ie leaves
153
154 int delete_rect (const finding& f); // delete found box
155 void delete_current_rect (); // delete box under cursor
156 void update_children (rect* R); // update extents of children of box R
157 void delete_children (rect* R); // delete children of box R
158 void update_parent (rect* C); // update parent (and ancestors) of box C
159 int delete_all_rects; // when active, once every frame
160
161 alarm_t auto_del_rect; // auto delete box?
162 alarm_t auto_split_rect; // auto split box?
163
164 int auto_split_orient;
165 int auto_split_at;
166 int auto_split_which;
167
168
169 rect* hit; // box hit when clicked
170 int edge; // edge hit
171 void set_edge (rect* R, int e, float x, float y); // set vertical (using x) or horizontal edge (using y) of box R
172
173 int sel_tar; // selection target
174 enum {SELECT_SLITS = 0, SELECT_BALLS};
175
176 // balls
177 //
178 std::list<ball*> balls;
179 int num_balls;
180
181 int adding_balls;
182 int added_ball_type;
183 int started_making_ball;
184 ball* new_ball;
185 void do_add_balls (int _type = ball::BOUNCER);
186
187 void split_balls (rect* P, rect* C1, rect* C2); // split balls among children C1 and C2 when parent P is deleted
188
189 void delete_ball (ball* b);
190 void delete_all_balls ();
191 void delete_selected_balls ();
192
193 float delta_speed;
194 void change_speed (spinner<float>& s, float d);
195
196 // ball selection
197 //
198 std::list<ball*> selected_balls;
199 int num_selected_balls;
200 void select_balls (const box<float>& rgn);
201 void select_box_balls ();
202 void after_selection ();
203 void select_type (int t);
204 struct browse_t {
205 int which, last, n;
206 std::vector<ball*> balls;
207 browse_t ();
208 void clear ();
209 } browse;
210 void browse_ball (int i);
211
212 std::list<ball*>& get_box_balls ();
213 std::list<ball*>& get_balls ();
214 std::list<ball*>& get_balls (int);
215 ball* get_one_selected_ball ();
216 void switch_balls_type ();
217
218 // freeze and thaw
219 void freeze_thaw_balls (std::list<ball*>& _balls);
220 void freeze_balls (std::list<ball*>& _balls);
221 void thaw_balls (std::list<ball*>& _balls);
222 void freeze_all_balls ();
223
224 void clear_modulations (std::list<ball*>& _balls);
225
226 // ball movement
227 int moving_balls;
228 void move_balls (float dx, float dy);
229 void do_move_balls ();
230 void locate_ball (ball* b);
231
232 // ball course
233 float delta_rotate_velocity;
234 void rotate_velocity (int dir);
235 void toggle_auto_rotate (int ar);
236 void set_auto_rotate (int ar);
237 void flip_velocity ();
238 void change_ball_dtheta (int dir);
239
240 // ball misc
241 void set_ball_param (int what, float value);
242 void change_ball_vol_mult (spinner<float>& s);
243 void clone_ball (ball* b);
244 void toggle_triggered_sound ();
245
246 // slits
247 //
248
249 enum {NOTHING, JUST_SLIT, ANIMATE_SLIT};
250 int slitting;
251 fader fdr; // for animating slit
252
253 int num_slits;
254 std::list<slit*> slits; // all slits
255 std::list<slit*> selected_slits;
256 int num_selected_slits;
257
258 void load_slits (std::ifstream& f, std::list<box_from_disk_t>& boxes);
259 void save_slits (std::ofstream& f);
260 int get_index_of_slit (slit* s);
261 slit* get_slit_from_index (int q);
262
263 rect* bxs[2]; // a slit can only be on 2 boxes
264
265 int find_hit_slit (float x, float y); // under cursor
266
267 slit_lip_t slit_lip;
268 int editing_slit;
269 int editing_edge;
270
271 void start_slitting ();
272 int try_slitting ();
273 int add_remove_slit (float x, float y, fader* fdr = 0, float sz = slit::HALF_SIZE);
274 void change_slit_size (spinner<float>& s);
275 void change_slit_anim_time (spinner<float>& s);
276 void remove_all_slits ();
277 void remove_selected_slits ();
278 void remove_slit (slit* s);
279 void remove_slits (rect* R);
280 void remove_slits_on_edge (rect* R, int e);
281 void remove_slits_on_current_edge ();
282 void remove_slits_on_current_box ();
283 void remove_slits_on_boxes_with_balls ();
284 void select_box_slits ();
285 void toggle_slit_anim ();
286 void remove_slit_anim ();
287 void start_slit_anim ();
288
289 void clear_selected_targets ();
290 void select_all_targets ();
291 void select_box_targets ();
292 void invert_selected_targets ();
293 void delete_selected_targets ();
294 void delete_all_targets ();
295
296 // visual
297 //
298 int n_pts;
299 float* pts; // balls are points
300 float* pts_d; // ball direction are lines
301 float* pts_clr; // ball colors
302 int n_mrk;
303 float* mrk;
304 float crsr [8];
305 int cursor;
306 textboard tb, tb_hz_vol;
307 void make_notes ();
308 void calc_visual_params ();
309 void randomise_box_color (); // of the box under cursor
310 void toggle_flag (int& flag, const std::string& poz, const std::string& neg = "");
311
312 slit_drawer slit_drawerr;
313
314 static const float gutter, gutter2; // for edge selection & slit making
315 static float min_split_size; // for auto box splitting
316
317 struct poly_t {
318 std::vector<float> coss, sinn;
319 int points;
320 float radius;
321 float delta_radius;
poly_tmondrian::poly_t322 poly_t () {
323 radius = 0;
324 delta_radius = 0;
325 points = 0;
326 }
327 } poly;
328 int set_note_poly_points (int p);
329 int set_note_poly_radius (float r);
330
331 // notes
332 float note_volume;
333 int voices;
334 int min_voices;
335 int auto_adjust_voices;
336 note N;
337 int num_triggered_notes;
338 std::list<triggered_note> triggered_notes;
339 std::list<ball*> triggering_balls;
340 void launch_note (ball* _ball, float t, float t0, float dt, const std::pair<float, float>& invl);
341 void remove_finished_notes ();
342 void print_num_triggered_notes ();
343 int change_param (float& param, float value, float& recent);
344 void change_attack_time_kb (spinner<float>& s); // using kb shortcut
345 void change_decay_time_kb (spinner<float>& s);
346 void change_trail_size (spinner<int>& s);
347 void change_min_voices (int d);
348
349 // others
350 //
351
352 int stop_editing_slit ();
353 int stop_editing_edge ();
354 int stop_adding_balls ();
355 int stop_moving_balls ();
356 int stop_slitting ();
357 int stop_doing_stuff ();
rectingmondrian358 int recting () {return editing_edge || editing_slit || splitting_rects; }
359
360 void scale_changed ();
361 void scale_loaded ();
362 void tonic_changed ();
363
364 int modulate_balls (int p);
365
366 void toggle_balls_type (int _type);
367
368 int render_audio (float* L, float* R);
369
370 void bg ();
371
372 void mark_selected_slits ();
373
374 box<float> rgn;
375 void region_begin ();
376 void region_end ();
377 const box<float>& region_update ();
378
379 help _help;
380
381 };
382
383 int edge_on_root (rect* root, rect** boxes, int* edges);
384 void draw_slit_cutter (int yesno);
385
386 extern mondrian mondrian0;
387
388 template<class T> void clear_selected (list<T*>& targets, int& num_targets, int aft_sel = 1) {
389 for (typename list<T*>::iterator p = targets.begin (), q = targets.end (); p != q; ++p) {
390 T* t = *p;
391 t->select = 0;
392 }
393 targets.clear ();
394 num_targets = 0;
395 if (aft_sel) mondrian0.after_selection ();
396 }
397
select_all(list<T * > & items,list<T * > & selection,int & num_selected)398 template <class T> void select_all (list<T*>& items, list<T*>& selection, int& num_selected) {
399 clear_selected<T> (selection, num_selected);
400 for (typename list<T*>::iterator p = items.begin (), q = items.end (); p != q; ++p) {
401 T* t = *p;
402 t->select = 1;
403 selection.push_back (t);
404 ++num_selected;
405 }
406 mondrian0.after_selection ();
407 }
408
invert_selection(list<T * > & items,list<T * > & selection,int & num_selected)409 template <class T> void invert_selection (list<T*>& items, list<T*>& selection, int& num_selected) {
410 num_selected = 0;
411 selection.clear ();
412 for (typename list<T*>::iterator p = items.begin(), q = items.end(); p != q; ++p) {
413 T* b = *p;
414 b->select = !b->select;
415 if (b->select) {
416 selection.push_back (b);
417 ++num_selected;
418 }
419 }
420 mondrian0.after_selection ();
421 }
422
select_using_modifiers(T * b,int ctrl,list<T * > & selection,int & num_selected)423 template <class T> void select_using_modifiers (T* b, int ctrl, list<T*>& selection, int& num_selected) {
424 typename list<T*>::iterator se = selection.end (), f = ::find (selection.begin (), se, b);
425 if (f == se) {
426 sel:
427 b->select = 1;
428 push_back (selection, b);
429 ++num_selected;
430 } else {
431 if (ctrl) {
432 if (b->select) {
433 b->select = 0;
434 selection.erase (f);
435 --num_selected;
436 } else
437 goto sel;
438 }
439 }
440 }
441
442
443 #endif
444