Noisegate.cc 3.85 KB
Newer Older
1
/*
2
	Noisegate.cc
3
	
4
	Copyright 2011-16 Tim Goetze <tim@quitte.de>
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
	
	http://quitte.de/dsp/

	Noise reduction measures

*/
/*
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 3
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA or point your web browser to http://www.gnu.org.
*/

#include "basics.h"
#include <stdio.h>

31
#include "Noisegate.h"
32 33 34
#include "Descriptor.h"

void
35
Noisegate::init()
36
{
37
	N = 3*960*fs/48000; /* 60 ms RMS accumulation when open */
38
	over_N = 1./N;
39
	hysteresis.threshold = (uint) (.180*fs); /* opening for at least 180 ms */
40
	gain.quiet = db2lin (-60);
41
	gain.lp.set_f (120*over_fs);
42 43 44
}

void
45
Noisegate::activate()
46 47 48
{
	rms.reset();
	remain = 0;
49
	hysteresis.age = 0;
50 51
	gain.current = gain.quiet;
	gain.delta = 0;
52
	gain.lp.reset();
53 54 55
	f_mains = -1; /* make sure filters are updated when processing */
}

56 57 58 59 60 61 62 63 64 65
void 
Noisegate::process (sample_t x)
{
	x += normal;
	normal = -normal;
	sample_t y = humfilter[0].process(x);
	y = humfilter[1].process(y);
	rms.store (x - .3*y);
}

66
void
67
Noisegate::cycle (uint frames)
68
{
69
	static int frame = 0;
70

71 72 73
	float open = db2lin(getport(0)-10);
	float attack = max(.005*N*getport(1), 2); /* in samples */
	float close = db2lin(getport(2));
74

75
	float f = getport(3);
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
	if (f != f_mains)
	{
		f_mains = f;
		if (!f) /* no mains hum filtering: set filters to identity */
		{
			humfilter[0].unity();
			humfilter[1].unity();
		}
		else
		{
			DSP::RBJ::BP (f_mains*over_fs, 5, humfilter[0]);
			DSP::RBJ::BP (f_mains*over_fs, 1, humfilter[1]);
		}
		humfilter[0].reset();
		humfilter[1].reset();
	}

93 94
	sample_t * s = ports[4];
	sample_t * d = ports[5]; 
95
	bool opennow = false;
96 97 98 99 100
	while (frames)
	{
		if (remain == 0)
		{
			remain = N;
101 102 103
			if (opennow)
			{
				remain = (int) attack;
104
				gain.delta = (1 - gain.current)/remain;
105 106 107
				hysteresis.age = 0;
				opennow = false;
			}
108
			else if (gain.delta > 0)
109 110 111
				gain.current = 1,
				gain.delta = 0;
			else if (gain.delta < 0) 
112
				gain.delta = 0;
113
			else if (gain.current > gain.quiet+.001 && rms.get() < close && hysteresis.age > hysteresis.threshold) 
114 115
			{
				//fprintf (stderr, "%.3f < %.3f\n", rms.get(), close);
116
				gain.delta = (gain.quiet - gain.current)*over_N;
117 118 119
			}
		}

120
		#define OUT (gain.current+0*gain.get())
121 122 123
		uint i = 0;
		uint n = min (frames, remain);
		//fprintf (stderr, "%d %.3f (%.3f)\n", n, gain.current, gain.delta);
124
		if (gain.delta > 0 || gain.current == 1) for (  ; i < n; ++i) /* opening or open */
125
		{
126 127
			sample_t a = s[i];
			process(a);
128
			d[i] = a*gain.get();
129
		}
130
		else for (  ; i < n; ++i) /* closed */
131
		{
132 133 134
			sample_t a = s[i];
			process(a);
			if (fabs(a) < open)
135
				d[i] = a*gain.get();
136 137
			else 
			{
138 139
				opennow = true;
				remain = i;
140 141 142 143
				break;
			}
		}
		
144
		hysteresis.age += i;
145 146 147
		s += i, d += i;
		frames -= i;
		remain -= i;
148
		frame += i;
149 150 151 152 153 154
	}
}

/* //////////////////////////////////////////////////////////////////////// */

PortInfo
155
Noisegate::port_info [] = 
156
{
157
	{ "open (dB)", CTRL_IN, {DEFAULT_LOW, -55, 0} }, 
158
	{ "attack (ms)", CTRL_IN, {DEFAULT_0, 0, 5} }, 
159
	{ "close (dB)", CTRL_IN, {DEFAULT_LOW, -80, 0} }, 
160 161 162 163

	/* mains */
	{ "mains (Hz)", CTRL_IN|GROUP, {INTEGER|DEFAULT_MID, 0, 100},
		"{0:'off',50:'global',60:'imperial'}"}, 
164 165 166

	{ "in", INPUT | AUDIO },
	{	"out", OUTPUT | AUDIO }
167 168 169
};

template <> void
170
Descriptor<Noisegate>::setup()
171
{
172
	Label = "Noisegate";
173
	Name = CAPS "Noisegate - Attenuating hum and noise";
174 175 176 177
	autogen();
}