Hi, On 3/17/20, Marshall Murmu <marshallmax1...@gmail.com> wrote: > Fixing noteon/off logic > > --- > Changelog | 1 + > configure | 4 + > doc/filters.texi | 29 ++++++ > libavfilter/Makefile | 1 + > libavfilter/allfilters.c | 1 + > libavfilter/asrc_atone.c | 197 +++++++++++++++++++++++++++++++++++++++ > libavfilter/version.h | 2 +- > 7 files changed, 234 insertions(+), 1 deletion(-) > create mode 100644 libavfilter/asrc_atone.c > > diff --git a/Changelog b/Changelog > index d1572553a5..5ddd2484b0 100644 > --- a/Changelog > +++ b/Changelog > @@ -48,6 +48,7 @@ version <next>: > - AMQP 0-9-1 protocol (RabbitMQ) > - Vulkan support > - avgblur_vulkan, overlay_vulkan, scale_vulkan and chromaber_vulkan filters > +- atone filter > > > version 4.2: > diff --git a/configure b/configure > index 18f2841765..b083ac6453 100755 > --- a/configure > +++ b/configure > @@ -233,6 +233,7 @@ External library support: > and libraw1394 [no] > --enable-libfdk-aac enable AAC de/encoding via libfdk-aac [no] > --enable-libflite enable flite (voice synthesis) support via > libflite [no] > + --enable-libfluidsynth enable fluidsynth support via libfluidsynth [no] > --enable-libfontconfig enable libfontconfig, useful for drawtext filter > [no] > --enable-libfreetype enable libfreetype, needed for drawtext filter > [no] > --enable-libfribidi enable libfribidi, improves drawtext filter [no] > @@ -1770,6 +1771,7 @@ EXTERNAL_LIBRARY_LIST=" > libdc1394 > libdrm > libflite > + libfluidsynth > libfontconfig > libfreetype > libfribidi > @@ -3465,6 +3467,7 @@ asr_filter_deps="pocketsphinx" > ass_filter_deps="libass" > atempo_filter_deps="avcodec" > atempo_filter_select="rdft" > +atone_filter_deps="libfluidsynth" > avgblur_opencl_filter_deps="opencl" > avgblur_vulkan_filter_deps="vulkan libglslang" > azmq_filter_deps="libzmq" > @@ -6270,6 +6273,7 @@ enabled libfdk_aac && { check_pkg_config > libfdk_aac fdk-aac "fdk-aac/aace > warn "using libfdk without pkg-config"; } > } > flite_extralibs="-lflite_cmu_time_awb -lflite_cmu_us_awb -lflite_cmu_us_kal > -lflite_cmu_us_kal16 -lflite_cmu_us_rms -lflite_cmu_us_slt -lflite_usenglish > -lflite_cmulex -lflite" > enabled libflite && require libflite "flite/flite.h" flite_init > $flite_extralibs > +enabled libfluidsynth && require_pkg_config libfluidsynth fluidsynth > "fluidsynth.h" fluid_log > enabled fontconfig && enable libfontconfig > enabled libfontconfig && require_pkg_config libfontconfig fontconfig > "fontconfig/fontconfig.h" FcInit > enabled libfreetype && require_pkg_config libfreetype freetype2 > "ft2build.h FT_FREETYPE_H" FT_Init_FreeType > diff --git a/doc/filters.texi b/doc/filters.texi > index 328e984e92..918b1703f8 100644 > --- a/doc/filters.texi > +++ b/doc/filters.texi > @@ -5946,6 +5946,35 @@ anullsrc=r=48000:cl=mono > > All the parameters need to be explicitly defined. > > +@section atone > + > +Synthesize random notes using libfluidsynth library. > + > +To compile this filter you need to configure FFmpeg with > +@code{--enable-libfluidsynth}. > + > +The filter accepts the following options: > + > +@table @option > +@item sample_rate, r > +Set the sample rate of the synthesizer. Default value is 44100. > + > +@item nb_samples, n > +Set the number of samples per frame. Default value is 1024. > + > +@item duration, d > +Set the duration of sound generation. Default value is 10 sec. > + > +@item soundfont > +Enter the location of the soundfont. Without loading the soundfont > fluidsynth won't be able to synthesize. > + > +@item mchan > +Set the MIDI channel. Default value is 0. > + > +@item seed > +Set the seed value for the PRNG > +@end table > + > @section flite > > Synthesize a voice utterance using the libflite library. > diff --git a/libavfilter/Makefile b/libavfilter/Makefile > index 750412da6b..020c4553cb 100644 > --- a/libavfilter/Makefile > +++ b/libavfilter/Makefile > @@ -147,6 +147,7 @@ OBJS-$(CONFIG_AEVALSRC_FILTER) += aeval.o > OBJS-$(CONFIG_AFIRSRC_FILTER) += asrc_afirsrc.o > OBJS-$(CONFIG_ANOISESRC_FILTER) += asrc_anoisesrc.o > OBJS-$(CONFIG_ANULLSRC_FILTER) += asrc_anullsrc.o > +OBJS-$(CONFIG_ATONE_FILTER) += asrc_atone.o > OBJS-$(CONFIG_FLITE_FILTER) += asrc_flite.o > OBJS-$(CONFIG_HILBERT_FILTER) += asrc_hilbert.o > OBJS-$(CONFIG_SINC_FILTER) += asrc_sinc.o > diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c > index 501e5d041b..d167499cf1 100644 > --- a/libavfilter/allfilters.c > +++ b/libavfilter/allfilters.c > @@ -141,6 +141,7 @@ extern AVFilter ff_asrc_aevalsrc; > extern AVFilter ff_asrc_afirsrc; > extern AVFilter ff_asrc_anoisesrc; > extern AVFilter ff_asrc_anullsrc; > +extern AVFilter ff_asrc_atone; > extern AVFilter ff_asrc_flite; > extern AVFilter ff_asrc_hilbert; > extern AVFilter ff_asrc_sinc; > diff --git a/libavfilter/asrc_atone.c b/libavfilter/asrc_atone.c > new file mode 100644 > index 0000000000..e3bb7faa34 > --- /dev/null > +++ b/libavfilter/asrc_atone.c > @@ -0,0 +1,197 @@ > +/* > + * 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 > + */ > + > +#include <fluidsynth.h> > +#include "libavutil/avassert.h" > +#include "libavutil/opt.h" > +#include "libavutil/lfg.h" > +#include "libavutil/random_seed.h" > +#include "avfilter.h" > +#include "audio.h" > +#include "formats.h" > +#include "internal.h" > + > +typedef struct AToneContext { > + const AVClass *class; > + fluid_settings_t *settings; > + fluid_synth_t *synth; > + int soundfont_id; > + int nb_samples; > + int sample_rate; > + int mchan; > + char *soundfont; > + int64_t pts; > + int64_t duration; > + int64_t interval; > + int64_t seed; > + AVLFG c; > +} AToneContext; > + > +#define OFFSET(x) offsetof(AToneContext, x) > +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM > + > +static const AVOption atone_options[] = { > + {"sample_rate", "set sample rate", > OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, > INT_MAX, FLAGS}, > + {"r", "set sample rate", > OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, > INT_MAX, FLAGS}, > + {"nb_samples", "set number of samples per requested frame", > OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, > INT64_MAX, FLAGS}, > + {"n", "set number of samples per requested frame", > OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, > INT64_MAX, FLAGS}, > + {"duration", "set duration", > OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=10000000}, 0, > INT64_MAX, FLAGS}, > + {"d", "set duration", > OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=10000000}, 0, > INT64_MAX, FLAGS}, > + {"soundfont", "location of soundfont", > OFFSET(soundfont), AV_OPT_TYPE_STRING, {.str=NULL}, > FLAGS}, > + {"mchan", "set MIDI channel", > OFFSET(mchan), AV_OPT_TYPE_INT, {.i64=0}, 0, 15, > FLAGS}, > + {"seed", "set random seed", > OFFSET(seed), AV_OPT_TYPE_INT64, {.i64=-1}, -1, > INT64_MAX, FLAGS}, > + {"t", "set interval between notes", > OFFSET(interval), AV_OPT_TYPE_DURATION, {.i64=0}, 0, > INT64_MAX, FLAGS}, > + { NULL } > +}; > + > +AVFILTER_DEFINE_CLASS(atone); > + > +static av_cold int init(AVFilterContext *ctx) > +{ > + AToneContext *fluidsynth = ctx->priv; > + fluidsynth->soundfont_id = -1; > + fluidsynth->settings = new_fluid_settings(); > + if(!fluidsynth->settings) {
Still wrong style, space is missing between 'if' and '(' > + av_log(ctx, AV_LOG_ERROR, "Failed to create fluidsynth > settings\n"); > + return AVERROR_EXTERNAL; > + } > + fluidsynth->synth = new_fluid_synth(fluidsynth->settings); > + if(!fluidsynth->synth) { > + av_log(ctx, AV_LOG_ERROR, "Failed to create fluidsynth > synthesizer\n"); > + return AVERROR_EXTERNAL; > + } > + fluidsynth->soundfont_id = fluid_synth_sfload(fluidsynth->synth, > fluidsynth->soundfont, 1); > + if(fluidsynth->soundfont_id < 0) { > + av_log(ctx, AV_LOG_ERROR, "Failed to load soundfont\n"); > + return AVERROR_EXTERNAL; > + } > + > + return 0; > +} > + > +static av_cold void uninit(AVFilterContext *ctx) > +{ > + AToneContext *fluidsynth = ctx->priv; > + delete_fluid_synth(fluidsynth->synth); > + delete_fluid_settings(fluidsynth->settings); > +} > + > +static int query_formats(AVFilterContext *ctx) > +{ > + AToneContext *fluidsynth = ctx->priv; > + AVFilterChannelLayouts *chanlayout = NULL; > + int64_t chanlayouts = > av_get_default_channel_layout(2*fluid_synth_count_audio_channels(fluidsynth->synth)); > + AVFilterFormats *formats = NULL; > + AVFilterFormats *sample_rate = NULL; > + int ret; > + > + if ((ret = ff_add_format (&formats , > AV_SAMPLE_FMT_FLT )) < 0 || > + (ret = ff_set_common_formats (ctx , formats > )) < 0 || > + (ret = ff_add_channel_layout (&chanlayout , chanlayouts > )) < 0 || > + (ret = ff_set_common_channel_layouts (ctx , chanlayout > )) < 0 || > + (ret = ff_add_format (&sample_rate, > fluidsynth->sample_rate)) < 0 || > + (ret = ff_set_common_samplerates (ctx , sample_rate > )) < 0) > + return ret; > + return 0; > +} > + > +static int config_output(AVFilterLink *outlink) > +{ > + AVFilterContext *ctx = outlink->src; > + AToneContext *fluidsynth = ctx->priv; > + > + if(fluidsynth->seed == -1) > + fluidsynth->seed = av_get_random_seed(); > + av_lfg_init(&fluidsynth->c, fluidsynth->seed); > + > + outlink->sample_rate = fluidsynth->sample_rate; > + fluidsynth->duration = av_rescale(fluidsynth->duration, > fluidsynth->sample_rate, AV_TIME_BASE); > + fluidsynth->interval = av_rescale(fluidsynth->interval, > fluidsynth->sample_rate, AV_TIME_BASE); > + return 0; > +} > + > +static int request_frame(AVFilterLink *outlink) > +{ > + AVFrame *frame; > + AToneContext *fluidsynth = outlink->src->priv; > + int nb_samples, key; > + int64_t off; > + > + if (fluidsynth->duration) { > + nb_samples = FFMIN(fluidsynth->nb_samples, fluidsynth->duration - > fluidsynth->pts); > + av_assert1(nb_samples >= 0); > + if (!nb_samples) > + return AVERROR_EOF; > + } > + > + if(!(frame = ff_get_audio_buffer(outlink, nb_samples))) > + return AVERROR(ENOMEM); > + > + key = av_lfg_get(&fluidsynth->c) % 128 ; > + if(fluidsynth->interval <= nb_samples) { > + fluid_synth_noteon(fluidsynth->synth, fluidsynth->mchan, key, 100); > + fluid_synth_write_float(fluidsynth->synth, nb_samples, > frame->data[0], 0, 2, frame->data[0], 1, 2); > + } > + if(nb_samples < fluidsynth->interval) { > + if(fluidsynth->interval % nb_samples == 0) { > + if(fluidsynth->pts % fluidsynth->interval == 0) { > + fluid_synth_noteon(fluidsynth->synth, fluidsynth->mchan, > key, 100); > + fluid_synth_write_float(fluidsynth->synth, nb_samples, > frame->data[0], 0, 2, frame->data[0], 1, 2); > + } else > + fluid_synth_write_float(fluidsynth->synth, nb_samples, > frame->data[0], 0, 2, frame->data[0], 1, 2); > + } else { > + if(fluidsynth->pts % fluidsynth->interval == 0) { > + fluid_synth_noteon(fluidsynth->synth, fluidsynth->mchan, > key, 100); > + fluid_synth_write_float(fluidsynth->synth, nb_samples, > frame->data[0], 0, 2, frame->data[0], 1, 2); > + } > + off = fluidsynth->interval - (fluidsynth->pts % > fluidsynth->interval); > + if(off < nb_samples) { > + fluid_synth_write_float(fluidsynth->synth, off, > frame->data[0], 0, 2, frame->data[0], 1, 2); > + fluid_synth_noteon(fluidsynth->synth, fluidsynth->mchan, > key, 100); > + fluid_synth_write_float(fluidsynth->synth, nb_samples-off, > frame->data[0], off*2, 2, frame->data[0], (off*2)+1, 2); > + } else > + fluid_synth_write_float(fluidsynth->synth, nb_samples, > frame->data[0], 0, 2, frame->data[0], 1, 2); > + } > + } > + I believe this is very fragile and non maintainable piece of code with too much complexity. This can be significantly simplified. > + frame->pts = fluidsynth->pts; > + fluidsynth->pts += nb_samples; > + return ff_filter_frame(outlink, frame); > +} > + > +static const AVFilterPad atone_outputs[] = { > + { > + .name = "default", > + .type = AVMEDIA_TYPE_AUDIO, > + .request_frame = request_frame, > + .config_props = config_output, > + }, > + { NULL } > +}; > + > +AVFilter ff_asrc_atone = { > + .name = "atone", > + .description = NULL_IF_CONFIG_SMALL("Synthesize tones using > libfluidsynth."), > + .query_formats = query_formats, > + .init = init, > + .uninit = uninit, > + .priv_size = sizeof(AToneContext), > + .inputs = NULL, > + .outputs = atone_outputs, > + .priv_class = &atone_class, > +}; > \ No newline at end of file > diff --git a/libavfilter/version.h b/libavfilter/version.h > index 7b41018be7..4c4e8afe2d 100644 > --- a/libavfilter/version.h > +++ b/libavfilter/version.h > @@ -30,7 +30,7 @@ > #include "libavutil/version.h" > > #define LIBAVFILTER_VERSION_MAJOR 7 > -#define LIBAVFILTER_VERSION_MINOR 77 > +#define LIBAVFILTER_VERSION_MINOR 78 > #define LIBAVFILTER_VERSION_MICRO 100 > > > -- > 2.25.0 > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".