]> git.sesse.net Git - mlt/blob - src/modules/normalize/filter_audiolevel.c
Fix compile error on Windows.
[mlt] / src / modules / normalize / filter_audiolevel.c
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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
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
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         int iec_scale = mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "iec_scale" );
60         *format = mlt_audio_s16;
61         int error = mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples );
62         if ( error || !buffer ) return error;
63
64         int num_channels = *channels;
65         int num_samples = *samples > 200 ? 200 : *samples;
66         int num_oversample = 0;
67         int c, s;
68         char key[ 50 ];
69         int16_t *pcm = (int16_t*) *buffer;
70
71         for ( c = 0; c < *channels; c++ )
72         {
73                 long val = 0;
74                 double level = 0.0;
75
76                 for ( s = 0; s < num_samples; s++ )
77                 {
78                         int sample = abs( pcm[c + s * num_channels] / 128 );
79                         val += sample;
80                         if ( sample == 128 )
81                                 num_oversample++;
82                         else
83                                 num_oversample = 0;
84                         // 10 samples @max => show max signal
85                         if ( num_oversample > 10 )
86                         {
87                                 level = 1.0;
88                                 break;
89                         }
90                         // if 3 samples over max => 1 peak over 0 db (0 dB = 40.0)
91                         if ( num_oversample > 3 )
92                                 level = 41.0/42.0;
93                 }
94                 // max amplitude = 40/42, 3to10  oversamples=41, more then 10 oversamples=42
95                 if ( level == 0.0 && num_samples > 0 )
96                         level = val / num_samples * 40.0/42.0 / 127.0;
97                 if ( iec_scale )
98                         level = IEC_Scale( AMPTODBFS( level ) );
99                 sprintf( key, "meta.media.audio_level.%d", c );
100                 mlt_properties_set_double( MLT_FRAME_PROPERTIES( frame ), key, level );
101                 sprintf( key, "_audio_level.%d", c );
102                 mlt_properties_set_double( MLT_FILTER_PROPERTIES( filter ), key, level );
103                 mlt_log_debug( MLT_FILTER_SERVICE( filter ), "channel %d level %f\n", c, level );
104         }
105
106         return error;
107 }
108
109 /** Filter processing.
110 */
111
112 static mlt_frame filter_process( mlt_filter filter, mlt_frame frame )
113 {
114         mlt_frame_push_audio( frame, filter );
115         mlt_frame_push_audio( frame, filter_get_audio );
116         return frame;
117 }
118
119 /** Constructor for the filter.
120 */
121
122 mlt_filter filter_audiolevel_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
123 {
124         mlt_filter filter = mlt_filter_new();
125         if ( filter )
126         {
127                 filter->process = filter_process;
128                 mlt_properties_set_int( MLT_FILTER_PROPERTIES(filter), "iec_scale", 1 );
129         }
130         return filter;
131 }