1 /********************************************************************
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. *
8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 *
9 * by the XIPHOPHORUS Company http://www.xiph.org/ *
11 ********************************************************************
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 $
18 ********************************************************************/
25 #include "vorbis/codec.h"
26 #include "codec_internal.h"
32 #include "iir.c" /* Yes, ugly, but needed for inlining */
34 /* Digital filter designed by mkfilter/mkshape/gencode A.J. Fisher */
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};
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};
43 /* 10kHz Chebyshev highpass */
44 static float cheb_highpass10k_gain= 54.34519586f;
45 static float cheb_highpass10k_A[]={
53 /* 6kHz-10kHz Chebyshev bandpass */
54 static float cheb_bandpass6k_gain=113.4643935f;
55 static float cheb_bandpass6k_A[]={
63 /* 3kHz-6kHz Chebyshev bandpass */
64 static float cheb_bandpass3k_gain= 248.8359377f;
65 static float cheb_bandpass3k_A[]={
73 /* 1.5kHz-3kHz Chebyshev bandpass */
74 static float cheb_bandpass1k_gain= 1798.537183f;
75 static float cheb_bandpass1k_A[]={
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;
87 int window=e->winlength=ci->blocksizes[0]/2; /* not random */
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));
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);
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]));
113 void _ve_envelope_clear(envelope_lookup *e){
115 for(i=0;i<e->ch*4;i++){
116 IIR_clear((e->iir+i));
117 _ogg_free(e->filtered[i]);
119 _ogg_free(e->filtered);
121 memset(e,0,sizeof(*e));
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;
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) */
135 float minV=ve->minenergy;
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;
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]));
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;
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]);
183 if(flag && ve->current+64<v->pcm_current){
192 ve->current=v->pcm_current;
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;
201 beginW-=ci->blocksizes[v->lW]/4;
203 beginW-=ci->blocksizes[0]/4;
205 if(ve->mark>=centerW && ve->mark<testW)return(0);
206 if(ve->mark>=testW)return(1);
211 j=centerW-ci->blocksizes[0]/4;
213 while(j+ve->winlength*3/2<=v->pcm_current){
214 if(j>=testW)return(1);
217 for(i=0;i<ve->ch;i++){
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);
224 if(m>gi->preecho_thresh[k] || m<gi->postecho_thresh[k]){
226 ve->prevmark=ve->mark=j;
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;
240 ve->prevmark=ve->mark;
242 if(flag>=testW)return(1);
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;
261 beginW-=ci->blocksizes[v->lW]/4;
262 endW+=ci->blocksizes[v->nW]/4;
264 beginW-=ci->blocksizes[0]/4;
265 endW+=ci->blocksizes[0]/4;
268 if(ve->prevmark>=beginW && ve->prevmark<endW)return(1);
269 if(ve->mark>=beginW && ve->mark<endW)return(1);
273 void _ve_envelope_shift(envelope_lookup *e,long shift){
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]));