[FFmpeg-devel,v2] avfilter: add dumpwave filter.

Submitted by dmitry.gumenyuk@gmail.com on Jan. 11, 2018, 9:11 p.m.

Details

Message ID 20180111211147.11434-1-dmitry.gumenyuk@gmail.com
State Withdrawn
Headers show

Commit Message

dmitry.gumenyuk@gmail.com Jan. 11, 2018, 9:11 p.m.
Signed-off-by: Dmytro Humeniuk <dmitry.gumenyuk@gmail.com>
---
 Changelog                            |   1 +
 doc/filters.texi                     |  23 +++
 libavfilter/Makefile                 |   1 +
 libavfilter/af_dumpwave.c            | 324 +++++++++++++++++++++++++++++++++++
 libavfilter/allfilters.c             |   1 +
 libavfilter/version.h                |   4 +-
 tests/fate/filter-audio.mak          |  13 ++
 tests/ref/fate/filter-dumpwave       |   1 +
 tests/ref/fate/filter-dumpwave-24bit |   1 +
 tests/ref/fate/filter-dumpwave-fltp  |   1 +
 10 files changed, 368 insertions(+), 2 deletions(-)
 create mode 100644 libavfilter/af_dumpwave.c
 create mode 100644 tests/ref/fate/filter-dumpwave
 create mode 100644 tests/ref/fate/filter-dumpwave-24bit
 create mode 100644 tests/ref/fate/filter-dumpwave-fltp

Comments

Michael Niedermayer Jan. 12, 2018, 2:49 a.m.
On Thu, Jan 11, 2018 at 10:11:47PM +0100, Dmytro Humeniuk wrote:
[...]

> +static const AVOption dumpwave_options[] = {
> +    { "s", "set width and height", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "1800x140"}, 0, 0, FLAGS },
> +    { "size", "set width and height", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "1800x140"}, 0, 0, FLAGS },
> +    { "n", "set number of samples per value per channel",  OFFSET(nb_samples), AV_OPT_TYPE_INT64,  {.i64 = 128}, 1, INT64_MAX, FLAGS },
> +    { "nb_samples", "set number of samples per value per channel",  OFFSET(nb_samples), AV_OPT_TYPE_INT64,  {.i64 = 128}, 1, INT64_MAX, FLAGS },
> +    { "f", "set json dump file", OFFSET(json_filename), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS },
> +    { "json", "set json dump file", OFFSET(json_filename), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS },
> +    { NULL }
> +};
> +
> +AVFILTER_DEFINE_CLASS(dumpwave);
> +

> +static av_cold int init(AVFilterContext *ctx)
> +{
> +    DumpWaveContext *dumpwave = ctx->priv;
> +    
> +    dumpwave->sum = dumpwave->i = dumpwave->n = 0;
> +    
> +    if (!dumpwave->json_filename) {
> +        dumpwave->dump_fp = stdout;

stdout is not safe as a output for filters and a bad default
2 filters writing to stdout would interfere
it would interfere with a user application using stdout



> +    } else {
> +        dumpwave->dump_fp = fopen(dumpwave->json_filename, "w");
> +        if (!dumpwave->dump_fp) {
> +            int err = AVERROR(errno);
> +            char buf[128];
> +            av_strerror(err, buf, sizeof(buf));
> +            av_log(ctx, AV_LOG_ERROR, "Could not open json file %s: %s\n",
> +                   dumpwave->json_filename, buf);
> +            return err;
> +        }
> +    }
> +    return 0;
> +}
> +
> +static av_cold void uninit(AVFilterContext *ctx)
> +{
> +    DumpWaveContext *dumpwave = ctx->priv;
> +    fclose(dumpwave->dump_fp);
> +    av_freep(&dumpwave->str);
> +    av_freep(&dumpwave->values);
> +}
> +
> +static int query_formats(AVFilterContext *ctx)
> +{
> +    static const enum AVSampleFormat sample_fmts[] = {
> +        AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8P,
> +        AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P,
> +        AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P,
> +        AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64P,
> +        AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
> +        AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP,
> +        AV_SAMPLE_FMT_NONE
> +    };
> +    AVFilterFormats *formats;
> +    AVFilterChannelLayouts *layouts;
> +    int ret;
> +    
> +    if (!(formats = ff_make_format_list(sample_fmts)))
> +        return AVERROR(ENOMEM);
> +    
> +    layouts = ff_all_channel_counts();
> +    if (!layouts)
> +        return AVERROR(ENOMEM);
> +    ret = ff_set_common_channel_layouts(ctx, layouts);
> +    if (ret < 0)
> +        return ret;
> +    
> +    return ff_set_common_formats(ctx, formats);
> +}
> +
> +static int config_output(AVFilterLink *outlink)
> +{
> +    AVFilterContext *ctx = outlink->src;
> +    DumpWaveContext *dumpwave = ctx->priv;
> +    const int width = dumpwave->w;
> +    dumpwave->values = av_realloc(NULL, width * sizeof(double));
> +    dumpwave->str = av_realloc(NULL, width * sizeof(int));
> +    dumpwave->max_samples = dumpwave->nb_samples * outlink->channels;
> +    
> +    return 0;
> +}
> +
> +static int dumpwave_request_frame(AVFilterLink *outlink)
> +{
> +    AVFilterContext *ctx = outlink->src;
> +    DumpWaveContext *dumpwave = ctx->priv;
> +    const int width = dumpwave->w;
> +    const int height = dumpwave->h;
> +    char *p, *result = dumpwave->str;
> +    
> +    AVFilterLink *inlink = ctx->inputs[0];
> +    int ret;
> +
> +    ret = ff_request_frame(inlink);
> +
> +    if (ret == AVERROR_EOF) {
> +        p = result;
> +
> +        for(int i = 0; i < width; i++)
> +            p += sprintf(p, "%d,", av_clip(dumpwave->h * dumpwave->values[i], 0, dumpwave->h));

sprintf is generally not safe as it does not check if there is enough space

[...]

Patch hide | download patch | download mbox

diff --git a/Changelog b/Changelog
index 61075b3392..40fd624449 100644
--- a/Changelog
+++ b/Changelog
@@ -38,6 +38,7 @@  version <next>:
 - Removed the ffserver program
 - Removed the ffmenc and ffmdec muxer and demuxer
 - VideoToolbox HEVC encoder and hwaccel
+- dumpwave audio filter
 
 
 version 3.4:
diff --git a/doc/filters.texi b/doc/filters.texi
index bd93e0ab84..1f7e4f5380 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -2538,6 +2538,29 @@  Optional. It should have a value much less than 1 (e.g. 0.05 or 0.02) and is
 used to prevent clipping.
 @end table
 
+@section dumpwave
+Dumps RMS amplitude to JSON file.
+Converts samples to decibels and calculates RMS (Root-Mean-Square) audio power scaled to desired values.
+
+@table @option
+@item s, size
+Dimensions @code{WxH}.
+@code{W} - number of data values in json, values will be scaled according to @code{H}.
+The default value is @var{1800x140}
+
+@item n, nb_samples
+Samples count per value per channel, default 128
+
+@item f, json
+Path to json file
+@end table
+
+For example, to generate RMS amplitude for 44.1 kHz 6 seconds length audio
+with dimensions @var{1800x140}, samples count @code{44100*6/1800=147} and store it to @var{/tmp/out.json}, you might use:
+@example
+dumpwave=s=1800x140:n=147:json=/tmp/out.json
+@end example
+
 @section dynaudnorm
 Dynamic Audio Normalizer.
 
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index ef4729dd3f..2ffbc9497a 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -87,6 +87,7 @@  OBJS-$(CONFIG_COMPENSATIONDELAY_FILTER)      += af_compensationdelay.o
 OBJS-$(CONFIG_CROSSFEED_FILTER)              += af_crossfeed.o
 OBJS-$(CONFIG_CRYSTALIZER_FILTER)            += af_crystalizer.o
 OBJS-$(CONFIG_DCSHIFT_FILTER)                += af_dcshift.o
+OBJS-$(CONFIG_DUMPWAVE_FILTER)               += af_dumpwave.o
 OBJS-$(CONFIG_DYNAUDNORM_FILTER)             += af_dynaudnorm.o
 OBJS-$(CONFIG_EARWAX_FILTER)                 += af_earwax.o
 OBJS-$(CONFIG_EBUR128_FILTER)                += f_ebur128.o
diff --git a/libavfilter/af_dumpwave.c b/libavfilter/af_dumpwave.c
new file mode 100644
index 0000000000..486f3a0d79
--- /dev/null
+++ b/libavfilter/af_dumpwave.c
@@ -0,0 +1,324 @@ 
+/*
+ * Copyright (c) 2017 Dmytro Humeniuk
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * waveform audio filter – dumps RMS amplitude to JSON file
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "audio.h"
+#include "internal.h"
+
+typedef struct DumpWaveContext {
+    const AVClass *class;   /**< class for AVOptions */
+    int w;                  /**< number of data values in json */
+    int h;                  /**< values will be scaled according to provided here */
+    int i;                  /**< index of current value */
+    char *json_filename;    /**< json filename */
+    char *str;              /**< comma separated values */
+    double *values;         /**< scaling factors */
+    int64_t nb_samples;     /**< samples per value per channel */
+    int64_t n;              /**< current number of samples counted */
+    int64_t max_samples;    /**< samples per value */
+    double sum;             /**< sum of the squared samples per value */
+    FILE *dump_fp;
+} DumpWaveContext;
+
+#define OFFSET(x) offsetof(DumpWaveContext, x)
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption dumpwave_options[] = {
+    { "s", "set width and height", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "1800x140"}, 0, 0, FLAGS },
+    { "size", "set width and height", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "1800x140"}, 0, 0, FLAGS },
+    { "n", "set number of samples per value per channel",  OFFSET(nb_samples), AV_OPT_TYPE_INT64,  {.i64 = 128}, 1, INT64_MAX, FLAGS },
+    { "nb_samples", "set number of samples per value per channel",  OFFSET(nb_samples), AV_OPT_TYPE_INT64,  {.i64 = 128}, 1, INT64_MAX, FLAGS },
+    { "f", "set json dump file", OFFSET(json_filename), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS },
+    { "json", "set json dump file", OFFSET(json_filename), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS },
+    { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(dumpwave);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+    DumpWaveContext *dumpwave = ctx->priv;
+    
+    dumpwave->sum = dumpwave->i = dumpwave->n = 0;
+    
+    if (!dumpwave->json_filename) {
+        dumpwave->dump_fp = stdout;
+    } else {
+        dumpwave->dump_fp = fopen(dumpwave->json_filename, "w");
+        if (!dumpwave->dump_fp) {
+            int err = AVERROR(errno);
+            char buf[128];
+            av_strerror(err, buf, sizeof(buf));
+            av_log(ctx, AV_LOG_ERROR, "Could not open json file %s: %s\n",
+                   dumpwave->json_filename, buf);
+            return err;
+        }
+    }
+    return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+    DumpWaveContext *dumpwave = ctx->priv;
+    fclose(dumpwave->dump_fp);
+    av_freep(&dumpwave->str);
+    av_freep(&dumpwave->values);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+    static const enum AVSampleFormat sample_fmts[] = {
+        AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8P,
+        AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P,
+        AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P,
+        AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64P,
+        AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
+        AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP,
+        AV_SAMPLE_FMT_NONE
+    };
+    AVFilterFormats *formats;
+    AVFilterChannelLayouts *layouts;
+    int ret;
+    
+    if (!(formats = ff_make_format_list(sample_fmts)))
+        return AVERROR(ENOMEM);
+    
+    layouts = ff_all_channel_counts();
+    if (!layouts)
+        return AVERROR(ENOMEM);
+    ret = ff_set_common_channel_layouts(ctx, layouts);
+    if (ret < 0)
+        return ret;
+    
+    return ff_set_common_formats(ctx, formats);
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+    AVFilterContext *ctx = outlink->src;
+    DumpWaveContext *dumpwave = ctx->priv;
+    const int width = dumpwave->w;
+    dumpwave->values = av_realloc(NULL, width * sizeof(double));
+    dumpwave->str = av_realloc(NULL, width * sizeof(int));
+    dumpwave->max_samples = dumpwave->nb_samples * outlink->channels;
+    
+    return 0;
+}
+
+static int dumpwave_request_frame(AVFilterLink *outlink)
+{
+    AVFilterContext *ctx = outlink->src;
+    DumpWaveContext *dumpwave = ctx->priv;
+    const int width = dumpwave->w;
+    const int height = dumpwave->h;
+    char *p, *result = dumpwave->str;
+    
+    AVFilterLink *inlink = ctx->inputs[0];
+    int ret;
+
+    ret = ff_request_frame(inlink);
+
+    if (ret == AVERROR_EOF) {
+        p = result;
+
+        for(int i = 0; i < width; i++)
+            p += sprintf(p, "%d,", av_clip(dumpwave->h * dumpwave->values[i], 0, dumpwave->h));
+        
+        p[-1] = '\0'; //removing trailing comma
+        
+        fprintf(dumpwave->dump_fp, "{\"width\":%d,\"height\":%d,\"samples\":[%s]}", width, height, result);
+    }
+
+    return ret;
+}
+
+/**
+ * Convert sample to dB and calculate root mean squared value
+ */
+static inline void calc_db_rms(DumpWaveContext *dumpwave, const double smpl)
+{
+    double s = 0.;
+    if (smpl != 0)
+        s = (20. * log10(fabs(smpl)) + 60.) / 60.;
+
+    dumpwave->sum += s * s;
+    
+    if (dumpwave->n++ == dumpwave->max_samples) {
+        dumpwave->values[dumpwave->i++] = av_clipd(sqrt(dumpwave->sum / dumpwave->max_samples), 0, 1.0);
+        dumpwave->sum = dumpwave->n = 0;
+    }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+    AVFilterContext *ctx = inlink->dst;
+    DumpWaveContext *dumpwave = ctx->priv;
+    int channels = frame->channels;
+    int c, i;
+    
+    if (dumpwave->i < dumpwave->w)
+        switch (inlink->format) {
+            case AV_SAMPLE_FMT_DBLP:
+                for (c = 0; c < channels; c++) {
+                    const double *src = (const double *)frame->extended_data[c];
+                    
+                    for (i = 0; i < frame->nb_samples; i++, src++)
+                        calc_db_rms(dumpwave, *src);
+                }
+                break;
+            case AV_SAMPLE_FMT_DBL: {
+                const double *src = (const double *)frame->extended_data[0];
+                
+                for (i = 0; i < frame->nb_samples; i++) {
+                    for (c = 0; c < channels; c++, src++)
+                        calc_db_rms(dumpwave, *src);
+                }
+                
+            } break;
+            case AV_SAMPLE_FMT_FLTP:
+                for (c = 0; c < channels; c++) {
+                    const float *src = (const float *)frame->extended_data[c];
+                    
+                    for (i = 0; i < frame->nb_samples; i++, src++)
+                        calc_db_rms(dumpwave, *src);
+                }
+                break;
+            case AV_SAMPLE_FMT_FLT: {
+                const float *src = (const float *)frame->extended_data[0];
+                
+                for (i = 0; i < frame->nb_samples; i++) {
+                    for (c = 0; c < channels; c++, src++)
+                        calc_db_rms(dumpwave, *src);
+                }
+                
+            } break;
+            case AV_SAMPLE_FMT_S64P:
+                for (c = 0; c < channels; c++) {
+                    const int64_t *src = (const int64_t *)frame->extended_data[c];
+                    
+                    for (i = 0; i < frame->nb_samples; i++, src++)
+                        calc_db_rms(dumpwave, *src / (double)INT64_MAX);
+                }
+                break;
+            case AV_SAMPLE_FMT_S64: {
+                const int64_t *src = (const int64_t *)frame->extended_data[0];
+                
+                for (i = 0; i < frame->nb_samples; i++) {
+                    for (c = 0; c < channels; c++, src++)
+                        calc_db_rms(dumpwave, *src / (double)INT64_MAX);
+                }
+                
+            } break;
+            case AV_SAMPLE_FMT_S32P:
+                for (c = 0; c < channels; c++) {
+                    const int32_t *src = (const int32_t *)frame->extended_data[c];
+                    
+                    for (i = 0; i < frame->nb_samples; i++, src++)
+                        calc_db_rms(dumpwave, *src / (double)INT32_MAX);
+                }
+                break;
+            case AV_SAMPLE_FMT_S32: {
+                const int32_t *src = (const int32_t *)frame->extended_data[0];
+                
+                for (i = 0; i < frame->nb_samples; i++) {
+                    for (c = 0; c < channels; c++, src++)
+                        calc_db_rms(dumpwave, *src / (double)INT32_MAX);
+                }
+                
+            } break;
+            case AV_SAMPLE_FMT_S16P:
+                for (c = 0; c < channels; c++) {
+                    const int16_t *src = (const int16_t *)frame->extended_data[c];
+                    
+                    for (i = 0; i < frame->nb_samples; i++, src++)
+                        calc_db_rms(dumpwave, *src / (double)INT16_MAX);
+                }
+                break;
+            case AV_SAMPLE_FMT_S16: {
+                const int16_t *src = (const int16_t *)frame->extended_data[0];
+                
+                for (i = 0; i < frame->nb_samples; i++) {
+                    for (c = 0; c < channels; c++, src++)
+                        calc_db_rms(dumpwave, *src / (double)INT16_MAX);
+                }
+                
+            } break;
+            case AV_SAMPLE_FMT_U8P:
+                for (c = 0; c < channels; c++) {
+                    const int8_t *src = (const int8_t *)frame->extended_data[c];
+                    
+                    for (i = 0; i < frame->nb_samples; i++, src++)
+                        calc_db_rms(dumpwave, *src / (double)INT8_MAX);
+                }
+                break;
+            case AV_SAMPLE_FMT_U8: {
+                const int8_t *src = (const int8_t *)frame->extended_data[0];
+                
+                for (i = 0; i < frame->nb_samples; i++) {
+                    for (c = 0; c < channels; c++, src++)
+                        calc_db_rms(dumpwave, *src / (double)INT8_MAX);
+                }
+                
+            } break;
+        }
+    return ff_filter_frame(inlink->dst->outputs[0], frame);
+}
+
+static const AVFilterPad dumpwave_inputs[] = {
+    {
+        .name         = "default",
+        .type         = AVMEDIA_TYPE_AUDIO,
+        .filter_frame = filter_frame,
+    },
+    { NULL }
+};
+
+static const AVFilterPad dumpwave_outputs[] = {
+    {
+        .name          = "default",
+        .type          = AVMEDIA_TYPE_AUDIO,
+        .request_frame = dumpwave_request_frame,
+        .config_props  = config_output
+    },
+    { NULL }
+};
+
+AVFilter ff_af_dumpwave = {
+    .name          = "dumpwave",
+    .description   = NULL_IF_CONFIG_SMALL("Dump RMS amplitude to JSON file"),
+    .init          = init,
+    .uninit        = uninit,
+    .query_formats = query_formats,
+    .priv_size     = sizeof(DumpWaveContext),
+    .inputs        = dumpwave_inputs,
+    .outputs       = dumpwave_outputs,
+    .priv_class    = &dumpwave_class,
+};
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 42516bbdf9..2539ee9e9a 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -98,6 +98,7 @@  static void register_all(void)
     REGISTER_FILTER(CROSSFEED,      crossfeed,      af);
     REGISTER_FILTER(CRYSTALIZER,    crystalizer,    af);
     REGISTER_FILTER(DCSHIFT,        dcshift,        af);
+    REGISTER_FILTER(DUMPWAVE,       dumpwave,       af);
     REGISTER_FILTER(DYNAUDNORM,     dynaudnorm,     af);
     REGISTER_FILTER(EARWAX,         earwax,         af);
     REGISTER_FILTER(EBUR128,        ebur128,        af);
diff --git a/libavfilter/version.h b/libavfilter/version.h
index 0f11721822..ca096962bb 100644
--- a/libavfilter/version.h
+++ b/libavfilter/version.h
@@ -30,8 +30,8 @@ 
 #include "libavutil/version.h"
 
 #define LIBAVFILTER_VERSION_MAJOR   7
-#define LIBAVFILTER_VERSION_MINOR  11
-#define LIBAVFILTER_VERSION_MICRO 101
+#define LIBAVFILTER_VERSION_MINOR  12
+#define LIBAVFILTER_VERSION_MICRO 100
 
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
                                                LIBAVFILTER_VERSION_MINOR, \
diff --git a/tests/fate/filter-audio.mak b/tests/fate/filter-audio.mak
index bd8b3d3c35..5ed0c61593 100644
--- a/tests/fate/filter-audio.mak
+++ b/tests/fate/filter-audio.mak
@@ -340,6 +340,18 @@  fate-filter-hdcd-s32p: CMD = md5 -i $(SRC) -af hdcd -f s32le
 fate-filter-hdcd-s32p: CMP = oneline
 fate-filter-hdcd-s32p: REF = 0c5513e83eedaa10ab6fac9ddc173cf5
 
+FATE_AFILTER-$(call FILTERDEMDEC, DUMPWAVE, WAV, PCM_S16LE) += fate-filter-dumpwave
+fate-filter-dumpwave: SRC = $(TARGET_PATH)/tests/data/asynth-44100-2.wav
+fate-filter-dumpwave: CMD = ffmpeg -i $(SRC) -af dumpwave=s=1800x140:n=147:f=$(TARGET_PATH)/tests/data/fate/filter-dumpwave.out -f null - && cat $(TARGET_PATH)/tests/data/fate/filter-dumpwave.out
+
+FATE_AFILTER-$(call FILTERDEMDEC, DUMPWAVE, TRUEHD, TRUEHD) += fate-filter-dumpwave-fltp
+fate-filter-dumpwave-fltp: SRC = $(TARGET_SAMPLES)/audiomatch/tones_afconvert_44100_stereo_aac_he2.m4a
+fate-filter-dumpwave-fltp: CMD = ffmpeg -i $(SRC) -f truehd -af dumpwave=s=1800x140:n=52:f=$(TARGET_PATH)/tests/data/fate/filter-dumpwave-fltp.out -f null - && cat $(TARGET_PATH)/tests/data/fate/filter-dumpwave-fltp.out
+
+FATE_AFILTER-$(call FILTERDEMDEC, DUMPWAVE, FLAC, FLAC) += fate-filter-dumpwave-24bit
+fate-filter-dumpwave-24bit: SRC = $(TARGET_SAMPLES)/lossless-audio/master_audio_2.0_24bit.wma
+fate-filter-dumpwave-24bit: CMD = ffmpeg -i $(SRC) -f truehd -af dumpwave=s=1800x140:n=51:f=$(TARGET_PATH)/tests/data/fate/filter-dumpwave-24bit.out -f null - && cat $(TARGET_PATH)/tests/data/fate/filter-dumpwave-24bit.out
+
 FATE_AFILTER-yes += fate-filter-formats
 fate-filter-formats: libavfilter/tests/formats$(EXESUF)
 fate-filter-formats: CMD = run libavfilter/tests/formats
@@ -347,3 +359,4 @@  fate-filter-formats: CMD = run libavfilter/tests/formats
 FATE_SAMPLES_AVCONV += $(FATE_AFILTER_SAMPLES-yes)
 FATE_FFMPEG += $(FATE_AFILTER-yes)
 fate-afilter: $(FATE_AFILTER-yes) $(FATE_AFILTER_SAMPLES-yes)
+
diff --git a/tests/ref/fate/filter-dumpwave b/tests/ref/fate/filter-dumpwave
new file mode 100644
index 0000000000..bd07098ef8
--- /dev/null
+++ b/tests/ref/fate/filter-dumpwave
@@ -0,0 +1 @@ 
+{"width":1800,"height":140,"samples":[103,104,103,103,104,103,103,104,103,103,103,104,103,103,104,103,103,104,103,103,104,103,103,103,104,103,103,104,103,103,104,103,103,104,103,103,104,103,103,103,104,103,103,104,103,103,104,103,103,104,103,103,103,104,103,103,104,103,103,104,103,103,104,103,102,104,103,102,104,104,102,103,104,103,103,104,103,103,104,103,103,104,103,103,103,104,103,103,104,103,103,104,103,102,104,103,102,104,104,102,103,104,102,103,104,103,103,104,103,103,104,103,103,103,104,103,103,104,103,103,104,103,103,104,103,102,104,104,102,103,104,102,103,104,103,103,104,103,103,104,103,103,104,103,103,103,104,103,103,104,103,103,104,103,103,104,103,102,103,104,102,103,104,103,103,104,103,103,104,103,103,104,103,103,103,104,103,103,104,103,103,104,103,103,104,103,103,103,104,103,103,104,103,103,104,103,103,104,103,103,104,103,103,103,104,103,103,104,103,103,104,103,103,104,103,103,103,104,103,103,104,103,103,104,103,103,104,103,103,104,103,103,104,103,103,103,104,103,103,104,103,103,104,103,103,104,103,103,103,104,103,103,104,103,103,104,103,103,104,103,102,104,103,103,103,104,103,103,104,103,103,104,103,103,104,103,103,103,104,103,103,104,103,103,104,103,102,104,103,102,104,103,102,103,104,102,103,104,103,101,104,105,104,103,102,104,104,102,102,103,104,104,103,103,104,104,102,103,103,103,104,103,103,103,104,102,104,103,103,104,103,103,103,103,103,103,103,103,103,104,103,103,103,104,103,103,103,103,104,103,103,103,103,103,103,103,104,103,103,103,103,103,104,103,103,103,103,103,103,103,103,103,103,103,104,103,103,103,104,104,103,103,103,103,103,103,103,103,103,103,103,102,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,104,103,103,103,103,103,104,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,104,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,104,103,103,103,103,103,103,103,103,103,104,103,103,105,103,103,103,103,103,103,104,103,103,103,104,103,103,103,104,103,103,103,103,103,103,103,103,104,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,104,103,103,106,106,103,103,104,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,104,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,100,104,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,104,104,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,96,98,100,97,99,98,97,97,97,96,98,97,98,97,99,98,97,95,98,97,98,101,96,95,96,94,97,99,99,95,98,96,98,98,98,98,98,98,99,98,96,97,99,97,98,99,99,99,96,98,97,98,98,99,99,97,100,95,98,97,99,94,98,96,99,98,97,99,98,97,96,98,95,96,97,100,99,96,99,97,97,97,99,98,97,96,97,97,99,99,100,95,99,98,95,96,99,97,99,99,95,98,96,97,96,99,96,97,98,96,97,95,97,99,99,96,99,96,98,98,96,96,97,96,99,98,97,98,100,98,100,96,98,98,99,97,99,99,99,97,99,97,99,99,98,96,100,97,95,112,119,121,121,118,122,122,120,121,123,121,120,118,121,120,121,123,124,122,120,124,121,122,121,120,121,122,122,120,119,118,122,121,122,121,120,123,120,121,122,121,121,119,120,119,120,121,121,120,122,120,122,123,122,124,122,120,122,121,121,119,122,123,123,122,120,121,119,123,121,125,119,121,119,120,121,121,121,123,122,120,122,123,120,120,123,121,119,122,120,122,123,121,123,121,121,123,120,120,121,123,123,120,122,122,119,120,122,122,120,122,122,120,123,120,121,120,121,121,123,120,121,119,122,117,124,122,122,119,120,122,121,121,123,121,120,121,122,120,121,123,121,119,123,120,123,125,121,120,121,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,104,103,103,103,103,103,104,103,104,103,103,104,103,104,103,104,103,103,104,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,104,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,104,103,104,103,104,102,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,104,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,104,103,103,103,103,103,103,103,103,103,103,103,104,103,103,103,104,103,103,103,104,103,103,104,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,104,103,103,103,103,103,103,103,103,103,103,104,103,103,103,103,104,103,103,104,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,104,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,104,103,103,103,103,103,103,103,102,81,75,74,74,75,76,78,78,79,81,81,82,84,84,84,86,86,86,87,88,88,88,90,88,89,90,89,89,90,89,89,89,89,88,88,89,87,87,87,85,85,85,83,83,82,81,80,79,78,76,75,75,73,75,80,76,79,75,74,74,76,77,77,79,81,80,82,84,83,84,86,86,86,88,87,87,89,89,88,89,90,89,89,90,89,89,90,89,88,89,88,87,87,87,86,85,86,84,83,83,81,80,80,78,77,76,75,73,74,76,81,81,76,73,74,75,76,76,79,79,80,82,83,83,84,85,85,86,87,87,87,89,88,88,90,89,89,89,90,89,89,90,89,89,89,88,87,88,87,86,86,86,84,84,84,82,81,81,78,77,77,75,74,74,74,79,76,79,74,74,75,75,76,78,78,80,81,82,82,84,84,85,86,87,86,87,89,88,88,90,89,89,90,89,89,90,89,89,89,89,88,88,89,87,86,87,85,84,85,83,82,82,81,79,79,78,75,75,75,73,75,81,80,76,74,74,75,76,77,78,79,81,81,82,84,84,84,86,86,86,88,88,87,88,89,88,89,90,89,89,90,89,89,90,89,88,89,88,87,87,87,85,85,85,83,83,83,81,80,80,78,76,75,75,73,74,78,76,79,75,74,74,75,77,77,79,80,80,82,84,83,84,86,85,86,88,87,87,89,89,88,89,90,89,89,90,89,89,90,89,88,89,88,87,88,87,86,86,85,84,83,83,81,80,80,78,77,76,75,74,74,75,81,80,77,73,74,75,75,76,79,79,80,82,82,83,84,85,85,86,87,87,87,89,88,88,90,89,89,90,90,89,89,90,89,89,89,88,88,88,87,86,86,85,84,84,83,82,81,81,79,78,78,75,74,75,74,77,76,80,75,74,74,75,76,78,78,80,81,81,82,84,84,85,86,87,86,87,88,88,88,90,89,89,90,89,89,90,89,89,89,89,88,88,89,87,87,87,85,84,85,83,82,82,81,79,79,78,76,75,75,73,75,80,81,76,75,74,75,76,77,78,79,81,81,82,84,84,84,86,86,86,88,88,87,89,89,88,89,90,89,89,90,89,89,90,89,88,89,88,87,87,87,85,85,86,83,83,83,81,80,80,78,77,76,75,73,74,77,78,79,76,74,74,75,76,77,79,80,80,82,83,83,84,86,85,86,88,87,87,89,88,88,90,89,89,90,90,89,89,90,89,88,89,88,87,88,87,86,86,85,84,84,83,81,81,80,78,77,77,75,74,74,75,80,81,78,74,74,75,75,76,79,79,80,82,82,82,85,85,85,86,87,86,87,89,88,88,90,89,89,90,89,89,90,90,89,89,89,88,88,88,87,86,87,85,84,0,0,0,0,0,0,0]}
diff --git a/tests/ref/fate/filter-dumpwave-24bit b/tests/ref/fate/filter-dumpwave-24bit
new file mode 100644
index 0000000000..4133761201
--- /dev/null
+++ b/tests/ref/fate/filter-dumpwave-24bit
@@ -0,0 +1 @@ 
+{"width":1800,"height":140,"samples":[0,0,0,0,0,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,0,0,0,0,31,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,117,110,104,100,96,91,89,88,88,88,88,91,92,91,92,140,140,140,140,140,118,107,106,98,95,94,92,98,106,101,98,96,96,105,101,95,93,92,94,94,91,92,92,90,89,90,93,94,96,100,103,103,99,100,100,107,103,99,97,93,89,92,92,96,107,111,102,99,93,102,115,116,134,138,130,97,96,96,97,96,99,96,97,97,98,101,100,101,103,103,100,101,101,100,101,99,99,90,93,96,101,130,121,104,97,89,96,105,110,129,111,140,128,114,94,106,106,109,107,106,103,104,106,105,105,106,107,112,112,111,111,107,108,107,99,93,102,111,127,140,125,99,92,95,99,108,126,125,128,140,113,95,99,101,108,104,106,107,103,106,103,110,118,117,132,137,133,116,113,117,111,112,106,110,119,140,139,126,108,108,103,98,109,138,140,140,140,116,106,101,103,127,123,140,123,111,120,117,121,124,125,119,122,119,112,113,113,110,108,118,118,121,140,140,136,112,114,115,106,115,140,133,140,128,107,107,104,109,127,140,140,130,105,109,136,126,128,127,124,129,125,126,120,125,120,120,118,119,126,126,134,124,132,132,113,104,126,121,136,140,122,104,103,102,131,128,133,121,131,110,106,106,103,119,128,123,136,139,125,132,140,132,135,121,124,121,129,130,132,135,131,139,133,138,140,136,140,132,106,103,110,119,131,130,121,135,140,139,131,106,129,140,140,135,137,132,128,139,125,123,119,116,118,123,134,135,140,140,138,135,137,136,134,135,138,116,108,107,116,137,137,140,136,126,114,137,140,124,136,140,139,140,122,126,135,132,133,126,132,133,129,137,133,138,134,138,135,134,134,119,124,131,137,120,118,134,118,122,118,117,132,126,134,138,118,135,137,125,127,123,119,134,125,136,131,137,134,134,140,139,139,132,140,140,138,137,137,133,134,132,127,130,130,136,135,116,104,128,140,125,123,115,136,140,124,129,114,120,140,116,127,136,136,129,133,133,129,130,132,135,137,135,133,140,137,136,131,135,133,127,130,135,131,113,135,132,138,122,135,137,140,123,124,120,140,135,137,134,137,123,123,140,126,139,140,140,137,139,138,140,134,132,134,127,118,124,134,134,137,133,129,133,128,140,126,140,140,113,128,140,140,133,126,127,132,120,106,116,133,137,139,110,130,136,137,134,131,133,138,132,134,133,134,131,134,136,138,130,135,133,136,135,132,134,114,110,110,132,123,99,117,130,140,102,105,120,140,131,112,129,140,105,132,133,135,138,140,133,134,140,136,134,136,138,139,139,139,131,137,133,133,135,104,107,113,133,97,105,111,140,119,138,123,133,127,110,118,135,113,107,102,109,135,138,134,129,134,133,132,133,131,135,139,133,130,128,124,133,140,140,140,129,129,107,132,135,135,140,140,140,136,118,115,117,138,121,117,112,119,134,120,136,134,133,133,134,137,134,131,137,137,133,137,135,134,132,136,134,122,137,137,140,140,140,128,140,140,132,107,105,114,140,121,113,113,119,132,115,139,140,121,127,135,123,129,137,134,136,133,135,138,132,134,140,133,133,135,133,138,132,136,129,110,132,129,103,104,111,140,132,105,107,134,125,114,113,124,131,134,116,121,135,140,136,136,137,133,133,136,137,128,129,131,140,139,136,130,134,135,139,135,136,119,108,109,136,127,117,113,105,136,140,123,140,139,139,136,131,131,139,132,136,137,136,135,133,133,137,135,130,130,132,131,129,138,138,135,130,128,126,128,119,137,137,140,126,125,127,118,139,140,135,140,140,128,140,140,131,140,138,140,130,138,135,137,133,134,127,132,132,137,135,140,135,137,136,140,137,136,132,131,138,135,127,117,135,140,128,137,137,140,140,132,135,140,129,117,124,127,125,0,0,0,0,0,0,0,0,0,0,0]}
\ No newline at end of file
diff --git a/tests/ref/fate/filter-dumpwave-fltp b/tests/ref/fate/filter-dumpwave-fltp
new file mode 100644
index 0000000000..6c50eb9eaf
--- /dev/null
+++ b/tests/ref/fate/filter-dumpwave-fltp
@@ -0,0 +1 @@ 
+{"width":1800,"height":140,"samples":[140,140,140,140,140,120,75,61,52,51,84,89,90,91,92,96,96,100,140,140,140,140,140,130,86,62,51,44,76,86,90,94,94,95,94,96,98,100,103,102,99,101,100,101,101,103,102,101,101,100,100,101,103,102,102,100,98,101,103,101,101,100,99,101,102,103,102,100,99,100,101,103,103,102,99,100,101,101,103,102,100,101,100,101,101,102,103,100,101,100,100,100,102,104,102,100,99,102,103,101,101,99,99,101,102,104,101,99,101,99,102,101,103,102,100,101,101,101,102,102,102,101,100,103,100,102,104,102,102,100,100,101,102,104,98,101,99,102,103,102,103,99,101,102,102,104,103,101,101,101,102,101,103,102,101,102,101,101,100,103,103,101,101,101,99,102,103,103,102,99,47,41,29,99,101,100,100,102,102,104,102,99,101,100,101,102,103,102,100,80,41,38,28,33,35,31,24,26,26,25,24,23,21,21,20,21,27,21,17,22,17,23,33,32,31,28,28,26,27,27,22,20,22,20,20,19,22,18,19,17,22,26,18,21,20,20,25,19,30,27,23,28,27,33,56,47,53,63,64,72,73,33,15,23,20,22,21,25,24,27,26,25,32,44,44,49,67,64,65,79,72,72,76,77,84,76,84,79,79,76,81,79,77,80,85,80,84,85,83,82,73,76,74,79,75,89,87,80,79,83,81,81,85,80,81,81,84,78,78,85,78,78,53,53,35,64,99,102,101,100,98,101,102,103,102,99,100,100,102,82,84,67,50,37,39,90,102,100,101,99,101,101,103,102,101,100,101,100,101,103,101,102,100,100,99,102,104,102,101,100,100,101,101,105,103,99,101,100,104,102,101,99,100,101,101,103,102,100,101,101,101,100,102,104,101,101,100,100,101,102,103,102,100,100,100,102,103,104,101,99,100,101,101,103,102,100,101,101,101,103,102,100,101,100,101,102,103,102,101,100,101,99,102,104,102,101,100,99,101,102,104,102,100,100,100,102,101,103,101,99,101,101,101,102,102,102,97,102,101,103,102,101,101,100,100,101,102,102,101,101,101,99,102,103,102,101,99,100,101,101,104,101,100,100,99,102,97,74,61,56,49,43,34,22,20,94,100,102,101,102,104,102,103,102,102,102,99,62,57,47,36,35,30,19,22,18,21,25,17,20,20,27,23,38,33,28,35,41,33,39,41,46,51,44,36,25,23,26,24,15,32,23,16,27,26,28,42,44,34,41,44,40,44,44,46,46,43,39,29,49,53,43,49,55,49,63,66,75,72,84,77,82,81,55,41,42,41,39,36,58,46,43,54,57,54,59,72,72,73,79,83,83,82,79,79,82,83,83,86,78,80,82,82,77,77,84,84,91,83,75,54,38,75,75,76,80,81,80,80,82,81,77,79,82,80,77,83,88,83,68,48,40,51,90,105,99,100,106,99,98,104,100,99,103,102,99,101,104,100,100,105,53,76,100,103,100,101,104,98,99,105,99,99,106,100,98,106,101,98,105,101,98,104,101,99,102,103,100,101,103,100,100,103,101,99,104,101,99,103,101,102,99,105,100,98,104,101,98,104,102,97,103,101,98,103,103,99,102,103,99,101,104,99,101,103,99,101,103,100,101,103,100,99,102,102,99,101,104,98,101,103,101,98,103,102,98,102,104,98,102,104,98,101,105,98,101,105,99,100,104,100,100,104,101,99,101,103,99,100,105,100,99,106,101,98,105,100,98,103,105,99,101,105,98,100,105,99,99,106,100,100,104,101,100,102,102,100,101,103,100,99,102,97,82,70,73,72,71,66,62,65,60,57,51,46,42,33,89,101,98,104,101,95,85,76,70,73,70,62,65,62,58,54,48,44,36,33,26,20,22,23,26,19,19,18,40,49,41,51,55,60,73,73,72,71,78,51,23,22,16,28,21,15,23,22,42,40,50,51,54,67,76,74,71,79,81,76,81,79,81,79,83,78,76,76,79,84,82,80,80,82,77,77,78,85,84,79,77,81,80,81,82,78,72,79,79,80,90,78,82,79,77,75,82,83,83,84,76,85,80,82,82,77,79,79,85,76,55,42,24,61,95,105,101,82,81,79,81,83,77,85,79,82,79,83,79,74,48,30,38,87,97,95,100,103,105,101,100,99,100,100,104,105,100,99,100,100,101,106,103,101,99,98,107,100,98,99,103,105,101,99,99,100,101,105,104,100,98,98,100,102,106,102,100,100,100,100,103,105,101,100,99,99,101,106,104,101,99,98,100,102,106,91,103,106,102,99,99,100,101,104,104,100,99,99,100,101,106,102,101,100,99,100,102,106,102,100,99,99,102,104,105,100,98,99,100,102,106,102,100,100,109,100,100,100,100,103,105,100,99,99,99,101,106,103,101,99,98,99,103,106,102,99,99,100,102,103,105,100,99,99,99,101,106,103,101,100,99,99,102,96,100,102,106,101,100,99,99,101,106,104,101,99,98,100,102,106,102,99,99,94,65,32,43,44,51,50,48,45,42,40,40,30,22,21,22,20,22,18,88,83,33,27,40,45,46,50,43,39,42,46,35,30,24,18,19,18,23,18,17,21,28,31,36,37,23,26,26,35,41,55,59,76,59,66,71,73,75,49,19,20,34,36,34,33,23,27,33,39,39,57,68,66,63,60,68,72,81,81,82,83,78,75,80,84,90,79,85,81,81,83,83,83,81,78,86,80,76,87,83,87,82,82,84,87,80,79,84,82,82,86,85,86,81,73,89,80,78,82,80,81,85,84,83,58,46,48,55,94,101,101,101,103,103,101,100,84,78,83,78,79,80,76,76,48,50,33,81,98,100,102,102,104,102,99,101,100,101,102,103,101,101,101,101,100,102,103,101,102,100,100,100,102,104,101,100,99,102,103,102,102,100,100,100,102,104,102,101,99,100,101,101,103,102,100,101,100,102,101,103,102,101,101,101,100,101,103,102,102,100,100,99,102,104,103,100,99,102,103,103,102,99,100,100,102,102,103,101,100,100,101,100,102,102,101,101,100,101,100,102,104,101,101,100,99,101,102,104,102,100,99,100,102,104,101,99,100,101,101,104,102,99,101,100,102,101,103,102,100,101,100,100,101,103,102,102,100,101,99,102,104,102,102,100,99,101,102,104,89,47,31,27,78,103,101,99,101,101,101,103,102,100,101,100,101,101,102,99,72,36,26,26,29,27,22,23,22,21,19,18,22,28,25,20,26,21,24,37,34,50,41,33,30,18,21,23,22,18,29,20,29,21,26,22,17,29,33,35,43,32,32,43,39,35,51,36,34,36,57,53,69,58,72,74,77,77,79,81,76,78,60,46,33,46,45,28,37,53,52,61,58,59,79,81,77,77,81,76,76,82,84,81,81,77,79,77,79,82,81,87,83,80,80,84,80,80,79,80,85,82,87,80,80,77,78,78,80,86,80,81,82,82,81,85,83,81,76,79,86,83,82,61,46,34,43,89,99,100,101,100,100,102,102,101,101,104,101,102,87,78,77,52,36,39,68,97,103,101,101,103,101,101,101,102,100,101,100,100,100,101,102,100,101,102,101,101,103,102,102,101,103,101,101,102,102,100,101,97,102,101,102,102,101,100,103,100,100,100,101,101,100,103,100,101,102,103,100,102,102,102,100,103,102,101,101,103,100,100,101,100,100,100,102,100,100,102,109,100,99,100,101,100,102,102,101,100,103,101,101,102,103,101,101,103,101,100,102,101,100,100,100,100,100,102,102,101,101,103,101,101,103,102,101,101,103,91,101,101,103,101,101,103,102,101,102,102,101,100,102,100,100,100,101,101,100,103,101,101,102,103,101,102,103,102,100,95,60,32,30,28,31,31,21,16,82,102,102,101,100,101,101,99,100,101,101,83,45,30,27,33,25,29,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}
\ No newline at end of file