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
14 last mod: $Id: envelope.c,v 1.43 2002/03/23 03:17:33 xiphmont Exp $
16 ********************************************************************/
23 #include "vorbis/codec.h"
24 #include "codec_internal.h"
32 void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi){
33 codec_setup_info *ci=vi->codec_setup;
34 vorbis_info_psy_global *gi=&ci->psy_g_param;
37 int n=e->winlength=ci->blocksizes[0];
38 e->searchstep=ci->blocksizes[0]/VE_DIV; /* not random */
40 e->minenergy=fromdB(gi->preecho_minenergy);
43 e->cursor=ci->blocksizes[1]/2;
44 e->mdct_win=_ogg_calloc(n,sizeof(*e->mdct_win));
45 mdct_init(&e->mdct,n);
48 e->mdct_win[i]=sin((i+.5)/n*M_PI);
49 e->mdct_win[i]*=e->mdct_win[i];
52 /* overlapping bands, assuming 22050 (which is not always true, but
54 /* 2(1.3-3) 4(2.6-6) 8(5.3-12) 16(10.6-18) */
56 e->band[0].begin=rint(1300.f/22050.f*n/4.f)*2.f;
57 e->band[0].end=rint(3000.f/22050.f*n/4.f)*2.f-e->band[0].begin;
58 e->band[1].begin=rint(2600.f/22050.f*n/4.f)*2.f;
59 e->band[1].end=rint(6000.f/22050.f*n/4.f)*2.f-e->band[1].begin;
60 e->band[2].begin=rint(5300.f/22050.f*n/4.f)*2.f;
61 e->band[2].end=rint(12000.f/22050.f*n/4.f)*2.f-e->band[2].begin;
62 e->band[3].begin=rint(10600.f/22050.f*n/4.f)*2.f;
63 e->band[3].end=rint(18000.f/22050.f*n/4.f)*2.f-e->band[3].begin;
65 e->band[0].window=_ogg_malloc((e->band[0].end)*sizeof(*e->band[0].window));
66 e->band[1].window=_ogg_malloc((e->band[1].end)*sizeof(*e->band[1].window));
67 e->band[2].window=_ogg_malloc((e->band[2].end)*sizeof(*e->band[2].window));
68 e->band[3].window=_ogg_malloc((e->band[3].end)*sizeof(*e->band[3].window));
72 e->band[0].window[i]=sin((i+.5)/n*M_PI);
75 e->band[1].window[i]=sin((i+.5)/n*M_PI);
78 e->band[2].window[i]=sin((i+.5)/n*M_PI);
81 e->band[3].window[i]=sin((i+.5)/n*M_PI);
83 e->filter=_ogg_calloc(VE_BANDS*ch,sizeof(*e->filter));
84 e->mark=_ogg_calloc(e->storage,sizeof(*e->mark));
89 void _ve_envelope_clear(envelope_lookup *e){
92 for(i=0;i<VE_BANDS;i++)
93 _ogg_free(e->band[i].window);
94 _ogg_free(e->mdct_win);
97 memset(e,0,sizeof(*e));
100 /* fairly straight threshhold-by-band based until we find something
101 that works better and isn't patented. */
103 static int _ve_amp(envelope_lookup *ve,
104 vorbis_info_psy_global *gi,
106 envelope_band *bands,
107 envelope_filter_state *filters,
109 long n=ve->winlength;
113 /* we want to have a 'minimum bar' for energy, else we're just
114 basing blocks on quantization noise that outweighs the signal
115 itself (for low power signals) */
117 float minV=ve->minenergy,acc[VE_BANDS];
118 float *vec=alloca(n*sizeof(*vec));
119 memset(acc,0,sizeof(acc));
121 /* window and transform */
123 vec[i]=data[i]*ve->mdct_win[i];
124 mdct_forward(&ve->mdct,vec,vec);
126 /* accumulate amplitude by band */
127 for(j=0;j<VE_BANDS;j++){
128 for(i=0;i<bands[j].end;i++){
129 float val=vec[i+bands[j].begin];
130 acc[j]+=val*val*bands[j].window[i];
133 if(acc[j]<minV*minV)acc[j]=minV*minV;
137 /* convert amplitude to delta */
138 for(j=0;j<VE_BANDS;j++){
139 float val=acc[j]-filters[j].ampbuf[filters[j].ampptr];
140 filters[j].ampbuf[filters[j].ampptr]=acc[j];
143 if(filters[j].ampptr>=VE_DIV)filters[j].ampptr=0;
146 /* convolve deltas to threshhold values */
147 for(j=0;j<VE_BANDS;j++){
148 float *buf=filters[j].delbuf;
149 float val=.14*buf[0]+.14*buf[1]+.72*acc[j];
150 buf[0]=buf[1];buf[1]=acc[j];
152 filters[j].markers[pos+1]=val;
155 /* look at local min/max */
156 for(j=0;j<VE_BANDS;j++){
157 float *buf=filters[j].convbuf;
158 if(buf[1]>gi->preecho_thresh[j] && buf[0]<buf[1] && acc[j]<buf[1])ret=1;
159 if(buf[1]<gi->postecho_thresh[j] && buf[0]>buf[1] && acc[j]>buf[1])ret=1;
160 buf[0]=buf[1];buf[1]=acc[j];
166 static ogg_int64_t totalshift=-1024;
168 long _ve_envelope_search(vorbis_dsp_state *v){
169 vorbis_info *vi=v->vi;
170 codec_setup_info *ci=vi->codec_setup;
171 vorbis_info_psy_global *gi=&ci->psy_g_param;
172 envelope_lookup *ve=((backend_lookup_state *)(v->backend_state))->ve;
175 int first=ve->current/ve->searchstep;
176 int last=v->pcm_current/ve->searchstep-VE_DIV;
179 /* make sure we have enough storage to match the PCM */
180 if(last>ve->storage){
181 ve->storage=last+VE_DIV;
182 ve->mark=_ogg_realloc(ve->mark,ve->storage*sizeof(*ve->mark));
185 for(j=first;j<last;j++){
187 for(i=0;i<ve->ch;i++){
188 /* the mark delay is one searchstep because of min/max finder */
189 float *pcm=v->pcm[i]+ve->searchstep*(j+1);
190 ret|=_ve_amp(ve,gi,pcm,ve->band,ve->filter+i*VE_BANDS,j);
193 /* we assume a 'transient' occupies half a short block; this way,
194 it's contained in two short blocks, else the first block is
195 short and the second long, causing smearing */
196 ve->mark[j+VE_DIV/2]=0;
198 for(i=0;i<=VE_DIV/2;i++)
202 ve->current=last*ve->searchstep;
205 long centerW=v->centerW;
208 ci->blocksizes[v->W]/4+
214 while(j<ve->current){
215 if(j>=testW)return(1);
216 if(ve->mark[j/ve->searchstep]){
221 float *marker=alloca(v->pcm_current*sizeof(*marker));
223 memset(marker,0,sizeof(*marker)*v->pcm_current);
225 fprintf(stderr,"mark! seq=%d, cursor:%fs time:%fs\n",
227 (totalshift+ve->cursor)/44100.,
228 (totalshift+j)/44100.);
230 _analysis_output_always("pcmL",seq,v->pcm[0],v->pcm_current,0,0,totalshift);
231 _analysis_output_always("pcmR",seq,v->pcm[1],v->pcm_current,0,0,totalshift);
233 _analysis_output_always("markL",seq,v->pcm[0],j,0,0,totalshift);
234 _analysis_output_always("markR",seq,v->pcm[1],j,0,0,totalshift);
237 for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->filter[0].markers[l]*.01;
238 _analysis_output_always("delL0",seq,marker,v->pcm_current,0,0,totalshift);
239 for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->filter[1].markers[l]*.01;
240 _analysis_output_always("delL1",seq,marker,v->pcm_current,0,0,totalshift);
241 for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->filter[2].markers[l]*.01;
242 _analysis_output_always("delL2",seq,marker,v->pcm_current,0,0,totalshift);
243 for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->filter[3].markers[l]*.01;
244 _analysis_output_always("delL3",seq,marker,v->pcm_current,0,0,totalshift);
245 for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->filter[4].markers[l]*.01;
246 _analysis_output_always("delR0",seq,marker,v->pcm_current,0,0,totalshift);
247 for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->filter[5].markers[l]*.01;
248 _analysis_output_always("delR1",seq,marker,v->pcm_current,0,0,totalshift);
249 for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->filter[6].markers[l]*.01;
250 _analysis_output_always("delR2",seq,marker,v->pcm_current,0,0,totalshift);
251 for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->filter[7].markers[l]*.01;
252 _analysis_output_always("delR3",seq,marker,v->pcm_current,0,0,totalshift);
261 if(j>=testW)return(1);
273 int _ve_envelope_mark(vorbis_dsp_state *v){
274 envelope_lookup *ve=((backend_lookup_state *)(v->backend_state))->ve;
275 vorbis_info *vi=v->vi;
276 codec_setup_info *ci=vi->codec_setup;
277 long centerW=v->centerW;
278 long beginW=centerW-ci->blocksizes[v->W]/4;
279 long endW=centerW+ci->blocksizes[v->W]/4;
281 beginW-=ci->blocksizes[v->lW]/4;
282 endW+=ci->blocksizes[v->nW]/4;
284 beginW-=ci->blocksizes[0]/4;
285 endW+=ci->blocksizes[0]/4;
288 if(ve->curmark>=beginW && ve->curmark<endW)return(1);
290 long first=beginW/ve->searchstep;
291 long last=endW/ve->searchstep;
293 for(i=first;i<last;i++)
294 if(ve->mark[i])return(1);
299 void _ve_envelope_shift(envelope_lookup *e,long shift){
300 int smallsize=e->current/e->searchstep+VE_DIV/2; /* VE_DIV/2 is to
305 int smallshift=shift/e->searchstep;
308 memmove(e->mark,e->mark+smallshift,(smallsize-smallshift)*sizeof(*e->mark));
310 for(i=0;i<VE_BANDS*e->ch;i++)
311 memmove(e->filter[i].markers,
312 e->filter[i].markers+smallshift,
313 (1024-smallshift)*sizeof(*(*e->filter).markers));