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