mostly wideband tuning...
[speexdsp.git] / libspeex / vbr.c
1 /* Copyright (C) 2002 Jean-Marc Valin 
2    File: vbr.c
3
4    VBR-related routines
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9    
10    - Redistributions of source code must retain the above copyright
11    notice, this list of conditions and the following disclaimer.
12    
13    - Redistributions in binary form must reproduce the above copyright
14    notice, this list of conditions and the following disclaimer in the
15    documentation and/or other materials provided with the distribution.
16    
17    - Neither the name of the Xiph.org Foundation nor the names of its
18    contributors may be used to endorse or promote products derived from
19    this software without specific prior written permission.
20    
21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
25    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33 */
34
35 #include "vbr.h"
36 #include <math.h>
37
38
39 #define sqr(x) ((x)*(x))
40
41 #define MIN_ENERGY 6000
42 #define NOISE_POW .3
43
44
45 float vbr_nb_thresh[8][11]={
46    {-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}, /*   CNG   */
47    { 3.5,  2.5,  2.0,  1.2,  0.5,  0.0, -0.5, -0.7, -0.8, -0.9, -1.0}, /*  2 kbps */
48    { 8.5,  5.6,  4.7,  4.2,  3.9,  3.5,  3.0,  2.5,  2.0,  1.0,  0.0}, /*  6 kbps */
49    {11.0,  8.5,  7.5,  6.5,  5.0,  3.9,  3.9,  3.9,  3.5,  3.0,  1.0}, /*  8 kbps */
50    {11.0, 11.0,  9.9,  9.0,  8.0,  7.0,  6.5,  6.0,  5.0,  4.0,  2.0}, /* 11 kbps */
51    {11.0, 11.0, 11.0, 11.0,  9.5,  9.0,  8.0,  7.0,  6.5,  5.0,  3.0}, /* 15 kbps */
52    {11.0, 11.0, 11.0, 11.0, 11.0, 11.0,  9.5,  8.5,  8.0,  6.5,  4.0}, /* 18 kbps */
53    {11.0, 11.0, 11.0, 11.0, 11.0, 11.0, 11.0, 11.0,  9.8,  7.5,  5.5}  /* 24 kbps */ 
54 };
55
56
57 float vbr_hb_thresh[5][11]={
58    {-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}, /* silence */
59    {-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}, /*  2 kbps */
60    {11.0, 11.0,  9.5,  8.5,  7.5,  6.0,  5.0,  3.9,  3.0,  2.0,  1.0}, /*  6 kbps */
61    {11.0, 11.0, 11.0, 11.0, 11.0,  9.5,  8.7,  7.8,  7.0,  6.5,  4.0}, /* 10 kbps */
62    {11.0, 11.0, 11.0, 11.0, 11.0, 11.0, 11.0, 11.0,  9.8,  7.5,  5.5}  /* 18 kbps */ 
63 };
64
65 float vbr_uhb_thresh[2][11]={
66    {-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}, /* silence */
67    { 3.9,  2.5,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0, -1.0}  /*  2 kbps */
68 };
69
70 void vbr_init(VBRState *vbr)
71 {
72    int i;
73
74    vbr->average_energy=0;
75    vbr->last_energy=1;
76    vbr->accum_sum=0;
77    vbr->energy_alpha=.1;
78    vbr->soft_pitch=0;
79    vbr->last_pitch_coef=0;
80    vbr->last_quality=0;
81
82    vbr->noise_accum = .05*pow(MIN_ENERGY, NOISE_POW);
83    vbr->noise_accum_count=.05;
84    vbr->noise_level=vbr->noise_accum/vbr->noise_accum_count;
85    vbr->consec_noise=0;
86
87
88    for (i=0;i<VBR_MEMORY_SIZE;i++)
89       vbr->last_log_energy[i] = log(MIN_ENERGY);
90 }
91
92
93 /*
94   This function should analyse the signal and decide how critical the
95   coding error will be perceptually. The following factors should be
96   taken into account:
97
98   -Attacks (positive energy derivative) should be coded with more bits
99
100   -Stationary voiced segments should receive more bits
101
102   -Segments with (very) low absolute energy should receive less bits (maybe
103   only shaped noise?)
104
105   -DTX for near-zero energy?
106
107   -Stationary fricative segments should have less bits
108
109   -Temporal masking: when energy slope is decreasing, decrease the bit-rate
110
111   -Decrease bit-rate for males (low pitch)?
112
113   -(wideband only) less bits in the high-band when signal is very 
114   non-stationary (harder to notice high-frequency noise)???
115
116 */
117
118 float vbr_analysis(VBRState *vbr, float *sig, int len, int pitch, float pitch_coef)
119 {
120    int i;
121    float ener=0, ener1=0, ener2=0;
122    float qual=7;
123    int va;
124    float log_energy;
125    float non_st=0;
126    float voicing;
127    float pow_ener;
128
129    for (i=0;i<len>>1;i++)
130       ener1 += sig[i]*sig[i];
131
132    for (i=len>>1;i<len;i++)
133       ener2 += sig[i]*sig[i];
134    ener=ener1+ener2;
135
136    log_energy = log(ener+MIN_ENERGY);
137    for (i=0;i<VBR_MEMORY_SIZE;i++)
138       non_st += sqr(log_energy-vbr->last_log_energy[i]);
139    non_st =  non_st/(30*VBR_MEMORY_SIZE);
140    if (non_st>1)
141       non_st=1;
142
143    voicing = 3*(pitch_coef-.4)*fabs(pitch_coef-.4);
144    vbr->average_energy = (1-vbr->energy_alpha)*vbr->average_energy + vbr->energy_alpha*ener;
145    vbr->noise_level=vbr->noise_accum/vbr->noise_accum_count;
146    pow_ener = pow(ener,NOISE_POW);
147    if (vbr->noise_accum_count<.06 && ener>MIN_ENERGY)
148       vbr->noise_accum = .05*pow_ener;
149
150    if ((voicing<.3 && non_st < .2 && pow_ener < 1.2*vbr->noise_level)
151        || (voicing<.3 && non_st < .05 && pow_ener < 1.5*vbr->noise_level)
152        || (voicing<.4 && non_st < .05 && pow_ener < 1.2*vbr->noise_level)
153        || (voicing<0 && non_st < .05))
154    {
155       float tmp;
156       va = 0;
157       vbr->consec_noise++;
158       if (pow_ener > 3*vbr->noise_level)
159          tmp = 3*vbr->noise_level;
160       else 
161          tmp = pow_ener;
162       if (vbr->consec_noise>=4)
163       {
164          vbr->noise_accum = .95*vbr->noise_accum + .05*tmp;
165          vbr->noise_accum_count = .95*vbr->noise_accum_count + .05;
166       }
167    } else {
168       va = 1;
169       vbr->consec_noise=0;
170    }
171
172    if (pow_ener < vbr->noise_level && ener>MIN_ENERGY)
173    {
174       vbr->noise_accum = .95*vbr->noise_accum + .05*pow_ener;
175       vbr->noise_accum_count = .95*vbr->noise_accum_count + .05;      
176    }
177
178    /* Checking for very low absolute energy */
179    if (ener < 30000)
180    {
181       qual -= .7;
182       if (ener < 10000)
183          qual-=.7;
184       if (ener < 3000)
185          qual-=.7;
186    } else {
187       float short_diff, long_diff;
188       short_diff = log((ener+1)/(1+vbr->last_energy));
189       long_diff = log((ener+1)/(1+vbr->average_energy));
190       /*fprintf (stderr, "%f %f\n", short_diff, long_diff);*/
191
192       if (long_diff<-5)
193          long_diff=-5;
194       if (long_diff>2)
195          long_diff=2;
196
197       if (long_diff>0)
198          qual += .6*long_diff;
199       if (long_diff<0)
200          qual += .5*long_diff;
201       if (short_diff>0)
202       {
203          if (short_diff>5)
204             short_diff=5;
205          qual += .5*short_diff;
206       }
207       /* Checking for energy increases */
208       if (ener2 > 1.6*ener1)
209          qual += .5;
210    }
211    vbr->last_energy = ener;
212    vbr->soft_pitch = .6*vbr->soft_pitch + .4*pitch_coef;
213    qual += 2.2*((pitch_coef-.4) + (vbr->soft_pitch-.4));
214
215    if (qual < vbr->last_quality)
216       qual = .5*qual + .5*vbr->last_quality;
217    if (qual<4)
218       qual=4;
219    if (qual>10)
220       qual=10;
221    
222    /*
223    if (vbr->consec_noise>=2)
224       qual-=1.3;
225    if (vbr->consec_noise>=5)
226       qual-=1.3;
227    if (vbr->consec_noise>=12)
228       qual-=1.3;
229    */
230    if (vbr->consec_noise>=3)
231       qual=4;
232
233    if (vbr->consec_noise)
234       qual -= 1.0 * (log(3.0 + vbr->consec_noise)-log(3));
235    if (qual<0)
236       qual=0;
237    
238    if (ener<60000)
239    {
240       if (vbr->consec_noise>2)
241          qual-=0.5*(log(3.0 + vbr->consec_noise)-log(3));
242       if (ener<10000&&vbr->consec_noise>2)
243          qual-=0.5*(log(3.0 + vbr->consec_noise)-log(3));
244       if (qual<0)
245          qual=0;
246       qual += .3*log(ener/60000.0);
247    }
248    if (qual<-1)
249       qual=-1;
250
251    /*printf ("%f %f %f %f %d\n", qual, voicing, non_st, pow_ener/(.01+vbr->noise_level), va);*/
252
253    vbr->last_pitch_coef = pitch_coef;
254    vbr->last_quality = qual;
255
256    for (i=VBR_MEMORY_SIZE-1;i>0;i--)
257       vbr->last_log_energy[i] = vbr->last_log_energy[i-1];
258    vbr->last_log_energy[0] = log_energy;
259
260    /*printf ("VBR: %f %f %f %d %f\n", (float)(log_energy-log(vbr->average_energy+MIN_ENERGY)), non_st, voicing, va, vbr->noise_level);*/
261
262    return qual;
263 }
264
265 void vbr_destroy(VBRState *vbr)
266 {
267 }