Blame bat/analyze.c

Packit Service a9274b
/*
Packit Service a9274b
 * Copyright (C) 2013-2015 Intel Corporation
Packit Service a9274b
 *
Packit Service a9274b
 * This program is free software; you can redistribute it and/or modify
Packit Service a9274b
 * it under the terms of the GNU General Public License as published by
Packit Service a9274b
 * the Free Software Foundation; either version 2 of the License, or
Packit Service a9274b
 * (at your option) any later version.
Packit Service a9274b
 *
Packit Service a9274b
 * This program is distributed in the hope that it will be useful,
Packit Service a9274b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a9274b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a9274b
 * GNU General Public License for more details.
Packit Service a9274b
 *
Packit Service a9274b
 */
Packit Service a9274b
Packit Service a9274b
#include <stdio.h>
Packit Service a9274b
#include <stdlib.h>
Packit Service a9274b
#include <errno.h>
Packit Service a9274b
#include <stdbool.h>
Packit Service a9274b
#include <stdint.h>
Packit Service a9274b
Packit Service a9274b
#include <math.h>
Packit Service a9274b
#include <fftw3.h>
Packit Service a9274b
Packit Service a9274b
#include "aconfig.h"
Packit Service a9274b
#include "gettext.h"
Packit Service a9274b
Packit Service a9274b
#include "common.h"
Packit Service a9274b
#include "bat-signal.h"
Packit Service a9274b
Packit Service a9274b
static void check_amplitude(struct bat *bat, float *buf)
Packit Service a9274b
{
Packit Service a9274b
	float sum, average, amplitude;
Packit Service a9274b
	int i, percent;
Packit Service a9274b
Packit Service a9274b
	/* calculate average value */
Packit Service a9274b
	for (i = 0, sum = 0.0, average = 0.0; i < bat->frames; i++)
Packit Service a9274b
		sum += buf[i];
Packit Service a9274b
	average = sum / bat->frames;
Packit Service a9274b
Packit Service a9274b
	/* calculate peak-to-average amplitude */
Packit Service a9274b
	for (i = 0, sum = 0.0; i < bat->frames; i++)
Packit Service a9274b
		sum += fabsf(buf[i] - average);
Packit Service a9274b
	amplitude = sum / bat->frames * M_PI / 2.0;
Packit Service a9274b
Packit Service a9274b
	/* calculate amplitude percentage against full range */
Packit Service a9274b
	percent = amplitude * 100 / ((1 << ((bat->sample_size << 3) - 1)) - 1);
Packit Service a9274b
Packit Service a9274b
	fprintf(bat->log, _("Amplitude: %.1f; Percentage: [%d]\n"),
Packit Service a9274b
			amplitude, percent);
Packit Service a9274b
	if (percent < 0)
Packit Service a9274b
		fprintf(bat->err, _("ERROR: Amplitude can't be negative!\n"));
Packit Service a9274b
	else if (percent < 1)
Packit Service a9274b
		fprintf(bat->err, _("WARNING: Signal too weak!\n"));
Packit Service a9274b
	else if (percent > 100)
Packit Service a9274b
		fprintf(bat->err, _("WARNING: Signal overflow!\n"));
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/**
Packit Service a9274b
 *
Packit Service a9274b
 * @return 0 if peak detected at right frequency,
Packit Service a9274b
 *         1 if peak detected somewhere else
Packit Service a9274b
 *         2 if DC detected
Packit Service a9274b
 */
Packit Service a9274b
int check_peak(struct bat *bat, struct analyze *a, int end, int peak, float hz,
Packit Service a9274b
		float mean, float p, int channel, int start)
Packit Service a9274b
{
Packit Service a9274b
	int err;
Packit Service a9274b
	float hz_peak = (float) (peak) * hz;
Packit Service a9274b
	float delta_rate = DELTA_RATE * bat->target_freq[channel];
Packit Service a9274b
	float delta_HZ = DELTA_HZ;
Packit Service a9274b
	float tolerance = (delta_rate > delta_HZ) ? delta_rate : delta_HZ;
Packit Service a9274b
Packit Service a9274b
	fprintf(bat->log, _("Detected peak at %2.2f Hz of %2.2f dB\n"), hz_peak,
Packit Service a9274b
			10.0 * log10f(a->mag[peak] / mean));
Packit Service a9274b
	fprintf(bat->log, _(" Total %3.1f dB from %2.2f to %2.2f Hz\n"),
Packit Service a9274b
			10.0 * log10f(p / mean), start * hz, end * hz);
Packit Service a9274b
Packit Service a9274b
	if (hz_peak < DC_THRESHOLD) {
Packit Service a9274b
		fprintf(bat->err, _(" WARNING: Found low peak %2.2f Hz,"),
Packit Service a9274b
				hz_peak);
Packit Service a9274b
		fprintf(bat->err, _(" very close to DC\n"));
Packit Service a9274b
		err = FOUND_DC;
Packit Service a9274b
	} else if (hz_peak < bat->target_freq[channel] - tolerance) {
Packit Service a9274b
		fprintf(bat->err, _(" FAIL: Peak freq too low %2.2f Hz\n"),
Packit Service a9274b
				hz_peak);
Packit Service a9274b
		err = FOUND_WRONG_PEAK;
Packit Service a9274b
	} else if (hz_peak > bat->target_freq[channel] + tolerance) {
Packit Service a9274b
		fprintf(bat->err, _(" FAIL: Peak freq too high %2.2f Hz\n"),
Packit Service a9274b
				hz_peak);
Packit Service a9274b
		err = FOUND_WRONG_PEAK;
Packit Service a9274b
	} else {
Packit Service a9274b
		fprintf(bat->log, _(" PASS: Peak detected"));
Packit Service a9274b
		fprintf(bat->log, _(" at target frequency\n"));
Packit Service a9274b
		err = 0;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return err;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/**
Packit Service a9274b
 * Search for main frequencies in fft results and compare it to target
Packit Service a9274b
 */
Packit Service a9274b
static int check(struct bat *bat, struct analyze *a, int channel)
Packit Service a9274b
{
Packit Service a9274b
	float hz = 1.0 / ((float) bat->frames / (float) bat->rate);
Packit Service a9274b
	float mean = 0.0, t, sigma = 0.0, p = 0.0;
Packit Service a9274b
	int i, start = -1, end = -1, peak = 0, signals = 0;
Packit Service a9274b
	int err = 0, N = bat->frames / 2;
Packit Service a9274b
Packit Service a9274b
	/* calculate mean */
Packit Service a9274b
	for (i = 0; i < N; i++)
Packit Service a9274b
		mean += a->mag[i];
Packit Service a9274b
	mean /= (float) N;
Packit Service a9274b
Packit Service a9274b
	/* calculate standard deviation */
Packit Service a9274b
	for (i = 0; i < N; i++) {
Packit Service a9274b
		t = a->mag[i] - mean;
Packit Service a9274b
		t *= t;
Packit Service a9274b
		sigma += t;
Packit Service a9274b
	}
Packit Service a9274b
	sigma /= (float) N;
Packit Service a9274b
	sigma = sqrtf(sigma);
Packit Service a9274b
Packit Service a9274b
	/* clip any data less than k sigma + mean */
Packit Service a9274b
	for (i = 0; i < N; i++) {
Packit Service a9274b
		if (a->mag[i] > mean + bat->sigma_k * sigma) {
Packit Service a9274b
Packit Service a9274b
			/* find peak start points */
Packit Service a9274b
			if (start == -1) {
Packit Service a9274b
				start = peak = end = i;
Packit Service a9274b
				signals++;
Packit Service a9274b
			} else {
Packit Service a9274b
				if (a->mag[i] > a->mag[peak])
Packit Service a9274b
					peak = i;
Packit Service a9274b
				end = i;
Packit Service a9274b
			}
Packit Service a9274b
			p += a->mag[i];
Packit Service a9274b
		} else if (start != -1) {
Packit Service a9274b
			/* Check if peak is as expected */
Packit Service a9274b
			err |= check_peak(bat, a, end, peak, hz, mean,
Packit Service a9274b
					p, channel, start);
Packit Service a9274b
			end = start = -1;
Packit Service a9274b
			if (signals == MAX_PEAKS)
Packit Service a9274b
				break;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	if (signals == 0)
Packit Service a9274b
		err = -ENOPEAK; /* No peak detected */
Packit Service a9274b
	else if ((err == FOUND_DC) && (signals == 1))
Packit Service a9274b
		err = -EONLYDC; /* Only DC detected */
Packit Service a9274b
	else if ((err & FOUND_WRONG_PEAK) == FOUND_WRONG_PEAK)
Packit Service a9274b
		err = -EBADPEAK; /* Bad peak detected */
Packit Service a9274b
	else
Packit Service a9274b
		err = 0; /* Correct peak detected */
Packit Service a9274b
Packit Service a9274b
	fprintf(bat->log, _("Detected at least %d signal(s) in total\n"),
Packit Service a9274b
			signals);
Packit Service a9274b
Packit Service a9274b
	return err;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void calc_magnitude(struct bat *bat, struct analyze *a, int N)
Packit Service a9274b
{
Packit Service a9274b
	float r2, i2;
Packit Service a9274b
	int i;
Packit Service a9274b
Packit Service a9274b
	for (i = 1; i < N / 2; i++) {
Packit Service a9274b
		r2 = a->out[i] * a->out[i];
Packit Service a9274b
		i2 = a->out[N - i] * a->out[N - i];
Packit Service a9274b
Packit Service a9274b
		a->mag[i] = sqrtf(r2 + i2);
Packit Service a9274b
	}
Packit Service a9274b
	a->mag[0] = 0.0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int find_and_check_harmonics(struct bat *bat, struct analyze *a,
Packit Service a9274b
		int channel)
Packit Service a9274b
{
Packit Service a9274b
	fftwf_plan p;
Packit Service a9274b
	int err = -ENOMEM, N = bat->frames;
Packit Service a9274b
Packit Service a9274b
	/* Allocate FFT buffers */
Packit Service a9274b
	a->in = (float *) fftwf_malloc(sizeof(float) * bat->frames);
Packit Service a9274b
	if (a->in == NULL)
Packit Service a9274b
		goto out1;
Packit Service a9274b
Packit Service a9274b
	a->out = (float *) fftwf_malloc(sizeof(float) * bat->frames);
Packit Service a9274b
	if (a->out == NULL)
Packit Service a9274b
		goto out2;
Packit Service a9274b
Packit Service a9274b
	a->mag = (float *) fftwf_malloc(sizeof(float) * bat->frames);
Packit Service a9274b
	if (a->mag == NULL)
Packit Service a9274b
		goto out3;
Packit Service a9274b
Packit Service a9274b
	/* create FFT plan */
Packit Service a9274b
	p = fftwf_plan_r2r_1d(N, a->in, a->out, FFTW_R2HC,
Packit Service a9274b
			FFTW_MEASURE | FFTW_PRESERVE_INPUT);
Packit Service a9274b
	if (p == NULL)
Packit Service a9274b
		goto out4;
Packit Service a9274b
Packit Service a9274b
	/* convert source PCM to floats */
Packit Service a9274b
	bat->convert_sample_to_float(a->buf, a->in, bat->frames);
Packit Service a9274b
Packit Service a9274b
	/* check amplitude */
Packit Service a9274b
	check_amplitude(bat, a->in);
Packit Service a9274b
Packit Service a9274b
	/* run FFT */
Packit Service a9274b
	fftwf_execute(p);
Packit Service a9274b
Packit Service a9274b
	/* FFT out is real and imaginary numbers - calc magnitude for each */
Packit Service a9274b
	calc_magnitude(bat, a, N);
Packit Service a9274b
Packit Service a9274b
	/* check data */
Packit Service a9274b
	err = check(bat, a, channel);
Packit Service a9274b
Packit Service a9274b
	fftwf_destroy_plan(p);
Packit Service a9274b
Packit Service a9274b
out4:
Packit Service a9274b
	fftwf_free(a->mag);
Packit Service a9274b
out3:
Packit Service a9274b
	fftwf_free(a->out);
Packit Service a9274b
out2:
Packit Service a9274b
	fftwf_free(a->in);
Packit Service a9274b
out1:
Packit Service a9274b
	return err;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int calculate_noise_one_period(struct bat *bat,
Packit Service a9274b
		struct noise_analyzer *na, float *src,
Packit Service a9274b
		int length, int channel)
Packit Service a9274b
{
Packit Service a9274b
	int i, shift = 0;
Packit Service a9274b
	float tmp, rms, gain, residual;
Packit Service a9274b
	float a = 0.0, b = 1.0;
Packit Service a9274b
Packit Service a9274b
	/* step 1. phase compensation */
Packit Service a9274b
Packit Service a9274b
	if (length < 2 * na->nsamples)
Packit Service a9274b
		return -EINVAL;
Packit Service a9274b
Packit Service a9274b
	/* search for the beginning of a sine period */
Packit Service a9274b
	for (i = 0, tmp = 0.0, shift = -1; i < na->nsamples; i++) {
Packit Service a9274b
		/* find i where src[i] >= 0 && src[i+1] < 0 */
Packit Service a9274b
		if (src[i] < 0.0)
Packit Service a9274b
			continue;
Packit Service a9274b
		if (src[i + 1] < 0.0) {
Packit Service a9274b
			tmp = src[i] - src[i + 1];
Packit Service a9274b
			a = src[i] / tmp;
Packit Service a9274b
			b = -src[i + 1] / tmp;
Packit Service a9274b
			shift = i;
Packit Service a9274b
			break;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	/* didn't find the beginning of a sine period */
Packit Service a9274b
	if (shift == -1)
Packit Service a9274b
		return -EINVAL;
Packit Service a9274b
Packit Service a9274b
	/* shift sine waveform to source[0] = 0.0 */
Packit Service a9274b
	for (i = 0; i < na->nsamples; i++)
Packit Service a9274b
		na->source[i] = a * src[i + shift + 1] + b * src[i + shift];
Packit Service a9274b
Packit Service a9274b
	/* step 2. gain compensation */
Packit Service a9274b
Packit Service a9274b
	/* calculate rms of signal amplitude */
Packit Service a9274b
	for (i = 0, tmp = 0.0; i < na->nsamples; i++)
Packit Service a9274b
		tmp += na->source[i] * na->source[i];
Packit Service a9274b
	rms = sqrtf(tmp / na->nsamples);
Packit Service a9274b
Packit Service a9274b
	gain = na->rms_tgt / rms;
Packit Service a9274b
Packit Service a9274b
	for (i = 0; i < na->nsamples; i++)
Packit Service a9274b
		na->source[i] *= gain;
Packit Service a9274b
Packit Service a9274b
	/* step 3. calculate snr in dB */
Packit Service a9274b
Packit Service a9274b
	for (i = 0, tmp = 0.0, residual = 0.0; i < na->nsamples; i++) {
Packit Service a9274b
		tmp = fabsf(na->target[i] - na->source[i]);
Packit Service a9274b
		residual += tmp * tmp;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	tmp = na->rms_tgt / sqrtf(residual / na->nsamples);
Packit Service a9274b
	na->snr_db = 20.0 * log10f(tmp);
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int calculate_noise(struct bat *bat, float *src, int channel)
Packit Service a9274b
{
Packit Service a9274b
	int err = 0;
Packit Service a9274b
	struct noise_analyzer na;
Packit Service a9274b
	float freq = bat->target_freq[channel];
Packit Service a9274b
	float tmp, sum_snr_pc, avg_snr_pc, avg_snr_db;
Packit Service a9274b
	int offset, i, cnt_noise, cnt_clean;
Packit Service a9274b
	/* num of samples in each sine period */
Packit Service a9274b
	int nsamples = (int) ceilf(bat->rate / freq);
Packit Service a9274b
	/* each section has 2 sine periods, the first one for locating
Packit Service a9274b
	 * and the second one for noise calculating */
Packit Service a9274b
	int nsamples_per_section = nsamples * 2;
Packit Service a9274b
	/* all sine periods will be calculated except the first one */
Packit Service a9274b
	int nsection = bat->frames / nsamples - 1;
Packit Service a9274b
Packit Service a9274b
	fprintf(bat->log, _("samples per period: %d\n"), nsamples);
Packit Service a9274b
	fprintf(bat->log, _("total sections to detect: %d\n"), nsection);
Packit Service a9274b
	na.source = (float *)malloc(sizeof(float) * nsamples);
Packit Service a9274b
	if (!na.source) {
Packit Service a9274b
		err = -ENOMEM;
Packit Service a9274b
		goto out1;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	na.target = (float *)malloc(sizeof(float) * nsamples);
Packit Service a9274b
	if (!na.target) {
Packit Service a9274b
		err = -ENOMEM;
Packit Service a9274b
		goto out2;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	/* generate standard single-tone signal */
Packit Service a9274b
	err = generate_sine_wave_raw_mono(bat, na.target, freq, nsamples);
Packit Service a9274b
	if (err < 0)
Packit Service a9274b
		goto out3;
Packit Service a9274b
Packit Service a9274b
	na.nsamples = nsamples;
Packit Service a9274b
Packit Service a9274b
	/* calculate rms of standard signal */
Packit Service a9274b
	for (i = 0, tmp = 0.0; i < nsamples; i++)
Packit Service a9274b
		tmp += na.target[i] * na.target[i];
Packit Service a9274b
	na.rms_tgt = sqrtf(tmp / nsamples);
Packit Service a9274b
Packit Service a9274b
	/* calculate average noise level */
Packit Service a9274b
	sum_snr_pc = 0.0;
Packit Service a9274b
	cnt_clean = cnt_noise = 0;
Packit Service a9274b
	for (i = 0, offset = 0; i < nsection; i++) {
Packit Service a9274b
		na.snr_db = SNR_DB_INVALID;
Packit Service a9274b
Packit Service a9274b
		err = calculate_noise_one_period(bat, &na, src + offset,
Packit Service a9274b
				nsamples_per_section, channel);
Packit Service a9274b
		if (err < 0)
Packit Service a9274b
			goto out3;
Packit Service a9274b
Packit Service a9274b
		if (na.snr_db > bat->snr_thd_db) {
Packit Service a9274b
			cnt_clean++;
Packit Service a9274b
			sum_snr_pc += 100.0 / powf(10.0, na.snr_db / 20.0);
Packit Service a9274b
		} else {
Packit Service a9274b
			cnt_noise++;
Packit Service a9274b
		}
Packit Service a9274b
		offset += nsamples;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	if (cnt_noise > 0) {
Packit Service a9274b
		fprintf(bat->err, _("Noise detected at %d points.\n"),
Packit Service a9274b
				cnt_noise);
Packit Service a9274b
		err = -cnt_noise;
Packit Service a9274b
		if (cnt_clean == 0)
Packit Service a9274b
			goto out3;
Packit Service a9274b
	} else {
Packit Service a9274b
		fprintf(bat->log, _("No noise detected.\n"));
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	avg_snr_pc = sum_snr_pc / cnt_clean;
Packit Service a9274b
	avg_snr_db = 20.0 * log10f(100.0 / avg_snr_pc);
Packit Service a9274b
	fprintf(bat->log, _("Average SNR is %.2f dB (%.2f %%) at %d points.\n"),
Packit Service a9274b
			avg_snr_db, avg_snr_pc, cnt_clean);
Packit Service a9274b
Packit Service a9274b
out3:
Packit Service a9274b
	free(na.target);
Packit Service a9274b
out2:
Packit Service a9274b
	free(na.source);
Packit Service a9274b
out1:
Packit Service a9274b
	return err;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int find_and_check_noise(struct bat *bat, void *buf, int channel)
Packit Service a9274b
{
Packit Service a9274b
	int err = 0;
Packit Service a9274b
	float *source;
Packit Service a9274b
Packit Service a9274b
	source = (float *)malloc(sizeof(float) * bat->frames);
Packit Service a9274b
	if (!source)
Packit Service a9274b
		return -ENOMEM;
Packit Service a9274b
Packit Service a9274b
	/* convert source PCM to floats */
Packit Service a9274b
	bat->convert_sample_to_float(buf, source, bat->frames);
Packit Service a9274b
Packit Service a9274b
	/* adjust waveform and calculate noise */
Packit Service a9274b
	err = calculate_noise(bat, source, channel);
Packit Service a9274b
Packit Service a9274b
	free(source);
Packit Service a9274b
	return err;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/**
Packit Service a9274b
 * Convert interleaved samples from channels in samples from a single channel
Packit Service a9274b
 */
Packit Service a9274b
static int reorder_data(struct bat *bat)
Packit Service a9274b
{
Packit Service a9274b
	char *p, *new_bat_buf;
Packit Service a9274b
	int ch, i, j;
Packit Service a9274b
Packit Service a9274b
	if (bat->channels == 1)
Packit Service a9274b
		return 0; /* No need for reordering */
Packit Service a9274b
Packit Service a9274b
	p = malloc(bat->frames * bat->frame_size);
Packit Service a9274b
	new_bat_buf = p;
Packit Service a9274b
	if (p == NULL)
Packit Service a9274b
		return -ENOMEM;
Packit Service a9274b
Packit Service a9274b
	for (ch = 0; ch < bat->channels; ch++) {
Packit Service a9274b
		for (j = 0; j < bat->frames; j++) {
Packit Service a9274b
			for (i = 0; i < bat->sample_size; i++) {
Packit Service a9274b
				*p++ = ((char *) (bat->buf))[j * bat->frame_size
Packit Service a9274b
						+ ch * bat->sample_size + i];
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	free(bat->buf);
Packit Service a9274b
	bat->buf = new_bat_buf;
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/* truncate sample frames for faster FFT analysis process */
Packit Service a9274b
static int truncate_frames(struct bat *bat)
Packit Service a9274b
{
Packit Service a9274b
	int shift = SHIFT_MAX;
Packit Service a9274b
Packit Service a9274b
	for (; shift > SHIFT_MIN; shift--)
Packit Service a9274b
		if (bat->frames & (1 << shift)) {
Packit Service a9274b
			bat->frames = 1 << shift;
Packit Service a9274b
			return 0;
Packit Service a9274b
		}
Packit Service a9274b
Packit Service a9274b
	return -EINVAL;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
int analyze_capture(struct bat *bat)
Packit Service a9274b
{
Packit Service a9274b
	int err = 0;
Packit Service a9274b
	size_t items;
Packit Service a9274b
	int c;
Packit Service a9274b
	struct analyze a;
Packit Service a9274b
Packit Service a9274b
	err = truncate_frames(bat);
Packit Service a9274b
	if (err < 0) {
Packit Service a9274b
		fprintf(bat->err, _("Invalid frame number for analysis: %d\n"),
Packit Service a9274b
				bat->frames);
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	fprintf(bat->log, _("\nBAT analysis: signal has %d frames at %d Hz,"),
Packit Service a9274b
			bat->frames, bat->rate);
Packit Service a9274b
	fprintf(bat->log, _(" %d channels, %d bytes per sample.\n"),
Packit Service a9274b
			bat->channels, bat->sample_size);
Packit Service a9274b
Packit Service a9274b
	bat->buf = malloc(bat->frames * bat->frame_size);
Packit Service a9274b
	if (bat->buf == NULL)
Packit Service a9274b
		return -ENOMEM;
Packit Service a9274b
Packit Service a9274b
	bat->fp = fopen(bat->capture.file, "rb");
Packit Service a9274b
	err = -errno;
Packit Service a9274b
	if (bat->fp == NULL) {
Packit Service a9274b
		fprintf(bat->err, _("Cannot open file: %s %d\n"),
Packit Service a9274b
				bat->capture.file, err);
Packit Service a9274b
		goto exit1;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	/* Skip header */
Packit Service a9274b
	err = read_wav_header(bat, bat->capture.file, bat->fp, true);
Packit Service a9274b
	if (err != 0)
Packit Service a9274b
		goto exit2;
Packit Service a9274b
Packit Service a9274b
	items = fread(bat->buf, bat->frame_size, bat->frames, bat->fp);
Packit Service a9274b
	if (items != bat->frames) {
Packit Service a9274b
		err = -EIO;
Packit Service a9274b
		goto exit2;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	err = reorder_data(bat);
Packit Service a9274b
	if (err != 0)
Packit Service a9274b
		goto exit2;
Packit Service a9274b
Packit Service a9274b
	for (c = 0; c < bat->channels; c++) {
Packit Service a9274b
		fprintf(bat->log, _("\nChannel %i - "), c + 1);
Packit Service a9274b
		fprintf(bat->log, _("Checking for target frequency %2.2f Hz\n"),
Packit Service a9274b
				bat->target_freq[c]);
Packit Service a9274b
		a.buf = bat->buf +
Packit Service a9274b
				c * bat->frames * bat->frame_size
Packit Service a9274b
				/ bat->channels;
Packit Service a9274b
		if (!bat->standalone) {
Packit Service a9274b
			err = find_and_check_harmonics(bat, &a, c);
Packit Service a9274b
			if (err != 0)
Packit Service a9274b
				goto exit2;
Packit Service a9274b
		}
Packit Service a9274b
Packit Service a9274b
		if (snr_is_valid(bat->snr_thd_db)) {
Packit Service a9274b
			fprintf(bat->log, _("\nChecking for SNR: "));
Packit Service a9274b
			fprintf(bat->log, _("Threshold is %.2f dB (%.2f%%)\n"),
Packit Service a9274b
					bat->snr_thd_db, 100.0
Packit Service a9274b
					/ powf(10.0, bat->snr_thd_db / 20.0));
Packit Service a9274b
			err = find_and_check_noise(bat, a.buf, c);
Packit Service a9274b
			if (err != 0)
Packit Service a9274b
				goto exit2;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
exit2:
Packit Service a9274b
	fclose(bat->fp);
Packit Service a9274b
exit1:
Packit Service a9274b
	free(bat->buf);
Packit Service a9274b
Packit Service a9274b
	return err;
Packit Service a9274b
}