Paul B Mahol (12019-07-14): > Signed-off-by: Paul B Mahol <[email protected]> > --- > 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 > > +@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: > + > +@table @option > +@item amplitude, a > +Set the carrier amplitude, Default is 0.2. > + > +@item frequency, f > +Set the carrier frequency. Default is 440 Hz. > + > +@item sample_rate, r > +Specify the sample rate, default is 44100. > + > +@item duration, d > +Specify the duration of the generated audio stream. > + > +@item samples_per_frame > +Set the number of samples per output frame. > + > +The expression can contain the following constants: > + > +@table @option > +@item n > +The (sequential) number of the output audio frame, starting from 0. > + > +@item pts > +The PTS (Presentation TimeStamp) of the output audio frame, > +expressed in @var{TB} units. > + > +@item t > +The PTS of the output audio frame, expressed in seconds. > + > +@item TB > +The timebase of the output audio frames. > +@end table > + > +Default is @code{1024}. > +@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
signature.asc
Description: PGP signature
_______________________________________________ ffmpeg-devel mailing list [email protected] https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email [email protected] with subject "unsubscribe".
