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)
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.
28 #include "singlecomp.h"
30 extern int input_size
;
31 extern int input_rate
;
35 sig_atomic_t u_thresh
;
38 sig_atomic_t o_thresh
;
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
];
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
;
93 typedef struct singlecomp_feedback
{
94 feedback_generic parent_class
;
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
);
110 memcpy(peak
,f
->peak
,sizeof(*peak
)*scs
->ch
);
112 memcpy(rms
,f
->rms
,sizeof(*rms
)*scs
->ch
);
113 feedback_old(&scs
->feedpool
,(feedback_generic
*)f
);
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
){
127 memset(scs
,0,sizeof(*scs
));
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
));
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
){
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
];
161 master_set_bundle
[i
]=&singlecomp_master_set
;
166 static void filter_set(float msec
,
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
);
181 filter
->Hz
=alpha
*input_rate
;
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 */
204 static void reset_filter(singlecomp_state
*scs
){
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
);
223 static void work_and_lapping(singlecomp_state
*scs
,
224 singlecomp_settings
**scset
,
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
272 if(scset
[i
]->panel_visible
){
276 float *x
=scs
->cache
[i
];
280 for(k
=0;k
<input_size
;k
++){
283 if(peak
<val
)peak
=val
;
286 peakfeed
[i
]=todB_a(peak
)*.5;
288 rmsfeed
[i
]=todB_a(rms
)*.5;
291 /* rotate data vectors */
293 float *temp
=out
->data
[i
];
294 out
->data
[i
]=scs
->cache
[i
];
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){
317 memset(scs
->u_peak
+i
,0,sizeof(peak_state
));
318 memset(scs
->u_iir
+i
,0,sizeof(iir_state
));
320 if(scs
->u_delay
[i
]-->0)currset
->u_ratio
=1000;
321 if(scs
->u_delay
[i
]<0)scs
->u_delay
[i
]=0;
325 if(prevset
->o_ratio
==1000 && currset
->o_ratio
==1000){
327 memset(scs
->o_peak
+i
,0,sizeof(peak_state
));
328 memset(scs
->o_iir
+i
,0,sizeof(iir_state
));
330 if(scs
->o_delay
[i
]-->0)currset
->o_ratio
=1000;
331 if(scs
->o_delay
[i
]<0)scs
->o_delay
[i
]=0;
335 if(prevset
->b_ratio
==1000 && currset
->b_ratio
==1000){
337 memset(scs
->b_peak
+i
,0,sizeof(peak_state
));
338 memset(scs
->b_iir
+i
,0,sizeof(iir_state
));
340 if(scs
->b_delay
[i
]-->0)currset
->b_ratio
=1000;
341 if(scs
->b_delay
[i
]<0)scs
->b_delay
[i
]=0;
345 /* run the filters */
346 memset(adj
,0,sizeof(*adj
)*input_size
);
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
,
356 scset
[i
]->u_softknee
,
357 scs
->u_attack
+i
,scs
->u_decay
+i
,
358 scs
->u_iir
+i
,scs
->u_peak
+i
,
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
,
369 scset
[i
]->o_softknee
,
370 scs
->o_attack
+i
,scs
->o_decay
+i
,
371 scs
->o_iir
+i
,scs
->o_peak
+i
,
375 /* feedback before base */
376 if(scset
[i
]->panel_visible
){
380 float *x
=scs
->cache
[i
];
384 for(k
=0;k
<input_size
;k
++){
385 float mul
=fromdB_a(adj
[k
]);
390 if(peak
<val
)peak
=val
;
394 peakfeed
[i
]=todB_a(peak
)*.5;
396 rmsfeed
[i
]=todB_a(rms
)*.5;
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
,
404 scs
->b_attack
+i
,scs
->b_decay
+i
,
405 scs
->b_iir
+i
,scs
->b_peak
+i
,
409 /* current frame should be manipulated; render into out,
410 handle transitioning after */
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 */
422 for(k
=0;k
<input_size
/2;k
++){
424 ox
[k
]= ox
[k
]*w
+ ix
[k
]*(1.-w
);
430 float *cox
=ox
+input_size
/2;
431 float *cix
=ix
+input_size
/2;
432 for(k
=0;k
<input_size
/2;k
++){
434 cox
[k
]= cox
[k
]*(1.-w
) + cix
[k
]*w
;
439 float *temp
=out
->data
[i
];
440 out
->data
[i
]=scs
->cache
[i
];
445 float *temp
=scs
->cache
[i
];
446 scs
->cache
[i
]=in
->data
[i
];
449 scs
->activeP
[i
]=active0
;
450 scs
->active0
[i
]=activeC
;
455 /* feedback is also triggered off of output */
456 singlecomp_feedback
*ff
=
457 (singlecomp_feedback
*)feedback_new(&scs
->feedpool
,new_singlecomp_feedback
);
460 ff
->peak
=malloc(scs
->ch
*sizeof(*ff
->peak
));
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
;
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
,
491 switch(scs
->fillstate
){
492 case 0: /* prime the cache */
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
);
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
);
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;
526 case 2: /* we've pushed out EOF already */
532 int tozero
=input_size
-scs
->out
.samples
;
534 for(i
=0;i
<scs
->out
.channels
;i
++)
535 memset(scs
->out
.data
[i
]+scs
->out
.samples
,0,sizeof(**scs
->out
.data
)*tozero
);
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
);