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-2009 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
11 ********************************************************************
13 function: PCM data envelope analysis
14 last mod: $Id: envelope.c 16227 2009-07-08 06:58:46Z xiphmont $
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
=128;
38 e
->searchstep
=64; /* not random */
40 e
->minenergy
=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
/(n
-1.)*M_PI
);
49 e
->mdct_win
[i
]*=e
->mdct_win
[i
];
53 e
->band
[0].begin
=2; e
->band
[0].end
=4;
54 e
->band
[1].begin
=4; e
->band
[1].end
=5;
55 e
->band
[2].begin
=6; e
->band
[2].end
=6;
56 e
->band
[3].begin
=9; e
->band
[3].end
=8;
57 e
->band
[4].begin
=13; e
->band
[4].end
=8;
58 e
->band
[5].begin
=17; e
->band
[5].end
=8;
59 e
->band
[6].begin
=22; e
->band
[6].end
=8;
61 for(j
=0;j
<VE_BANDS
;j
++){
63 e
->band
[j
].window
=_ogg_malloc(n
*sizeof(*e
->band
[0].window
));
65 e
->band
[j
].window
[i
]=sin((i
+.5)/n
*M_PI
);
66 e
->band
[j
].total
+=e
->band
[j
].window
[i
];
68 e
->band
[j
].total
=1./e
->band
[j
].total
;
71 e
->filter
=_ogg_calloc(VE_BANDS
*ch
,sizeof(*e
->filter
));
72 e
->mark
=_ogg_calloc(e
->storage
,sizeof(*e
->mark
));
76 void _ve_envelope_clear(envelope_lookup
*e
){
79 for(i
=0;i
<VE_BANDS
;i
++)
80 _ogg_free(e
->band
[i
].window
);
81 _ogg_free(e
->mdct_win
);
84 memset(e
,0,sizeof(*e
));
87 /* fairly straight threshhold-by-band based until we find something
88 that works better and isn't patented. */
90 static int _ve_amp(envelope_lookup
*ve
,
91 vorbis_info_psy_global
*gi
,
94 envelope_filter_state
*filters
){
100 /* we want to have a 'minimum bar' for energy, else we're just
101 basing blocks on quantization noise that outweighs the signal
102 itself (for low power signals) */
104 float minV
=ve
->minenergy
;
105 float *vec
=alloca(n
*sizeof(*vec
));
107 /* stretch is used to gradually lengthen the number of windows
108 considered prevoius-to-potential-trigger */
109 int stretch
=max(VE_MINSTRETCH
,ve
->stretch
/2);
110 float penalty
=gi
->stretch_penalty
-(ve
->stretch
/2-VE_MINSTRETCH
);
111 if(penalty
<0.f
)penalty
=0.f
;
112 if(penalty
>gi
->stretch_penalty
)penalty
=gi
->stretch_penalty
;
114 /*_analysis_output_always("lpcm",seq2,data,n,0,0,
115 totalshift+pos*ve->searchstep);*/
117 /* window and transform */
119 vec
[i
]=data
[i
]*ve
->mdct_win
[i
];
120 mdct_forward(&ve
->mdct
,vec
,vec
);
122 /*_analysis_output_always("mdct",seq2,vec,n/2,0,1,0); */
124 /* near-DC spreading function; this has nothing to do with
125 psychoacoustics, just sidelobe leakage and window size */
127 float temp
=vec
[0]*vec
[0]+.7*vec
[1]*vec
[1]+.2*vec
[2]*vec
[2];
128 int ptr
=filters
->nearptr
;
130 /* the accumulation is regularly refreshed from scratch to avoid
131 floating point creep */
133 decay
=filters
->nearDC_acc
=filters
->nearDC_partialacc
+temp
;
134 filters
->nearDC_partialacc
=temp
;
136 decay
=filters
->nearDC_acc
+=temp
;
137 filters
->nearDC_partialacc
+=temp
;
139 filters
->nearDC_acc
-=filters
->nearDC
[ptr
];
140 filters
->nearDC
[ptr
]=temp
;
142 decay
*=(1./(VE_NEARDC
+1));
144 if(filters
->nearptr
>=VE_NEARDC
)filters
->nearptr
=0;
145 decay
=todB(&decay
)*.5-15.f
;
148 /* perform spreading and limiting, also smooth the spectrum. yes,
149 the MDCT results in all real coefficients, but it still *behaves*
150 like real/imaginary pairs */
152 float val
=vec
[i
]*vec
[i
]+vec
[i
+1]*vec
[i
+1];
154 if(val
<decay
)val
=decay
;
155 if(val
<minV
)val
=minV
;
160 /*_analysis_output_always("spread",seq2++,vec,n/4,0,0,0);*/
162 /* perform preecho/postecho triggering by band */
163 for(j
=0;j
<VE_BANDS
;j
++){
167 /* accumulate amplitude */
168 for(i
=0;i
<bands
[j
].end
;i
++)
169 acc
+=vec
[i
+bands
[j
].begin
]*bands
[j
].window
[i
];
173 /* convert amplitude to delta */
175 int p
,this=filters
[j
].ampptr
;
176 float postmax
,postmin
,premax
=-99999.f
,premin
=99999.f
;
181 postmax
=max(acc
,filters
[j
].ampbuf
[p
]);
182 postmin
=min(acc
,filters
[j
].ampbuf
[p
]);
184 for(i
=0;i
<stretch
;i
++){
187 premax
=max(premax
,filters
[j
].ampbuf
[p
]);
188 premin
=min(premin
,filters
[j
].ampbuf
[p
]);
191 valmin
=postmin
-premin
;
192 valmax
=postmax
-premax
;
194 /*filters[j].markers[pos]=valmax;*/
195 filters
[j
].ampbuf
[this]=acc
;
197 if(filters
[j
].ampptr
>=VE_AMP
)filters
[j
].ampptr
=0;
200 /* look at min/max, decide trigger */
201 if(valmax
>gi
->preecho_thresh
[j
]+penalty
){
205 if(valmin
<gi
->postecho_thresh
[j
]-penalty
)ret
|=2;
213 static ogg_int64_t totalshift
=-1024;
216 long _ve_envelope_search(vorbis_dsp_state
*v
){
217 vorbis_info
*vi
=v
->vi
;
218 codec_setup_info
*ci
=vi
->codec_setup
;
219 vorbis_info_psy_global
*gi
=&ci
->psy_g_param
;
220 envelope_lookup
*ve
=((private_state
*)(v
->backend_state
))->ve
;
223 int first
=ve
->current
/ve
->searchstep
;
224 int last
=v
->pcm_current
/ve
->searchstep
-VE_WIN
;
227 /* make sure we have enough storage to match the PCM */
228 if(last
+VE_WIN
+VE_POST
>ve
->storage
){
229 ve
->storage
=last
+VE_WIN
+VE_POST
; /* be sure */
230 ve
->mark
=_ogg_realloc(ve
->mark
,ve
->storage
*sizeof(*ve
->mark
));
233 for(j
=first
;j
<last
;j
++){
237 if(ve
->stretch
>VE_MAXSTRETCH
*2)
238 ve
->stretch
=VE_MAXSTRETCH
*2;
240 for(i
=0;i
<ve
->ch
;i
++){
241 float *pcm
=v
->pcm
[i
]+ve
->searchstep
*(j
);
242 ret
|=_ve_amp(ve
,gi
,pcm
,ve
->band
,ve
->filter
+i
*VE_BANDS
);
245 ve
->mark
[j
+VE_POST
]=0;
253 if(j
>0)ve
->mark
[j
-1]=1;
256 if(ret
&4)ve
->stretch
=-1;
259 ve
->current
=last
*ve
->searchstep
;
262 long centerW
=v
->centerW
;
265 ci
->blocksizes
[v
->W
]/4+
271 while(j
<ve
->current
-(ve
->searchstep
)){/* account for postecho
272 working back one window */
273 if(j
>=testW
)return(1);
277 if(ve
->mark
[j
/ve
->searchstep
]){
282 float *marker
=alloca(v
->pcm_current
*sizeof(*marker
));
284 memset(marker
,0,sizeof(*marker
)*v
->pcm_current
);
285 fprintf(stderr
,"mark! seq=%d, cursor:%fs time:%fs\n",
287 (totalshift
+ve
->cursor
)/44100.,
288 (totalshift
+j
)/44100.);
289 _analysis_output_always("pcmL",seq
,v
->pcm
[0],v
->pcm_current
,0,0,totalshift
);
290 _analysis_output_always("pcmR",seq
,v
->pcm
[1],v
->pcm_current
,0,0,totalshift
);
292 _analysis_output_always("markL",seq
,v
->pcm
[0],j
,0,0,totalshift
);
293 _analysis_output_always("markR",seq
,v
->pcm
[1],j
,0,0,totalshift
);
295 for(m
=0;m
<VE_BANDS
;m
++){
297 sprintf(buf
,"delL%d",m
);
298 for(l
=0;l
<last
;l
++)marker
[l
*ve
->searchstep
]=ve
->filter
[m
].markers
[l
]*.1;
299 _analysis_output_always(buf
,seq
,marker
,v
->pcm_current
,0,0,totalshift
);
302 for(m
=0;m
<VE_BANDS
;m
++){
304 sprintf(buf
,"delR%d",m
);
305 for(l
=0;l
<last
;l
++)marker
[l
*ve
->searchstep
]=ve
->filter
[m
+VE_BANDS
].markers
[l
]*.1;
306 _analysis_output_always(buf
,seq
,marker
,v
->pcm_current
,0,0,totalshift
);
309 for(l
=0;l
<last
;l
++)marker
[l
*ve
->searchstep
]=ve
->mark
[l
]*.4;
310 _analysis_output_always("mark",seq
,marker
,v
->pcm_current
,0,0,totalshift
);
319 if(j
>=testW
)return(1);
330 int _ve_envelope_mark(vorbis_dsp_state
*v
){
331 envelope_lookup
*ve
=((private_state
*)(v
->backend_state
))->ve
;
332 vorbis_info
*vi
=v
->vi
;
333 codec_setup_info
*ci
=vi
->codec_setup
;
334 long centerW
=v
->centerW
;
335 long beginW
=centerW
-ci
->blocksizes
[v
->W
]/4;
336 long endW
=centerW
+ci
->blocksizes
[v
->W
]/4;
338 beginW
-=ci
->blocksizes
[v
->lW
]/4;
339 endW
+=ci
->blocksizes
[v
->nW
]/4;
341 beginW
-=ci
->blocksizes
[0]/4;
342 endW
+=ci
->blocksizes
[0]/4;
345 if(ve
->curmark
>=beginW
&& ve
->curmark
<endW
)return(1);
347 long first
=beginW
/ve
->searchstep
;
348 long last
=endW
/ve
->searchstep
;
350 for(i
=first
;i
<last
;i
++)
351 if(ve
->mark
[i
])return(1);
356 void _ve_envelope_shift(envelope_lookup
*e
,long shift
){
357 int smallsize
=e
->current
/e
->searchstep
+VE_POST
; /* adjust for placing marks
358 ahead of ve->current */
359 int smallshift
=shift
/e
->searchstep
;
361 memmove(e
->mark
,e
->mark
+smallshift
,(smallsize
-smallshift
)*sizeof(*e
->mark
));
364 for(i
=0;i
<VE_BANDS
*e
->ch
;i
++)
365 memmove(e
->filter
[i
].markers
,
366 e
->filter
[i
].markers
+smallshift
,
367 (1024-smallshift
)*sizeof(*(*e
->filter
).markers
));