Lower the highpass cutoff frequency a bit; midrange has preecho too.
[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 SOURCE IS GOVERNED BY *
5  * THE GNU LESSER/LIBRARY PUBLIC LICENSE, WHICH IS INCLUDED WITH    *
6  * THIS SOURCE. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.        *
7  *                                                                  *
8  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2000             *
9  * by Monty <monty@xiph.org> and the XIPHOPHORUS Company            *
10  * http://www.xiph.org/                                             *
11  *                                                                  *
12  ********************************************************************
13
14  function: PCM data envelope analysis and manipulation
15  last mod: $Id: envelope.c,v 1.30 2001/01/31 23:58:49 xiphmont Exp $
16
17  Preecho calculation.
18
19  ********************************************************************/
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <math.h>
25 #include <ogg/ogg.h>
26 #include "vorbis/codec.h"
27 #include "codec_internal.h"
28
29 #include "os.h"
30 #include "scales.h"
31 #include "envelope.h"
32 #include "misc.h"
33
34 /* Digital filter designed by mkfilter/mkshape/gencode A.J. Fisher
35    Command line: /www/usr/fisher/helpers/mkfilter -Ch \
36    -6.0000000000e+00 -Bp -o 5 -a 1.3605442177e-01 3.1746031746e-01 -l */
37
38 #if 0
39 static int    cheb_bandpass_stages=10;
40 static float cheb_bandpass_gain=5.589612458e+01f;
41 static float cheb_bandpass_B[]={-1.f,0.f,5.f,0.f,-10.f,0.f,
42                                 10.f,0.f,-5.f,0.f,1f};
43 static float cheb_bandpass_A[]={
44   -0.1917409386f,
45   0.0078657069f,
46   -0.7126903444f,
47   0.0266343467f,
48   -1.4047174730f,
49   0.0466964232f,
50   -1.9032773429f,
51   0.0451493360f,
52   -1.4471447397f,
53   0.0303413711f};
54 #endif 
55
56 /* 4kHz Chebyshev highpass */
57 static int    cheb_highpass_stages=10;
58 static float cheb_highpass_gain= 1.314337427e+01f;
59 /* z^-stage, z^-stage+1... */
60 static float cheb_highpass_B[]={1.f,-10.f,45.f,-120.f,210.f,
61                                 -252.f,210.f,-120.f,45.f,-10.f,1.f};
62 static float cheb_highpass_A[]={
63   -0.1013448254f,
64   0.4524819695f,
65   -1.3268091670f,
66   3.2875726855f,
67   -7.2782468961f,
68   13.0298867474f,
69   -17.6698599469f,
70   17.2757670409f,
71   -11.6207967046f,
72   4.8672119675f};
73
74 #if 0
75 /* 6kHz Chebyshev highpass */
76 static int    cheb_highpass_stages=10;
77 static float cheb_highpass_gain= 5.291963434e+01f;
78 /* z^-stage, z^-stage+1... */
79 static float cheb_highpass_B[]={1.f,-10.f,45.f,-120.f,210.f,
80                                 -252.f,210.f,-120.f,45.f,-10.f,1.f};
81 static float cheb_highpass_A[]={
82   -0.1247628029f,
83   0.1334086523f,
84   -0.3997715614f,
85   0.3213011089f,
86   -1.1131924119f,
87   1.7692446626f,
88   -3.6241199038f,
89   4.1950871291f,
90   -4.2771757867f,
91   2.3920318913f};
92 #endif
93
94 void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi){
95   codec_setup_info *ci=vi->codec_setup;
96   int ch=vi->channels;
97   int window=ci->envelopesa;
98   int i;
99   e->winlength=window;
100   e->minenergy=fromdB(ci->preecho_minenergy);
101   e->iir=_ogg_calloc(ch,sizeof(IIR_state));
102   e->filtered=_ogg_calloc(ch,sizeof(float *));
103   e->ch=ch;
104   e->storage=128;
105   for(i=0;i<ch;i++){
106     IIR_init(e->iir+i,cheb_highpass_stages,cheb_highpass_gain,
107              cheb_highpass_A,cheb_highpass_B);
108     e->filtered[i]=_ogg_calloc(e->storage,sizeof(float));
109   }
110
111   drft_init(&e->drft,window);
112   e->window=_ogg_malloc(e->winlength*sizeof(float));
113   /* We just use a straight sin(x) window for this */
114   for(i=0;i<e->winlength;i++)
115     e->window[i]=sin((i+.5)/e->winlength*M_PI);
116 }
117
118 void _ve_envelope_clear(envelope_lookup *e){
119   int i;
120   for(i=0;i<e->ch;i++){
121     IIR_clear((e->iir+i));
122     _ogg_free(e->filtered[i]);
123   }
124   drft_clear(&e->drft);
125   _ogg_free(e->window);
126   _ogg_free(e->filtered);
127   _ogg_free(e->iir);
128   memset(e,0,sizeof(envelope_lookup));
129 }
130
131 /* straight threshhold based until we find something that works better
132    and isn't patented */
133 static float _ve_deltai(envelope_lookup *ve,float *pre,float *post){
134   long n=ve->winlength;
135
136   long i;
137
138   /* we want to have a 'minimum bar' for energy, else we're just
139      basing blocks on quantization noise that outweighs the signal
140      itself (for low power signals) */
141
142   float min=ve->minenergy;
143   float A=min*min*n;
144   float B=A;
145
146   /*_analysis_output("A",granulepos,pre,n,0,0);
147     _analysis_output("B",granulepos,post,n,0,0);*/
148
149   for(i=0;i<n;i++){
150     A+=pre[i]*pre[i];
151     B+=post[i]*post[i];
152   }
153
154   A=todB(A);
155   B=todB(B);
156
157   return(B-A);
158 }
159
160 static float _ve_ampi(envelope_lookup *ve,float *pre){
161   long n=ve->winlength;
162
163   long i;
164
165   /* we want to have a 'minimum bar' for energy, else we're just
166      basing blocks on quantization noise that outweighs the signal
167      itself (for low power signals) */
168
169   float min=ve->minenergy;
170   float A=min*min*n;
171
172   for(i=0;i<n;i++){
173     A+=pre[i]*pre[i];
174   }
175
176   A=todB(A);
177   return(A);
178 }
179
180 long _ve_envelope_search(vorbis_dsp_state *v,long searchpoint){
181   vorbis_info *vi=v->vi;
182   codec_setup_info *ci=vi->codec_setup;
183   envelope_lookup *ve=((backend_lookup_state *)(v->backend_state))->ve;
184   long i,j,k;
185   float *work=alloca(sizeof(float)*ve->winlength*2);
186
187   /* make sure we have enough storage to match the PCM */
188   if(v->pcm_storage>ve->storage){
189     ve->storage=v->pcm_storage;
190     for(i=0;i<ve->ch;i++)
191       ve->filtered[i]=_ogg_realloc(ve->filtered[i],ve->storage*sizeof(float));
192   }
193
194   /* catch up the highpass to match the pcm */
195   for(i=0;i<ve->ch;i++){
196     float *filtered=ve->filtered[i];
197     float *pcm=v->pcm[i];
198     IIR_state *iir=ve->iir+i;
199     int flag=1;
200     
201     for(j=ve->current;j<v->pcm_current;j++){
202       filtered[j]=IIR_filter(iir,pcm[j]);
203       if(pcm[j])flag=0;
204     }
205     if(flag && ve->current+64<v->pcm_current)IIR_reset(iir);
206   }
207
208   ve->current=v->pcm_current;
209
210   /* Now search through our cached highpass data for breaking points */
211   /* starting point */
212   if(v->W)
213     j=v->centerW+ci->blocksizes[1]/4-ci->blocksizes[0]/4;
214   else
215     j=v->centerW;
216   
217   while(j+ve->winlength<=v->pcm_current){
218     for(i=0;i<ve->ch;i++){
219       float *filtered=ve->filtered[i]+j;
220       float m=_ve_deltai(ve,filtered-ve->winlength,filtered);
221       
222       if(m>ci->preecho_thresh){
223         /*granulepos++;*/
224         return(0);
225       }
226       if(m<ci->postecho_thresh){
227         /*granulepos++;*/
228         return(0);
229       }
230       /*granulepos++;*/
231     }
232
233     /* look also for preecho in coupled channel pairs with the center
234        subtracted out (A-B) */
235     for(i=1;i<ve->ch;i+=2){
236       float *filteredA=ve->filtered[i-1]+j-ve->winlength;
237       float *filteredB=ve->filtered[i]+j-ve->winlength;
238       float m;
239
240       for(k=0;k<ve->winlength*2;k++)
241         work[k]=filteredA[k]-filteredB[k];
242
243       m=_ve_deltai(ve,work,work+ve->winlength);
244       
245       if(m>ci->preecho_thresh){
246         /*granulepos++;*/
247         return(0);
248       }
249       if(m<ci->postecho_thresh){
250         /*granulepos++;*/
251         return(0);
252       }
253       /*granulepos++;*/
254     }
255
256
257     j+=min(ci->blocksizes[0],ve->winlength)/2;
258
259     if(j>=searchpoint){
260       return(1);
261     }
262   }
263  
264   return(-1);
265 }
266
267 void _ve_envelope_shift(envelope_lookup *e,long shift){
268   int i;
269   for(i=0;i<e->ch;i++)
270     memmove(e->filtered[i],e->filtered[i]+shift,(e->current-shift)*
271             sizeof(float));
272   e->current-=shift;
273 }
274
275