1 /*
2 * filter_audiolevel.c -- get the audio level of each channel
3 * Copyright (C) 2002 Steve Harris
4 * Copyright (C) 2010 Marco Gittler <g.marco@freenet.de>
5 * Copyright (C) 2012 Dan Dennedy <dan@dennedy.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 #include <framework/mlt_filter.h>
23 #include <framework/mlt_frame.h>
24 #include <framework/mlt_log.h>
25
26 #include <stdlib.h>
27 #include <math.h>
28
29 #define AMPTODBFS(n) (log10(n) * 20.0)
30
31 //----------------------------------------------------------------------------
32 // IEC standard dB scaling -- as borrowed from meterbridge (c) Steve Harris
33
IEC_Scale(double dB)34 static inline double IEC_Scale(double dB)
35 {
36 double fScale = 1.0f;
37
38 if (dB < -70.0f)
39 fScale = 0.0f;
40 else if (dB < -60.0f) // 0.0 .. 2.5
41 fScale = (dB + 70.0f) * 0.0025f;
42 else if (dB < -50.0f) // 2.5 .. 7.5
43 fScale = (dB + 60.0f) * 0.005f + 0.025f;
44 else if (dB < -40.0) // 7.5 .. 15.0
45 fScale = (dB + 50.0f) * 0.0075f + 0.075f;
46 else if (dB < -30.0f) // 15.0 .. 30.0
47 fScale = (dB + 40.0f) * 0.015f + 0.15f;
48 else if (dB < -20.0f) // 30.0 .. 50.0
49 fScale = (dB + 30.0f) * 0.02f + 0.3f;
50 else if (dB < -0.001f || dB > 0.001f) // 50.0 .. 100.0
51 fScale = (dB + 20.0f) * 0.025f + 0.5f;
52
53 return fScale;
54 }
55
filter_get_audio(mlt_frame frame,void ** buffer,mlt_audio_format * format,int * frequency,int * channels,int * samples)56 static int filter_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
57 {
58 mlt_filter filter = mlt_frame_pop_audio( frame );
59
60 // Get the properties from the filter
61 mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter );
62
63 int iec_scale = mlt_properties_get_int( filter_props, "iec_scale" );
64 *format = mlt_audio_s16;
65 int error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
66 if ( error || !buffer ) return error;
67
68 int num_channels = *channels;
69 int num_samples = *samples > 200 ? 200 : *samples;
70 int num_oversample = 0;
71 int c, s;
72 char key[ 50 ];
73 int16_t *pcm = (int16_t*) *buffer;
74
75 for ( c = 0; c < *channels; c++ )
76 {
77 double val = 0;
78 double level = 0.0;
79
80 for ( s = 0; s < num_samples; s++ )
81 {
82 double sample = fabs( pcm[c + s * num_channels] / 128.0 );
83 val += sample;
84 if ( sample == 128 )
85 num_oversample++;
86 else
87 num_oversample = 0;
88 // 10 samples @max => show max signal
89 if ( num_oversample > 10 )
90 {
91 level = 1.0;
92 break;
93 }
94 // if 3 samples over max => 1 peak over 0 db (0 dB = 40.0)
95 if ( num_oversample > 3 )
96 level = 41.0/42.0;
97 }
98 // max amplitude = 40/42, 3to10 oversamples=41, more then 10 oversamples=42
99 if ( level == 0.0 && num_samples > 0 )
100 level = val / num_samples * 40.0/42.0 / 127.0;
101 if ( iec_scale )
102 level = IEC_Scale( AMPTODBFS( level ) );
103 sprintf( key, "meta.media.audio_level.%d", c );
104 mlt_properties_set_double( MLT_FRAME_PROPERTIES( frame ), key, level );
105 sprintf( key, "_audio_level.%d", c );
106 mlt_properties_set_double( filter_props, key, level );
107 mlt_log_debug( MLT_FILTER_SERVICE( filter ), "channel %d level %f\n", c, level );
108 }
109 mlt_properties_set_position( filter_props, "_position", mlt_filter_get_position( filter, frame ) );
110
111 return error;
112 }
113
114 /** Filter processing.
115 */
116
filter_process(mlt_filter filter,mlt_frame frame)117 static mlt_frame filter_process( mlt_filter filter, mlt_frame frame )
118 {
119 mlt_frame_push_audio( frame, filter );
120 mlt_frame_push_audio( frame, filter_get_audio );
121 return frame;
122 }
123
124 /** Constructor for the filter.
125 */
126
filter_audiolevel_init(mlt_profile profile,mlt_service_type type,const char * id,char * arg)127 mlt_filter filter_audiolevel_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
128 {
129 mlt_filter filter = mlt_filter_new();
130 if ( filter )
131 {
132 filter->process = filter_process;
133 mlt_properties_set_int( MLT_FILTER_PROPERTIES(filter), "iec_scale", 1 );
134 }
135 return filter;
136 }
137