1 /********************************************************************
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. *
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/ *
12 ********************************************************************
14 function: PCM data envelope analysis and manipulation
15 last mod: $Id: envelope.c,v 1.28 2000/12/21 21:04:39 xiphmont Exp $
19 ********************************************************************/
26 #include "vorbis/codec.h"
27 #include "codec_internal.h"
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) */
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 */
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[]={
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[]={
77 void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi){
78 codec_setup_info *ci=vi->codec_setup;
80 int window=ci->envelopesa;
83 e->minenergy=fromdB(ci->preecho_minenergy);
84 e->iir=_ogg_calloc(ch,sizeof(IIR_state));
85 e->filtered=_ogg_calloc(ch,sizeof(float *));
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));
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);
101 void _ve_envelope_clear(envelope_lookup *e){
103 for(i=0;i<e->ch;i++){
104 IIR_clear((e->iir+i));
105 _ogg_free(e->filtered[i]);
107 drft_clear(&e->drft);
108 _ogg_free(e->window);
109 _ogg_free(e->filtered);
111 memset(e,0,sizeof(envelope_lookup));
114 static float _ve_deltai(envelope_lookup *ve,
115 float *pre,float *post){
116 long n2=ve->winlength*2;
117 long n=ve->winlength;
119 float *workA=alloca(sizeof(float)*n2),A=0.f;
120 float *workB=alloca(sizeof(float)*n2),B=0.f;
123 /*_analysis_output("A",granulepos,pre,n,0,0);
124 _analysis_output("B",granulepos,post,n,0,0);*/
127 workA[i]=pre[i]*ve->window[i];
128 workB[i]=post[i]*ve->window[i];
131 /*_analysis_output("Awin",granulepos,workA,n,0,0);
132 _analysis_output("Bwin",granulepos,workB,n,0,0);*/
134 drft_forward(&ve->drft,workA);
135 drft_forward(&ve->drft,workB);
137 /* we want to have a 'minimum bar' for energy, else we're just
138 basing blocks on quantization noise that outweighs the signal
139 itself (for low power signals) */
141 float min=ve->minenergy;
143 if(fabs(workA[i])<min)workA[i]=min;
144 if(fabs(workB[i])<min)workB[i]=min;
148 /*_analysis_output("Afft",granulepos,workA,n,0,0);
149 _analysis_output("Bfft",granulepos,workB,n,0,0);*/
152 A+=workA[i]*workA[i];
153 B+=workB[i]*workB[i];
162 long _ve_envelope_search(vorbis_dsp_state *v,long searchpoint){
163 vorbis_info *vi=v->vi;
164 codec_setup_info *ci=vi->codec_setup;
165 envelope_lookup *ve=((backend_lookup_state *)(v->backend_state))->ve;
168 /* make sure we have enough storage to match the PCM */
169 if(v->pcm_storage>ve->storage){
170 ve->storage=v->pcm_storage;
171 for(i=0;i<ve->ch;i++)
172 ve->filtered[i]=_ogg_realloc(ve->filtered[i],ve->storage*sizeof(float));
175 /* catch up the highpass to match the pcm */
176 for(i=0;i<ve->ch;i++){
177 float *filtered=ve->filtered[i];
178 float *pcm=v->pcm[i];
179 IIR_state *iir=ve->iir+i;
182 for(j=ve->current;j<v->pcm_current;j++){
183 filtered[j]=IIR_filter(iir,pcm[j]);
186 if(flag && ve->current+64<v->pcm_current)IIR_reset(iir);
189 ve->current=v->pcm_current;
191 /* Now search through our cached highpass data for breaking points */
194 j=v->centerW+ci->blocksizes[1]/4-ci->blocksizes[0]/4;
198 while(j+ve->winlength<=v->pcm_current){
199 for(i=0;i<ve->ch;i++){
200 float *filtered=ve->filtered[i]+j;
201 float m=_ve_deltai(ve,filtered-ve->winlength,filtered);
203 if(m>ci->preecho_thresh){
210 j+=ci->blocksizes[0]/2;
211 if(j>=searchpoint)return(1);
217 void _ve_envelope_shift(envelope_lookup *e,long shift){
220 memmove(e->filtered[i],e->filtered[i]+shift,(e->current-shift)*