mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	filter-graph: add a simple noise gate
This commit is contained in:
		
							parent
							
								
									616db9809e
								
							
						
					
					
						commit
						ef5d9ff028
					
				
					 2 changed files with 148 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -60,6 +60,9 @@ struct builtin {
 | 
			
		|||
	int mode;
 | 
			
		||||
	uint32_t count;
 | 
			
		||||
	float last;
 | 
			
		||||
 | 
			
		||||
	float gate;
 | 
			
		||||
	float hold;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void *builtin_instantiate(const struct spa_fga_plugin *plugin, const struct spa_fga_descriptor * Descriptor,
 | 
			
		||||
| 
						 | 
				
			
			@ -2876,6 +2879,136 @@ static const struct spa_fga_descriptor zeroramp_desc = {
 | 
			
		|||
	.cleanup = builtin_cleanup,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* noisegate */
 | 
			
		||||
static struct spa_fga_port noisegate_ports[] = {
 | 
			
		||||
	{ .index = 0,
 | 
			
		||||
	  .name = "In",
 | 
			
		||||
	  .flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_AUDIO,
 | 
			
		||||
	},
 | 
			
		||||
	{ .index = 1,
 | 
			
		||||
	  .name = "Out",
 | 
			
		||||
	  .flags = SPA_FGA_PORT_OUTPUT | SPA_FGA_PORT_AUDIO,
 | 
			
		||||
	},
 | 
			
		||||
	{ .index = 2,
 | 
			
		||||
	  .name = "Open Threshold",
 | 
			
		||||
	  .flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
 | 
			
		||||
	  .def = 0.004f, .min = 0.0f, .max = 1.0f
 | 
			
		||||
	},
 | 
			
		||||
	{ .index = 3,
 | 
			
		||||
	  .name = "Close Threshold",
 | 
			
		||||
	  .flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
 | 
			
		||||
	  .def = 0.003f, .min = 0.0f, .max = 1.0f
 | 
			
		||||
	},
 | 
			
		||||
	{ .index = 4,
 | 
			
		||||
	  .name = "Attack (s)",
 | 
			
		||||
	  .flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
 | 
			
		||||
	  .def = 0.005f, .min = 0.0f, .max = 1.0f
 | 
			
		||||
	},
 | 
			
		||||
	{ .index = 5,
 | 
			
		||||
	  .name = "Hold (s)",
 | 
			
		||||
	  .flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
 | 
			
		||||
	  .def = 0.050f, .min = 0.0f, .max = 1.0f
 | 
			
		||||
	},
 | 
			
		||||
	{ .index = 6,
 | 
			
		||||
	  .name = "Release (s)",
 | 
			
		||||
	  .flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
 | 
			
		||||
	  .def = 0.010f, .min = 0.0f, .max = 1.0f
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void noisegate_run(void * Instance, unsigned long SampleCount)
 | 
			
		||||
{
 | 
			
		||||
	struct builtin *impl = Instance;
 | 
			
		||||
	float *in = impl->port[0];
 | 
			
		||||
	float *out = impl->port[1];
 | 
			
		||||
	unsigned long n;
 | 
			
		||||
	float o_thres = impl->port[2][0];
 | 
			
		||||
	float c_thres = impl->port[3][0];
 | 
			
		||||
	float gate, hold, o_rate, c_rate, level;
 | 
			
		||||
	int mode;
 | 
			
		||||
 | 
			
		||||
	if (out == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (in == NULL) {
 | 
			
		||||
		memset(out, 0, SampleCount * sizeof(float));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	o_rate = 1.0f / (impl->port[4][0] * impl->rate);
 | 
			
		||||
	c_rate = 1.0f / (impl->port[6][0] * impl->rate);
 | 
			
		||||
	gate = impl->gate;
 | 
			
		||||
	hold = impl->hold;
 | 
			
		||||
	mode = impl->mode;
 | 
			
		||||
	level = impl->last;
 | 
			
		||||
 | 
			
		||||
	for (n = 0; n < SampleCount; n++) {
 | 
			
		||||
		float lev = fabsf(in[n]);
 | 
			
		||||
 | 
			
		||||
		if (lev > level)
 | 
			
		||||
			level = lev;
 | 
			
		||||
		else
 | 
			
		||||
			level = lev * 0.05f + level * 0.95f;
 | 
			
		||||
 | 
			
		||||
		switch (mode) {
 | 
			
		||||
		case 0:
 | 
			
		||||
			/* closed */
 | 
			
		||||
			if (level >= o_thres)
 | 
			
		||||
				mode = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case 1:
 | 
			
		||||
			/* opening */
 | 
			
		||||
			gate += o_rate;
 | 
			
		||||
			if (gate >= 1.0f) {
 | 
			
		||||
				gate = 1.0f;
 | 
			
		||||
				mode = 2;
 | 
			
		||||
				hold = impl->port[5][0] * impl->rate;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case 2:
 | 
			
		||||
			/* hold */
 | 
			
		||||
			hold -= 1.0f;
 | 
			
		||||
			if (hold <= 0.0f)
 | 
			
		||||
				mode = 3;
 | 
			
		||||
			break;
 | 
			
		||||
		case 3:
 | 
			
		||||
			/* open */
 | 
			
		||||
			if (level < c_thres)
 | 
			
		||||
				mode = 4;
 | 
			
		||||
			break;
 | 
			
		||||
		case 4:
 | 
			
		||||
			/* closing */
 | 
			
		||||
			gate -= c_rate;
 | 
			
		||||
			if (level >= o_thres)
 | 
			
		||||
				mode = 1;
 | 
			
		||||
			else if (gate <= 0.0f) {
 | 
			
		||||
				gate = 0.0f;
 | 
			
		||||
				mode = 0;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		out[n] = in[n] * gate;
 | 
			
		||||
	}
 | 
			
		||||
	impl->gate = gate;
 | 
			
		||||
	impl->hold = hold;
 | 
			
		||||
	impl->mode = mode;
 | 
			
		||||
	impl->last = level;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct spa_fga_descriptor noisegate_desc = {
 | 
			
		||||
	.name = "noisegate",
 | 
			
		||||
	.flags = SPA_FGA_DESCRIPTOR_SUPPORTS_NULL_DATA,
 | 
			
		||||
 | 
			
		||||
	.n_ports = SPA_N_ELEMENTS(noisegate_ports),
 | 
			
		||||
	.ports = noisegate_ports,
 | 
			
		||||
 | 
			
		||||
	.instantiate = builtin_instantiate,
 | 
			
		||||
	.connect_port = builtin_connect_port,
 | 
			
		||||
	.run = noisegate_run,
 | 
			
		||||
	.cleanup = builtin_cleanup,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct spa_fga_descriptor * builtin_descriptor(unsigned long Index)
 | 
			
		||||
{
 | 
			
		||||
	switch(Index) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2939,6 +3072,8 @@ static const struct spa_fga_descriptor * builtin_descriptor(unsigned long Index)
 | 
			
		|||
		return &pipe_desc;
 | 
			
		||||
	case 29:
 | 
			
		||||
		return &zeroramp_desc;
 | 
			
		||||
	case 30:
 | 
			
		||||
		return &noisegate_desc;
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -623,6 +623,19 @@ extern struct spa_handle_factory spa_filter_graph_factory;
 | 
			
		|||
 * "Duration (s)" determines how long the fade-in and fade-out should last
 | 
			
		||||
 * (default 0.000666).
 | 
			
		||||
 *
 | 
			
		||||
 * ### Noisegate
 | 
			
		||||
 *
 | 
			
		||||
 * The `noisegate` plugin can be used to remove low volume noise.
 | 
			
		||||
 *
 | 
			
		||||
 * It has an "In" input port and an "Out" output data ports. Normally the input
 | 
			
		||||
 * data is passed directly to the output.
 | 
			
		||||
 *
 | 
			
		||||
 * If the volume drops below "Close threshold", the noisegate will ramp down the
 | 
			
		||||
 * volume to zero for a duration of "Release (s)" seconds. When the volume is above
 | 
			
		||||
 * "Open threshold", the noisegate will ramp up the volume to 1 for a duration
 | 
			
		||||
 * of "Attack (s)" seconds. The noise gate stays open for at least "Hold (s)"
 | 
			
		||||
 * seconds before it can close again.
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * ## SOFA filters
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue