1 /*
2 * sine_mixer.cc
3 * DIN Is Noise is copyright (c) 2006-2021 Jagannathan Sampath
4 * DIN Is Noise is released under GNU Public License 2.0
5 * For more information, please visit https://dinisnoise.org/
6 */
7 
8 #include "dingl.h"
9 #include "input.h"
10 #include "viewwin.h"
11 #include "sine_mixer.h"
12 #include "ui_list.h"
13 #include "viewwin.h"
14 #include "vector2d.h"
15 #include "circler.h"
16 #include "log.h"
17 #include "console.h"
18 #include "container.h"
19 #include <math.h>
20 using namespace std;
21 
22 extern const float PI;
23 extern const float TWO_PI;
24 extern curve_library sin_lib;
25 extern int line_height;
26 extern const char SPC;
27 
sine_mixer()28 sine_mixer::sine_mixer () : cp_sin ("sine_mixer_sin.crv"), sin_ed ("sine_mixer_sin.ed"), harms ("harmonics"), phase ("phases") {
29   plugin::name = "Sine_Mixer";
30   shapeform = 0;
31   type = 0;
32   sin_ed.add (&cp_sin.crv, this);
33   sin_ed.attach_library (&sin_lib);
34   harms.paintl = this;
35   harms.chgl = this;
36   harms.shftl = this;
37   harms.szr.movlis = &szm;
38   phase.paintl = this;
39   phase.chgl = this;
40   phase.shftl = this;
41   phase.szr.movlis = &szm;
42   szm.data = this;
43 
44   static const float fac = 0.6;
45   phase.set_color (1.0f - fac * harms.clr.r, 1.0f - fac * harms.clr.g, 1.0f - fac * harms.clr.b);
46   paintphase = 0;
47 }
48 
load_params()49 void sine_mixer::load_params () {
50   ifstream f (make_fname().c_str(), ios::in);
51   string ignore;
52   f >> ignore >> num_points >> ignore >> make_shapeform >> ignore >> type >> ignore >> auto_apply;
53 	NUM_SINE_SAMPLES = num_points + 1;
54 }
55 
save_params()56 void sine_mixer::save_params () {
57   ofstream f (make_fname().c_str(), ios::out);
58 	string ignore;
59 	f << "num_points " << int (sp_points.f_value) << " make_shapeform " << cb_make_shapeform.state << " type " << type \
60   << " auto_apply " << cb_auto_apply.state << endl;
61 }
62 
~sine_mixer()63 sine_mixer::~sine_mixer () {
64 	save_params ();
65   widget_save ("d_sine_mixer", ctrls);
66   dlog << "--- destroyed sine mixer ---" << endl;
67 }
68 
num_harmonics(int h)69 void sine_mixer::num_harmonics (int h) {
70   nharmonics = h;
71   if (nharmonics < 1) nharmonics = 1;
72   prep_harmonics ();
73 }
74 
prep_harmonics()75 void sine_mixer::prep_harmonics () {
76 	harmonics.resize (nharmonics);
77 	float df = TWO_PI / (NUM_SINE_SAMPLES - 1);
78   funktion& f_sin = *pf_sin;
79   for (int i = 0, j = 1; i < nharmonics; ++i, ++j) {
80     vector< point<float> >& harmonic = harmonics[i];
81 		harmonic.resize (NUM_SINE_SAMPLES);
82     float dx = j * df;
83     float x = phase.values[i] * TWO_PI;
84     for (int p = 0; p < NUM_SINE_SAMPLES; ++p) {
85 			point<float>& hp = harmonic[p];
86 			hp.x = cos(x);
87 			hp.y = f_sin (x, TWO_PI);
88       x += dx;
89       if (x > TWO_PI) x -= TWO_PI;
90     }
91   }
92 	norm.resize (NUM_SINE_SAMPLES);
93   mix ();
94 }
95 
mix()96 void sine_mixer::mix () {
97 	for (int p = 0; p < NUM_SINE_SAMPLES; ++p) { point<float>& pi = norm[p]; pi.x = pi.y = 0;}
98 	ss.str(""); ss << plugin::name;
99   for (int i = 0; i < nharmonics; ++i) {
100     float lev = harms.values[i];
101     if (lev > 0) {
102       vector< point<float> >& harmonic = harmonics[i];
103       for (int p = 0; p < NUM_SINE_SAMPLES; ++p) {
104 				point<float>& np = norm[p];
105 				point<float>& hp = harmonic[p];
106 				np.x += (lev * hp.x);
107 				np.y += (lev * hp.y);
108     	}
109 			ss << '_' << (i+1);
110   	}
111 	}
112   normalise ();
113 }
114 
normalise()115 void sine_mixer::normalise () {
116 	int n = NUM_SINE_SAMPLES;
117   if (n) {
118 		point<float>& np0 = norm[0];
119 		float maxy = fabs (np0.y), maxx = fabs (np0.x);
120     for (int i = 0; i < n; ++i) {
121 			point<float>& pi = norm[i];
122 			float vx = fabs (pi.x), vy = fabs (pi.y);
123 			if (vx > maxx) maxx = vx;
124 			if (vy > maxy) maxy = vy;
125     }
126     if (maxx != 0) for (int p = 0; p < n; ++p) norm[p].x /= maxx;
127 		if (maxy != 0) for (int p = 0; p < n; ++p) norm[p].y /= maxy;
128   }
129 }
130 
render()131 void sine_mixer::render () {
132 
133 	undo = !cb_auto_apply.state;
134 	shapeform = cb_make_shapeform.state;
135 
136 	int ns = norm.size ();
137 	points.resize (ns);
138 	if (shapeform) {
139   	for (int i = 0; i < ns; ++i) {
140     	point<float>& ni = norm[i];
141 			point<float>& pi = points[i];
142 			pi.x = ni.x;
143 			pi.y = ni.y;
144   	}
145 	} else {
146 		float x = 0;
147 		float dx = 1.0f / (NUM_SINE_SAMPLES - 1);
148   	for (int i = 0; i < ns; ++i) {
149     	point<float>& ni = norm[i];
150 			point<float>& pi = points[i];
151 			pi.x = x;
152 			pi.y = ni.y;
153 			x += dx;
154   	}
155 	}
156 
157 	gen_pts ();
158 
159 }
160 
setup()161 void sine_mixer::setup () {
162 
163   plugin::setup ();
164 
165   widget* _ctrls [] = {
166     &sp_points,
167     &cb_make_shapeform,
168     &ol_sin,
169     &b_edit,
170     &cbpaint,
171     &olpaint,
172   };
173 
174 	num_ctrls = 8;
175 
176 	ctrls.resize (num_ctrls);
177   for (int i = 0, j = 2; j < num_ctrls; ++i, ++j) ctrls[j] = _ctrls[i];
178 
179   load_params ();
180 
181 	sp_points.set ("Points", 1, 1, MILLION, this, 0);
182 	sp_points.set_value (num_points);
183 
184 	cb_make_shapeform.set_text ("Make shapeform");
185 	cb_make_shapeform.set_state (make_shapeform);
186 	cb_make_shapeform.set_listener (this);
187 	cbpaint.set_text ("Paint");
188 
189   levs[0] = &harms;
190   levs[1] = &phase;
191   LISTEN (cbpaint, this)
192   pail.data = this;
193   LISTEN (olpaint, &pail)
194 
195 	if (auto_apply) {
196 		cb_auto_apply.set_state (1, 0);
197 		plugin::mix = undo = 0;
198 	}
199 
200   ol_sin.set_listener (this);
201 
202   widget_load ("d_sine_mixer", ctrls);
203 
204   ctrls.push_back (&harms);
205   olpaint.set_text (" Harmonics");
206 
207   num_ctrls = 9;
208 
209   //for (int i = 0; i < num_ctrls; ++i) ctrls[i]->set_moveable(1);
210 
211   b_edit.set_text ("Edit");
212 
213   set_type ();
214   num_harmonics (harms.n);
215   render ();
216 
217 }
218 
set_type()219 void sine_mixer::set_type () {
220   if (type) {
221     pf_sin = &cp_sin;
222     ol_sin.option.set_text (" Custom sin");
223     b_edit.set_color (clr.r, clr.g, clr.b);
224     b_edit.set_listener (this);
225   } else {
226     pf_sin = &st_sin;
227     ol_sin.option.set_text (" Standard sin");
228     b_edit.set_color (0.25f, 0.25f, 0.25f);
229     b_edit.set_listener (0);
230   }
231   int spacer = 10; b_edit.set_pos (ol_sin.option.extents.right + spacer, ol_sin.option.extents.bottom);
232 }
233 
changed(field & f)234 void sine_mixer::changed (field& f) {
235 	if (&f == &sp_points.f_value) {
236 		set_samples (f);
237 		do_render ();
238 	}
239 }
240 
changed(levels & l)241 void sine_mixer::changed (levels& l) {
242   if (&l == &phase) prep_harmonics ();
243 	mix ();
244 	do_render ();
245 }
246 
changed(checkbutton & cb)247 void sine_mixer::changed (checkbutton& cb) {
248 	if (&cb == &cb_make_shapeform) {
249 		render ();
250 		apply_not_auto_apply ();
251 	} else if (&cb == &cbpaint) {
252     levs[paintphase]->paint = cbpaint.state;
253 	} else plugin::changed (cb);
254 }
255 
set_samples(int s)256 void sine_mixer::set_samples (int s) {
257   NUM_SINE_SAMPLES = s + 1;
258   if (NUM_SINE_SAMPLES < MIN_SINE_SAMPLES) NUM_SINE_SAMPLES = MIN_SINE_SAMPLES;
259   prep_harmonics ();
260 }
261 
apply_not_auto_apply()262 void sine_mixer::apply_not_auto_apply () {
263 	if (cb_auto_apply.state) {
264 		plugin::mix = undo = 1;
265 		uis.crved->apply_plugin (this);
266 		plugin::mix = undo = 0;
267 	} else uis.crved->apply_plugin (this);
268 }
269 
picked(label & lbl,int dir)270 void sine_mixer::picked (label& lbl, int dir) {
271   type = !type;
272   set_type ();
273   prep_harmonics ();
274   render ();
275 }
276 
shift_apply()277 void sine_mixer::shift_apply () {
278 	mix ();
279 	render ();
280 	apply_not_auto_apply ();
281 }
282 
clicked(button & b)283 void sine_mixer::clicked (button& b) {
284 	if (&b == &b_edit) uis.set_current (&sin_ed);
285   else plugin::clicked (b);
286 }
287 
edited(curve_editor * e,int i)288 void sine_mixer::edited (curve_editor* e, int i) {
289   cp_sin.sol.update ();
290   curve_listener::edited (e, i);
291   prep_harmonics ();
292   render ();
293 }
294 
295 
moused(int dx,double scl)296 void sine_mixer::moused (int dx, double scl) {
297 	if (dx > 0) harms.rshift (); else harms.lshift ();
298 	shift_apply ();
299 }
300 
paint(levels & l)301 void sine_mixer::paint (levels& l) {
302   cbpaint.set_state (levs[paintphase]->paint, 0);
303 }
304 
shifted(levels & l)305 void sine_mixer::shifted (levels& l) {
306   if (&l == &phase) prep_harmonics ();
307   shift_apply ();
308 }
309 
toggpaint(label & l)310 void sine_mixer::toggpaint (label& l) {
311   static const char* pp [] = {" Harmonics", " Phase"};
312   paintphase = !paintphase;
313   ctrls.pop_back ();
314   if (paintphase) {
315     uis.plugin__browser.l_title.swapchild (&harms, &phase);
316     ctrls.push_back (&phase);
317     phase.setpos2 (harms);
318   }
319   else {
320     uis.plugin__browser.l_title.swapchild (&phase, &harms);
321     ctrls.push_back (&harms);
322     harms.setpos2 (phase);
323   }
324 
325   l.set_text (pp[paintphase]);
326 
327   levels* lp = levs[paintphase];
328   olpaint.option.set_color (lp->clr.r, lp->clr.g, lp->clr.b);
329   cbpaint.set_state (lp->paint,0);
330 
331 }
332 
handle_input()333 int sine_mixer::handle_input () {
334   int r = plugin::handle_input ();
335   if (!_folded) {
336     if (keypressed (SDLK_g)) {
337       pressed.g = 1;
338       toggpaint (olpaint.option);
339       r |= 1;
340     }
341   }
342   return r;
343 }
344 
PICKED_OPTION(sine_mixer,paintlis)345 PICKED_OPTION (sine_mixer, paintlis) {
346   sine_mixer& sm = (* (sine_mixer*) data);
347   sm.toggpaint (l);
348 }
349 
MOVED(sine_mixer,szrmov)350 MOVED (sine_mixer, szrmov) {
351   sine_mixer& sm = (* (sine_mixer*) data);
352   levels* pla = sm.levs[sm.paintphase];
353   pla->moved ();
354   levels* plb = sm.levs[!sm.paintphase];
355   plb->extents = pla->extents;
356   plb->szr.setpos2 (pla->szr);
357   plb->moved ();
358 }
359