Recognizes if input is ogg or not.
[xiph.git] / postfish / singlecomp.c
blob67f1c64a381069ec9d05aeb0aa7a20bbb3f2b642
1 /*
3 * postfish
4 *
5 * Copyright (C) 2002-2005 Monty and Xiph.Org
7 * Postfish is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
12 * Postfish is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Postfish; see the file COPYING. If not, write to the
19 * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "postfish.h"
25 #include "feedback.h"
26 #include "window.h"
27 #include "follower.h"
28 #include "singlecomp.h"
30 extern int input_size;
31 extern int input_rate;
32 extern int input_ch;
34 typedef struct {
35 sig_atomic_t u_thresh;
36 sig_atomic_t u_ratio;
38 sig_atomic_t o_thresh;
39 sig_atomic_t o_ratio;
41 sig_atomic_t b_ratio;
42 } atten_cache;
44 typedef struct{
45 time_linkage out;
46 feedback_generic_pool feedpool;
48 iir_state o_iir[MAX_INPUT_CHANNELS];
49 iir_state u_iir[MAX_INPUT_CHANNELS];
50 iir_state b_iir[MAX_INPUT_CHANNELS];
51 int o_delay[MAX_INPUT_CHANNELS];
52 int u_delay[MAX_INPUT_CHANNELS];
53 int b_delay[MAX_INPUT_CHANNELS];
55 peak_state o_peak[MAX_INPUT_CHANNELS];
56 peak_state u_peak[MAX_INPUT_CHANNELS];
57 peak_state b_peak[MAX_INPUT_CHANNELS];
59 iir_filter o_attack[MAX_INPUT_CHANNELS];
60 iir_filter u_attack[MAX_INPUT_CHANNELS];
61 iir_filter b_attack[MAX_INPUT_CHANNELS];
62 iir_filter o_decay[MAX_INPUT_CHANNELS];
63 iir_filter u_decay[MAX_INPUT_CHANNELS];
64 iir_filter b_decay[MAX_INPUT_CHANNELS];
66 int fillstate;
67 float **cache;
68 int cache_samples;
70 int *activeP;
71 int *active0;
73 int mutemaskP;
74 int mutemask0;
75 int ch;
77 atten_cache *prevset;
78 atten_cache *currset;
79 } singlecomp_state;
81 static float *window;
83 singlecomp_settings singlecomp_master_set;
84 singlecomp_settings *singlecomp_channel_set;
86 static singlecomp_settings **master_set_bundle;
87 static singlecomp_settings **channel_set_bundle;
89 static singlecomp_state master_state;
90 static singlecomp_state channel_state;
92 /* feedback! */
93 typedef struct singlecomp_feedback{
94 feedback_generic parent_class;
95 float *peak;
96 float *rms;
97 } singlecomp_feedback;
99 static feedback_generic *new_singlecomp_feedback(void){
100 singlecomp_feedback *ret=calloc(1,sizeof(*ret));
101 return (feedback_generic *)ret;
104 static int pull_singlecomp_feedback(singlecomp_state *scs, float *peak,float *rms){
105 singlecomp_feedback *f=(singlecomp_feedback *)feedback_pull(&scs->feedpool);
107 if(!f)return 0;
109 if(peak)
110 memcpy(peak,f->peak,sizeof(*peak)*scs->ch);
111 if(rms)
112 memcpy(rms,f->rms,sizeof(*rms)*scs->ch);
113 feedback_old(&scs->feedpool,(feedback_generic *)f);
114 return 1;
117 int pull_singlecomp_feedback_master(float *peak,float *rms){
118 return pull_singlecomp_feedback(&master_state,peak,rms);
121 int pull_singlecomp_feedback_channel(float *peak,float *rms){
122 return pull_singlecomp_feedback(&channel_state,peak,rms);
125 static void singlecomp_load_helper(singlecomp_state *scs,int ch){
126 int i;
127 memset(scs,0,sizeof(*scs));
129 scs->ch=ch;
130 scs->activeP=calloc(scs->ch,sizeof(*scs->activeP));
131 scs->active0=calloc(scs->ch,sizeof(*scs->active0));
133 scs->out.channels=scs->ch;
134 scs->out.data=malloc(scs->ch*sizeof(*scs->out.data));
135 for(i=0;i<scs->ch;i++)
136 scs->out.data[i]=malloc(input_size*sizeof(**scs->out.data));
138 scs->fillstate=0;
139 scs->cache=malloc(scs->ch*sizeof(*scs->cache));
140 for(i=0;i<scs->ch;i++)
141 scs->cache[i]=malloc(input_size*sizeof(**scs->cache));
143 scs->prevset=malloc(ch*sizeof(*scs->prevset));
144 scs->currset=malloc(ch*sizeof(*scs->currset));
147 /* called only by initial setup */
148 int singlecomp_load(int outch){
149 int i;
150 singlecomp_load_helper(&master_state,outch);
151 singlecomp_load_helper(&channel_state,input_ch);
153 window=window_get(1,input_size/2);
155 singlecomp_channel_set=calloc(input_ch,sizeof(*singlecomp_channel_set));
156 master_set_bundle=malloc(outch*sizeof(*master_set_bundle));
157 channel_set_bundle=malloc(input_ch*sizeof(*channel_set_bundle));
158 for(i=0;i<input_ch;i++)
159 channel_set_bundle[i]=&singlecomp_channel_set[i];
160 for(i=0;i<outch;i++)
161 master_set_bundle[i]=&singlecomp_master_set;
163 return 0;
166 static void filter_set(float msec,
167 int order,
168 int attackp,
169 iir_filter *filter){
170 float alpha;
171 float corner_freq= 500./msec;
173 /* make sure the chosen frequency doesn't require a lookahead
174 greater than what's available */
175 if(step_freq(input_size)*1.01>corner_freq && attackp && order==2)
176 corner_freq=step_freq(input_size);
178 alpha=corner_freq/input_rate;
179 filter->g=mkbessel(alpha,order,filter->c);
180 filter->alpha=alpha;
181 filter->Hz=alpha*input_rate;
182 filter->ms=msec;
185 static void reset_onech_filter(singlecomp_state *scs,int i){
186 memset(scs->o_peak+i,0,sizeof(*scs->o_peak));
187 memset(scs->u_peak+i,0,sizeof(*scs->u_peak));
188 memset(scs->b_peak+i,0,sizeof(*scs->b_peak));
190 /* all filters are set to 0, even the ones that steady-state at one,
191 because we know that our steepest attack will complete in the
192 pre-charge time, but there's no such guarantee about decay */
193 memset(scs->o_iir+i,0,sizeof(*scs->o_iir));
194 memset(scs->u_iir+i,0,sizeof(*scs->u_iir));
195 memset(scs->b_iir+i,0,sizeof(*scs->b_iir));
197 /* delays are only used for soft-starting individual filters when we
198 know things began at unity multiplier */
199 scs->o_delay[i]=0;
200 scs->u_delay[i]=0;
201 scs->b_delay[i]=0;
204 static void reset_filter(singlecomp_state *scs){
205 int i;
206 for(i=0;i<scs->ch;i++)
207 reset_onech_filter(scs,i);
210 /* called only in playback thread */
211 int singlecomp_reset(void){
212 /* reset cached pipe state */
213 master_state.fillstate=0;
214 channel_state.fillstate=0;
215 while(pull_singlecomp_feedback_master(NULL,NULL));
216 while(pull_singlecomp_feedback_channel(NULL,NULL));
218 reset_filter(&master_state);
219 reset_filter(&channel_state);
220 return 0;
223 static void work_and_lapping(singlecomp_state *scs,
224 singlecomp_settings **scset,
225 time_linkage *in,
226 time_linkage *out,
227 int *active){
228 int i;
229 int have_feedback=0;
230 u_int32_t mutemaskC=in->active;
231 u_int32_t mutemask0=scs->mutemask0;
232 u_int32_t mutemaskP=scs->mutemaskP;
234 float peakfeed[scs->ch];
235 float rmsfeed[scs->ch];
236 memset(peakfeed,0,sizeof(peakfeed));
237 memset(rmsfeed,0,sizeof(rmsfeed));
239 for(i=0;i<scs->ch;i++){
241 int o_active=0,u_active=0,b_active=0;
243 int activeC= active[i] && !mute_channel_muted(mutemaskC,i);
244 int active0= scs->active0[i];
245 int activeP= scs->activeP[i];
247 int mutedC=mute_channel_muted(mutemaskC,i);
248 int muted0=mute_channel_muted(mutemask0,i);
249 int mutedP=mute_channel_muted(mutemaskP,i);
251 float o_attackms=scset[i]->o_attack*.1;
252 float o_decayms=scset[i]->o_decay*.1;
253 float u_attackms=scset[i]->u_attack*.1;
254 float u_decayms=scset[i]->u_decay*.1;
255 float b_attackms=scset[i]->b_attack*.1;
256 float b_decayms=scset[i]->b_decay*.1;
258 if(o_attackms!=scs->o_attack[i].ms)filter_set(o_attackms,2,1,&scs->o_attack[i]);
259 if(o_decayms!=scs->o_decay[i].ms)filter_set(o_decayms,1,0,&scs->o_decay[i]);
260 if(u_attackms!=scs->u_attack[i].ms)filter_set(u_attackms,2,1,&scs->u_attack[i]);
261 if(u_decayms!=scs->u_decay[i].ms)filter_set(u_decayms,1,0,&scs->u_decay[i]);
262 if(b_attackms!=scs->b_attack[i].ms)filter_set(b_attackms,2,1,&scs->b_attack[i]);
263 if(b_decayms!=scs->b_decay[i].ms)filter_set(b_decayms,1,0,&scs->b_decay[i]);
265 if(!active0 && !activeC){
267 if(activeP) reset_onech_filter(scs,i); /* just became inactive;
268 reset all filters for
269 this channel */
271 /* feedback */
272 if(scset[i]->panel_visible){
273 int k;
274 float rms=0.;
275 float peak=0.;
276 float *x=scs->cache[i];
277 have_feedback=1;
279 if(!muted0){
280 for(k=0;k<input_size;k++){
281 float val=x[k]*x[k];
282 rms+= val;
283 if(peak<val)peak=val;
286 peakfeed[i]=todB_a(peak)*.5;
287 rms/=input_size;
288 rmsfeed[i]=todB_a(rms)*.5;
291 /* rotate data vectors */
292 if(out){
293 float *temp=out->data[i];
294 out->data[i]=scs->cache[i];
295 scs->cache[i]=temp;
299 }else if(active0 || activeC){
300 float adj[input_size]; // under will set it
301 atten_cache *prevset=scs->prevset+i;
302 atten_cache *currset=scs->currset+i;
304 currset->u_thresh=scset[i]->u_thresh;
305 currset->o_thresh=scset[i]->o_thresh;
306 currset->u_ratio=scset[i]->u_ratio;
307 currset->o_ratio=scset[i]->o_ratio;
308 currset->b_ratio=scset[i]->b_ratio;
310 /* don't slew from an unknown value */
311 if(!activeP || !scs->fillstate)
312 memcpy(prevset,currset,sizeof(*currset));
314 /* don't run filters that will be applied at unity */
315 if(prevset->u_ratio==1000 && currset->u_ratio==1000){
316 scs->u_delay[i]=1;
317 memset(scs->u_peak+i,0,sizeof(peak_state));
318 memset(scs->u_iir+i,0,sizeof(iir_state));
319 }else{
320 if(scs->u_delay[i]-->0)currset->u_ratio=1000;
321 if(scs->u_delay[i]<0)scs->u_delay[i]=0;
322 u_active=1;
325 if(prevset->o_ratio==1000 && currset->o_ratio==1000){
326 scs->o_delay[i]=1;
327 memset(scs->o_peak+i,0,sizeof(peak_state));
328 memset(scs->o_iir+i,0,sizeof(iir_state));
329 }else{
330 if(scs->o_delay[i]-->0)currset->o_ratio=1000;
331 if(scs->o_delay[i]<0)scs->o_delay[i]=0;
332 o_active=1;
335 if(prevset->b_ratio==1000 && currset->b_ratio==1000){
336 scs->b_delay[i]=1;
337 memset(scs->b_peak+i,0,sizeof(peak_state));
338 memset(scs->b_iir+i,0,sizeof(iir_state));
339 }else{
340 if(scs->b_delay[i]-->0)currset->b_ratio=1000;
341 if(scs->b_delay[i]<0)scs->b_delay[i]=0;
342 b_active=1;
345 /* run the filters */
346 memset(adj,0,sizeof(*adj)*input_size);
348 if(u_active)
349 bi_compand(scs->cache[i],in->data[i],adj,
350 //scs->prevset[i].u_thresh,
351 scs->currset[i].u_thresh,
352 1.f-1000./scs->prevset[i].u_ratio,
353 1.f-1000./scs->currset[i].u_ratio,
354 scset[i]->u_lookahead/1000.f,
355 scset[i]->u_mode,
356 scset[i]->u_softknee,
357 scs->u_attack+i,scs->u_decay+i,
358 scs->u_iir+i,scs->u_peak+i,
359 active0,0);
361 if(o_active)
362 bi_compand(scs->cache[i],in->data[i],adj,
363 //scs->prevset[i].o_thresh,
364 scs->currset[i].o_thresh,
365 1.f-1000.f/scs->prevset[i].o_ratio,
366 1.f-1000.f/scs->currset[i].o_ratio,
367 scset[i]->o_lookahead/1000.f,
368 scset[i]->o_mode,
369 scset[i]->o_softknee,
370 scs->o_attack+i,scs->o_decay+i,
371 scs->o_iir+i,scs->o_peak+i,
372 active0,1);
375 /* feedback before base */
376 if(scset[i]->panel_visible){
377 int k;
378 float rms=0.;
379 float peak=0.;
380 float *x=scs->cache[i];
381 have_feedback=1;
383 if(!muted0){
384 for(k=0;k<input_size;k++){
385 float mul=fromdB_a(adj[k]);
386 float val=x[k]*mul;
388 val*=val;
389 rms+= val;
390 if(peak<val)peak=val;
394 peakfeed[i]=todB_a(peak)*.5;
395 rms/=input_size;
396 rmsfeed[i]=todB_a(rms)*.5;
399 if(b_active)
400 full_compand(scs->cache[i],in->data[i],adj,
401 1.-1000./scs->prevset[i].b_ratio,
402 1.-1000./scs->currset[i].b_ratio,
403 scset[i]->b_mode,
404 scs->b_attack+i,scs->b_decay+i,
405 scs->b_iir+i,scs->b_peak+i,
406 active0);
408 if(active0 && out){
409 /* current frame should be manipulated; render into out,
410 handle transitioning after */
411 int k;
412 float *ix=scs->cache[i];
413 float *ox=out->data[i];
415 for(k=0;k<input_size;k++)
416 ox[k]=ix[k]*fromdB_a(adj[k]);
418 /* is this frame preceeded/followed by an 'inactive' frame?
419 If so, smooth the transition */
420 if(!activeP){
421 if(!mutedP){
422 for(k=0;k<input_size/2;k++){
423 float w=window[k];
424 ox[k]= ox[k]*w + ix[k]*(1.-w);
428 if(!activeC){
429 if(!mutedC){
430 float *cox=ox+input_size/2;
431 float *cix=ix+input_size/2;
432 for(k=0;k<input_size/2;k++){
433 float w=window[k];
434 cox[k]= cox[k]*(1.-w) + cix[k]*w;
438 }else if(out){
439 float *temp=out->data[i];
440 out->data[i]=scs->cache[i];
441 scs->cache[i]=temp;
445 float *temp=scs->cache[i];
446 scs->cache[i]=in->data[i];
447 in->data[i]=temp;
449 scs->activeP[i]=active0;
450 scs->active0[i]=activeC;
454 if(out){
455 /* feedback is also triggered off of output */
456 singlecomp_feedback *ff=
457 (singlecomp_feedback *)feedback_new(&scs->feedpool,new_singlecomp_feedback);
459 if(!ff->peak)
460 ff->peak=malloc(scs->ch*sizeof(*ff->peak));
462 if(!ff->rms)
463 ff->rms=malloc(scs->ch*sizeof(*ff->rms));
465 memcpy(ff->peak,peakfeed,sizeof(peakfeed));
466 memcpy(ff->rms,rmsfeed,sizeof(rmsfeed));
468 feedback_push(&scs->feedpool,(feedback_generic *)ff);
470 out->active=mutemask0;
471 out->samples=scs->cache_samples;
475 atten_cache *temp=scs->prevset;
476 scs->prevset=scs->currset;
477 scs->currset=temp;
480 scs->cache_samples=in->samples;
481 scs->mutemaskP=mutemask0;
482 scs->mutemask0=mutemaskC;
485 time_linkage *singlecomp_read_helper(time_linkage *in,
486 singlecomp_state *scs,
487 singlecomp_settings **scset,
488 int *active){
489 int i;
491 switch(scs->fillstate){
492 case 0: /* prime the cache */
493 if(in->samples==0){
494 scs->out.samples=0;
495 return &scs->out;
498 for(i=0;i<scs->ch;i++){
499 memset(scs->o_iir+i,0,sizeof(*scs->o_iir));
500 memset(scs->u_iir+i,0,sizeof(*scs->u_iir));
501 memset(scs->b_iir+i,0,sizeof(*scs->b_iir));
502 memset(scs->o_peak+i,0,sizeof(*scs->o_peak));
503 memset(scs->u_peak+i,0,sizeof(*scs->u_peak));
504 memset(scs->b_peak+i,0,sizeof(*scs->b_peak));
505 memset(scs->cache[i],0,sizeof(**scs->cache)*input_size);
506 scs->activeP[i]=scs->active0[i]=active[i];
508 scs->mutemaskP=scs->mutemask0=in->active;
510 work_and_lapping(scs,scset,in,0,active);
512 scs->fillstate=1;
513 scs->out.samples=0;
514 if(in->samples==input_size)goto tidy_up;
516 for(i=0;i<scs->ch;i++)
517 memset(in->data[i],0,sizeof(**in->data)*input_size);
518 in->samples=0;
519 /* fall through */
520 case 1: /* nominal processing */
522 work_and_lapping(scs,scset,in,&scs->out,active);
524 if(scs->out.samples<input_size)scs->fillstate=2;
525 break;
526 case 2: /* we've pushed out EOF already */
527 scs->out.samples=0;
530 tidy_up:
532 int tozero=input_size-scs->out.samples;
533 if(tozero)
534 for(i=0;i<scs->out.channels;i++)
535 memset(scs->out.data[i]+scs->out.samples,0,sizeof(**scs->out.data)*tozero);
538 return &scs->out;
541 time_linkage *singlecomp_read_master(time_linkage *in){
542 int active[master_state.ch],i;
544 /* local copy required to avoid concurrency problems */
545 for(i=0;i<master_state.ch;i++)
546 active[i]=singlecomp_master_set.panel_active;
548 return singlecomp_read_helper(in, &master_state, master_set_bundle,active);
551 time_linkage *singlecomp_read_channel(time_linkage *in){
552 int active[channel_state.ch],i;
554 /* local copy required to avoid concurrency problems */
555 for(i=0;i<channel_state.ch;i++)
556 active[i]=singlecomp_channel_set[i].panel_active;
558 return singlecomp_read_helper(in, &channel_state, channel_set_bundle,active);