Initial beta 4 merge
[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.29 2001/01/22 01:38:24 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 /* We use a Chebyshev bandbass for the preecho trigger bandpass; it's
35    close enough for sample rates 32000-48000 Hz (corner frequencies at
36    6k/14k assuming sample rate of 44.1kHz) */
37
38 /* Digital filter designed by mkfilter/mkshape/gencode A.J. Fisher
39    Command line: /www/usr/fisher/helpers/mkfilter -Ch \
40    -6.0000000000e+00 -Bp -o 5 -a 1.3605442177e-01 3.1746031746e-01 -l */
41
42 #if 0
43 static int    cheb_bandpass_stages=10;
44 static float cheb_bandpass_gain=5.589612458e+01f;
45 static float cheb_bandpass_B[]={-1.f,0.f,5.f,0.f,-10.f,0.f,
46                                 10.f,0.f,-5.f,0.f,1f};
47 static float cheb_bandpass_A[]={
48   -0.1917409386f,
49   0.0078657069f,
50   -0.7126903444f,
51   0.0266343467f,
52   -1.4047174730f,
53   0.0466964232f,
54   -1.9032773429f,
55   0.0451493360f,
56   -1.4471447397f,
57   0.0303413711f};
58 #endif 
59
60 static int    cheb_highpass_stages=10;
61 static float cheb_highpass_gain= 5.291963434e+01f;
62 /* z^-stage, z^-stage+1... */
63 static float cheb_highpass_B[]={1.f,-10.f,45.f,-120.f,210.f,
64                                 -252.f,210.f,-120.f,45.f,-10.f,1.f};
65 static float cheb_highpass_A[]={
66   -0.1247628029f,
67   0.1334086523f,
68   -0.3997715614f,
69   0.3213011089f,
70   -1.1131924119f,
71   1.7692446626f,
72   -3.6241199038f,
73   4.1950871291f,
74   -4.2771757867f,
75   2.3920318913f};
76
77 void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi){
78   codec_setup_info *ci=vi->codec_setup;
79   int ch=vi->channels;
80   int window=ci->envelopesa;
81   int i;
82   e->winlength=window;
83   e->minenergy=fromdB(ci->preecho_minenergy);
84   e->iir=_ogg_calloc(ch,sizeof(IIR_state));
85   e->filtered=_ogg_calloc(ch,sizeof(float *));
86   e->ch=ch;
87   e->storage=128;
88   for(i=0;i<ch;i++){
89     IIR_init(e->iir+i,cheb_highpass_stages,cheb_highpass_gain,
90              cheb_highpass_A,cheb_highpass_B);
91     e->filtered[i]=_ogg_calloc(e->storage,sizeof(float));
92   }
93
94   drft_init(&e->drft,window);
95   e->window=_ogg_malloc(e->winlength*sizeof(float));
96   /* We just use a straight sin(x) window for this */
97   for(i=0;i<e->winlength;i++)
98     e->window[i]=sin((i+.5)/e->winlength*M_PI);
99 }
100
101 void _ve_envelope_clear(envelope_lookup *e){
102   int i;
103   for(i=0;i<e->ch;i++){
104     IIR_clear((e->iir+i));
105     _ogg_free(e->filtered[i]);
106   }
107   drft_clear(&e->drft);
108   _ogg_free(e->window);
109   _ogg_free(e->filtered);
110   _ogg_free(e->iir);
111   memset(e,0,sizeof(envelope_lookup));
112 }
113
114 /* straight threshhold based until we find something that works better
115    and isn't patented */
116 static float _ve_deltai(envelope_lookup *ve,float *pre,float *post){
117   long n=ve->winlength;
118
119   long i;
120
121   /* we want to have a 'minimum bar' for energy, else we're just
122      basing blocks on quantization noise that outweighs the signal
123      itself (for low power signals) */
124
125   float min=ve->minenergy;
126   float A=min*min*n;
127   float B=A;
128
129   /*_analysis_output("A",granulepos,pre,n,0,0);
130     _analysis_output("B",granulepos,post,n,0,0);*/
131
132   for(i=0;i<n;i++){
133     A+=pre[i]*pre[i];
134     B+=post[i]*post[i];
135   }
136
137   A=todB(A);
138   B=todB(B);
139
140   return(B-A);
141 }
142
143 static float _ve_ampi(envelope_lookup *ve,float *pre){
144   long n=ve->winlength;
145
146   long i;
147
148   /* we want to have a 'minimum bar' for energy, else we're just
149      basing blocks on quantization noise that outweighs the signal
150      itself (for low power signals) */
151
152   float min=ve->minenergy;
153   float A=min*min*n;
154
155   for(i=0;i<n;i++){
156     A+=pre[i]*pre[i];
157   }
158
159   A=todB(A);
160   return(A);
161 }
162
163 long _ve_envelope_search(vorbis_dsp_state *v,long searchpoint){
164   vorbis_info *vi=v->vi;
165   codec_setup_info *ci=vi->codec_setup;
166   envelope_lookup *ve=((backend_lookup_state *)(v->backend_state))->ve;
167   long i,j;
168
169   /* make sure we have enough storage to match the PCM */
170   if(v->pcm_storage>ve->storage){
171     ve->storage=v->pcm_storage;
172     for(i=0;i<ve->ch;i++)
173       ve->filtered[i]=_ogg_realloc(ve->filtered[i],ve->storage*sizeof(float));
174   }
175
176   /* catch up the highpass to match the pcm */
177   for(i=0;i<ve->ch;i++){
178     float *filtered=ve->filtered[i];
179     float *pcm=v->pcm[i];
180     IIR_state *iir=ve->iir+i;
181     int flag=1;
182     
183     for(j=ve->current;j<v->pcm_current;j++){
184       filtered[j]=IIR_filter(iir,pcm[j]);
185       if(pcm[j])flag=0;
186     }
187     if(flag && ve->current+64<v->pcm_current)IIR_reset(iir);
188   }
189
190   ve->current=v->pcm_current;
191
192   /* Now search through our cached highpass data for breaking points */
193   /* starting point */
194   if(v->W)
195     j=v->centerW+ci->blocksizes[1]/4-ci->blocksizes[0]/4;
196   else
197     j=v->centerW;
198   
199   while(j+ve->winlength<=v->pcm_current){
200     for(i=0;i<ve->ch;i++){
201       float *filtered=ve->filtered[i]+j;
202       float m=_ve_deltai(ve,filtered-ve->winlength,filtered);
203       
204       if(m>ci->preecho_thresh){
205         /*granulepos++;*/
206         return(0);
207       }
208       if(m<ci->postecho_thresh){
209         /*granulepos++;*/
210         return(0);
211       }
212       /*granulepos++;*/
213     }
214     
215     j+=min(ci->blocksizes[0],ve->winlength)/2;
216
217     if(j>=searchpoint){
218       return(1);
219     }
220   }
221  
222   return(-1);
223 }
224
225 void _ve_envelope_shift(envelope_lookup *e,long shift){
226   int i;
227   for(i=0;i<e->ch;i++)
228     memmove(e->filtered[i],e->filtered[i]+shift,(e->current-shift)*
229             sizeof(float));
230   e->current-=shift;
231 }
232
233