mirror of
https://github.com/librempeg/librempeg
synced 2024-11-22 00:51:37 +00:00
avfilter/af_apulsator: add float sample format support
This commit is contained in:
parent
e717bedcb2
commit
ce164b6ab9
@ -107,112 +107,16 @@ static const AVOption apulsator_options[] = {
|
||||
|
||||
AVFILTER_DEFINE_CLASS(apulsator);
|
||||
|
||||
static double lfo_get_value(const int mode, double amount,
|
||||
double phase, double width, double offset)
|
||||
{
|
||||
double phs = phase / width + offset;
|
||||
double val;
|
||||
|
||||
if (phs > 1)
|
||||
phs = fmod(phs, 1.);
|
||||
|
||||
switch (mode) {
|
||||
case SINE:
|
||||
val = sin(phs * 2.0 * M_PI);
|
||||
break;
|
||||
case TRIANGLE:
|
||||
if (phs > 0.75)
|
||||
val = (phs - 0.75) * 4.0 - 1.0;
|
||||
else if (phs > 0.25)
|
||||
val = -4.0 * phs + 2.0;
|
||||
else
|
||||
val = phs * 4.0;
|
||||
break;
|
||||
case SQUARE:
|
||||
val = phs < 0.5 ? -1.0 : 1.0;
|
||||
break;
|
||||
case SAWUP:
|
||||
val = phs * 2.0 - 1.0;
|
||||
break;
|
||||
case SAWDOWN:
|
||||
val = 1.0 - phs * 2.0;
|
||||
break;
|
||||
default:
|
||||
av_assert0(0);
|
||||
}
|
||||
|
||||
return val * amount;
|
||||
}
|
||||
|
||||
typedef struct ThreadData {
|
||||
AVFrame *out, *in;
|
||||
} ThreadData;
|
||||
|
||||
static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
|
||||
{
|
||||
AudioPulsatorContext *s = ctx->priv;
|
||||
ThreadData *td = arg;
|
||||
AVFrame *out = td->out;
|
||||
AVFrame *in = td->in;
|
||||
const int nb_channels = in->ch_layout.nb_channels;
|
||||
const int start = (nb_channels * jobnr) / nb_jobs;
|
||||
const int end = (nb_channels * (jobnr+1)) / nb_jobs;
|
||||
#define DEPTH 32
|
||||
#include "apulsator_template.c"
|
||||
|
||||
for (int ch = start; ch < end; ch++) {
|
||||
const double *src = (const double *)in->extended_data[ch];
|
||||
const double level_out = s->level_out[FFMIN(ch, s->nb_level_out-1)];
|
||||
const double level_in = s->level_in[FFMIN(ch, s->nb_level_in-1)];
|
||||
const double amount = s->amount[FFMIN(ch, s->nb_amount-1)];
|
||||
const int timing = s->timing[FFMIN(ch, s->nb_timing-1)];
|
||||
const double offset = s->offset[FFMIN(ch, s->nb_offset-1)];
|
||||
const double width = s->width[FFMIN(ch, s->nb_width-1)];
|
||||
const double hertz = s->hertz[FFMIN(ch, s->nb_hertz-1)];
|
||||
const double bpm = s->bpm[FFMIN(ch, s->nb_bpm-1)];
|
||||
const int mode = s->mode[FFMIN(ch, s->nb_mode-1)];
|
||||
const double ms = s->ms[FFMIN(ch, s->nb_ms-1)];
|
||||
double *dst = (double *)out->extended_data[ch];
|
||||
const double fs = 1.0 / in->sample_rate;
|
||||
const int nb_samples = in->nb_samples;
|
||||
double phase = s->phase[ch];
|
||||
double freq;
|
||||
|
||||
switch (timing) {
|
||||
case UNIT_BPM:
|
||||
freq = bpm / 60.0;
|
||||
break;
|
||||
case UNIT_MS:
|
||||
freq = 1.0 / (ms / 1000.0);
|
||||
break;
|
||||
case UNIT_HZ:
|
||||
freq = hertz;
|
||||
break;
|
||||
default:
|
||||
av_assert0(0);
|
||||
}
|
||||
|
||||
for (int n = 0; n < nb_samples; n++) {
|
||||
double in = src[n] * level_in;
|
||||
double proc = in;
|
||||
double out;
|
||||
|
||||
proc *= lfo_get_value(mode, amount, phase, width,
|
||||
offset) * 0.5 + amount / 2.0;
|
||||
|
||||
out = proc + in * (1.0 - amount);
|
||||
out *= level_out;
|
||||
|
||||
dst[n] = out;
|
||||
|
||||
phase = fabs(phase + freq * fs);
|
||||
if (phase >= 1.0)
|
||||
phase = fmod(phase, 1.0);
|
||||
}
|
||||
|
||||
s->phase[ch] = phase;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#undef DEPTH
|
||||
#define DEPTH 64
|
||||
#include "apulsator_template.c"
|
||||
|
||||
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
|
||||
{
|
||||
@ -250,7 +154,16 @@ static int config_input(AVFilterLink *inlink)
|
||||
AVFilterContext *ctx = inlink->dst;
|
||||
AudioPulsatorContext *s = ctx->priv;
|
||||
|
||||
s->filter_channels = filter_channels;
|
||||
switch (inlink->format) {
|
||||
case AV_SAMPLE_FMT_FLTP:
|
||||
s->filter_channels = filter_channels_fltp;
|
||||
break;
|
||||
case AV_SAMPLE_FMT_DBLP:
|
||||
s->filter_channels = filter_channels_dblp;
|
||||
break;
|
||||
default:
|
||||
return AVERROR_BUG;
|
||||
}
|
||||
|
||||
s->phase = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->phase));
|
||||
if (!s->phase)
|
||||
@ -283,7 +196,7 @@ const AVFilter ff_af_apulsator = {
|
||||
.uninit = uninit,
|
||||
FILTER_INPUTS(inputs),
|
||||
FILTER_OUTPUTS(ff_audio_default_filterpad),
|
||||
FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP),
|
||||
FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP),
|
||||
.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC |
|
||||
AVFILTER_FLAG_SLICE_THREADS,
|
||||
.process_command = ff_filter_process_command,
|
||||
|
145
libavfilter/apulsator_template.c
Normal file
145
libavfilter/apulsator_template.c
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#undef ftype
|
||||
#undef FABS
|
||||
#undef FMOD
|
||||
#undef SIN
|
||||
#undef SAMPLE_FORMAT
|
||||
#if DEPTH == 32
|
||||
#define SAMPLE_FORMAT fltp
|
||||
#define FABS fabsf
|
||||
#define FMOD fmodf
|
||||
#define SIN sinf
|
||||
#define ftype float
|
||||
#else
|
||||
#define SAMPLE_FORMAT dblp
|
||||
#define FABS fabs
|
||||
#define FMOD fmod
|
||||
#define SIN sin
|
||||
#define ftype double
|
||||
#endif
|
||||
|
||||
#define F(x) ((ftype)(x))
|
||||
|
||||
#define fn3(a,b) a##_##b
|
||||
#define fn2(a,b) fn3(a,b)
|
||||
#define fn(a) fn2(a, SAMPLE_FORMAT)
|
||||
|
||||
static ftype fn(lfo_get_value)(const int mode, ftype amount,
|
||||
ftype phase, ftype width, ftype offset)
|
||||
{
|
||||
ftype phs = phase / width + offset;
|
||||
ftype val;
|
||||
|
||||
if (phs > F(1.0))
|
||||
phs = FMOD(phs, F(1.0));
|
||||
|
||||
switch (mode) {
|
||||
case SINE:
|
||||
val = SIN(phs * F(2.0 * M_PI));
|
||||
break;
|
||||
case TRIANGLE:
|
||||
if (phs > F(0.75))
|
||||
val = (phs - F(0.75)) * F(4.0) - F(1.0);
|
||||
else if (phs > F(0.25))
|
||||
val = F(-4.0) * phs + F(2.0);
|
||||
else
|
||||
val = phs * F(4.0);
|
||||
break;
|
||||
case SQUARE:
|
||||
val = phs < F(0.5) ? -F(1.0) : F(1.0);
|
||||
break;
|
||||
case SAWUP:
|
||||
val = phs * F(2.0) - F(1.0);
|
||||
break;
|
||||
case SAWDOWN:
|
||||
val = F(1.0) - phs * F(2.0);
|
||||
break;
|
||||
default:
|
||||
av_assert0(0);
|
||||
}
|
||||
|
||||
return val * amount;
|
||||
}
|
||||
|
||||
static int fn(filter_channels)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
|
||||
{
|
||||
AudioPulsatorContext *s = ctx->priv;
|
||||
ThreadData *td = arg;
|
||||
AVFrame *out = td->out;
|
||||
AVFrame *in = td->in;
|
||||
const int nb_channels = in->ch_layout.nb_channels;
|
||||
const int start = (nb_channels * jobnr) / nb_jobs;
|
||||
const int end = (nb_channels * (jobnr+1)) / nb_jobs;
|
||||
|
||||
for (int ch = start; ch < end; ch++) {
|
||||
const ftype *src = (const ftype *)in->extended_data[ch];
|
||||
const ftype level_out = s->level_out[FFMIN(ch, s->nb_level_out-1)];
|
||||
const ftype level_in = s->level_in[FFMIN(ch, s->nb_level_in-1)];
|
||||
const ftype amount = s->amount[FFMIN(ch, s->nb_amount-1)];
|
||||
const int timing = s->timing[FFMIN(ch, s->nb_timing-1)];
|
||||
const ftype offset = s->offset[FFMIN(ch, s->nb_offset-1)];
|
||||
const ftype width = s->width[FFMIN(ch, s->nb_width-1)];
|
||||
const ftype hertz = s->hertz[FFMIN(ch, s->nb_hertz-1)];
|
||||
const ftype bpm = s->bpm[FFMIN(ch, s->nb_bpm-1)];
|
||||
const int mode = s->mode[FFMIN(ch, s->nb_mode-1)];
|
||||
const ftype ms = s->ms[FFMIN(ch, s->nb_ms-1)];
|
||||
ftype *dst = (ftype *)out->extended_data[ch];
|
||||
const ftype fs = F(1.0) / in->sample_rate;
|
||||
const int nb_samples = in->nb_samples;
|
||||
ftype phase = s->phase[ch];
|
||||
ftype freq;
|
||||
|
||||
switch (timing) {
|
||||
case UNIT_BPM:
|
||||
freq = bpm / F(60.0);
|
||||
break;
|
||||
case UNIT_MS:
|
||||
freq = F(1.0) / (ms / F(1000.0));
|
||||
break;
|
||||
case UNIT_HZ:
|
||||
freq = hertz;
|
||||
break;
|
||||
default:
|
||||
av_assert0(0);
|
||||
}
|
||||
|
||||
for (int n = 0; n < nb_samples; n++) {
|
||||
ftype in = src[n] * level_in;
|
||||
ftype proc = in;
|
||||
ftype out;
|
||||
|
||||
proc *= fn(lfo_get_value)(mode, amount, phase, width,
|
||||
offset) * F(0.5) + amount / F(2.0);
|
||||
|
||||
out = proc + in * (F(1.0) - amount);
|
||||
out *= level_out;
|
||||
|
||||
dst[n] = out;
|
||||
|
||||
phase = FABS(phase + freq * fs);
|
||||
if (phase >= F(1.0))
|
||||
phase = FMOD(phase, F(1.0));
|
||||
}
|
||||
|
||||
s->phase[ch] = phase;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user