Initial branch merge toward rc3
[platform/upstream/libvorbis.git] / lib / envelope.c
1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
4  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
5  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
7  *                                                                  *
8  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001             *
9  * by the XIPHOPHORUS Company http://www.xiph.org/                  *
10
11  ********************************************************************
12
13  function: PCM data envelope analysis and manipulation
14  last mod: $Id: envelope.c,v 1.39 2001/12/12 09:45:24 xiphmont Exp $
15
16  Preecho calculation.
17
18  ********************************************************************/
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <math.h>
24 #include <ogg/ogg.h>
25 #include "vorbis/codec.h"
26 #include "codec_internal.h"
27
28 #include "os.h"
29 #include "scales.h"
30 #include "envelope.h"
31 #include "misc.h"
32 #include "iir.c" /* Yes, ugly, but needed for inlining */
33
34 /* Digital filter designed by mkfilter/mkshape/gencode A.J. Fisher */
35
36 static int   cheb_highpass_stages=6;
37 static float cheb_highpass_B[]={1.f,-6.f,15.f,-20.f,15.f,-6.f,1.f};
38
39 static int   cheb_bandpass_stages=6;
40 static float cheb_bandpass_B[]={-1.f,0.f,3.f,0.f,-3.f,0.f,1.f};
41
42
43 /* 10kHz Chebyshev highpass */
44 static float cheb_highpass10k_gain= 54.34519586f;
45 static float cheb_highpass10k_A[]={
46   -0.2064797169f,
47   -0.5609713214f,
48   -1.1352465327f,
49   -1.4495555418f,
50   -1.7938140760f,
51   -0.9473564683f};
52
53 /* 6kHz-10kHz Chebyshev bandpass */
54 static float cheb_bandpass6k_gain=113.4643935f;
55 static float cheb_bandpass6k_A[]={
56   -0.5712621337f,
57   1.5626130710f,
58   -3.3348854983f,
59   4.0471340821f,
60   -4.0051680331f,
61   2.2786325610f};
62
63 /* 3kHz-6kHz Chebyshev bandpass */
64 static float cheb_bandpass3k_gain= 248.8359377f;
65 static float cheb_bandpass3k_A[]={
66   -0.6564230022f,
67   3.3747911257f,
68   -8.0098635981f,
69   11.0040876874f,
70   -9.2250963484f,
71   4.4760355389f};
72
73 /* 1.5kHz-3kHz Chebyshev bandpass */
74 static float cheb_bandpass1k_gain= 1798.537183f;
75 static float cheb_bandpass1k_A[]={
76   -0.8097527363f,
77   4.7725742682f,
78   -11.9800219408f,
79   16.3770336223f,
80   -12.8553129536f,
81   5.4948074309f};
82
83 void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi){
84   codec_setup_info *ci=vi->codec_setup;
85   vorbis_info_psy_global *gi=&ci->psy_g_param;
86   int ch=vi->channels;
87   int window=e->winlength=ci->blocksizes[0]/2; /* not random */
88   int i;
89   e->minenergy=fromdB(gi->preecho_minenergy);
90   e->iir=_ogg_calloc(ch*4,sizeof(*e->iir));
91   e->filtered=_ogg_calloc(ch*4,sizeof(*e->filtered));
92   e->ch=ch;
93   e->storage=128;
94   for(i=0;i<ch*4;i+=4){
95
96     IIR_init(e->iir+i,cheb_highpass_stages,cheb_highpass10k_gain,
97              cheb_highpass10k_A,cheb_highpass_B);
98     IIR_init(e->iir+i+1,cheb_bandpass_stages,cheb_bandpass6k_gain,
99              cheb_bandpass6k_A,cheb_bandpass_B);
100     IIR_init(e->iir+i+2,cheb_bandpass_stages,cheb_bandpass3k_gain,
101              cheb_bandpass3k_A,cheb_bandpass_B);
102     IIR_init(e->iir+i+3,cheb_bandpass_stages,cheb_bandpass1k_gain,
103              cheb_bandpass1k_A,cheb_bandpass_B);
104
105     e->filtered[i]=_ogg_calloc(e->storage,sizeof(*e->filtered[i]));
106     e->filtered[i+1]=_ogg_calloc(e->storage,sizeof(*e->filtered[i+1]));
107     e->filtered[i+2]=_ogg_calloc(e->storage,sizeof(*e->filtered[i+2]));
108     e->filtered[i+3]=_ogg_calloc(e->storage,sizeof(*e->filtered[i+3]));
109   }
110
111 }
112
113 void _ve_envelope_clear(envelope_lookup *e){
114   int i;
115   for(i=0;i<e->ch*4;i++){
116     IIR_clear((e->iir+i));
117     _ogg_free(e->filtered[i]);
118   }
119   _ogg_free(e->filtered);
120   _ogg_free(e->iir);
121   memset(e,0,sizeof(*e));
122 }
123
124 /* straight threshhold based until we find something that works better
125    and isn't patented */
126 static float _ve_deltai(envelope_lookup *ve,float *pre,float *post){
127   long n=ve->winlength;
128
129   long i;
130
131   /* we want to have a 'minimum bar' for energy, else we're just
132      basing blocks on quantization noise that outweighs the signal
133      itself (for low power signals) */
134
135   float minV=ve->minenergy;
136   float A=minV*minV*n;
137   float B=A;
138
139   for(i=0;i<n;i++){
140     A+=pre[i]*pre[i];
141     B+=post[i]*post[i];
142   }
143
144   A=todB(&A);
145   B=todB(&B);
146
147   return(B-A);
148 }
149
150 long _ve_envelope_search(vorbis_dsp_state *v){
151   vorbis_info *vi=v->vi;
152   codec_setup_info *ci=vi->codec_setup;
153   vorbis_info_psy_global *gi=&ci->psy_g_param;
154   envelope_lookup *ve=((backend_lookup_state *)(v->backend_state))->ve;
155   long i,j,k;
156
157   /* make sure we have enough storage to match the PCM */
158   if(v->pcm_storage>ve->storage){
159     ve->storage=v->pcm_storage;
160     for(i=0;i<ve->ch*4;i++)
161       ve->filtered[i]=_ogg_realloc(ve->filtered[i],ve->storage*sizeof(*ve->filtered[i]));
162   }
163
164   /* catch up the highpass to match the pcm */
165   for(i=0;i<ve->ch;i++){
166     float *pcm=v->pcm[i];
167     float *filtered0=ve->filtered[i*4];
168     float *filtered1=ve->filtered[i*4+1];
169     float *filtered2=ve->filtered[i*4+2];
170     float *filtered3=ve->filtered[i*4+3];
171     IIR_state *iir0=ve->iir+i*4;
172     IIR_state *iir1=ve->iir+i*4+1;
173     IIR_state *iir2=ve->iir+i*4+2;
174     IIR_state *iir3=ve->iir+i*4+3;
175     int flag=1;
176     for(j=ve->current;j<v->pcm_current;j++){
177       filtered0[j]=IIR_filter(iir0,pcm[j]);
178       filtered1[j]=IIR_filter_Band(iir1,pcm[j]);
179       filtered2[j]=IIR_filter_Band(iir2,pcm[j]);
180       filtered3[j]=IIR_filter_Band(iir3,pcm[j]);
181       if(pcm[j])flag=0;
182     }
183     if(flag && ve->current+64<v->pcm_current){
184       IIR_reset(iir0);
185       IIR_reset(iir1);
186       IIR_reset(iir2);
187       IIR_reset(iir3);
188     }
189
190   }
191
192   ve->current=v->pcm_current;
193
194   {
195     int flag=-1;
196     long centerW=v->centerW;
197     long beginW=centerW-ci->blocksizes[v->W]/4;
198     //long endW=centerW+ci->blocksizes[v->W]/4+ci->blocksizes[0]/4;
199     long testW=centerW+ci->blocksizes[v->W]/4+ci->blocksizes[1]/2+ci->blocksizes[0]/4;
200     if(v->W)
201       beginW-=ci->blocksizes[v->lW]/4;
202     else
203       beginW-=ci->blocksizes[0]/4;
204
205     if(ve->mark>=centerW && ve->mark<testW)return(0);
206     if(ve->mark>=testW)return(1);
207
208     if(v->W)
209       j=ve->cursor;
210     else
211       j=centerW-ci->blocksizes[0]/4;
212     
213     while(j+ve->winlength*3/2<=v->pcm_current){
214       if(j>=testW)return(1);
215       ve->cursor=j;
216
217       for(i=0;i<ve->ch;i++){
218         for(k=0;k<4;k++){
219           float *filtered=ve->filtered[i*4+k]+j;
220           float *filtered2=ve->filtered[i*4+k]+j+ve->winlength/2;
221           float m=_ve_deltai(ve,filtered-ve->winlength,filtered);
222           float mm=_ve_deltai(ve,filtered2-ve->winlength,filtered2);
223           
224           if(m>gi->preecho_thresh[k] || m<gi->postecho_thresh[k]){
225             if(j<=centerW){
226               ve->prevmark=ve->mark=j;
227             }else{
228               /* if a quarter-short-block advance is an even stronger
229                  reading, set *that* as the impulse point. */
230               if((m>0. && mm>m) || (m<0. && mm<m))
231                 flag=j+ve->winlength/2;
232               else
233                 if(flag<0)flag=j;
234             }
235           }
236         }
237       }
238       
239       if(flag>=0){
240         ve->prevmark=ve->mark;
241         ve->mark=flag;
242         if(flag>=testW)return(1);
243         return(0);
244       }
245       
246       j+=ve->winlength/2;
247     }
248   }
249  
250   return(-1);
251 }
252
253 int _ve_envelope_mark(vorbis_dsp_state *v){
254   envelope_lookup *ve=((backend_lookup_state *)(v->backend_state))->ve;
255   vorbis_info *vi=v->vi;
256   codec_setup_info *ci=vi->codec_setup;
257   long centerW=v->centerW;
258   long beginW=centerW-ci->blocksizes[v->W]/4;
259   long endW=centerW+ci->blocksizes[v->W]/4;
260   if(v->W){
261     beginW-=ci->blocksizes[v->lW]/4;
262     endW+=ci->blocksizes[v->nW]/4;
263   }else{
264     beginW-=ci->blocksizes[0]/4;
265     endW+=ci->blocksizes[0]/4;
266   }
267
268   if(ve->prevmark>=beginW && ve->prevmark<endW)return(1);
269   if(ve->mark>=beginW && ve->mark<endW)return(1);
270   return(0);
271 }
272
273 void _ve_envelope_shift(envelope_lookup *e,long shift){
274   int i;
275   for(i=0;i<e->ch*4;i++)
276     memmove(e->filtered[i],e->filtered[i]+shift,(e->current-shift)*
277             sizeof(*e->filtered[i]));
278   e->current-=shift;
279   if(e->prevmark>=0)
280     e->prevmark-=shift;
281   if(e->mark>=0)
282     e->mark-=shift;
283   e->cursor-=shift;
284 }
285
286