pipewire/spa/plugins/audioconvert/gaps-ops.c
Wim Taymans 8971c488f3 audioconvert: add zeroramp and gap detection to audioconvert
Make a new zeroramp.duration and zeroramp.gap property on audioconver.
It detects N samples of silence before triggering a fade-in or fade-out
of the given zeroramp.duration.

The zeroramp.duration is by default 5ms and zeroramp.gap is set to 0.

When the zeroramp.gap is set to 0, the audioconver will not do any gap
detection but it will only do fade-out from the last sample when the IO
Buffer area is removed from a port.

This by default makes the audio adapter perform a fade-out when the last
input of the port mixer was removed and the mixer is no longer scheduled
and the IO Area removed from the audioconverter input port.
2026-06-17 17:11:42 +02:00

77 lines
1.7 KiB
C

/* Spa */
/* SPDX-FileCopyrightText: Copyright © 2022 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <spa/support/cpu.h>
#include <spa/support/log.h>
#include <spa/utils/defs.h>
#include "gaps-ops.h"
typedef int (*gaps_check_func_t) (struct gaps *gaps, const float * SPA_RESTRICT src[],
uint32_t n_samples);
typedef void (*gaps_fix_func_t) (struct gaps *gaps, float * SPA_RESTRICT dst[],
const float * SPA_RESTRICT src[], uint32_t n_samples);
#define MAKE(check,fix,...) \
{ check, fix, #fix , __VA_ARGS__ }
static const struct gaps_info {
gaps_check_func_t check;
gaps_fix_func_t fix;
const char *name;
uint32_t cpu_flags;
} gaps_table[] =
{
MAKE(gaps_check_c, gaps_fix_c, 0),
};
#undef MAKE
#define MATCH_CPU_FLAGS(a,b) ((a) == 0 || ((a) & (b)) == a)
static const struct gaps_info *find_gaps_info(uint32_t cpu_flags)
{
SPA_FOR_EACH_ELEMENT_VAR(gaps_table, t) {
if (MATCH_CPU_FLAGS(t->cpu_flags, cpu_flags))
return t;
}
return NULL;
}
static void impl_gaps_free(struct gaps *gaps)
{
gaps->fix = NULL;
}
int gaps_init(struct gaps *gaps)
{
const struct gaps_info *info;
uint32_t i;
info = find_gaps_info(gaps->cpu_flags);
if (info == NULL)
return -ENOTSUP;
if (gaps->channels > SPA_AUDIO_MAX_CHANNELS)
return -EINVAL;
gaps->duration = SPA_MIN(gaps->duration, GAPS_MAX_CURVE);
for (i = 0; i < gaps->duration; i++)
gaps->curve[i] = (float)(0.5 + 0.5 * cos(M_PI + M_PI * i / gaps->duration));
for (i = 0; i < gaps->channels; i++)
spa_zero(gaps->states[i]);
gaps->cpu_flags = info->cpu_flags;
gaps->func_name = info->name;
gaps->free = impl_gaps_free;
gaps->check = info->check;
gaps->fix = info->fix;
return 0;
}