110 lines
3.0 KiB
C
110 lines
3.0 KiB
C
/* critical-bands.c
|
|
* atsa: ATS analysis implementation
|
|
* Oscar Pablo Di Liscia / Pete Moss / Juan Pampin
|
|
*/
|
|
|
|
#include "atsa.h"
|
|
|
|
#include <math.h>
|
|
|
|
/* Definition of critical band frequency edges, based on data from:
|
|
* Zwicker, Fastl (1990) "Psychoacoustics Facts and Models",
|
|
* Berlin ; New York : Springer-Verlag */
|
|
double ATSA_CRITICAL_BAND_EDGES[ATSA_CRITICAL_BANDS+1] =
|
|
{ 0.0, 100.0, 200.0, 300.0, 400.0, 510.0,
|
|
630.0, 770.0, 920.0, 1080.0, 1270.0,
|
|
1480.0, 1720.0, 2000.0, 2320.0, 2700.0,
|
|
3150.0, 3700.0, 4400.0, 5300.0, 6400.0,
|
|
7700.0, 9500.0, 12000.0, 15500.0, 20000.0 };
|
|
|
|
/* private function prototypes */
|
|
void clear_mask(ATS_PEAK *peaks, int peaks_size);
|
|
double compute_slope_r(double val);
|
|
double frq2bark(double frq, double *edges);
|
|
int find_band(double frq, double *edges);
|
|
|
|
/* frq2bark
|
|
* ========
|
|
* frequency to bark scale conversion
|
|
*/
|
|
double frq2bark(double frq, double *edges)
|
|
{
|
|
double lo_frq, hi_frq;
|
|
int band;
|
|
|
|
if(frq <= 400.0) return(frq * .01);
|
|
if(frq >= 20000.0) return(NIL);
|
|
|
|
band = find_band(frq, edges);
|
|
lo_frq = edges[band];
|
|
hi_frq = edges[band+1];
|
|
return(1 + band + fabs(log10(frq/lo_frq) / log10(lo_frq/hi_frq)));
|
|
}
|
|
|
|
/* find_band
|
|
* =========
|
|
* returns the critical band number
|
|
* corresponding to frq
|
|
*/
|
|
int find_band(double frq, double *edges)
|
|
{
|
|
int i = 0;
|
|
while(frq > edges[i++]);
|
|
return(i-2);
|
|
}
|
|
|
|
/* compute_slope_r
|
|
* ===============
|
|
* computes masking curve's right slope from val
|
|
*/
|
|
double compute_slope_r(double val)
|
|
{
|
|
double i = val - 40.0;
|
|
return(((i > 0.0) ? i : 0.0) * 0.37 - 27.0);
|
|
}
|
|
|
|
/* clear_mask
|
|
* ==========
|
|
* clears masking curves
|
|
* peaks: array of peaks representing the masking curve
|
|
* peaks_size: number of peaks in curve
|
|
*/
|
|
void clear_mask(ATS_PEAK *peaks, int peaks_size)
|
|
{
|
|
while(peaks_size--) peaks[peaks_size].smr = 0.0;
|
|
}
|
|
|
|
/* evaluate_smr
|
|
* ============
|
|
* evalues the masking curves of an analysis frame
|
|
* setting the peaks smr slot.
|
|
* peaks: pointer to an array of peaks
|
|
* peaks_size: number of peaks
|
|
*/
|
|
void evaluate_smr(ATS_PEAK *peaks, int peaks_size)
|
|
{
|
|
double slope_l = -27.0, slope_r, delta_dB = -50.0;
|
|
double frq_masker, amp_masker, frq_maskee, amp_maskee, mask_term;
|
|
int i, j;
|
|
ATS_PEAK *maskee;
|
|
double *edges = ATSA_CRITICAL_BAND_EDGES;
|
|
clear_mask(peaks, peaks_size);
|
|
if(peaks_size == 1) peaks[0].smr = amp2db_spl(peaks[0].amp);
|
|
else for(i=0; i<peaks_size; i++) {
|
|
maskee = &peaks[i];
|
|
frq_maskee = frq2bark(maskee->frq, edges);
|
|
amp_maskee = amp2db_spl(maskee->amp);
|
|
for(j=0; j<peaks_size; j++)
|
|
if(i != j) {
|
|
frq_masker = frq2bark(peaks[j].frq, edges);
|
|
amp_masker = amp2db_spl(peaks[j].amp);
|
|
slope_r = compute_slope_r(amp_masker);
|
|
mask_term = (frq_masker < frq_maskee) ?
|
|
(amp_masker + delta_dB + (slope_r * (frq_maskee - frq_masker))) :
|
|
(amp_masker + delta_dB + (slope_l * (frq_masker - frq_maskee)));
|
|
if(mask_term > maskee->smr) maskee->smr = mask_term;
|
|
}
|
|
maskee->smr = amp_maskee - maskee->smr;
|
|
}
|
|
}
|