Signed-off-by: Nicolas George <geo...@nsup.org> --- libavfilter/Makefile | 2 +- libavfilter/asrc_sine.c | 53 ++++----------------------------- libavfilter/intsine.c | 65 +++++++++++++++++++++++++++++++++++++++++ libavfilter/intsine.h | 44 ++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 49 deletions(-) create mode 100644 libavfilter/intsine.c create mode 100644 libavfilter/intsine.h
diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 5123540653..83d939f0b1 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -151,7 +151,7 @@ OBJS-$(CONFIG_ANULLSRC_FILTER) += asrc_anullsrc.o 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_SINE_FILTER) += asrc_sine.o intsine.o OBJS-$(CONFIG_ANULLSINK_FILTER) += asink_anullsink.o diff --git a/libavfilter/asrc_sine.c b/libavfilter/asrc_sine.c index 3a87210b4b..8fff1dda8b 100644 --- a/libavfilter/asrc_sine.c +++ b/libavfilter/asrc_sine.c @@ -27,6 +27,7 @@ #include "audio.h" #include "avfilter.h" #include "internal.h" +#include "intsine.h" typedef struct SineContext { const AVClass *class; @@ -81,50 +82,6 @@ static const AVOption sine_options[] = { AVFILTER_DEFINE_CLASS(sine); -#define LOG_PERIOD 15 -#define AMPLITUDE 4095 -#define AMPLITUDE_SHIFT 3 - -static void make_sin_table(int16_t *sin) -{ - unsigned half_pi = 1 << (LOG_PERIOD - 2); - unsigned ampls = AMPLITUDE << AMPLITUDE_SHIFT; - uint64_t unit2 = (uint64_t)(ampls * ampls) << 32; - unsigned step, i, c, s, k, new_k, n2; - - /* Principle: if u = exp(i*a1) and v = exp(i*a2), then - exp(i*(a1+a2)/2) = (u+v) / length(u+v) */ - sin[0] = 0; - sin[half_pi] = ampls; - for (step = half_pi; step > 1; step /= 2) { - /* k = (1 << 16) * amplitude / length(u+v) - In exact values, k is constant at a given step */ - k = 0x10000; - for (i = 0; i < half_pi / 2; i += step) { - s = sin[i] + sin[i + step]; - c = sin[half_pi - i] + sin[half_pi - i - step]; - n2 = s * s + c * c; - /* Newton's method to solve n² * k² = unit² */ - while (1) { - new_k = (k + unit2 / ((uint64_t)k * n2) + 1) >> 1; - if (k == new_k) - break; - k = new_k; - } - sin[i + step / 2] = (k * s + 0x7FFF) >> 16; - sin[half_pi - i - step / 2] = (k * c + 0x8000) >> 16; - } - } - /* Unshift amplitude */ - for (i = 0; i <= half_pi; i++) - sin[i] = (sin[i] + (1 << (AMPLITUDE_SHIFT - 1))) >> AMPLITUDE_SHIFT; - /* Use symmetries to fill the other three quarters */ - for (i = 0; i < half_pi; i++) - sin[half_pi * 2 - i] = sin[i]; - for (i = 0; i < 2 * half_pi; i++) - sin[i + 2 * half_pi] = -sin[i]; -} - static const char *const var_names[] = { "n", "pts", @@ -146,10 +103,10 @@ static av_cold int init(AVFilterContext *ctx) int ret; SineContext *sine = ctx->priv; - if (!(sine->sin = av_malloc(sizeof(*sine->sin) << LOG_PERIOD))) + if (!(sine->sin = av_malloc(sizeof(*sine->sin) << SINE_LOG_PERIOD))) return AVERROR(ENOMEM); sine->dphi = ldexp(sine->frequency, 32) / sine->sample_rate + 0.5; - make_sin_table(sine->sin); + ff_make_sin_table(sine->sin); if (sine->beep_factor) { sine->beep_period = sine->sample_rate; @@ -244,10 +201,10 @@ static int request_frame(AVFilterLink *outlink) samples = (int16_t *)frame->data[0]; for (i = 0; i < nb_samples; i++) { - samples[i] = sine->sin[sine->phi >> (32 - LOG_PERIOD)]; + samples[i] = sine->sin[sine->phi >> (32 - SINE_LOG_PERIOD)]; sine->phi += sine->dphi; if (sine->beep_index < sine->beep_length) { - samples[i] += sine->sin[sine->phi_beep >> (32 - LOG_PERIOD)] << 1; + samples[i] += sine->sin[sine->phi_beep >> (32 - SINE_LOG_PERIOD)] << 1; sine->phi_beep += sine->dphi_beep; } if (++sine->beep_index == sine->beep_period) diff --git a/libavfilter/intsine.c b/libavfilter/intsine.c new file mode 100644 index 0000000000..ad99dc0147 --- /dev/null +++ b/libavfilter/intsine.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020 Nicolas George + * + * 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 "intsine.h" + +#define AMPLITUDE_SHIFT 3 + +void ff_make_sin_table(int16_t *sin) +{ + unsigned half_pi = 1 << (SINE_LOG_PERIOD - 2); + unsigned ampls = SINE_AMPLITUDE << AMPLITUDE_SHIFT; + uint64_t unit2 = (uint64_t)(ampls * ampls) << 32; + unsigned step, i, c, s, k, new_k, n2; + + /* Principle: if u = exp(i*a1) and v = exp(i*a2), then + exp(i*(a1+a2)/2) = (u+v) / length(u+v) */ + sin[0] = 0; + sin[half_pi] = ampls; + for (step = half_pi; step > 1; step /= 2) { + /* k = (1 << 16) * amplitude / length(u+v) + In exact values, k is constant at a given step */ + k = 0x10000; + for (i = 0; i < half_pi / 2; i += step) { + s = sin[i] + sin[i + step]; + c = sin[half_pi - i] + sin[half_pi - i - step]; + n2 = s * s + c * c; + /* Newton's method to solve n² * k² = unit² */ + while (1) { + new_k = (k + unit2 / ((uint64_t)k * n2) + 1) >> 1; + if (k == new_k) + break; + k = new_k; + } + sin[i + step / 2] = (k * s + 0x7FFF) >> 16; + sin[half_pi - i - step / 2] = (k * c + 0x8000) >> 16; + } + } + /* Unshift amplitude */ + for (i = 0; i <= half_pi; i++) + sin[i] = (sin[i] + (1 << (AMPLITUDE_SHIFT - 1))) >> AMPLITUDE_SHIFT; + /* Use symmetries to fill the other three quarters */ + for (i = 0; i < half_pi; i++) + sin[half_pi * 2 - i] = sin[i]; + for (i = 0; i < 2 * half_pi; i++) + sin[i + 2 * half_pi] = -sin[i]; +} + + diff --git a/libavfilter/intsine.h b/libavfilter/intsine.h new file mode 100644 index 0000000000..0723a9f141 --- /dev/null +++ b/libavfilter/intsine.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Nicolas George + * + * 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 + */ + +#ifndef AVFILTER_INTSINE_H +#define AVFILTER_INTSINE_H + +#include <stdint.h> + +/** + * Make a sin() table with integer arithmetic. + * + * The provided pointer must point to an array of SINE_PERIOD. + * It will be filled with one period ([0,2π[) of sine values with amplitude + * SINE_AMPLITUDE. + * + * A good way to use this table is to use a phase variable phi of type + * uint32_t, with 0 for 0 and 1<<32 for 2π and access the table at + * sin[phi >> SINE_SHIFT_PHI]. + */ +void ff_make_sin_table(int16_t *sin); + +#define SINE_LOG_PERIOD 15 +#define SINE_PERIOD (1U<<SINE_LOG_PERIOD) +#define SINE_AMPLITUDE 4095 +#define SINE_SHIFT_PHI (32 - SINE_LOG_PERIOD) + +#endif -- 2.26.2 _______________________________________________ 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".