]> git.sesse.net Git - mlt/commitdiff
Add audiolevel filter.
authorDan Dennedy <dan@dennedy.org>
Sun, 11 Nov 2012 21:06:58 +0000 (13:06 -0800)
committerDan Dennedy <dan@dennedy.org>
Tue, 13 Nov 2012 03:21:45 +0000 (19:21 -0800)
src/modules/core/factory.c
src/modules/normalize/Makefile
src/modules/normalize/factory.c
src/modules/normalize/filter_audiolevel.c [new file with mode: 0644]
src/modules/normalize/filter_audiolevel.yml [new file with mode: 0644]

index 34246ed2be79cab250452de876aa06837afbbfb4..7adb8fcc6385592035ae7afe0b166643aa787208 100644 (file)
@@ -75,8 +75,8 @@ MLT_REPOSITORY
        MLT_REGISTER( filter_type, "audiowave", filter_audiowave_init );
        MLT_REGISTER( filter_type, "brightness", filter_brightness_init );
        MLT_REGISTER( filter_type, "channelcopy", filter_channelcopy_init );
-    MLT_REGISTER( filter_type, "channelswap", filter_channelcopy_init );
-    MLT_REGISTER( filter_type, "crop", filter_crop_init );
+       MLT_REGISTER( filter_type, "channelswap", filter_channelcopy_init );
+       MLT_REGISTER( filter_type, "crop", filter_crop_init );
        MLT_REGISTER( filter_type, "data_feed", filter_data_feed_init );
        MLT_REGISTER( filter_type, "data_show", filter_data_show_init );
        MLT_REGISTER( filter_type, "fieldorder", filter_fieldorder_init );
index 38624578b15a9f3a96ee4b890e4fe9c8ddca4b16..cc04b08cf110107e364a57ca3dcb684592ccb601 100644 (file)
@@ -7,6 +7,7 @@ include ../../../config.mak
 TARGET = ../libmltnormalize$(LIBSUF)
 
 OBJS = factory.o \
+          filter_audiolevel.o \
           filter_volume.o 
 
 SRCS := $(OBJS:.o=.c)
index 1dda79b02536ffd7bf7c2acca9d276e56095174f..ac02263d19587d96ec961ae19b183b0f076a293c 100644 (file)
@@ -22,6 +22,7 @@
 #include <limits.h>
 #include <framework/mlt.h>
 
+extern mlt_filter filter_audiolevel_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
 extern mlt_filter filter_volume_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg );
 
 static mlt_properties metadata( mlt_service_type type, const char *id, void *data )
@@ -33,6 +34,8 @@ static mlt_properties metadata( mlt_service_type type, const char *id, void *dat
 
 MLT_REPOSITORY
 {
+       MLT_REGISTER( filter_type, "audiolevel", filter_audiolevel_init );
        MLT_REGISTER( filter_type, "volume", filter_volume_init );
+       MLT_REGISTER_METADATA( filter_type, "audiolevel", metadata, "filter_audiolevel.yml" );
        MLT_REGISTER_METADATA( filter_type, "volume", metadata, "filter_volume.yml" );
 }
diff --git a/src/modules/normalize/filter_audiolevel.c b/src/modules/normalize/filter_audiolevel.c
new file mode 100644 (file)
index 0000000..fa8be07
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * filter_audiolevel.c -- get the audio level of each channel
+ * Copyright (C) 2002 Steve Harris
+ * Copyright (C) 2010 Marco Gittler <g.marco@freenet.de>
+ * Copyright (C) 2012 Dan Dennedy <dan@dennedy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <framework/mlt_filter.h>
+#include <framework/mlt_frame.h>
+#include <framework/mlt_log.h>
+
+#include <stdlib.h>
+#include <math.h>
+
+#define AMPTODBFS(n) (log10(n) * 20.0)
+
+//----------------------------------------------------------------------------
+// IEC standard dB scaling -- as borrowed from meterbridge (c) Steve Harris
+
+static inline double IEC_Scale(double dB)
+{
+       double fScale = 1.0f;
+
+       if (dB < -70.0f)
+               fScale = 0.0f;
+       else if (dB < -60.0f)                 //  0.0  ..   2.5
+               fScale = (dB + 70.0f) * 0.0025f;
+       else if (dB < -50.0f)                 //  2.5  ..   7.5
+               fScale = (dB + 60.0f) * 0.005f + 0.025f;
+       else if (dB < -40.0)                  //  7.5  ..  15.0
+               fScale = (dB + 50.0f) * 0.0075f + 0.075f;
+       else if (dB < -30.0f)                 // 15.0  ..  30.0
+               fScale = (dB + 40.0f) * 0.015f + 0.15f;
+       else if (dB < -20.0f)                 // 30.0  ..  50.0
+               fScale = (dB + 30.0f) * 0.02f + 0.3f;
+       else if (dB < -0.001f || dB > 0.001f) // 50.0  .. 100.0
+               fScale = (dB + 20.0f) * 0.025f + 0.5f;
+
+       return fScale;
+}
+
+static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
+{
+       mlt_filter filter = mlt_frame_pop_audio( frame );
+       int iec_scale = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "iec_scale" );
+       *format = mlt_audio_s16;
+       int error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
+       if ( error || !buffer ) return error;
+
+       int num_channels = *channels;
+       int num_samples = *samples > 200 ? 200 : *samples;
+       int num_oversample = 0;
+       int c, s;
+       char key[ 50 ];
+       int16_t *pcm = (int16_t*) *buffer;
+
+       for ( c = 0; c < *channels; c++ )
+       {
+               long val = 0;
+               double level = 0.0;
+
+               for ( s = 0; s < num_samples; s++ )
+               {
+                       int sample = abs( pcm[c + s * num_channels] / 128 );
+                       val += sample;
+                       if ( sample == 128 )
+                               num_oversample++;
+                       else
+                               num_oversample = 0;
+                       // 10 samples @max => show max signal
+                       if ( num_oversample > 10 )
+                       {
+                               level = 1.0;
+                               break;
+                       }
+                       // if 3 samples over max => 1 peak over 0 db (0 dB = 40.0)
+                       if ( num_oversample > 3 )
+                               level = 41.0/42.0;
+               }
+               // max amplitude = 40/42, 3to10  oversamples=41, more then 10 oversamples=42
+               if ( level == 0.0 )
+                       level = val / num_samples * 40.0/42.0 / 127.0;
+               if ( iec_scale )
+                       level = IEC_Scale( AMPTODBFS( level ) );
+               sprintf( key, "meta.media.audio_level.%d", c );
+               mlt_properties_set_double( MLT_FRAME_PROPERTIES( frame ), key, level );
+               sprintf( key, "_audio_level.%d", c );
+               mlt_properties_set_double( MLT_FILTER_PROPERTIES( filter ), key, level );
+               mlt_log_debug( MLT_FILTER_SERVICE( filter ), "channel %d level %f\n", c, level );
+       }
+
+       return error;
+}
+
+/** Filter processing.
+*/
+
+static mlt_frame filter_process( mlt_filter filter, mlt_frame frame )
+{
+       mlt_frame_push_audio( frame, filter );
+       mlt_frame_push_audio( frame, filter_get_audio );
+       return frame;
+}
+
+/** Constructor for the filter.
+*/
+
+mlt_filter filter_audiolevel_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
+{
+       mlt_filter filter = mlt_filter_new();
+       if ( filter )
+       {
+               filter->process = filter_process;
+               mlt_properties_set_int( MLT_FILTER_PROPERTIES(filter), "iec_scale", 1 );
+       }
+       return filter;
+}
diff --git a/src/modules/normalize/filter_audiolevel.yml b/src/modules/normalize/filter_audiolevel.yml
new file mode 100644 (file)
index 0000000..2592847
--- /dev/null
@@ -0,0 +1,38 @@
+schema_version: 0.1
+type: filter
+identifier: audiolevel
+title: Audio Levels
+version: 1
+copyright: Dan Dennedy, Marco Gittler, and Steve Harris
+creator: Dan Dennedy
+contributor:
+  - Marco Gittler
+  - Steve Harris
+license: GPLv2
+language: en
+description: Compute the audio amplitude.
+notes: >
+  This filter provides the amplitude level as a percentage value in floating point.
+  This does not do any "slowing" of the data by averaging out peaks and
+  troughs of short duration like a VU meter.
+  Applications can also get this data on the frame as meta.media.audio_level.<N>
+  where <N> is the channel number starting with 0.
+tags:
+  - Audio
+parameters:
+  - identifier: iec_scale
+    title: Use IEC 60268-18 Scale
+    type: integer
+    minimum: 0
+    maximum: 1
+    default: 1
+    widget: checkbox
+
+  - identifier: _audio_level.<N>
+    description: >
+        <N> is the channel number starting with 0.
+        This is updated on every frame with audio.
+    readonly: yes
+    type: float
+    minimum: 0
+    maximum: 1