~ubuntu-branches/ubuntu/vivid/linphone/vivid

« back to all changes in this revision

Viewing changes to mediastreamer2/src/msvolume.c

  • Committer: Bazaar Package Importer
  • Author(s): Mark Purcell
  • Date: 2009-10-14 08:26:02 UTC
  • mfrom: (1.3.1 upstream) (6.1.1 sid)
  • Revision ID: james.westby@ubuntu.com-20091014082602-751618nxdjooja3l
Tags: 3.2.1-1
New upstream release 

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
18
*/
19
19
 
 
20
#ifdef HAVE_CONFIG_H
 
21
#include "mediastreamer-config.h"
 
22
#endif
 
23
 
20
24
#include "mediastreamer2/msvolume.h"
 
25
#include "mediastreamer2/msticker.h"
21
26
#include <math.h>
22
27
 
 
28
#ifdef HAVE_SPEEXDSP
 
29
#include <speex/speex_preprocess.h>
 
30
#endif
 
31
 
23
32
static const float max_e=32767*32767;
24
33
static const float coef=0.1;
25
34
static const float gain_k=0.02;
30
39
typedef struct Volume{
31
40
        float energy;
32
41
        float norm_en;
33
 
        float gain;
34
 
        float static_gain;
 
42
        float gain; /*the one really applied, smoothed by noise gate and echo limiter*/
 
43
        float static_gain; /*the one fixed by the user*/
35
44
        float gain_k;
36
45
        float thres;
37
46
        float force;
 
47
        float target_gain; /*the target gain choosed by echo limiter and noise gate*/
 
48
        float last_peer_en;
 
49
        int sustain_time; /* time in ms for which echo limiter remains active after resuming from speech to silence.*/
 
50
        uint64_t sustain_start;
38
51
        MSFilter *peer;
 
52
#ifdef HAVE_SPEEXDSP
 
53
        SpeexPreprocessState *speex_pp;
 
54
#endif
 
55
        int sample_rate;
 
56
        int nsamples;
 
57
        int ng_cut_time; /*noise gate cut time, after last speech detected*/
 
58
        int ng_noise_dur;
 
59
        float ng_threshold;
 
60
        MSBufferizer *buffer;
39
61
        bool_t ea_active;
 
62
        bool_t agc_enabled;
 
63
        bool_t noise_gate_enabled;
40
64
}Volume;
41
65
 
42
66
static void volume_init(MSFilter *f){
49
73
        v->thres=noise_thres;
50
74
        v->force=en_weight;
51
75
        v->peer=NULL;
 
76
        v->last_peer_en=0;
 
77
        v->sustain_time=200;
 
78
        v->sustain_start=0;
 
79
        v->agc_enabled=FALSE;
 
80
        v->buffer=ms_bufferizer_new();
 
81
        v->sample_rate=8000;
 
82
        v->nsamples=80;
 
83
        v->noise_gate_enabled=FALSE;
 
84
        v->ng_cut_time=100;/*milliseconds*/
 
85
        v->ng_noise_dur=0;
 
86
        v->ng_threshold=noise_thres;
 
87
#ifdef HAVE_SPEEXDSP
 
88
        v->speex_pp=NULL;
 
89
#endif
52
90
        f->data=v;
53
91
}
54
92
 
55
93
static void volume_uninit(MSFilter *f){
 
94
        Volume *v=(Volume*)f->data;
 
95
#ifdef HAVE_SPEEXDSP
 
96
        if (v->speex_pp)
 
97
                speex_preprocess_state_destroy(v->speex_pp);
 
98
#endif
 
99
        ms_bufferizer_destroy(v->buffer);
56
100
        ms_free(f->data);
57
101
}
58
102
 
63
107
        return 0;
64
108
}
65
109
 
 
110
static int volume_set_sample_rate(MSFilter *f, void *arg){
 
111
        Volume *v=(Volume*)f->data;
 
112
        v->sample_rate=*(int*)arg;
 
113
        return 0;
 
114
}
 
115
 
66
116
static int volume_get_linear(MSFilter *f, void *arg){
67
117
        float *farg=(float*)arg;
68
118
        Volume *v=(Volume*)f->data;
69
119
        *farg=(v->energy+1)/max_e;
70
120
        return 0;
71
121
}
 
122
#ifdef HAVE_SPEEXDSP
 
123
static void volume_agc_process(Volume *v, mblk_t *om){
 
124
        speex_preprocess_run(v->speex_pp,(int16_t*)om->b_rptr);
 
125
}
 
126
#else
 
127
 
 
128
static void volume_agc_process(Volume *v, mblk_t *om){
 
129
}
 
130
 
 
131
#endif
 
132
 
72
133
 
73
134
static inline float compute_gain(float static_gain, float energy, float weight){
74
135
        float ret=static_gain*(1 - (energy*weight));
76
137
        return ret;
77
138
}
78
139
 
79
 
static void volume_echo_avoider_process(Volume *v){
 
140
/*
 
141
The principle of this algorithm is that we apply a gain to the input signal which is opposite to the 
 
142
energy measured by the peer MSVolume.
 
143
For example if some noise is played by the speaker, then the signal captured by the microphone will be lowered.
 
144
The gain changes smoothly when the peer energy is decreasing, but is immediately changed when the peer energy is 
 
145
increasing.
 
146
*/
 
147
 
 
148
static void volume_echo_avoider_process(Volume *v, uint64_t curtime){
80
149
        float peer_e;
81
150
        float gain;
82
151
        ms_filter_call_method(v->peer,MS_VOLUME_GET_LINEAR,&peer_e);
85
154
                if (peer_e>v->thres){
86
155
                        /*lower our output*/
87
156
                        gain=compute_gain(v->static_gain,peer_e,v->force);
 
157
                        if (peer_e>v->last_peer_en)
 
158
                                v->gain=gain;
88
159
                }else {
89
 
                        gain=v->static_gain;
 
160
                        v->sustain_start=curtime;
90
161
                        v->ea_active=FALSE;
 
162
                        gain=v->gain;
91
163
                }
92
 
                v->gain=(v->gain*(1-v->gain_k)) + (v->gain_k*gain);
93
164
        }else{
94
165
                int peer_active=FALSE;
95
166
                ms_filter_call_method(v->peer,MS_VOLUME_GET_EA_STATE,&peer_active);
99
170
                        v->ea_active=TRUE;
100
171
                        v->gain=gain;
101
172
                }else {
102
 
                        gain=v->static_gain;
103
 
                        v->gain=(v->gain*(1-v->gain_k)) + (v->gain_k*gain);
 
173
                        if (curtime!=0 && (curtime-v->sustain_start)<v->sustain_time){
 
174
                                gain=v->gain;
 
175
                        }else{/*restore normal gain*/
 
176
                                gain=v->static_gain;
 
177
                                v->sustain_start=0;
 
178
                        }
104
179
                }
105
180
        }
106
 
        
 
181
        v->last_peer_en=peer_e;
 
182
        v->target_gain=gain;
107
183
        ms_message("ea_active=%i, peer_e=%f gain=%f gain_k=%f force=%f",v->ea_active,peer_e,v->gain, v->gain_k,v->force);
108
184
}
109
185
 
 
186
static void volume_noise_gate_process(Volume *v , float energy, mblk_t *om){
 
187
        int nsamples=((om->b_wptr-om->b_rptr)/2);
 
188
        if ((energy/max_e)<v->ng_threshold){
 
189
                v->ng_noise_dur+=(nsamples*1000)/v->sample_rate;
 
190
                if (v->ng_noise_dur>v->ng_cut_time){
 
191
                        v->target_gain=0;
 
192
                }
 
193
        }else{
 
194
                v->ng_noise_dur=0;
 
195
                /*let the target gain unchanged, ie let the echo-limiter choose the gain*/
 
196
        }
 
197
}
 
198
 
110
199
static int volume_set_gain(MSFilter *f, void *arg){
111
200
        float *farg=(float*)arg;
112
201
        Volume *v=(Volume*)f->data;
113
 
        v->gain=v->static_gain=*farg;
 
202
        v->gain=v->static_gain=v->target_gain=*farg;
114
203
        return 0;
115
204
}
116
205
 
129
218
        return 0;
130
219
}
131
220
 
 
221
static int volume_set_agc(MSFilter *f, void *arg){
 
222
        Volume *v=(Volume*)f->data;
 
223
        v->agc_enabled=*(int*)arg;
 
224
        return 0;
 
225
}
 
226
 
132
227
static int volume_set_ea_threshold(MSFilter *f, void*arg){
133
228
        Volume *v=(Volume*)f->data;
134
229
        float val=*(float*)arg;
158
253
        return 0;
159
254
}
160
255
 
 
256
static int volume_set_ea_sustain(MSFilter *f, void *arg){
 
257
        Volume *v=(Volume*)f->data;
 
258
        v->sustain_time=*(int*)arg;
 
259
        return 0;
 
260
}
 
261
 
 
262
static int volume_enable_noise_gate(MSFilter *f, void *arg){
 
263
        Volume *v=(Volume*)f->data;
 
264
        v->noise_gate_enabled=*(int*)arg;
 
265
        return 0;
 
266
}
 
267
 
 
268
static int volume_set_noise_gate_threshold(MSFilter *f, void *arg){
 
269
        Volume *v=(Volume*)f->data;
 
270
        v->ng_threshold=*(float*)arg;
 
271
        return 0;
 
272
}
 
273
 
161
274
static inline int16_t saturate(float val){
162
275
        return (val>32767) ? 32767 : ( (val<-32767) ? -32767 : val);
163
276
}
164
277
 
 
278
static float update_energy(int16_t *signal, int numsamples, float last_energy_value){
 
279
        int i;
 
280
        float en=last_energy_value;
 
281
        for (i=0;i<numsamples;++i){
 
282
                float s=(float)signal[i];
 
283
                en=(s*s*coef) + (1.0-coef)*en;
 
284
        }
 
285
        return en;
 
286
}
 
287
 
 
288
static void apply_gain(Volume *v, mblk_t *m){
 
289
        int16_t *sample;
 
290
        float gain=v->target_gain;
 
291
 
 
292
        if (gain==1 && v->gain==1) return;
 
293
        v->gain=(v->gain*(1-v->gain_k)) + (v->gain_k*gain);
 
294
        for (   sample=(int16_t*)m->b_rptr;
 
295
                                sample<(int16_t*)m->b_wptr;
 
296
                                ++sample){
 
297
                float s=*sample;
 
298
                *sample=saturate(s*v->gain);
 
299
        }
 
300
}
 
301
 
 
302
static void volume_preprocess(MSFilter *f){
 
303
        Volume *v=(Volume*)f->data;
 
304
        /*process agc by chunks of 10 ms*/
 
305
        v->nsamples=(int)(0.01*(float)v->sample_rate);
 
306
        if (v->agc_enabled){
 
307
                ms_message("AGC is enabled.");
 
308
#ifdef HAVE_SPEEXDSP
 
309
                if (v->speex_pp==NULL){
 
310
                        int tmp=1;
 
311
                        v->speex_pp=speex_preprocess_state_init(v->nsamples,v->sample_rate);
 
312
                        if (speex_preprocess_ctl(v->speex_pp,SPEEX_PREPROCESS_SET_AGC,&tmp)==-1){
 
313
                                ms_warning("Speex AGC is not available.");
 
314
                        }
 
315
                        tmp=0;
 
316
                        speex_preprocess_ctl(v->speex_pp,SPEEX_PREPROCESS_SET_VAD,&tmp);
 
317
                        speex_preprocess_ctl(v->speex_pp,SPEEX_PREPROCESS_SET_DENOISE,&tmp);
 
318
                        speex_preprocess_ctl(v->speex_pp,SPEEX_PREPROCESS_SET_DEREVERB,&tmp);
 
319
                }
 
320
#else
 
321
                ms_error("No AGC possible, mediastreamer2 was compiled without libspeexdsp.");
 
322
#endif
 
323
        }
 
324
}
 
325
 
 
326
 
 
327
 
165
328
static void volume_process(MSFilter *f){
166
329
        mblk_t *m;
167
 
        int16_t *sample;
168
330
        Volume *v=(Volume*)f->data;
169
331
        float en=v->energy;
170
 
        while((m=ms_queue_get(f->inputs[0]))!=NULL){
171
 
                for (   sample=(int16_t*)m->b_rptr;
172
 
                        sample<(int16_t*)m->b_wptr;
173
 
                        ++sample){
174
 
                        float s=*sample;
175
 
                        en=(s*s*coef) + (1.0-coef)*en;
176
 
                }
177
 
                if (v->peer){
178
 
                        volume_echo_avoider_process(v); 
179
 
                }
180
 
                if (v->gain!=1){
181
 
                        for (   sample=(int16_t*)m->b_rptr;
182
 
                                sample<(int16_t*)m->b_wptr;
183
 
                                ++sample){
184
 
                                float s=*sample;
185
 
                                *sample=saturate(s*v->gain);
186
 
                        }
187
 
                }
188
 
                ms_queue_put(f->outputs[0],m);
 
332
 
 
333
        if (v->agc_enabled){
 
334
                mblk_t *om;
 
335
                int nbytes=v->nsamples*2;
 
336
                ms_bufferizer_put_from_queue(v->buffer,f->inputs[0]);
 
337
                while(ms_bufferizer_get_avail(v->buffer)>=nbytes){
 
338
                        om=allocb(nbytes,0);
 
339
                        ms_bufferizer_read(v->buffer,om->b_wptr,nbytes);
 
340
                        om->b_wptr+=nbytes;
 
341
                        en=update_energy((int16_t*)om->b_rptr,v->nsamples,en);
 
342
                        volume_agc_process(v,om);
 
343
        
 
344
                        if (v->peer){
 
345
                                volume_echo_avoider_process(v,f->ticker->time);
 
346
                        }else v->target_gain=v->static_gain;
 
347
 
 
348
                        if (v->noise_gate_enabled)
 
349
                                volume_noise_gate_process(v,en,om);
 
350
                        apply_gain(v,om);
 
351
                        ms_queue_put(f->outputs[0],om);
 
352
                }
 
353
        }else{
 
354
                /*light processing: no agc. Work in place in the input buffer*/
 
355
                while((m=ms_queue_get(f->inputs[0]))!=NULL){
 
356
                        en=update_energy((int16_t*)m->b_rptr,(m->b_wptr-m->b_rptr)/2,en);
 
357
                        if (v->peer){
 
358
                                volume_echo_avoider_process(v,f->ticker->time); 
 
359
                        }else v->target_gain=v->static_gain;
 
360
 
 
361
                        if (v->noise_gate_enabled)
 
362
                                volume_noise_gate_process(v,en,m);
 
363
                        apply_gain(v,m);
 
364
                        ms_queue_put(f->outputs[0],m);
 
365
                }
189
366
        }
190
367
        v->energy=en;
191
368
}
199
376
        {       MS_VOLUME_SET_EA_THRESHOLD ,    volume_set_ea_threshold },
200
377
        {       MS_VOLUME_SET_EA_SPEED  ,       volume_set_ea_speed     },
201
378
        {       MS_VOLUME_SET_EA_FORCE  ,       volume_set_ea_force     },
 
379
        {       MS_VOLUME_SET_EA_SUSTAIN,       volume_set_ea_sustain   },
 
380
        {       MS_FILTER_SET_SAMPLE_RATE,      volume_set_sample_rate  },
 
381
        {       MS_VOLUME_ENABLE_AGC    ,       volume_set_agc          },
 
382
        {       MS_VOLUME_ENABLE_NOISE_GATE,    volume_enable_noise_gate},
 
383
        {       MS_VOLUME_SET_NOISE_GATE_THRESHOLD,     volume_set_noise_gate_threshold},
202
384
        {       0                       ,       NULL                    }
203
385
};
204
386
 
205
387
#ifndef _MSC_VER
206
388
MSFilterDesc ms_volume_desc={
207
389
        .name="MSVolume",
208
 
        .text=N_("A filter to make level measurements on 16 bits pcm audio stream"),
 
390
        .text=N_("A filter that controls and measure sound volume"),
209
391
        .id=MS_VOLUME_ID,
210
392
        .category=MS_FILTER_OTHER,
211
393
        .ninputs=1,
212
394
        .noutputs=1,
213
395
        .init=volume_init,
214
396
        .uninit=volume_uninit,
 
397
        .preprocess=volume_preprocess,
215
398
        .process=volume_process,
216
399
        .methods=methods
217
400
};
219
402
MSFilterDesc ms_volume_desc={
220
403
        MS_VOLUME_ID,
221
404
        "MSVolume",
222
 
        N_("A filter to make level measurements on 16 bits pcm audio stream"),
 
405
        N_("A filter that controls and measure sound volume"),
223
406
        MS_FILTER_OTHER,
224
407
        NULL,
225
408
        1,
226
409
        1,
227
410
        volume_init,
228
 
        NULL,
 
411
        volume_preprocess,
229
412
        volume_process,
230
413
        NULL,
231
414
        volume_uninit,