Changed license to BSD
[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 #ifdef DEBUG
39 #include <stdio.h>
40 #endif
41
42 #define sqr(x) ((x)*(x))
43
44 #define MIN_ENERGY 1000
45 #define NOISE_POW .3
46
47 void vbr_init(VBRState *vbr)
48 {
49    int i;
50
51    vbr->average_energy=0;
52    vbr->last_energy=1;
53    vbr->accum_sum=0;
54    vbr->energy_alpha=.1;
55    vbr->soft_pitch=0;
56    vbr->last_pitch_coef=0;
57    vbr->last_quality=0;
58
59    vbr->noise_accum = .05*pow(MIN_ENERGY, NOISE_POW);
60    vbr->noise_accum_count=.05;
61    vbr->noise_level=vbr->noise_accum/vbr->noise_accum_count;
62    vbr->consec_noise=0;
63
64
65    for (i=0;i<VBR_MEMORY_SIZE;i++)
66       vbr->last_log_energy[i] = log(MIN_ENERGY);
67 }
68
69
70 /*
71   This function should analyse the signal and decide how critical the
72   coding error will be perceptually. The following factors should be
73   taken into account:
74
75   -Attacks (positive energy derivative) should be coded with more bits
76
77   -Stationary voiced segments should receive more bits
78
79   -Segments with (very) low absolute energy should receive less bits (maybe
80   only shaped noise?)
81
82   -DTX for near-zero energy?
83
84   -Stationary fricative segments should have less bits
85
86   -Temporal masking: when energy slope is decreasing, decrease the bit-rate
87
88   -Decrease bit-rate for males (low pitch)?
89
90   -(wideband only) less bits in the high-band when signal is very 
91   non-stationary (harder to notice high-frequency noise)???
92
93 */
94 float vbr_analysis(VBRState *vbr, float *sig, int len, int pitch, float pitch_coef)
95 {
96    int i;
97    float ener=0, ener1=0, ener2=0;
98    float qual=0;
99    int va;
100    float log_energy;
101    float non_st=0;
102    float voicing;
103    float pow_ener;
104
105    for (i=0;i<len>>1;i++)
106       ener1 += sig[i]*sig[i];
107
108    for (i=len>>1;i<len;i++)
109       ener2 += sig[i]*sig[i];
110    ener=ener1+ener2;
111
112    log_energy = log(ener+MIN_ENERGY);
113    for (i=0;i<VBR_MEMORY_SIZE;i++)
114       non_st += sqr(log_energy-vbr->last_log_energy[i]);
115    non_st =  non_st/(30*VBR_MEMORY_SIZE);
116    if (non_st>1)
117       non_st=1;
118
119    voicing = 3*(pitch_coef-.4)*fabs(pitch_coef-.4);
120    vbr->average_energy = (1-vbr->energy_alpha)*vbr->average_energy + vbr->energy_alpha*ener;
121    vbr->noise_level=vbr->noise_accum/vbr->noise_accum_count;
122    pow_ener = pow(ener,NOISE_POW);
123    if ((voicing<.3 && non_st < .2 && pow_ener < 1.2*vbr->noise_level)
124        || (voicing<.2 && non_st < .1))
125    {
126       float tmp;
127       va = 0;
128       vbr->consec_noise++;
129       if (pow_ener > 3*vbr->noise_level)
130          tmp = 3*vbr->noise_level;
131       else 
132          tmp = pow_ener;
133       if (vbr->consec_noise>=4)
134       {
135          vbr->noise_accum = .95*vbr->noise_accum + .05*tmp;
136          vbr->noise_accum_count = .95*vbr->noise_accum_count + .05;
137       }
138    } else {
139       va = 1;
140       vbr->consec_noise=0;
141    }
142
143    /* Checking for "pseudo temporal masking" */
144    if (ener < .1*vbr->average_energy)
145       qual -= .7;
146    if (ener < .01*vbr->average_energy)
147       qual -= .7;
148    if (ener < .001*vbr->average_energy)
149       qual -= .7;
150    /* Checking for very low absolute energy */
151    if (ener < 30000)
152    {
153       qual -= .7;
154       if (ener < 10000)
155          qual-=.7;
156       if (ener < 3000)
157          qual-=.7;
158    } else {
159       /* Checking for energy increases */
160       if (ener > vbr->last_energy*4.0)
161          qual += .7;
162       if (ener > vbr->last_energy*1.8)
163          qual += .7;
164       if (ener > 3*vbr->average_energy)
165          qual += .7;
166       if (ener2 > 1.6*ener1)
167          qual += .7;
168       if (ener2 < .6*ener1)
169          qual -= .5;
170
171       if (ener < .3*vbr->last_energy)
172          qual -= .6;
173    }
174    vbr->soft_pitch = .6*vbr->soft_pitch + .4*pitch_coef;
175    qual += (pitch_coef-.4) + (vbr->soft_pitch-.4);
176
177    if (qual < vbr->last_quality)
178       qual = .5*qual + .5*vbr->last_quality;
179    if (qual<-3)
180       qual=-3;
181    if (qual>3)
182       qual=3;
183
184    if (vbr->consec_noise>=1)
185       qual-=1.2;
186    if (vbr->consec_noise>=4)
187       qual-=1.2;
188    if (vbr->consec_noise>=8)
189       qual-=1.2;
190
191    vbr->last_pitch_coef = pitch_coef;
192    vbr->last_quality = qual;
193
194    for (i=VBR_MEMORY_SIZE-1;i>0;i--)
195       vbr->last_log_energy[i] = vbr->last_log_energy[i-1];
196    vbr->last_log_energy[0] = log_energy;
197
198    /*printf ("VBR: %f %f %f %d %f\n", (float)(log_energy-log(vbr->average_energy+MIN_ENERGY)), non_st, voicing, va, vbr->noise_level);*/
199
200    return qual;
201 }
202
203 void vbr_destroy(VBRState *vbr)
204 {
205 }