Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH] WIP: avfilter: add Bungee audio stretch filter (PR #20697)
@ 2025-10-13  8:16 kupix via ffmpeg-devel
  2025-10-13  8:26 ` [FFmpeg-devel] " Nicolas George via ffmpeg-devel
  0 siblings, 1 reply; 4+ messages in thread
From: kupix via ffmpeg-devel @ 2025-10-13  8:16 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: kupix

PR #20697 opened by kupix
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20697
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20697.patch

This adds an audio filter using the [Bungee](https://github.com/bungee-audio-stretch/bungee) open source audio timescale manipulation library. It also adds support for the proprietary "Bungee Pro" variant.


>From 135787f1a1b3ab51b3b5d9f290ac4575891848f8 Mon Sep 17 00:00:00 2001
From: John Funnell <john@parabolaresearch.com>
Date: Sun, 23 Feb 2025 20:46:22 +0000
Subject: [PATCH 1/4] avfilter: add Bungee wrapper

---
 Changelog                  |   1 +
 configure                  |   8 ++
 doc/filters.texi           |  24 ++++
 libavfilter/Makefile       |   2 +
 libavfilter/af_bungee.c    |  26 ++++
 libavfilter/af_bungeepro.c |  26 ++++
 libavfilter/allfilters.c   |   2 +
 libavfilter/bungee.h       | 280 +++++++++++++++++++++++++++++++++++++
 8 files changed, 369 insertions(+)
 create mode 100644 libavfilter/af_bungee.c
 create mode 100644 libavfilter/af_bungeepro.c
 create mode 100644 libavfilter/bungee.h

diff --git a/Changelog b/Changelog
index 6fd95c9136..9986e89452 100644
--- a/Changelog
+++ b/Changelog
@@ -45,6 +45,7 @@ version 8.0:
 - ffprobe -codec option
 - HDR10+ metadata passthrough when decoding/encoding with libaom-av1
 
+- Bungee audio stretch and pitch shift filter
 
 version 7.1:
 - Raw Captions with Time (RCWT) closed caption demuxer
diff --git a/configure b/configure
index 7828381b5d..897b3e8d23 100755
--- a/configure
+++ b/configure
@@ -220,6 +220,8 @@ External library support:
                            needed for subtitles and ass filter [no]
   --enable-libbluray       enable BluRay reading using libbluray [no]
   --enable-libbs2b         enable bs2b DSP library [no]
+  --enable-libbungee       enable enable Bungee audio stretch [no]
+  --enable-libbungeepro    enable enable Bungee Pro audio stretch [no]
   --enable-libcaca         enable textual display using libcaca [no]
   --enable-libcelt         enable CELT decoding via libcelt [no]
   --enable-libcdio         enable audio CD grabbing with libcdio [no]
@@ -1962,6 +1964,8 @@ EXTERNAL_LIBRARY_LIST="
     libass
     libbluray
     libbs2b
+    libbungee
+    libbungeepro
     libcaca
     libcelt
     libcodec2
@@ -3978,6 +3982,8 @@ blend_vulkan_filter_deps="vulkan spirv_compiler"
 boxblur_filter_deps="gpl"
 boxblur_opencl_filter_deps="opencl gpl"
 bs2b_filter_deps="libbs2b"
+bungee_filter_deps="libbungee"
+bungeepro_filter_deps="libbungeepro"
 bwdif_cuda_filter_deps="ffnvcodec"
 bwdif_cuda_filter_deps_any="cuda_nvcc cuda_llvm"
 bwdif_vulkan_filter_deps="vulkan spirv_compiler"
@@ -7107,6 +7113,8 @@ enabled libiec61883       && require libiec61883 libiec61883/iec61883.h iec61883
 enabled libass            && require_pkg_config libass "libass >= 0.11.0" ass/ass.h ass_library_init
 enabled libbluray         && require_pkg_config libbluray libbluray libbluray/bluray.h bd_open
 enabled libbs2b           && require_pkg_config libbs2b libbs2b bs2b.h bs2b_open
+enabled libbungee         && require_pkg_config libbungee "libbungee >= 0.0.0" bungee/Bungee.h getFunctionsBungeeBasic
+enabled libbungeepro      && require_pkg_config libbungeepro "libbungeepro >= 0.0.0" bungee/Bungee.h getFunctionsBungeePro
 enabled libcelt           && require libcelt celt/celt.h celt_decode -lcelt0 &&
                              { check_lib libcelt celt/celt.h celt_decoder_create_custom -lcelt0 ||
                                die "ERROR: libcelt must be installed and version must be >= 0.11.0."; }
diff --git a/doc/filters.texi b/doc/filters.texi
index 5863041d1a..69afa5fc29 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -4292,6 +4292,30 @@ Feed level (in Hz).
 
 @end table
 
+@section bungee
+
+Stretch audio timescale and/or modify pitch using Bungee Basic.
+
+This filter accepts the following parameters:
+@table @option
+@item speed
+Controls the speed or tempo of the output audio. The default value 1 will not change speed.
+@item pitch
+Sets a pitch adjustment as a frequency multiplier. The default value 1 will have no effect on pitch.
+@end table
+
+
+To enable compilation of this filter, you need to configure FFmpeg with
+@code{--enable-libbungee}.
+
+@section bungeepro
+
+Stretch audio timescale and/or modify pitch using Bungee Pro. This filter accepts 
+the same options as @ref{bungee}.
+
+To enable compilation of this filter, you need to configure FFmpeg with
+@code{--enable-libbungeepron }.
+
 @section channelmap
 
 Remap input channels to new locations.
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 1f5de29ba2..d02dbe841e 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -126,6 +126,8 @@ OBJS-$(CONFIG_BANDREJECT_FILTER)             += af_biquads.o
 OBJS-$(CONFIG_BASS_FILTER)                   += af_biquads.o
 OBJS-$(CONFIG_BIQUAD_FILTER)                 += af_biquads.o
 OBJS-$(CONFIG_BS2B_FILTER)                   += af_bs2b.o
+OBJS-$(CONFIG_BUNGEE_FILTER)                 += af_bungee.o
+OBJS-$(CONFIG_BUNGEEPRO_FILTER)              += af_bungeepro.o
 OBJS-$(CONFIG_CHANNELMAP_FILTER)             += af_channelmap.o
 OBJS-$(CONFIG_CHANNELSPLIT_FILTER)           += af_channelsplit.o
 OBJS-$(CONFIG_CHORUS_FILTER)                 += af_chorus.o generate_wave_table.o
diff --git a/libavfilter/af_bungee.c b/libavfilter/af_bungee.c
new file mode 100644
index 0000000000..cfcb1c3e58
--- /dev/null
+++ b/libavfilter/af_bungee.c
@@ -0,0 +1,26 @@
+/*
+ * 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
+ */
+
+#define BUNGEE bungee
+#define BUNGEE_CLASS bungee_class
+#define BUNGEE_AF ff_af_bungee
+#define BUNGEE_name "bungee"
+#define BUNGEE_Name "Bungee"
+#define BUNGEE_GET_FUNCTIONS getFunctionsBungeeBasic
+
+#include "bungee.h"
diff --git a/libavfilter/af_bungeepro.c b/libavfilter/af_bungeepro.c
new file mode 100644
index 0000000000..f625e64481
--- /dev/null
+++ b/libavfilter/af_bungeepro.c
@@ -0,0 +1,26 @@
+/*
+ * 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
+ */
+
+#define BUNGEE bungeepro
+#define BUNGEE_CLASS bungeepro_class
+#define BUNGEE_AF ff_af_bungeepro
+#define BUNGEE_name "bungeepro"
+#define BUNGEE_Name "Bungee Pro"
+#define BUNGEE_GET_FUNCTIONS getFunctionsBungeePro
+
+#include "bungee.h"
\ No newline at end of file
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 84f15f85c5..90409e814d 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -112,6 +112,8 @@ extern const FFFilter ff_af_bandreject;
 extern const FFFilter ff_af_bass;
 extern const FFFilter ff_af_biquad;
 extern const FFFilter ff_af_bs2b;
+extern const FFFilter ff_af_bungee;
+extern const FFFilter ff_af_bungeepro;
 extern const FFFilter ff_af_channelmap;
 extern const FFFilter ff_af_channelsplit;
 extern const FFFilter ff_af_chorus;
diff --git a/libavfilter/bungee.h b/libavfilter/bungee.h
new file mode 100644
index 0000000000..9fad792421
--- /dev/null
+++ b/libavfilter/bungee.h
@@ -0,0 +1,280 @@
+/*
+ * 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 "bungee/Bungee.h"
+
+#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/common.h"
+#include "libavutil/mem.h"
+#include "libavutil/opt.h"
+
+#include "audio.h"
+#include "avfilter.h"
+#include "filters.h"
+
+typedef struct BungeeContext
+{
+    const AVClass *class;
+
+    const struct Functions *functions;
+
+    void *stretcher;
+    int debug;
+
+    struct SampleRates sampleRates;
+    int channelCount;
+
+    float *inputBuffer;
+    int inputBufferSampleCount;
+
+    int64_t inputBufferBeginPosition;
+    int64_t inputBufferEndPosition;
+    int64_t inputStartPosition;
+    int64_t inputFinishPosition;
+
+    int64_t ptsOriginPosition;
+
+    struct Request request;
+    struct InputChunk inputChunk;
+
+    int64_t start_pts;
+    int64_t last_pts;
+
+    int64_t outputSampleCount;
+    int eof; // end of input
+} BungeeContext;
+
+static int samplesNeeded(const BungeeContext *s)
+{
+    return s->inputChunk.end - s->inputBufferEndPosition;
+}
+
+static void appendToInputBuffer(BungeeContext *s, const AVFrame *in)
+{
+    int moveOffset = s->inputBufferBeginPosition - s->inputChunk.begin;
+    int moveCount = s->inputBufferEndPosition - s->inputChunk.begin;
+
+    av_assert1(!in || in->nb_samples <= samplesNeeded(s));
+
+    if (moveCount < 0)
+        moveCount = 0;
+
+    for (int c = 0; c < s->channelCount; ++c)
+        memmove(
+            &s->inputBuffer[c * s->inputBufferSampleCount],
+            &s->inputBuffer[c * s->inputBufferSampleCount - moveOffset],
+            moveCount * sizeof(float));
+
+    s->inputBufferBeginPosition = s->inputChunk.begin;
+
+    if (in) {
+        const float *const *source = (const float *const *)in->extended_data;
+
+        for (int c = 0; c < s->channelCount; ++c)
+            memcpy(
+                &s->inputBuffer[moveCount + c * s->inputBufferSampleCount],
+                source[c],
+                in->nb_samples * sizeof(float));
+
+        s->inputBufferEndPosition += in->nb_samples;
+    }
+}
+
+#define BUNGEE_OPTIONS BUNGEE##_options
+
+static const AVOption BUNGEE_OPTIONS[] = {
+    {"speed", "set speed as a tempo multiplier", offsetof(BungeeContext, request.speed), AV_OPT_TYPE_DOUBLE, {.dbl = 1}, 0.01, 100, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_RUNTIME_PARAM},
+    {"pitch", "set pitch as a frequency multiplier", offsetof(BungeeContext, request.pitch), AV_OPT_TYPE_DOUBLE, {.dbl = 1}, 0.25, 2, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_RUNTIME_PARAM},
+    {"debug", "verbose debug checks", offsetof(BungeeContext, debug), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_AUDIO_PARAM},
+    {NULL},
+};
+
+AVFILTER_DEFINE_CLASS(BUNGEE);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+    BungeeContext *s = ctx->priv;
+    s->functions = BUNGEE_GET_FUNCTIONS();
+    if (!s->functions)
+    {
+        av_log(ctx, AV_LOG_ERROR, "No functions found for " BUNGEE_Name "\n");
+        return AVERROR_INVALIDDATA;
+    }
+    s->stretcher = NULL;
+    return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+    BungeeContext *s = ctx->priv;
+    if (s->stretcher)
+        s->functions->destroy(s->stretcher);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+    AVFilterContext *ctx = inlink->dst;
+    BungeeContext *s = ctx->priv;
+    s->sampleRates.input = inlink->sample_rate;
+    s->sampleRates.output = inlink->sample_rate;
+    s->channelCount = inlink->ch_layout.nb_channels;
+
+    if (s->stretcher)
+        s->functions->destroy(s->stretcher);
+    s->stretcher = NULL;
+
+    s->stretcher = s->functions->create(s->sampleRates, s->channelCount, 0);
+    s->functions->enableInstrumentation(s->stretcher, s->debug);
+
+    s->request.position = 0;
+    s->functions->next(s->stretcher, &s->request);
+    s->request.reset = 1;
+    s->inputChunk = s->functions->specifyGrain(s->stretcher, &s->request, 0.);
+
+    s->inputBufferSampleCount = s->inputChunk.end - s->inputChunk.begin;
+    s->inputStartPosition = s->inputBufferSampleCount / 2;
+    s->inputBufferBeginPosition = s->inputStartPosition - s->inputBufferSampleCount;
+    s->inputBufferEndPosition = s->inputStartPosition;
+
+    s->inputBuffer = av_calloc(s->inputBufferSampleCount * s->channelCount, sizeof(float));
+    if (!s->inputBuffer)
+        return AVERROR(ENOMEM);
+
+    s->outputSampleCount = 0;
+
+    s->ptsOriginPosition = AV_NOPTS_VALUE;
+    s->eof = 0;
+
+    return 0;
+}
+
+static int activate(AVFilterContext *ctx)
+{
+    AVFilterLink *inlink = ctx->inputs[0];
+    AVFilterLink *outlink = ctx->outputs[0];
+    BungeeContext *s = ctx->priv;
+    struct OutputChunk outputChunk;
+    int64_t pts;
+    int status, ret = 0, endOfOutput = 0;
+
+    FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
+
+    if (!s->eof)
+    {
+        AVFrame *in;
+        ret = ff_inlink_consume_samples(inlink, 1, samplesNeeded(s), &in);
+
+        if (ff_inlink_acknowledge_status(inlink, &status, &pts))
+            s->eof = status == AVERROR_EOF;
+
+        if (in)
+        {
+            if (s->start_pts == AV_NOPTS_VALUE)
+                s->start_pts = av_rescale_q(in->pts, inlink->time_base, outlink->time_base);
+
+            appendToInputBuffer(s, in);
+            av_frame_free(&in);
+        }
+
+        if (s->eof)
+            s->inputFinishPosition = s->inputBufferEndPosition;
+    }
+    else
+        appendToInputBuffer(s, NULL);
+
+    av_assert1(s->inputBufferEndPosition == s->inputChunk.end);
+
+    if (samplesNeeded(s) == 0 || s->eof)
+    {
+        s->functions->next(s->stretcher, &s->request);
+        s->functions->analyseGrain(s->stretcher, s->inputBuffer, s->inputBufferSampleCount, 0, samplesNeeded(s));
+        s->functions->synthesiseGrain(s->stretcher, &outputChunk);
+        s->inputChunk = s->functions->specifyGrain(s->stretcher, &s->request, 0);
+
+        endOfOutput = s->eof && outputChunk.request[1]->position >= s->inputFinishPosition;
+
+        if (outputChunk.request[0]->position >= s->inputStartPosition)
+        {
+            AVRational outputTimebase = {1, s->sampleRates.output};
+            AVFrame *out = ff_get_audio_buffer(outlink, outputChunk.frameCount);
+            float *const *p = (float *const *)out->extended_data;
+
+            if (!out)
+                return AVERROR(ENOMEM);
+
+            if (endOfOutput)
+            {
+                const double fraction = (s->inputFinishPosition - outputChunk.request[0]->position) / (outputChunk.request[1]->position - outputChunk.request[0]->position);
+                int frameCount = round(outputChunk.frameCount * fraction);
+                if (frameCount < 0)
+                    frameCount = 0;
+                if (frameCount > outputChunk.frameCount)
+                    frameCount = outputChunk.frameCount;
+                outputChunk.frameCount = frameCount;
+            }
+
+            for (int c = 0; c < s->channelCount; ++c)
+                memcpy(p[c], &outputChunk.data[c * outputChunk.channelStride], sizeof(float) * outputChunk.frameCount);
+
+            out->pts = s->start_pts + av_rescale_q(s->outputSampleCount, outputTimebase, outlink->time_base);
+            s->last_pts = out->pts;
+
+            out->nb_samples = outputChunk.frameCount;
+            s->outputSampleCount += outputChunk.frameCount;
+
+            ret = ff_filter_frame(outlink, out);
+            if (ret < 0)
+                return ret;
+        }
+    }
+
+    if (ff_inlink_queued_samples(inlink) >= samplesNeeded(s))
+        ff_filter_set_ready(ctx, 100);
+
+    if (endOfOutput)
+    {
+        ff_outlink_set_status(outlink, AVERROR_EOF, s->last_pts);
+        return 0;
+    }
+
+    FF_FILTER_FORWARD_WANTED(outlink, inlink);
+
+    return FFERROR_NOT_READY;
+}
+
+static const AVFilterPad bungee_inputs[] = {
+    {
+        .name = "default",
+        .type = AVMEDIA_TYPE_AUDIO,
+        .config_props = config_input,
+    },
+};
+
+const FFFilter BUNGEE_AF = {
+    .p.name = BUNGEE_name,
+    .p.description = NULL_IF_CONFIG_SMALL("Adjust audio speed and pitch using " BUNGEE_Name "."),
+    .p.priv_class = &BUNGEE_CLASS,
+    .priv_size = sizeof(BungeeContext),
+    .init = init,
+    .uninit = uninit,
+    .activate = activate,
+    FILTER_INPUTS(bungee_inputs),
+    FILTER_OUTPUTS(ff_audio_default_filterpad),
+    FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP),
+};
-- 
2.49.1


>From ac8a018d6b17a6a9965d272684e4ff3a5fcd9029 Mon Sep 17 00:00:00 2001
From: John Funnell <john@parabolaresearch.com>
Date: Sun, 12 Oct 2025 11:35:13 +0100
Subject: [PATCH 2/4] use semitones for pitch parameters; add resample
 parameter

---
 libavfilter/bungee.h | 36 +++++++++++++++++++++++++++++++++---
 1 file changed, 33 insertions(+), 3 deletions(-)

diff --git a/libavfilter/bungee.h b/libavfilter/bungee.h
index 9fad792421..e4cc105de7 100644
--- a/libavfilter/bungee.h
+++ b/libavfilter/bungee.h
@@ -50,6 +50,8 @@ typedef struct BungeeContext
 
     int64_t ptsOriginPosition;
 
+    double semitones;
+
     struct Request request;
     struct InputChunk inputChunk;
 
@@ -98,10 +100,35 @@ static void appendToInputBuffer(BungeeContext *s, const AVFrame *in)
 
 #define BUNGEE_OPTIONS BUNGEE##_options
 
+
+enum BungeeModeCounts {
+
+#define X_BEGIN(Type, type) count##Type = 0
+#define X_ITEM(Type, type, mode, description) + 1
+#define X_END(Type, type) ,
+BUNGEE_MODES
+#undef X_BEGIN
+#undef X_ITEM
+#undef X_END
+
+};
+
+
+static const int flags = AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_RUNTIME_PARAM;
+
 static const AVOption BUNGEE_OPTIONS[] = {
-    {"speed", "set speed as a tempo multiplier", offsetof(BungeeContext, request.speed), AV_OPT_TYPE_DOUBLE, {.dbl = 1}, 0.01, 100, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_RUNTIME_PARAM},
-    {"pitch", "set pitch as a frequency multiplier", offsetof(BungeeContext, request.pitch), AV_OPT_TYPE_DOUBLE, {.dbl = 1}, 0.25, 2, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_RUNTIME_PARAM},
-    {"debug", "verbose debug checks", offsetof(BungeeContext, debug), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_AUDIO_PARAM},
+    {"speed", "set speed as a tempo multiplier", offsetof(BungeeContext, request.speed), AV_OPT_TYPE_DOUBLE, {.dbl = 1}, 0.01, 100, flags},
+    {"pitch", "set pitch as a semitone offset", offsetof(BungeeContext, semitones), AV_OPT_TYPE_DOUBLE, {.dbl = 0}, -24, 24, flags},
+    {"debug", "verbose debug checks", offsetof(BungeeContext, debug), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 0, AV_OPT_FLAG_AUDIO_PARAM},
+
+#define X_BEGIN(Type, type) { #type, "set " #type " mode", offsetof(BungeeContext, request.type##Mode), AV_OPT_TYPE_INT, {.i64=0}, 0, count##Type - 1, flags, .unit = #type },
+#define X_ITEM(Type, type, mode, description) {#mode, description, 0, AV_OPT_TYPE_CONST,  {.i64=type##Mode_##mode}, 0, 0, flags, .unit = #type },
+#define X_END(Type, type)
+BUNGEE_MODES
+#undef X_BEGIN
+#undef X_ITEM
+#undef X_END
+
     {NULL},
 };
 
@@ -143,6 +170,7 @@ static int config_input(AVFilterLink *inlink)
     s->functions->enableInstrumentation(s->stretcher, s->debug);
 
     s->request.position = 0;
+    s->request.pitch = pow(2., s->semitones * (1. / 12));
     s->functions->next(s->stretcher, &s->request);
     s->request.reset = 1;
     s->inputChunk = s->functions->specifyGrain(s->stretcher, &s->request, 0.);
@@ -202,6 +230,8 @@ static int activate(AVFilterContext *ctx)
 
     if (samplesNeeded(s) == 0 || s->eof)
     {
+        s->request.pitch = pow(2., s->semitones * (1. / 12));
+
         s->functions->next(s->stretcher, &s->request);
         s->functions->analyseGrain(s->stretcher, s->inputBuffer, s->inputBufferSampleCount, 0, samplesNeeded(s));
         s->functions->synthesiseGrain(s->stretcher, &outputChunk);
-- 
2.49.1


>From b95aeb32ba210d3c982f27ac6cd57c36f514d5c7 Mon Sep 17 00:00:00 2001
From: John Funnell <john@parabolaresearch.com>
Date: Sun, 12 Oct 2025 17:28:15 +0100
Subject: [PATCH 3/4] require libbungee v2.4

---
 configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/configure b/configure
index 897b3e8d23..a76e83c709 100755
--- a/configure
+++ b/configure
@@ -7113,7 +7113,7 @@ enabled libiec61883       && require libiec61883 libiec61883/iec61883.h iec61883
 enabled libass            && require_pkg_config libass "libass >= 0.11.0" ass/ass.h ass_library_init
 enabled libbluray         && require_pkg_config libbluray libbluray libbluray/bluray.h bd_open
 enabled libbs2b           && require_pkg_config libbs2b libbs2b bs2b.h bs2b_open
-enabled libbungee         && require_pkg_config libbungee "libbungee >= 0.0.0" bungee/Bungee.h getFunctionsBungeeBasic
+enabled libbungee         && require_pkg_config libbungee "libbungee >= 2.4.0 libbungee < 3.0.0" bungee/Bungee.h getFunctionsBungeeBasic
 enabled libbungeepro      && require_pkg_config libbungeepro "libbungeepro >= 0.0.0" bungee/Bungee.h getFunctionsBungeePro
 enabled libcelt           && require libcelt celt/celt.h celt_decode -lcelt0 &&
                              { check_lib libcelt celt/celt.h celt_decoder_create_custom -lcelt0 ||
-- 
2.49.1


>From 529304750258cac5055b0766d70db6f50a34f413 Mon Sep 17 00:00:00 2001
From: John Funnell <john@parabolaresearch.com>
Date: Mon, 13 Oct 2025 05:48:51 +0100
Subject: [PATCH 4/4] tidying before push

---
 Changelog        | 2 +-
 doc/filters.texi | 4 +++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/Changelog b/Changelog
index 9986e89452..42bfa1cd1d 100644
--- a/Changelog
+++ b/Changelog
@@ -7,6 +7,7 @@ version <next>:
 - gfxcapture: Windows.Graphics.Capture based window/monitor capture
 - hxvs demuxer for HXVS/HXVT IP camera format
 - MPEG-H 3D Audio decoding via mpeghdec
+- Bungee and Bungee Pro audio stretch filters
 
 
 version 8.0:
@@ -45,7 +46,6 @@ version 8.0:
 - ffprobe -codec option
 - HDR10+ metadata passthrough when decoding/encoding with libaom-av1
 
-- Bungee audio stretch and pitch shift filter
 
 version 7.1:
 - Raw Captions with Time (RCWT) closed caption demuxer
diff --git a/doc/filters.texi b/doc/filters.texi
index 69afa5fc29..00189d41bf 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -4294,7 +4294,7 @@ Feed level (in Hz).
 
 @section bungee
 
-Stretch audio timescale and/or modify pitch using Bungee Basic.
+Stretch audio timescale and/or modify pitch using Bungee.
 
 This filter accepts the following parameters:
 @table @option
@@ -4302,6 +4302,8 @@ This filter accepts the following parameters:
 Controls the speed or tempo of the output audio. The default value 1 will not change speed.
 @item pitch
 Sets a pitch adjustment as a frequency multiplier. The default value 1 will have no effect on pitch.
+@item resample
+Controls whether Bungee should apply any resampling necessary to change pitch on the input or output of the filter.
 @end table
 
 
-- 
2.49.1

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2025-10-13 19:16 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-13  8:16 [FFmpeg-devel] [PATCH] WIP: avfilter: add Bungee audio stretch filter (PR #20697) kupix via ffmpeg-devel
2025-10-13  8:26 ` [FFmpeg-devel] " Nicolas George via ffmpeg-devel
2025-10-13 16:23   ` Kieran Kunhya via ffmpeg-devel
2025-10-13 19:16     ` john--- via ffmpeg-devel

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git