Skip to content

Commit

Permalink
Add audiolevel filter.
Browse files Browse the repository at this point in the history
  • Loading branch information
ddennedy committed Nov 13, 2012
1 parent c48ed74 commit af7a121
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/modules/core/factory.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down
1 change: 1 addition & 0 deletions src/modules/normalize/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ include ../../../config.mak
TARGET = ../libmltnormalize$(LIBSUF)

OBJS = factory.o \
filter_audiolevel.o \
filter_volume.o

SRCS := $(OBJS:.o=.c)
Expand Down
3 changes: 3 additions & 0 deletions src/modules/normalize/factory.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand All @@ -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" );
}
131 changes: 131 additions & 0 deletions src/modules/normalize/filter_audiolevel.c
Original file line number Diff line number Diff line change
@@ -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;
}
38 changes: 38 additions & 0 deletions src/modules/normalize/filter_audiolevel.yml
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit af7a121

Please sign in to comment.