1 /********************************************************************
3 * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
5 * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
6 * PLEASE READ THESE TERMS DISTRIBUTING. *
8 * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
9 * by Monty <monty@xiph.org> and The XIPHOPHORUS Company *
10 * http://www.xiph.org/ *
12 ********************************************************************
14 function: PCM data envelope analysis and manipulation
15 last mod: $Id: envelope.c,v 1.22 2000/08/31 08:01:34 xiphmont Exp $
19 ********************************************************************/
25 #include "vorbis/codec.h"
33 /* We use a Chebyshev bandbass for the preecho trigger bandpass; it's
34 close enough for sample rates 32000-48000 Hz (corner frequencies at
35 6k/14k assuming sample rate of 44.1kHz) */
37 /* Digital filter designed by mkfilter/mkshape/gencode A.J. Fisher
38 Command line: /www/usr/fisher/helpers/mkfilter -Ch \
39 -6.0000000000e+00 -Bp -o 5 -a 1.3605442177e-01 3.1746031746e-01 -l */
42 static int cheb_bandpass_stages=10;
43 static double cheb_bandpass_gain=5.589612458e+01;
44 static double cheb_bandpass_B[]={-1.,0.,5.,0.,-10.,0.,10.,0.,-5.,0.,1};
45 static double cheb_bandpass_A[]={
58 static int cheb_highpass_stages=10;
59 static double cheb_highpass_gain= 5.291963434e+01;
60 /* z^-stage, z^-stage+1... */
61 static double cheb_highpass_B[]={1,-10,45,-120,210,-252,210,-120,45,-10,1};
62 static double cheb_highpass_A[]={
74 void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi){
76 int window=vi->envelopesa;
79 e->minenergy=fromdB(vi->preecho_minenergy);
80 e->iir=calloc(ch,sizeof(IIR_state));
81 e->filtered=calloc(ch,sizeof(double *));
85 IIR_init(e->iir+i,cheb_highpass_stages,cheb_highpass_gain,
86 cheb_highpass_A,cheb_highpass_B);
87 e->filtered[i]=calloc(e->storage,sizeof(double));
90 drft_init(&e->drft,window);
91 e->window=malloc(e->winlength*sizeof(double));
92 /* We just use a straight sin(x) window for this */
93 for(i=0;i<e->winlength;i++)
94 e->window[i]=sin((i+.5)/e->winlength*M_PI);
97 void _ve_envelope_clear(envelope_lookup *e){
100 IIR_clear((e->iir+i));
101 free(e->filtered[i]);
103 drft_clear(&e->drft);
106 memset(e,0,sizeof(envelope_lookup));
109 static double _ve_deltai(envelope_lookup *ve,IIR_state *iir,
110 double *pre,double *post){
111 long n2=ve->winlength*2;
112 long n=ve->winlength;
114 double *workA=alloca(sizeof(double)*n2),A=0.;
115 double *workB=alloca(sizeof(double)*n2),B=0.;
118 /*_analysis_output("A",frameno,pre,n,0,0);
119 _analysis_output("B",frameno,post,n,0,0);*/
122 workA[i]=pre[i]*ve->window[i];
123 workB[i]=post[i]*ve->window[i];
126 /*_analysis_output("Awin",frameno,workA,n,0,0);
127 _analysis_output("Bwin",frameno,workB,n,0,0);*/
129 drft_forward(&ve->drft,workA);
130 drft_forward(&ve->drft,workB);
132 /* we want to have a 'minimum bar' for energy, else we're just
133 basing blocks on quantization noise that outweighs the signal
134 itself (for low power signals) */
136 double min=ve->minenergy;
138 if(fabs(workA[i])<min)workA[i]=min;
139 if(fabs(workB[i])<min)workB[i]=min;
143 /*_analysis_output("Afft",frameno,workA,n,0,0);
144 _analysis_output("Bfft",frameno,workB,n,0,0);*/
147 A+=workA[i]*workA[i];
148 B+=workB[i]*workB[i];
157 long _ve_envelope_search(vorbis_dsp_state *v,long searchpoint){
158 vorbis_info *vi=v->vi;
159 envelope_lookup *ve=v->ve;
162 /* make sure we have enough storage to match the PCM */
163 if(v->pcm_storage>ve->storage){
164 ve->storage=v->pcm_storage;
165 for(i=0;i<ve->ch;i++)
166 ve->filtered[i]=realloc(ve->filtered[i],ve->storage*sizeof(double));
169 /* catch up the highpass to match the pcm */
170 for(i=0;i<ve->ch;i++){
171 double *filtered=ve->filtered[i];
172 double *pcm=v->pcm[i];
173 IIR_state *iir=ve->iir+i;
175 for(j=ve->current;j<v->pcm_current;j++)
176 filtered[j]=IIR_filter(iir,pcm[j]);
178 ve->current=v->pcm_current;
180 /* Now search through our cached highpass data for breaking points */
183 j=v->centerW+vi->blocksizes[1]/4-vi->blocksizes[0]/4;
187 while(j+ve->winlength<=v->pcm_current){
188 for(i=0;i<ve->ch;i++){
189 double *filtered=ve->filtered[i]+j;
190 IIR_state *iir=ve->iir+i;
191 double m=_ve_deltai(ve,iir,filtered-ve->winlength,filtered);
193 if(m>vi->preecho_thresh){
200 j+=vi->blocksizes[0]/2;
201 if(j>=searchpoint)return(1);
207 void _ve_envelope_shift(envelope_lookup *e,long shift){
210 memmove(e->filtered[i],e->filtered[i]+shift,(e->current-shift)*