1 // samplv1_fx.h
2 //
3 /****************************************************************************
4    Copyright (C) 2012-2021, rncbc aka Rui Nuno Capela. All rights reserved.
5 
6    This program is free software; you can redistribute it and/or
7    modify it under the terms of the GNU General Public License
8    as published by the Free Software Foundation; either version 2
9    of the License, or (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License along
17    with this program; if not, write to the Free Software Foundation, Inc.,
18    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 
20 *****************************************************************************/
21 
22 #ifndef __samplv1_fx_h
23 #define __samplv1_fx_h
24 
25 #include <cstdint>
26 #include <cstdlib>
27 #include <cmath>
28 
29 
30 //-------------------------------------------------------------------------
31 // samplv1_fx
32 //
33 // -- borrowed, stirred and refactored from Highlife --
34 //    Copyright (C) 2007 arguru, discodsp.com
35 //
36 
37 //-------------------------------------------------------------------------
38 // samplv1_fx_filter - RBJ biquad filter implementation.
39 //
40 //   http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
41 
42 class samplv1_fx_filter
43 {
44 public:
45 
46 	enum Type {
47 		Low = 0, High, Band1, Band2, Notch, AllPass, Peak, LoShelf, HiShelf
48 	};
49 
50 	samplv1_fx_filter(float srate = 44100.0f)
m_srate(srate)51 		: m_srate(srate) { reset(); }
52 
setSampleRate(float srate)53 	void setSampleRate(float srate)
54 		{ m_srate = srate; }
sampleRate()55 	float sampleRate() const
56 		{ return m_srate; }
57 
58 	void reset(Type type, float freq, float q, float gain, bool bwq = false)
59 	{
60 		reset();
61 
62 		// temp vars
63 		float alpha, a0, a1, a2, b0, b1, b2;
64 
65 		// peaking, lowshelf and hishelf
66 		if (type >= Peak) {
67 			const float amp   = ::powf(10.0f, (gain / 40.0f));
68 			const float omega = 2.0f * M_PI * freq / m_srate;
69 			const float tsin  = ::sinf(omega);
70 			const float tcos  = ::cosf(omega);
71 			const float beta  = ::sqrtf(amp) / q;
72 			if (bwq)
73 				alpha = tsin * ::sinhf(::logf(2.0f) / 2.0f * q * omega / tsin);
74 			else
75 				alpha = tsin / (2.0f * q);
76 			switch (type) {
77 			case Peak:
78 				// peaking
79 				b0 =  1.0f + alpha * amp;
80 				b1 = -2.0f * tcos;
81 				b2 =  1.0f - alpha * amp;
82 				a0 =  1.0f + alpha / amp;
83 				a1 = -2.0f * tcos;
84 				a2 =  1.0f - alpha / amp;
85 				break;
86 			case LoShelf:
87 				// low-shelf
88 				b0 = amp * ((amp + 1.0f) - (amp - 1.0f) * tcos + beta * tsin);
89 				b1 = 2.0f * amp *((amp - 1.0f) - (amp + 1.0f) * tcos);
90 				b2 = amp * ((amp + 1.0f) - (amp - 1.0f) * tcos - beta * tsin);
91 				a0 = (amp + 1.0f) + (amp - 1.0f) * tcos + beta * tsin;
92 				a1 = -2.0f *((amp - 1.0f) + (amp + 1.0f) * tcos);
93 				a2 = (amp + 1.0f) + (amp - 1.0f) * tcos - beta * tsin;
94 				break;
95 			case HiShelf:
96 			default:
97 				// high-shelf
98 				b0 = amp * ((amp + 1.0f) + (amp - 1.0f) * tcos + beta * tsin);
99 				b1 = -2.0f * amp * ((amp - 1.0f) + (amp + 1.0f) * tcos);
100 				b2 = amp * ((amp + 1.0f) + (amp - 1.0f) * tcos - beta * tsin);
101 				a0 = (amp + 1.0f) - (amp - 1.0f) * tcos + beta * tsin;
102 				a1 = 2.0f * ((amp - 1.0f) - (amp + 1.0f) * tcos);
103 				a2 = (amp + 1.0f) - (amp - 1.0f) * tcos - beta * tsin;
104 				break;
105 			}
106 		} else {
107 			// other filters
108 			const float omega = 2.0f * M_PI * freq / m_srate;
109 			const float tsin  = ::sinf(omega);
110 			const float tcos  = ::cosf(omega);
111 			if (bwq)
112 				alpha = tsin * ::sinhf(::logf(2.0f) / 2.0f * q * omega / tsin);
113 			else
114 				alpha = tsin / (2.0f * q);
115 			switch (type) {
116 			case Low:
117 				// low-pass
118 				b0 = (1.0f - tcos) / 2.0f;
119 				b1 =  1.0f - tcos;
120 				b2 = (1.0f - tcos) / 2.0f;
121 				a0 =  1.0f + alpha;
122 				a1 = -2.0f * tcos;
123 				a2 =  1.0f - alpha;
124 				break;
125 			case High:
126 				// high-pass
127 				b0 = (1.0f + tcos) / 2.0f;
128 				b1 = -1.0f - tcos;
129 				b2 = (1.0f + tcos) / 2.0f;
130 				a0 =  1.0f + alpha;
131 				a1 = -2.0f * tcos;
132 				a2 =  1.0f - alpha;
133 				break;
134 			case Band1:
135 				// band-pass csg
136 				b0 =  tsin / 2.0f;
137 				b1 =  0.0f;
138 				b2 = -tsin / 2.0f;
139 				a0 =  1.0f + alpha;
140 				a1 = -2.0f * tcos;
141 				a2 =  1.0f - alpha;
142 				break;
143 			case Band2:
144 				// band-pass czpg
145 				b0 =  alpha;
146 				b1 =  0.0f;
147 				b2 = -alpha;
148 				a0 =  1.0f + alpha;
149 				a1 = -2.0f * tcos;
150 				a2 =  1.0f - alpha;
151 				break;
152 			case Notch:
153 				// notch
154 				b0 =  1.0f;
155 				b1 = -2.0f * tcos;
156 				b2 =  1.0f;
157 				a0 =  1.0f + alpha;
158 				a1 = -2.0f * tcos;
159 				a2 =  1.0f - alpha;
160 				break;
161 			case AllPass:
162 			default:
163 				// all-pass
164 				b0 =  1.0f - alpha;
165 				b1 = -2.0f * tcos;
166 				b2 =  1.0f + alpha;
167 				a0 =  1.0f + alpha;
168 				a1 = -2.0f * tcos;
169 				a2 =  1.0f - alpha;
170 				break;
171 			}
172 		}
173 		// set filter coeffs
174 		m_b0a0 = b0 / a0;
175 		m_b1a0 = b1 / a0;
176 		m_b2a0 = b2 / a0;
177 		m_a1a0 = a1 / a0;
178 		m_a2a0 = a2 / a0;
179 	};
180 
output(float in)181 	float output(float in)
182 	{
183 		// filter
184 		const float out = m_b0a0 * in
185 			+ m_b1a0 * m_in1  + m_b2a0 * m_in2
186 			- m_a1a0 * m_out1 - m_a2a0 * m_out2;
187 		// push in/out buffers
188 		m_in2  = m_in1;
189 		m_in1  = in;
190 		m_out2 = m_out1;
191 		m_out1 = out;
192 		// return output
193 		return out;
194 	}
195 
196 protected:
197 
reset()198 	void reset()
199 	{
200 		m_b0a0 = m_b1a0 = m_b2a0 = m_a1a0 = m_a2a0 = 0.0f;
201 		m_out1 = m_out2 = 0.0f;
202 		m_in1 = m_in2 = 0.0f;
203 	}
204 
205 private:
206 
207 	// nominal sample-rate
208 	float m_srate;
209 
210 	// filter coeffs
211 	float m_b0a0, m_b1a0, m_b2a0, m_a1a0, m_a2a0;
212 
213 	// in/out history
214 	float m_out1, m_out2, m_in1, m_in2;
215 };
216 
217 
218 //-------------------------------------------------------------------------
219 // samplv1_fx_comp - DiscoDSP's "rock da disco" compressor/eq.
220 
221 class samplv1_fx_comp
222 {
223 public:
224 
225 	samplv1_fx_comp(float srate = 44100.0f)
m_srate(srate)226 		: m_srate(srate), m_peak(0.0f),
227 			m_attack(0.0f), m_release(0.0f),
228 			m_lo(srate), m_mi(srate), m_hi(srate) {}
229 
setSampleRate(float srate)230 	void setSampleRate(float srate)
231 	{
232 		m_srate = srate;
233 
234 		m_lo.setSampleRate(srate);
235 		m_mi.setSampleRate(srate);
236 		m_hi.setSampleRate(srate);
237 	}
238 
sampleRate()239 	float sampleRate() const
240 		{ return m_srate; }
241 
reset()242 	void reset()
243 	{
244 		m_peak = 0.0f;
245 
246 		m_attack  = ::expf(-1000.0f / (m_srate * 3.6f));
247 		m_release = ::expf(-1000.0f / (m_srate * 150.0f));
248 
249 		// rock-da-house eq.
250 		m_lo.reset(samplv1_fx_filter::Peak,      100.0f, 1.0f, 6.0f);
251 		m_mi.reset(samplv1_fx_filter::LoShelf,  1000.0f, 1.0f, 3.0f);
252 		m_hi.reset(samplv1_fx_filter::HiShelf, 10000.0f, 1.0f, 4.0f);
253 	}
254 
process(float * in,uint32_t nframes)255 	void process(float *in, uint32_t nframes)
256 	{
257 		// compressor
258 		const float threshold = 0.251f;	//~= powf(10.0f, -12.0f / 20.0f);
259 		const float post_gain = 1.995f;	//~= powf(10.0f, 6.0f / 20.0f);
260 		// process buffers
261 		for (uint32_t i = 0; i < nframes; ++i) {
262 			// anti-denormalizer noise
263 			const float ad = 1E-14f * float(::rand());
264 			// process
265 			const float lo = m_lo.output(m_mi.output(m_hi.output(*in + ad)));
266 			// compute peak
267 			const float peak = ::fabsf(lo);
268 			// compute gain
269 			float gain = 1.0f;
270 			if (peak > threshold)
271 				gain = threshold / peak;
272 			// envelope
273 			if (m_peak > gain) {
274 				m_peak *= m_attack;
275 				m_peak += (1.0f - m_attack) * gain;
276 			} else {
277 				m_peak *= m_release;
278 				m_peak += (1.0f - m_release) * gain;
279 			}
280 			// output
281 			*in++ = lo * m_peak * post_gain;
282 		}
283 	}
284 
285 private:
286 
287 	float m_srate;
288 
289 	float m_peak;
290 	float m_attack;
291 	float m_release;
292 
293 	samplv1_fx_filter m_lo, m_mi, m_hi;
294 };
295 
296 
297 //-------------------------------------------------------------------------
298 // samplv1_fx_flanger - Flanger implementation.
299 
300 
301 class samplv1_fx_flanger
302 {
303 public:
304 
samplv1_fx_flanger()305 	samplv1_fx_flanger()
306 		{ reset(); }
307 
reset()308 	void reset()
309 	{
310 		for(uint32_t i = 0; i < MAX_SIZE; ++i)
311 			m_buffer[i] = 0.0f;
312 
313 		m_frames = 0;
314 	}
315 
output(float in,float delay,float feedb)316 	float output(float in, float delay, float feedb)
317 	{
318 		// calculate delay offset
319 		float delta = float(m_frames) - delay;
320 		// clip lookback buffer-bound
321 		if (delta < 0.0f)
322 			delta += float(MAX_SIZE);
323 		// get index
324 		const uint32_t index = uint32_t(delta);
325 		// 4 samples hermite
326 		const float y0 = m_buffer[(index + 0) & MAX_MASK];
327 		const float y1 = m_buffer[(index + 1) & MAX_MASK];
328 		const float y2 = m_buffer[(index + 2) & MAX_MASK];
329 		const float y3 = m_buffer[(index + 3) & MAX_MASK];
330 		// csi calculate
331 		const float c0 = y1;
332 		const float c1 = 0.5f * (y2 - y0);
333 		const float c2 = y0 - 2.5f * y1 + 2.0f * y2 - 0.5f * y3;
334 		const float c3 = 0.5f * (y3 - y0) + 1.5f * (y1 - y2);
335 		// compute interpolation x
336 		const float x = delta - ::floorf(delta);
337 		// get output
338 		const float out = ((c3 * x + c2) * x + c1) * x + c0;
339 		// add to delay buffer
340 		m_buffer[(m_frames++) & MAX_MASK] = in + out * feedb;
341 		// return output
342 		return out;
343 	}
344 
process(float * in,uint32_t nframes,float wet,float delay,float feedb,float daft)345 	void process(float *in, uint32_t nframes,
346 		float wet, float delay, float feedb, float daft)
347 	{
348 		if (wet < 1E-9f)
349 			return;
350 		// daft effect
351 		if (daft > 0.001f) {
352 			delay *= (1.0f - daft);
353 		//	feedb *= (1.0f - daft);
354 		}
355 		delay *= float(MAX_SIZE);
356 		// process
357 		for (uint32_t i = 0; i < nframes; ++i)
358 			in[i] += wet * output(in[i], delay, feedb);
359 	}
360 
361 	static const uint32_t MAX_SIZE = (1 << 12);	//= 4096;
362 	static const uint32_t MAX_MASK = MAX_SIZE - 1;
363 
364 private:
365 
366 	float m_buffer[MAX_SIZE];
367 
368 	uint32_t m_frames;
369 };
370 
371 
372 //-------------------------------------------------------------------------
373 // samplv1_fx_chorus - Chorus implementation.
374 
375 class samplv1_fx_chorus
376 {
377 public:
378 
379 	samplv1_fx_chorus(float srate = 44100.0f)
m_srate(srate)380 		: m_srate(srate) { reset(); }
381 
setSampleRate(float srate)382 	void setSampleRate(float srate)
383 		{ m_srate = srate; }
sampleRate()384 	float sampleRate() const
385 		{ return m_srate; }
386 
reset()387 	void reset()
388 	{
389 		m_flang1.reset();
390 		m_flang2.reset();
391 
392 		m_lfo = 0.0f;
393 	}
394 
process(float * in1,float * in2,uint32_t nframes,float wet,float delay,float feedb,float rate,float mod)395 	void process(float *in1, float *in2, uint32_t nframes,
396 		float wet, float delay, float feedb, float rate, float mod)
397 	{
398 		if (wet < 1E-9f)
399 			return;
400 		// constrained feedback
401 		feedb *= 0.95f;
402 		// calculate delay time
403 		const float d0 = 0.5f * delay * float(samplv1_fx_flanger::MAX_SIZE);
404 		const float a1 = 0.99f * d0 * mod * mod;
405 		const float r2 = 4.0f * M_PI * rate * rate / m_srate;
406 		// process
407 		for (uint32_t i = 0; i < nframes; ++i) {
408 			// modulation
409 			const float lfo = a1 * pseudo_sinf(m_lfo);
410 			const float delay1 = d0 - lfo;
411 			const float delay2 = d0 - lfo * 0.9f;
412 			// chorus mix
413 			in1[i] += wet * m_flang1.output(in1[i], delay1, feedb);
414 			in2[i] += wet * m_flang2.output(in2[i], delay2, feedb);
415 			// lfo advance
416 			m_lfo += r2;
417 			// lfo wrap
418 			if (m_lfo >= 1.0f)
419 				m_lfo -= 2.0f;
420 		}
421 	}
422 
423 protected:
424 
pseudo_sinf(float x)425 	float pseudo_sinf(float x) const
426 	{
427 		x *= x;
428 		x -= 1.0f;
429 		return x * x;
430 	}
431 
432 private:
433 
434 	float m_srate;
435 
436 	samplv1_fx_flanger m_flang1;
437 	samplv1_fx_flanger m_flang2;
438 
439 	float m_lfo;
440 };
441 
442 
443 //-------------------------------------------------------------------------
444 // samplv1_fx_delay - Delay implementation.
445 
446 class samplv1_fx_delay
447 {
448 public:
449 
450 	samplv1_fx_delay(float srate = 44100.0f)
m_srate(srate)451 		: m_srate(srate) { reset(); }
452 
setSampleRate(float srate)453 	void setSampleRate(float srate)
454 		{ m_srate = srate; }
sampleRate()455 	float sampleRate() const
456 		{ return m_srate; }
457 
reset()458 	void reset()
459 	{
460 		for (uint32_t i = 0; i < MAX_SIZE; ++i)
461 			m_buffer[i] = 0.0f;
462 
463 		m_out = 0.0f;
464 		m_frames = 0;
465 	}
466 
467 	void process(float *in, uint32_t nframes,
468 		float wet, float delay, float feedb, float bpm = 0.0f)
469 	{
470 		if (wet < 1E-9f)
471 			return;
472 		// constrained feedback
473 		feedb *= 0.95f;
474 		// calculate delay time
475 		float delay_time = delay * m_srate;
476 		if (bpm > 0.0f)
477 			delay_time *= 60.f / bpm;
478 		// set integer delay
479 		uint32_t ndelay = uint32_t(delay_time);
480 		// clamp
481 		if (ndelay < MIN_SIZE)
482 			ndelay = MIN_SIZE;
483 		else
484 		if (ndelay > MAX_SIZE)
485 			ndelay = MAX_SIZE;
486 		// delay process
487 		for (uint32_t i = 0; i < nframes; ++i) {
488 			const uint32_t j = (m_frames++) & MAX_MASK;
489 			m_out = m_buffer[(j - ndelay) & MAX_MASK];
490 			m_buffer[j] = *in + m_out * feedb;
491 			*in++ += wet * m_out;
492 		}
493 	}
494 
495 	static const uint32_t MIN_SIZE = (1 <<  8);	//= 256;
496 	static const uint32_t MAX_SIZE = (1 << 16);	//= 65536;
497 	static const uint32_t MAX_MASK = MAX_SIZE - 1;
498 
499 private:
500 
501 	float m_srate;
502 
503 	float m_buffer[MAX_SIZE];
504 	float m_out;
505 
506 	uint32_t m_frames;
507 };
508 
509 
510 //-------------------------------------------------------------------------
511 // samplv1_fx_allpass - All-pass delay implementation.
512 
513 class samplv1_fx_allpass
514 {
515 public:
516 
samplv1_fx_allpass()517 	samplv1_fx_allpass()
518 		{ reset(); }
519 
reset()520 	void reset()
521 		{ m_out = 0.0f; }
522 
output(float in,float delay)523 	float output(float in, float delay)
524 	{
525 		const float a1 = (1.0f - delay) / (1.0f + delay);
526 		const float out = m_out - a1 * in;
527 		m_out = in + a1 * out;
528 		return out;
529 	}
530 
531 private:
532 
533 	float m_out;
534 };
535 
536 
537 //-------------------------------------------------------------------------
538 // samplv1_fx_phaser - Phaser implementation.
539 
540 class samplv1_fx_phaser
541 {
542 public:
543 
544 	samplv1_fx_phaser(float srate = 44100.0f)
m_srate(srate)545 		: m_srate(srate) { reset(); }
546 
setSampleRate(float srate)547 	void setSampleRate(float srate)
548 		{ m_srate = srate; }
sampleRate()549 	float sampleRate() const
550 		{ return m_srate; }
551 
reset()552 	void reset()
553 	{
554 		// initialize vars
555 		m_lfo_phase = 0.0f;
556 		m_out = 0.0f;
557 		// reset taps
558 		for (uint16_t n = 0; n < MAX_TAPS; ++n)
559 			m_taps[n].reset();
560 	}
561 
process(float * in,uint32_t nframes,float wet,float rate,float feedb,float depth,float daft)562 	void process(float *in, uint32_t nframes, float wet,
563 		float rate, float feedb, float depth, float daft)
564 	{
565 		if (wet < 1E-9f)
566 			return;
567 		// daft effect
568 		if (daft > 0.001f && daft < 1.0f) {
569 			rate  *= (1.0f - 0.5f * daft);
570 		//	feedb *= (1.0f - daft);
571 			depth *= (1.0f - daft);
572 		}
573 		depth += 1.0f;
574 		// update coeffs
575 		const float delay_min = 2.0f * 440.0f / m_srate;
576 		const float delay_max = 2.0f * 4400.0f / m_srate;
577 		const float lfo_inc   = 2.0f * M_PI * rate / m_srate;
578 		// anti-denormal noise
579 		const float adenormal = 1E-14f * float(::rand());
580 		// sweep...
581 		for (uint32_t i = 0; i < nframes; ++i) {
582 			// calculate and update phaser lfo
583 			const float delay = delay_min + (delay_max - delay_min)
584 				* 0.5f * (1.0f + ::sinf(m_lfo_phase));
585 			// increment phase
586 			m_lfo_phase += lfo_inc;
587 			// positive wrap phase
588 			if (m_lfo_phase >= 2.0f * M_PI)
589 				m_lfo_phase -= 2.0f * M_PI;
590 			// get input
591 			m_out = in[i] + adenormal + m_out * feedb;
592 			// update filter coeffs and calculate output
593 			for (uint16_t n = 0; n < MAX_TAPS; ++n)
594 				m_out = m_taps[n].output(m_out, delay);
595 			// output
596 			in[i] += wet * m_out * depth;
597 		}
598 	}
599 
600 private:
601 
602 	float m_srate;
603 
604 	static const uint16_t MAX_TAPS = 6;
605 
606 	samplv1_fx_allpass m_taps[MAX_TAPS];
607 
608 	float m_dmin;
609 	float m_dmax;
610 	float m_feedb;
611 	float m_lfo_phase;
612 	float m_lfo_inc;
613 	float m_depth;
614 
615 	float m_out;
616 };
617 
618 
619 #endif	// __samplv1_fx_h
620 
621 // end of samplv1_fx.h
622