[FFmpeg-devel] [PATCH] avfilter: add square audio source filter
Paul B Mahol
onemda at gmail.com
Sun Jul 14 13:26:09 EEST 2019
Signed-off-by: Paul B Mahol <onemda at gmail.com>
---
doc/filters.texi | 44 ++++++++++++++++++++
libavfilter/Makefile | 1 +
libavfilter/allfilters.c | 1 +
libavfilter/asrc_sine.c | 86 ++++++++++++++++++++++++++++++++++------
4 files changed, 119 insertions(+), 13 deletions(-)
diff --git a/doc/filters.texi b/doc/filters.texi
index 3108ad349e..b94eddefe5 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -5895,6 +5895,50 @@ sine=1000:samples_per_frame='st(0,mod(n,5)); 1602-not(not(eq(ld(0),1)+eq(ld(0),3
@end example
@end itemize
+ at section square
+
+Generate an audio signal made of a square wave with custom amplitude.
+
+The audio signal is bit-exact.
+
+The filter accepts the following options:
+
+ at table @option
+ at item amplitude, a
+Set the carrier amplitude, Default is 0.2.
+
+ at item frequency, f
+Set the carrier frequency. Default is 440 Hz.
+
+ at item sample_rate, r
+Specify the sample rate, default is 44100.
+
+ at item duration, d
+Specify the duration of the generated audio stream.
+
+ at item samples_per_frame
+Set the number of samples per output frame.
+
+The expression can contain the following constants:
+
+ at table @option
+ at item n
+The (sequential) number of the output audio frame, starting from 0.
+
+ at item pts
+The PTS (Presentation TimeStamp) of the output audio frame,
+expressed in @var{TB} units.
+
+ at item t
+The PTS of the output audio frame, expressed in seconds.
+
+ at item TB
+The timebase of the output audio frames.
+ at end table
+
+Default is @code{1024}.
+ at end table
+
@c man end AUDIO SOURCES
@chapter Audio Sinks
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 455c809b15..b958450a80 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -148,6 +148,7 @@ OBJS-$(CONFIG_FLITE_FILTER) += asrc_flite.o
OBJS-$(CONFIG_HILBERT_FILTER) += asrc_hilbert.o
OBJS-$(CONFIG_SINC_FILTER) += asrc_sinc.o
OBJS-$(CONFIG_SINE_FILTER) += asrc_sine.o
+OBJS-$(CONFIG_SQUARE_FILTER) += asrc_sine.o
OBJS-$(CONFIG_ANULLSINK_FILTER) += asink_anullsink.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 04a3df7d56..510e0d65dd 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -140,6 +140,7 @@ extern AVFilter ff_asrc_flite;
extern AVFilter ff_asrc_hilbert;
extern AVFilter ff_asrc_sinc;
extern AVFilter ff_asrc_sine;
+extern AVFilter ff_asrc_square;
extern AVFilter ff_asink_anullsink;
diff --git a/libavfilter/asrc_sine.c b/libavfilter/asrc_sine.c
index 3a87210b4b..e3153f03e4 100644
--- a/libavfilter/asrc_sine.c
+++ b/libavfilter/asrc_sine.c
@@ -30,6 +30,7 @@
typedef struct SineContext {
const AVClass *class;
+ double amplitude;
double frequency;
double beep_factor;
char *samples_per_frame;
@@ -38,6 +39,7 @@ typedef struct SineContext {
int64_t duration;
int16_t *sin;
int64_t pts;
+ int square_amplitude;
uint32_t phi; ///< current phase of the sine (2pi = 1<<32)
uint32_t dphi; ///< phase increment between two samples
unsigned beep_period;
@@ -45,6 +47,8 @@ typedef struct SineContext {
unsigned beep_length;
uint32_t phi_beep; ///< current phase of the beep
uint32_t dphi_beep; ///< phase increment of the beep
+
+ void (*generate)(struct SineContext *sine, AVFrame *frame);
} SineContext;
#define CONTEXT SineContext
@@ -141,11 +145,51 @@ enum {
VAR_VARS_NB
};
+static void generate_sine(SineContext *sine, AVFrame *frame)
+{
+ int16_t *samples = (int16_t *)frame->data[0];
+
+ for (int i = 0; i < frame->nb_samples; i++) {
+ samples[i] = sine->sin[sine->phi >> (32 - LOG_PERIOD)];
+ sine->phi += sine->dphi;
+ if (sine->beep_index < sine->beep_length) {
+ samples[i] += sine->sin[sine->phi_beep >> (32 - LOG_PERIOD)] << 1;
+ sine->phi_beep += sine->dphi_beep;
+ }
+ if (++sine->beep_index == sine->beep_period)
+ sine->beep_index = 0;
+ }
+}
+
+static void generate_square(SineContext *sine, AVFrame *frame)
+{
+ int16_t *samples = (int16_t *)frame->data[0];
+
+ for (int i = 0; i < frame->nb_samples; i++) {
+ int16_t sample = sine->sin[sine->phi >> (32 - LOG_PERIOD)];
+
+ if (sample >= 0)
+ sample = sine->square_amplitude;
+ else
+ sample = -sine->square_amplitude;
+
+ samples[i] = sample;
+ sine->phi += sine->dphi;
+ }
+}
+
static av_cold int init(AVFilterContext *ctx)
{
int ret;
SineContext *sine = ctx->priv;
+ if (!strcmp(ctx->filter->name, "square")) {
+ sine->square_amplitude = -sine->amplitude * INT16_MIN;
+ sine->generate = generate_square;
+ } else {
+ sine->generate = generate_sine;
+ }
+
if (!(sine->sin = av_malloc(sizeof(*sine->sin) << LOG_PERIOD)))
return AVERROR(ENOMEM);
sine->dphi = ldexp(sine->frequency, 32) / sine->sample_rate + 0.5;
@@ -224,8 +268,7 @@ static int request_frame(AVFilterLink *outlink)
[VAR_T] = sine->pts * av_q2d(outlink->time_base),
[VAR_TB] = av_q2d(outlink->time_base),
};
- int i, nb_samples = lrint(av_expr_eval(sine->samples_per_frame_expr, values, sine));
- int16_t *samples;
+ int nb_samples = lrint(av_expr_eval(sine->samples_per_frame_expr, values, sine));
if (nb_samples <= 0) {
av_log(sine, AV_LOG_WARNING, "nb samples expression evaluated to %d, "
@@ -241,18 +284,8 @@ static int request_frame(AVFilterLink *outlink)
}
if (!(frame = ff_get_audio_buffer(outlink, nb_samples)))
return AVERROR(ENOMEM);
- samples = (int16_t *)frame->data[0];
- for (i = 0; i < nb_samples; i++) {
- samples[i] = sine->sin[sine->phi >> (32 - LOG_PERIOD)];
- sine->phi += sine->dphi;
- if (sine->beep_index < sine->beep_length) {
- samples[i] += sine->sin[sine->phi_beep >> (32 - LOG_PERIOD)] << 1;
- sine->phi_beep += sine->dphi_beep;
- }
- if (++sine->beep_index == sine->beep_period)
- sine->beep_index = 0;
- }
+ sine->generate(sine, frame);
frame->pts = sine->pts;
sine->pts += nb_samples;
@@ -280,3 +313,30 @@ AVFilter ff_asrc_sine = {
.outputs = sine_outputs,
.priv_class = &sine_class,
};
+
+static const AVOption square_options[] = {
+ OPT_DBL("amplitude", amplitude, 0.2, 0, 1, "set the square amplitude",),
+ OPT_DBL("a", amplitude, 0.2, 0, 1, "set the square amplitude",),
+ OPT_DBL("frequency", frequency, 440, 0, DBL_MAX, "set the square frequency",),
+ OPT_DBL("f", frequency, 440, 0, DBL_MAX, "set the square frequency",),
+ OPT_INT("sample_rate", sample_rate, 44100, 1, INT_MAX, "set the sample rate",),
+ OPT_INT("r", sample_rate, 44100, 1, INT_MAX, "set the sample rate",),
+ OPT_DUR("duration", duration, 0, 0, INT64_MAX, "set the audio duration",),
+ OPT_DUR("d", duration, 0, 0, INT64_MAX, "set the audio duration",),
+ OPT_STR("samples_per_frame", samples_per_frame, "1024", 0, 0, "set the number of samples per frame",),
+ {NULL}
+};
+
+AVFILTER_DEFINE_CLASS(square);
+
+AVFilter ff_asrc_square = {
+ .name = "square",
+ .description = NULL_IF_CONFIG_SMALL("Generate square wave audio signal."),
+ .query_formats = query_formats,
+ .init = init,
+ .uninit = uninit,
+ .priv_size = sizeof(SineContext),
+ .inputs = NULL,
+ .outputs = sine_outputs,
+ .priv_class = &square_class,
+};
--
2.17.1
More information about the ffmpeg-devel
mailing list