[FFmpeg-devel] [PATCH] avfilter: add square audio source filter

Nicolas George george at nsup.org
Sat Jul 27 17:07:20 EEST 2019


Paul B Mahol (12019-07-14):
> 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;

Only used locally, do not put it in the context.

>      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);

Ditto. There is really no need for a function pointer at all.

>  } 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;
> +    }
> +}

This looks like a needlessly complicated way of generating a square
wave. "sample = phi & 0x80000000 ? amplitude : -amplitude" should be
enough.

> +
>  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,
> +};

Missing conditional guards.

Regards,

-- 
  Nicolas George
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20190727/f0704f02/attachment.sig>


More information about the ffmpeg-devel mailing list