* [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* [FFmpeg-devel] Re: [PATCH] WIP: avfilter: add Bungee audio stretch filter (PR #20697)
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 ` Nicolas George via ffmpeg-devel
2025-10-13 16:23 ` Kieran Kunhya via ffmpeg-devel
0 siblings, 1 reply; 4+ messages in thread
From: Nicolas George via ffmpeg-devel @ 2025-10-13 8:26 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: kupix, Nicolas George
kupix via ffmpeg-devel (HE12025-10-13):
> 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.
Hi.
Thanks for the patch. What is the benefit of this library over
librubberband. That last one has the merit of being included in major
distributions.
Also, please explain the deal with “Bungee Pro”: if it is a proprietary
variant, I am not sure we want it, and it will require --enable-nonfree
at least.
Regards,
--
Nicolas George
_______________________________________________
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
* [FFmpeg-devel] Re: [PATCH] WIP: avfilter: add Bungee audio stretch filter (PR #20697)
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
0 siblings, 1 reply; 4+ messages in thread
From: Kieran Kunhya via ffmpeg-devel @ 2025-10-13 16:23 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Cc: kupix, Nicolas George, Kieran Kunhya
On Mon, 13 Oct 2025, 09:27 Nicolas George via ffmpeg-devel, <
ffmpeg-devel@ffmpeg.org> wrote:
> kupix via ffmpeg-devel (HE12025-10-13):
> > 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.
>
> Hi.
>
> Thanks for the patch. What is the benefit of this library over
> librubberband. That last one has the merit of being included in major
> distributions.
>
Bungee appears to be MPL whereas librubberband is gpl.
I don't know enough about time stretching libs to comment further.
Kieran
>
_______________________________________________
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
* [FFmpeg-devel] Re: [PATCH] WIP: avfilter: add Bungee audio stretch filter (PR #20697)
2025-10-13 16:23 ` Kieran Kunhya via ffmpeg-devel
@ 2025-10-13 19:16 ` john--- via ffmpeg-devel
0 siblings, 0 replies; 4+ messages in thread
From: john--- via ffmpeg-devel @ 2025-10-13 19:16 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: john
Thank you for taking a look. Bungee is the result of independent research and optimisation. It was released in Feb 2024 as MPL v2.0. Bungee Pro was released alongside Bungee: although it shares an API, its algorithms are proprietary, its audio quality is industry leading and it is highly optimised for web and mobile platforms.
I don't like to compare to other implementations, but since you asked, Nicolas, here are three main differences between libbungee and librubberband:
1. Bungee is a new and different algorithm. In my opinion, the audio quality is improved in many situations, avoiding some of librubberband's artifacts. Here is a random example at 56% input tempo, taken from the comparison page on the Bungee site:
https://bungee.parabolaresearch.com/audio/bungee/wrong-0.56-0.aac
https://bungee.parabolaresearch.com/audio/rubberband/wrong-0.56-0.aac
That said, such comparisons are subjective and very dependent upon the input audio and on the listener. And Bungee is still far from the perfect time stretcher (Bungee Pro is closer but I'll not say more about that...)
2. Bungee can be faster than rubberband: 1.7x faster in a quick test on Mac M4 of a tempo change to 56% of original tempo
3. Bungee has a different license: MPL-2.0 which is compatible with LGPL-2.1. librubberband is GPL-2.0 which requires --enable-gpl
This PR is an offer of maybe useful code and I won't be at all offended if Bungee and FFmpeg are not a good fit at this time.
John
_______________________________________________
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