audiobargraph_a.c 10.2 KB
Newer Older
1 2 3
/*****************************************************************************
 * audiobargraph_a.c : audiobargraph audio plugin for vlc
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2002-2009 VLC authors and VideoLAN
5 6 7 8 9
 * $Id$
 *
 * Authors: Clement CHESNIN <clement.chesnin@gmail.com>
 *          Philippe COENT <philippe.coent@tdf.fr>
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
10 11 12
 * This program 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
13 14 15 16
 * (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
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
17 18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
19
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
20 21 22
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_aout.h>
#include <vlc_filter.h>

#include <math.h>

39
#define BARGRAPH_TEXT N_("Defines if BarGraph information should be sent")
Christophe Mutricy's avatar
Christophe Mutricy committed
40
#define BARGRAPH_LONGTEXT N_("Defines if BarGraph information should be sent. "\
41
                "1 if the information should be sent, 0 otherwise (default 1)." )
42
#define BARGRAPH_REPETITION_TEXT N_("Sends the barGraph information every n audio packets")
43 44
#define BARGRAPH_REPETITION_LONGTEXT N_("Defines how often the barGraph information should be sent. "\
                "Sends the barGraph information every n audio packets (default 4)." )
45
#define SILENCE_TEXT N_("Defines if silence alarm information should be sent")
Christophe Mutricy's avatar
Christophe Mutricy committed
46
#define SILENCE_LONGTEXT N_("Defines if silence alarm information should be sent. "\
47
                "1 if the information should be sent, 0 otherwise (default 1)." )
48
#define TIME_WINDOW_TEXT N_("Time window to use in ms")
49 50 51
#define TIME_WINDOW_LONGTEXT N_("Time Window during when the audio level is measured in ms for silence detection. "\
                "If the audio level is under the threshold during this time, "\
                "an alarm is sent (default 5000)." )
52
#define ALARM_THRESHOLD_TEXT N_("Minimum Audio level to raise the alarm")
53 54 55
#define ALARM_THRESHOLD_LONGTEXT N_("Threshold to be attained to raise an alarm. "\
                "If the audio level is under the threshold during this time, "\
                "an alarm is sent (default 0.1)." )
56
#define REPETITION_TIME_TEXT N_("Time between two alarm messages in ms" )
57 58 59 60 61 62 63 64 65 66 67 68 69 70
#define REPETITION_TIME_LONGTEXT N_("Time between two alarm messages in ms. "\
                "This value is used to avoid alarm saturation (default 2000)." )

#define CFG_PREFIX "audiobargraph_a-"

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  Open( vlc_object_t * );
static void Close( vlc_object_t * );
static block_t *DoWork( filter_t *, block_t * );

vlc_module_begin ()
    set_description( N_("Audio part of the BarGraph function") )
71
    set_shortname( N_("Audiobar Graph") )
72 73 74
    set_capability( "audio filter", 0 )
    set_category( CAT_AUDIO )
    set_subcategory( SUBCAT_AUDIO_AFILTER )
75

76 77
    add_obsolete_string( CFG_PREFIX "address" )
    add_obsolete_integer( CFG_PREFIX "port" )
78 79 80 81
    add_integer( CFG_PREFIX "bargraph", 1, BARGRAPH_TEXT, BARGRAPH_LONGTEXT, false )
    add_integer( CFG_PREFIX "bargraph_repetition", 4, BARGRAPH_REPETITION_TEXT, BARGRAPH_REPETITION_LONGTEXT, false )
    add_integer( CFG_PREFIX "silence", 1, SILENCE_TEXT, SILENCE_LONGTEXT, false )
    add_integer( CFG_PREFIX "time_window", 5000, TIME_WINDOW_TEXT, TIME_WINDOW_LONGTEXT, false )
82
    add_float( CFG_PREFIX "alarm_threshold", 0.1, ALARM_THRESHOLD_TEXT, ALARM_THRESHOLD_LONGTEXT, false )
83
    add_integer( CFG_PREFIX "repetition_time", 2000, REPETITION_TIME_TEXT, REPETITION_TIME_LONGTEXT, false )
84
    add_obsolete_integer( CFG_PREFIX "connection_reset" )
85

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
    set_callbacks( Open, Close )
vlc_module_end ()

typedef struct ValueDate_t {
    float value;
    mtime_t date;
    struct ValueDate_t* next;
} ValueDate_t;

struct filter_sys_t
{
    int             bargraph;
    int             bargraph_repetition;
    int             silence;
    int             time_window;
    float           alarm_threshold;
    int             repetition_time;
    int             counter;
    ValueDate_t*    first;
    ValueDate_t*    last;
    int             started;
    mtime_t         lastAlarm;
};

/*****************************************************************************
 * Open: open the visualizer
 *****************************************************************************/
static int Open( vlc_object_t *p_this )
{
    filter_t     *p_filter = (filter_t *)p_this;
116
    filter_sys_t *p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
117 118
    if( !p_sys )
        return VLC_ENOMEM;
119

120 121 122 123 124 125
    p_sys->bargraph = var_CreateGetInteger( p_filter, CFG_PREFIX "bargraph" );
    p_sys->bargraph_repetition = var_CreateGetInteger( p_filter, CFG_PREFIX "bargraph_repetition" );
    p_sys->silence = var_CreateGetInteger( p_filter, CFG_PREFIX "silence" );
    p_sys->time_window = var_CreateGetInteger( p_filter, CFG_PREFIX "time_window" );
    p_sys->alarm_threshold = var_CreateGetFloat( p_filter, CFG_PREFIX "alarm_threshold" );
    p_sys->repetition_time = var_CreateGetInteger( p_filter, CFG_PREFIX "repetition_time" );
126 127 128 129 130 131
    p_sys->counter = 0;
    p_sys->first = NULL;
    p_sys->last = NULL;
    p_sys->started = 0;
    p_sys->lastAlarm = 0;

132 133 134 135
    p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32;
    p_filter->fmt_out.audio = p_filter->fmt_in.audio;
    p_filter->pf_audio_filter = DoWork;

136
    var_Create( p_filter->p_libvlc, "audiobargraph_v-alarm", VLC_VAR_BOOL );
137
    var_Create( p_filter->p_libvlc, "audiobargraph_v-i_values", VLC_VAR_STRING );
138

139 140 141 142 143 144 145 146 147
    return VLC_SUCCESS;
}

/*****************************************************************************
 * DoWork: treat an audio buffer
 ****************************************************************************/
static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
{
    filter_sys_t *p_sys = p_filter->p_sys;
148
    int i;
149
    float *p_sample = (float *)p_in_buf->p_buffer;
150
    float i_value[AOUT_CHAN_MAX];
151 152 153 154 155
    float ch;
    float max = 0.0;
    ValueDate_t* current = NULL;
    float sum;
    int count = 0;
156

157
    int nbChannels = aout_FormatNbChannels( &p_filter->fmt_in.audio );
158

159
    for (i=0; i<nbChannels; i++) {
160
        i_value[i] = 0.;
161
    }
162

163 164 165
    /* 1 - Compute the peack values */
    for ( i = 0 ; i < (int)(p_in_buf->i_nb_samples); i++ )
    {
166
        for (int j = 0; j<nbChannels; j++) {
167 168 169 170 171 172 173
            ch = (*p_sample++);
            if (ch > i_value[j])
                i_value[j] = ch;
            if (ch > max)
                max = ch;
        }
    }
174
    max = powf( max, 2 );
175

176 177
    if (p_sys->silence) {
        /* 2 - store the new value */
178
        ValueDate_t *new = xmalloc(sizeof(*new));
179 180 181 182 183 184 185 186 187 188
        new->value = max;
        new->date = p_in_buf->i_pts;
        new->next = NULL;
        if (p_sys->last != NULL) {
            p_sys->last->next = new;
        }
        p_sys->last = new;
        if (p_sys->first == NULL) {
            p_sys->first = new;
        }
189

190 191 192 193 194 195 196
        /* 3 - delete too old values */
        while (p_sys->first->date < (new->date - (p_sys->time_window*1000))) {
            p_sys->started = 1; // we have enough values to compute a valid total
            current = p_sys->first;
            p_sys->first = p_sys->first->next;
            free(current);
        }
197

198 199
        /* If last message was sent enough time ago */
        if ((p_sys->started) && (p_in_buf->i_pts > p_sys->lastAlarm + (p_sys->repetition_time*1000))) {
200

201 202 203 204 205 206 207 208
            /* 4 - compute the RMS */
            current = p_sys->first;
            sum = 0.0;
            while (current != NULL) {
                sum += current->value;
                count ++;
                current = current->next;
            }
209 210
            sum /= count;
            sum = sqrtf(sum);
211

212
            /* 5 - compare it to the threshold */
213 214
            var_SetBool(p_filter->p_libvlc, "audiobargraph_v-alarm",
                        sum < p_sys->alarm_threshold);
215

216 217 218 219 220 221 222 223 224 225 226
            p_sys->lastAlarm = p_in_buf->i_pts;
        }
    }

    /*for (i=0; i<nbChannels; i++) {
        value[i] = abs(i_value[i]*100);
        if ( value[i] > p_sys->value[i] - 6 )
            p_sys->value[i] = value[i];
        else
            p_sys->value[i] = p_sys->value[i] - 6;
    }*/
227

228 229 230
    if (p_sys->bargraph) {
        /* 6 - sent the message with the values for the BarGraph */
        if ((nbChannels > 0) && (p_sys->counter%(p_sys->bargraph_repetition) == 0)) {
231 232
            char message[256];
            size_t j = 0;
233

234 235 236 237 238
            for (i = 0; i < nbChannels; i++) {
                if (j >= sizeof (message))
                    break;
                j += snprintf(message + j, sizeof (message),"%f:", i_value[i]);
            }
239

240 241
            message[--j] = '\0';
            msg_Dbg( p_filter, "values: %s", message );
242

243 244
            var_SetString(p_filter->p_libvlc, "audiobargraph_v-i_values",
                          message);
245 246
        }
    }
247

248
    if (p_sys->counter > p_sys->bargraph_repetition*100)
249
        p_sys->counter = 0;
250

251
    p_sys->counter++;
252

253 254 255 256 257 258 259 260 261 262
    return p_in_buf;
}

/*****************************************************************************
 * Close: close the plugin
 *****************************************************************************/
static void Close( vlc_object_t *p_this )
{
    filter_t * p_filter = (filter_t *)p_this;
    filter_sys_t *p_sys = p_filter->p_sys;
263

264
    var_Destroy( p_filter->p_libvlc, "audiobargraph_v-i_values" );
265 266
    var_Destroy( p_filter->p_libvlc, "audiobargraph_v-alarm" );

267
    while (p_sys->first != NULL) {
268
        ValueDate_t *current = p_sys->first;
269 270 271
        p_sys->first = p_sys->first->next;
        free(current);
    }
272
    free( p_sys );
273
}