1 /* noiseprof - SoX Noise Profiling Effect.
3 * Written by Ian Turner (vectro@vectro.org)
4 * Copyright 1999 Ian Turner and others
6 * This library is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or (at
9 * your option) any later version.
11 * This library is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
14 * General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this library; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
35 char* output_filename
;
43 * Get the filename, if any. We don't open it until sox_noiseprof_start.
45 static int sox_noiseprof_getopts(sox_effect_t
* effp
, int argc
, char **argv
)
47 priv_t
* data
= (priv_t
*) effp
->priv
;
51 data
->output_filename
= argv
[0];
53 return lsx_usage(effp
);
60 * Do all initializations.
62 static int sox_noiseprof_start(sox_effect_t
* effp
)
64 priv_t
* data
= (priv_t
*) effp
->priv
;
65 unsigned channels
= effp
->in_signal
.channels
;
68 /* Note: don't fall back to stderr if stdout is unavailable
69 * since we already use stderr for diagnostics. */
70 if (!data
->output_filename
|| !strcmp(data
->output_filename
, "-")) {
71 if (effp
->global_info
->global_info
->stdout_in_use_by
) {
72 lsx_fail("stdout already in use by `%s'", effp
->global_info
->global_info
->stdout_in_use_by
);
75 effp
->global_info
->global_info
->stdout_in_use_by
= effp
->handler
.name
;
76 data
->output_file
= stdout
;
78 else if ((data
->output_file
= fopen(data
->output_filename
, "wb")) == NULL
) {
79 lsx_fail("Couldn't open profile file %s: %s", data
->output_filename
, strerror(errno
));
83 data
->chandata
= lsx_calloc(channels
, sizeof(*(data
->chandata
)));
85 for (i
= 0; i
< channels
; i
++) {
86 data
->chandata
[i
].sum
= lsx_calloc(FREQCOUNT
, sizeof(float));
87 data
->chandata
[i
].profilecount
= lsx_calloc(FREQCOUNT
, sizeof(int));
88 data
->chandata
[i
].window
= lsx_calloc(WINDOWSIZE
, sizeof(float));
94 /* Collect statistics from the complete window on channel chan. */
95 static void collect_data(chandata_t
* chan
) {
96 float *out
= lsx_calloc(FREQCOUNT
, sizeof(float));
99 lsx_power_spectrum_f(WINDOWSIZE
, chan
->window
, out
);
101 for (i
= 0; i
< FREQCOUNT
; i
++) {
103 float value
= log(out
[i
]);
104 chan
->sum
[i
] += value
;
105 chan
->profilecount
[i
] ++;
113 * Grab what we can from ibuf, and process if we have a whole window.
115 static int sox_noiseprof_flow(sox_effect_t
* effp
, const sox_sample_t
*ibuf
, sox_sample_t
*obuf
,
116 size_t *isamp
, size_t *osamp
)
118 priv_t
* p
= (priv_t
*) effp
->priv
;
119 size_t samp
= min(*isamp
, *osamp
);
120 size_t chans
= effp
->in_signal
.channels
;
121 size_t i
, j
, n
= min(samp
/ chans
, WINDOWSIZE
- p
->bufdata
);
123 memcpy(obuf
, ibuf
, n
* chans
* sizeof(*obuf
)); /* Pass on audio unaffected */
124 *isamp
= *osamp
= n
* chans
;
126 /* Collect data for every channel. */
127 for (i
= 0; i
< chans
; i
++) {
129 chandata_t
* chan
= &(p
->chandata
[i
]);
130 for (j
= 0; j
< n
; j
++)
131 chan
->window
[j
+ p
->bufdata
] =
132 SOX_SAMPLE_TO_FLOAT_32BIT(ibuf
[i
+ j
* chans
],);
133 if (n
+ p
->bufdata
== WINDOWSIZE
)
138 assert(p
->bufdata
<= WINDOWSIZE
);
139 if (p
->bufdata
== WINDOWSIZE
)
146 * Finish off the last window.
149 static int sox_noiseprof_drain(sox_effect_t
* effp
, sox_sample_t
*obuf UNUSED
, size_t *osamp
)
151 priv_t
* data
= (priv_t
*) effp
->priv
;
152 int tracks
= effp
->in_signal
.channels
;
157 if (data
->bufdata
== 0) {
161 for (i
= 0; i
< tracks
; i
++) {
163 for (j
= data
->bufdata
+1; j
< WINDOWSIZE
; j
++) {
164 data
->chandata
[i
].window
[j
] = 0;
166 collect_data(&(data
->chandata
[i
]));
169 if (data
->bufdata
== WINDOWSIZE
|| data
->bufdata
== 0)
176 * Print profile and clean up.
178 static int sox_noiseprof_stop(sox_effect_t
* effp
)
180 priv_t
* data
= (priv_t
*) effp
->priv
;
183 for (i
= 0; i
< effp
->in_signal
.channels
; i
++) {
185 chandata_t
* chan
= &(data
->chandata
[i
]);
187 fprintf(data
->output_file
, "Channel %lu: ", (unsigned long)i
);
189 for (j
= 0; j
< FREQCOUNT
; j
++) {
190 double r
= chan
->profilecount
[j
] != 0 ?
191 chan
->sum
[j
] / chan
->profilecount
[j
] : 0;
192 fprintf(data
->output_file
, "%s%f", j
== 0 ? "" : ", ", r
);
194 fprintf(data
->output_file
, "\n");
197 free(chan
->profilecount
);
200 free(data
->chandata
);
202 if (data
->output_file
!= stdout
)
203 fclose(data
->output_file
);
205 return (SOX_SUCCESS
);
208 static sox_effect_handler_t sox_noiseprof_effect
= {
211 SOX_EFF_MCHAN
| SOX_EFF_MODIFY
,
212 sox_noiseprof_getopts
,
220 const sox_effect_handler_t
*lsx_noiseprof_effect_fn(void)
222 return &sox_noiseprof_effect
;