1c72fcc34Sopenharmony_ci/* 2c72fcc34Sopenharmony_ci * Copyright (C) 2013-2015 Intel Corporation 3c72fcc34Sopenharmony_ci * 4c72fcc34Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 5c72fcc34Sopenharmony_ci * it under the terms of the GNU General Public License as published by 6c72fcc34Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 7c72fcc34Sopenharmony_ci * (at your option) any later version. 8c72fcc34Sopenharmony_ci * 9c72fcc34Sopenharmony_ci * This program is distributed in the hope that it will be useful, 10c72fcc34Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 11c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12c72fcc34Sopenharmony_ci * GNU General Public License for more details. 13c72fcc34Sopenharmony_ci * 14c72fcc34Sopenharmony_ci */ 15c72fcc34Sopenharmony_ci 16c72fcc34Sopenharmony_ci#include "aconfig.h" 17c72fcc34Sopenharmony_ci 18c72fcc34Sopenharmony_ci#include <stdio.h> 19c72fcc34Sopenharmony_ci#include <stdlib.h> 20c72fcc34Sopenharmony_ci#include <errno.h> 21c72fcc34Sopenharmony_ci#include <stdbool.h> 22c72fcc34Sopenharmony_ci#include <stdint.h> 23c72fcc34Sopenharmony_ci 24c72fcc34Sopenharmony_ci#include <math.h> 25c72fcc34Sopenharmony_ci#include <fftw3.h> 26c72fcc34Sopenharmony_ci 27c72fcc34Sopenharmony_ci#include "gettext.h" 28c72fcc34Sopenharmony_ci 29c72fcc34Sopenharmony_ci#include "common.h" 30c72fcc34Sopenharmony_ci#include "bat-signal.h" 31c72fcc34Sopenharmony_ci 32c72fcc34Sopenharmony_cistatic void check_amplitude(struct bat *bat, float *buf) 33c72fcc34Sopenharmony_ci{ 34c72fcc34Sopenharmony_ci float sum, average, amplitude; 35c72fcc34Sopenharmony_ci int i, percent; 36c72fcc34Sopenharmony_ci 37c72fcc34Sopenharmony_ci /* calculate average value */ 38c72fcc34Sopenharmony_ci for (i = 0, sum = 0.0, average = 0.0; i < bat->frames; i++) 39c72fcc34Sopenharmony_ci sum += buf[i]; 40c72fcc34Sopenharmony_ci average = sum / bat->frames; 41c72fcc34Sopenharmony_ci 42c72fcc34Sopenharmony_ci /* calculate peak-to-average amplitude */ 43c72fcc34Sopenharmony_ci for (i = 0, sum = 0.0; i < bat->frames; i++) 44c72fcc34Sopenharmony_ci sum += fabsf(buf[i] - average); 45c72fcc34Sopenharmony_ci amplitude = sum / bat->frames * M_PI / 2.0; 46c72fcc34Sopenharmony_ci 47c72fcc34Sopenharmony_ci /* calculate amplitude percentage against full range */ 48c72fcc34Sopenharmony_ci percent = amplitude * 100 / ((1 << ((bat->sample_size << 3) - 1)) - 1); 49c72fcc34Sopenharmony_ci 50c72fcc34Sopenharmony_ci fprintf(bat->log, _("Amplitude: %.1f; Percentage: [%d]\n"), 51c72fcc34Sopenharmony_ci amplitude, percent); 52c72fcc34Sopenharmony_ci if (percent < 0) 53c72fcc34Sopenharmony_ci fprintf(bat->err, _("ERROR: Amplitude can't be negative!\n")); 54c72fcc34Sopenharmony_ci else if (percent < 1) 55c72fcc34Sopenharmony_ci fprintf(bat->err, _("WARNING: Signal too weak!\n")); 56c72fcc34Sopenharmony_ci else if (percent > 100) 57c72fcc34Sopenharmony_ci fprintf(bat->err, _("WARNING: Signal overflow!\n")); 58c72fcc34Sopenharmony_ci} 59c72fcc34Sopenharmony_ci 60c72fcc34Sopenharmony_ci/** 61c72fcc34Sopenharmony_ci * 62c72fcc34Sopenharmony_ci * @return 0 if peak detected at right frequency, 63c72fcc34Sopenharmony_ci * 1 if peak detected somewhere else 64c72fcc34Sopenharmony_ci * 2 if DC detected 65c72fcc34Sopenharmony_ci */ 66c72fcc34Sopenharmony_ciint check_peak(struct bat *bat, struct analyze *a, int end, int peak, float hz, 67c72fcc34Sopenharmony_ci float mean, float p, int channel, int start) 68c72fcc34Sopenharmony_ci{ 69c72fcc34Sopenharmony_ci int err; 70c72fcc34Sopenharmony_ci float hz_peak = (float) (peak) * hz; 71c72fcc34Sopenharmony_ci float delta_rate = DELTA_RATE * bat->target_freq[channel]; 72c72fcc34Sopenharmony_ci float delta_HZ = DELTA_HZ; 73c72fcc34Sopenharmony_ci float tolerance = (delta_rate > delta_HZ) ? delta_rate : delta_HZ; 74c72fcc34Sopenharmony_ci 75c72fcc34Sopenharmony_ci fprintf(bat->log, _("Detected peak at %2.2f Hz of %2.2f dB\n"), hz_peak, 76c72fcc34Sopenharmony_ci 10.0 * log10f(a->mag[peak] / mean)); 77c72fcc34Sopenharmony_ci fprintf(bat->log, _(" Total %3.1f dB from %2.2f to %2.2f Hz\n"), 78c72fcc34Sopenharmony_ci 10.0 * log10f(p / mean), start * hz, end * hz); 79c72fcc34Sopenharmony_ci 80c72fcc34Sopenharmony_ci if (hz_peak < DC_THRESHOLD) { 81c72fcc34Sopenharmony_ci fprintf(bat->err, _(" WARNING: Found low peak %2.2f Hz,"), 82c72fcc34Sopenharmony_ci hz_peak); 83c72fcc34Sopenharmony_ci fprintf(bat->err, _(" very close to DC\n")); 84c72fcc34Sopenharmony_ci err = FOUND_DC; 85c72fcc34Sopenharmony_ci } else if (hz_peak < bat->target_freq[channel] - tolerance) { 86c72fcc34Sopenharmony_ci fprintf(bat->err, _(" FAIL: Peak freq too low %2.2f Hz\n"), 87c72fcc34Sopenharmony_ci hz_peak); 88c72fcc34Sopenharmony_ci err = FOUND_WRONG_PEAK; 89c72fcc34Sopenharmony_ci } else if (hz_peak > bat->target_freq[channel] + tolerance) { 90c72fcc34Sopenharmony_ci fprintf(bat->err, _(" FAIL: Peak freq too high %2.2f Hz\n"), 91c72fcc34Sopenharmony_ci hz_peak); 92c72fcc34Sopenharmony_ci err = FOUND_WRONG_PEAK; 93c72fcc34Sopenharmony_ci } else { 94c72fcc34Sopenharmony_ci fprintf(bat->log, _(" PASS: Peak detected")); 95c72fcc34Sopenharmony_ci fprintf(bat->log, _(" at target frequency\n")); 96c72fcc34Sopenharmony_ci err = 0; 97c72fcc34Sopenharmony_ci } 98c72fcc34Sopenharmony_ci 99c72fcc34Sopenharmony_ci return err; 100c72fcc34Sopenharmony_ci} 101c72fcc34Sopenharmony_ci 102c72fcc34Sopenharmony_ci/** 103c72fcc34Sopenharmony_ci * Search for main frequencies in fft results and compare it to target 104c72fcc34Sopenharmony_ci */ 105c72fcc34Sopenharmony_cistatic int check(struct bat *bat, struct analyze *a, int channel) 106c72fcc34Sopenharmony_ci{ 107c72fcc34Sopenharmony_ci float hz = 1.0 / ((float) bat->frames / (float) bat->rate); 108c72fcc34Sopenharmony_ci float mean = 0.0, t, sigma = 0.0, p = 0.0; 109c72fcc34Sopenharmony_ci int i, start = -1, end = -1, peak = 0, signals = 0; 110c72fcc34Sopenharmony_ci int err = 0, N = bat->frames / 2; 111c72fcc34Sopenharmony_ci 112c72fcc34Sopenharmony_ci /* calculate mean */ 113c72fcc34Sopenharmony_ci for (i = 0; i < N; i++) 114c72fcc34Sopenharmony_ci mean += a->mag[i]; 115c72fcc34Sopenharmony_ci mean /= (float) N; 116c72fcc34Sopenharmony_ci 117c72fcc34Sopenharmony_ci /* calculate standard deviation */ 118c72fcc34Sopenharmony_ci for (i = 0; i < N; i++) { 119c72fcc34Sopenharmony_ci t = a->mag[i] - mean; 120c72fcc34Sopenharmony_ci t *= t; 121c72fcc34Sopenharmony_ci sigma += t; 122c72fcc34Sopenharmony_ci } 123c72fcc34Sopenharmony_ci sigma /= (float) N; 124c72fcc34Sopenharmony_ci sigma = sqrtf(sigma); 125c72fcc34Sopenharmony_ci 126c72fcc34Sopenharmony_ci /* clip any data less than k sigma + mean */ 127c72fcc34Sopenharmony_ci for (i = 0; i < N; i++) { 128c72fcc34Sopenharmony_ci if (a->mag[i] > mean + bat->sigma_k * sigma) { 129c72fcc34Sopenharmony_ci 130c72fcc34Sopenharmony_ci /* find peak start points */ 131c72fcc34Sopenharmony_ci if (start == -1) { 132c72fcc34Sopenharmony_ci start = peak = end = i; 133c72fcc34Sopenharmony_ci signals++; 134c72fcc34Sopenharmony_ci } else { 135c72fcc34Sopenharmony_ci if (a->mag[i] > a->mag[peak]) 136c72fcc34Sopenharmony_ci peak = i; 137c72fcc34Sopenharmony_ci end = i; 138c72fcc34Sopenharmony_ci } 139c72fcc34Sopenharmony_ci p += a->mag[i]; 140c72fcc34Sopenharmony_ci } else if (start != -1) { 141c72fcc34Sopenharmony_ci /* Check if peak is as expected */ 142c72fcc34Sopenharmony_ci err |= check_peak(bat, a, end, peak, hz, mean, 143c72fcc34Sopenharmony_ci p, channel, start); 144c72fcc34Sopenharmony_ci end = start = -1; 145c72fcc34Sopenharmony_ci if (signals == MAX_PEAKS) 146c72fcc34Sopenharmony_ci break; 147c72fcc34Sopenharmony_ci } 148c72fcc34Sopenharmony_ci } 149c72fcc34Sopenharmony_ci if (signals == 0) 150c72fcc34Sopenharmony_ci err = -ENOPEAK; /* No peak detected */ 151c72fcc34Sopenharmony_ci else if ((err == FOUND_DC) && (signals == 1)) 152c72fcc34Sopenharmony_ci err = -EONLYDC; /* Only DC detected */ 153c72fcc34Sopenharmony_ci else if ((err & FOUND_WRONG_PEAK) == FOUND_WRONG_PEAK) 154c72fcc34Sopenharmony_ci err = -EBADPEAK; /* Bad peak detected */ 155c72fcc34Sopenharmony_ci else 156c72fcc34Sopenharmony_ci err = 0; /* Correct peak detected */ 157c72fcc34Sopenharmony_ci 158c72fcc34Sopenharmony_ci fprintf(bat->log, _("Detected at least %d signal(s) in total\n"), 159c72fcc34Sopenharmony_ci signals); 160c72fcc34Sopenharmony_ci 161c72fcc34Sopenharmony_ci return err; 162c72fcc34Sopenharmony_ci} 163c72fcc34Sopenharmony_ci 164c72fcc34Sopenharmony_cistatic void calc_magnitude(struct bat *bat, struct analyze *a, int N) 165c72fcc34Sopenharmony_ci{ 166c72fcc34Sopenharmony_ci float r2, i2; 167c72fcc34Sopenharmony_ci int i; 168c72fcc34Sopenharmony_ci 169c72fcc34Sopenharmony_ci for (i = 1; i < N / 2; i++) { 170c72fcc34Sopenharmony_ci r2 = a->out[i] * a->out[i]; 171c72fcc34Sopenharmony_ci i2 = a->out[N - i] * a->out[N - i]; 172c72fcc34Sopenharmony_ci 173c72fcc34Sopenharmony_ci a->mag[i] = sqrtf(r2 + i2); 174c72fcc34Sopenharmony_ci } 175c72fcc34Sopenharmony_ci a->mag[0] = 0.0; 176c72fcc34Sopenharmony_ci} 177c72fcc34Sopenharmony_ci 178c72fcc34Sopenharmony_cistatic int find_and_check_harmonics(struct bat *bat, struct analyze *a, 179c72fcc34Sopenharmony_ci int channel) 180c72fcc34Sopenharmony_ci{ 181c72fcc34Sopenharmony_ci fftwf_plan p; 182c72fcc34Sopenharmony_ci int err = -ENOMEM, N = bat->frames; 183c72fcc34Sopenharmony_ci 184c72fcc34Sopenharmony_ci /* Allocate FFT buffers */ 185c72fcc34Sopenharmony_ci a->in = (float *) fftwf_malloc(sizeof(float) * bat->frames); 186c72fcc34Sopenharmony_ci if (a->in == NULL) 187c72fcc34Sopenharmony_ci goto out1; 188c72fcc34Sopenharmony_ci 189c72fcc34Sopenharmony_ci a->out = (float *) fftwf_malloc(sizeof(float) * bat->frames); 190c72fcc34Sopenharmony_ci if (a->out == NULL) 191c72fcc34Sopenharmony_ci goto out2; 192c72fcc34Sopenharmony_ci 193c72fcc34Sopenharmony_ci a->mag = (float *) fftwf_malloc(sizeof(float) * bat->frames); 194c72fcc34Sopenharmony_ci if (a->mag == NULL) 195c72fcc34Sopenharmony_ci goto out3; 196c72fcc34Sopenharmony_ci 197c72fcc34Sopenharmony_ci /* create FFT plan */ 198c72fcc34Sopenharmony_ci p = fftwf_plan_r2r_1d(N, a->in, a->out, FFTW_R2HC, 199c72fcc34Sopenharmony_ci FFTW_MEASURE | FFTW_PRESERVE_INPUT); 200c72fcc34Sopenharmony_ci if (p == NULL) 201c72fcc34Sopenharmony_ci goto out4; 202c72fcc34Sopenharmony_ci 203c72fcc34Sopenharmony_ci /* convert source PCM to floats */ 204c72fcc34Sopenharmony_ci bat->convert_sample_to_float(a->buf, a->in, bat->frames); 205c72fcc34Sopenharmony_ci 206c72fcc34Sopenharmony_ci /* check amplitude */ 207c72fcc34Sopenharmony_ci check_amplitude(bat, a->in); 208c72fcc34Sopenharmony_ci 209c72fcc34Sopenharmony_ci /* run FFT */ 210c72fcc34Sopenharmony_ci fftwf_execute(p); 211c72fcc34Sopenharmony_ci 212c72fcc34Sopenharmony_ci /* FFT out is real and imaginary numbers - calc magnitude for each */ 213c72fcc34Sopenharmony_ci calc_magnitude(bat, a, N); 214c72fcc34Sopenharmony_ci 215c72fcc34Sopenharmony_ci /* check data */ 216c72fcc34Sopenharmony_ci err = check(bat, a, channel); 217c72fcc34Sopenharmony_ci 218c72fcc34Sopenharmony_ci fftwf_destroy_plan(p); 219c72fcc34Sopenharmony_ci 220c72fcc34Sopenharmony_ciout4: 221c72fcc34Sopenharmony_ci fftwf_free(a->mag); 222c72fcc34Sopenharmony_ciout3: 223c72fcc34Sopenharmony_ci fftwf_free(a->out); 224c72fcc34Sopenharmony_ciout2: 225c72fcc34Sopenharmony_ci fftwf_free(a->in); 226c72fcc34Sopenharmony_ciout1: 227c72fcc34Sopenharmony_ci return err; 228c72fcc34Sopenharmony_ci} 229c72fcc34Sopenharmony_ci 230c72fcc34Sopenharmony_cistatic int calculate_noise_one_period(struct bat *bat, 231c72fcc34Sopenharmony_ci struct noise_analyzer *na, float *src, 232c72fcc34Sopenharmony_ci int length, int channel) 233c72fcc34Sopenharmony_ci{ 234c72fcc34Sopenharmony_ci int i, shift = 0; 235c72fcc34Sopenharmony_ci float tmp, rms, gain, residual; 236c72fcc34Sopenharmony_ci float a = 0.0, b = 1.0; 237c72fcc34Sopenharmony_ci 238c72fcc34Sopenharmony_ci /* step 1. phase compensation */ 239c72fcc34Sopenharmony_ci 240c72fcc34Sopenharmony_ci if (length < 2 * na->nsamples) 241c72fcc34Sopenharmony_ci return -EINVAL; 242c72fcc34Sopenharmony_ci 243c72fcc34Sopenharmony_ci /* search for the beginning of a sine period */ 244c72fcc34Sopenharmony_ci for (i = 0, tmp = 0.0, shift = -1; i < na->nsamples; i++) { 245c72fcc34Sopenharmony_ci /* find i where src[i] >= 0 && src[i+1] < 0 */ 246c72fcc34Sopenharmony_ci if (src[i] < 0.0) 247c72fcc34Sopenharmony_ci continue; 248c72fcc34Sopenharmony_ci if (src[i + 1] < 0.0) { 249c72fcc34Sopenharmony_ci tmp = src[i] - src[i + 1]; 250c72fcc34Sopenharmony_ci a = src[i] / tmp; 251c72fcc34Sopenharmony_ci b = -src[i + 1] / tmp; 252c72fcc34Sopenharmony_ci shift = i; 253c72fcc34Sopenharmony_ci break; 254c72fcc34Sopenharmony_ci } 255c72fcc34Sopenharmony_ci } 256c72fcc34Sopenharmony_ci 257c72fcc34Sopenharmony_ci /* didn't find the beginning of a sine period */ 258c72fcc34Sopenharmony_ci if (shift == -1) 259c72fcc34Sopenharmony_ci return -EINVAL; 260c72fcc34Sopenharmony_ci 261c72fcc34Sopenharmony_ci /* shift sine waveform to source[0] = 0.0 */ 262c72fcc34Sopenharmony_ci for (i = 0; i < na->nsamples; i++) 263c72fcc34Sopenharmony_ci na->source[i] = a * src[i + shift + 1] + b * src[i + shift]; 264c72fcc34Sopenharmony_ci 265c72fcc34Sopenharmony_ci /* step 2. gain compensation */ 266c72fcc34Sopenharmony_ci 267c72fcc34Sopenharmony_ci /* calculate rms of signal amplitude */ 268c72fcc34Sopenharmony_ci for (i = 0, tmp = 0.0; i < na->nsamples; i++) 269c72fcc34Sopenharmony_ci tmp += na->source[i] * na->source[i]; 270c72fcc34Sopenharmony_ci rms = sqrtf(tmp / na->nsamples); 271c72fcc34Sopenharmony_ci 272c72fcc34Sopenharmony_ci gain = na->rms_tgt / rms; 273c72fcc34Sopenharmony_ci 274c72fcc34Sopenharmony_ci for (i = 0; i < na->nsamples; i++) 275c72fcc34Sopenharmony_ci na->source[i] *= gain; 276c72fcc34Sopenharmony_ci 277c72fcc34Sopenharmony_ci /* step 3. calculate snr in dB */ 278c72fcc34Sopenharmony_ci 279c72fcc34Sopenharmony_ci for (i = 0, tmp = 0.0, residual = 0.0; i < na->nsamples; i++) { 280c72fcc34Sopenharmony_ci tmp = fabsf(na->target[i] - na->source[i]); 281c72fcc34Sopenharmony_ci residual += tmp * tmp; 282c72fcc34Sopenharmony_ci } 283c72fcc34Sopenharmony_ci 284c72fcc34Sopenharmony_ci tmp = na->rms_tgt / sqrtf(residual / na->nsamples); 285c72fcc34Sopenharmony_ci na->snr_db = 20.0 * log10f(tmp); 286c72fcc34Sopenharmony_ci 287c72fcc34Sopenharmony_ci return 0; 288c72fcc34Sopenharmony_ci} 289c72fcc34Sopenharmony_ci 290c72fcc34Sopenharmony_cistatic int calculate_noise(struct bat *bat, float *src, int channel) 291c72fcc34Sopenharmony_ci{ 292c72fcc34Sopenharmony_ci int err = 0; 293c72fcc34Sopenharmony_ci struct noise_analyzer na; 294c72fcc34Sopenharmony_ci float freq = bat->target_freq[channel]; 295c72fcc34Sopenharmony_ci float tmp, sum_snr_pc, avg_snr_pc, avg_snr_db; 296c72fcc34Sopenharmony_ci int offset, i, cnt_noise, cnt_clean; 297c72fcc34Sopenharmony_ci /* num of samples in each sine period */ 298c72fcc34Sopenharmony_ci int nsamples = (int) ceilf(bat->rate / freq); 299c72fcc34Sopenharmony_ci /* each section has 2 sine periods, the first one for locating 300c72fcc34Sopenharmony_ci * and the second one for noise calculating */ 301c72fcc34Sopenharmony_ci int nsamples_per_section = nsamples * 2; 302c72fcc34Sopenharmony_ci /* all sine periods will be calculated except the first and last one */ 303c72fcc34Sopenharmony_ci int nsection = bat->frames / nsamples - 1; 304c72fcc34Sopenharmony_ci 305c72fcc34Sopenharmony_ci fprintf(bat->log, _("samples per period: %d\n"), nsamples); 306c72fcc34Sopenharmony_ci fprintf(bat->log, _("total sections to detect: %d\n"), nsection); 307c72fcc34Sopenharmony_ci na.source = (float *)malloc(sizeof(float) * nsamples); 308c72fcc34Sopenharmony_ci if (!na.source) { 309c72fcc34Sopenharmony_ci err = -ENOMEM; 310c72fcc34Sopenharmony_ci goto out1; 311c72fcc34Sopenharmony_ci } 312c72fcc34Sopenharmony_ci 313c72fcc34Sopenharmony_ci na.target = (float *)malloc(sizeof(float) * nsamples); 314c72fcc34Sopenharmony_ci if (!na.target) { 315c72fcc34Sopenharmony_ci err = -ENOMEM; 316c72fcc34Sopenharmony_ci goto out2; 317c72fcc34Sopenharmony_ci } 318c72fcc34Sopenharmony_ci 319c72fcc34Sopenharmony_ci /* generate standard single-tone signal */ 320c72fcc34Sopenharmony_ci err = generate_sine_wave_raw_mono(bat, na.target, freq, nsamples); 321c72fcc34Sopenharmony_ci if (err < 0) 322c72fcc34Sopenharmony_ci goto out3; 323c72fcc34Sopenharmony_ci 324c72fcc34Sopenharmony_ci na.nsamples = nsamples; 325c72fcc34Sopenharmony_ci 326c72fcc34Sopenharmony_ci /* calculate rms of standard signal */ 327c72fcc34Sopenharmony_ci for (i = 0, tmp = 0.0; i < nsamples; i++) 328c72fcc34Sopenharmony_ci tmp += na.target[i] * na.target[i]; 329c72fcc34Sopenharmony_ci na.rms_tgt = sqrtf(tmp / nsamples); 330c72fcc34Sopenharmony_ci 331c72fcc34Sopenharmony_ci /* calculate average noise level */ 332c72fcc34Sopenharmony_ci sum_snr_pc = 0.0; 333c72fcc34Sopenharmony_ci cnt_clean = cnt_noise = 0; 334c72fcc34Sopenharmony_ci for (i = 1, offset = nsamples; i < nsection; i++) { 335c72fcc34Sopenharmony_ci na.snr_db = SNR_DB_INVALID; 336c72fcc34Sopenharmony_ci 337c72fcc34Sopenharmony_ci err = calculate_noise_one_period(bat, &na, src + offset, 338c72fcc34Sopenharmony_ci nsamples_per_section, channel); 339c72fcc34Sopenharmony_ci if (err < 0) 340c72fcc34Sopenharmony_ci goto out3; 341c72fcc34Sopenharmony_ci 342c72fcc34Sopenharmony_ci if (na.snr_db > bat->snr_thd_db) { 343c72fcc34Sopenharmony_ci cnt_clean++; 344c72fcc34Sopenharmony_ci sum_snr_pc += 100.0 / powf(10.0, na.snr_db / 20.0); 345c72fcc34Sopenharmony_ci } else { 346c72fcc34Sopenharmony_ci cnt_noise++; 347c72fcc34Sopenharmony_ci } 348c72fcc34Sopenharmony_ci offset += nsamples; 349c72fcc34Sopenharmony_ci } 350c72fcc34Sopenharmony_ci 351c72fcc34Sopenharmony_ci if (cnt_noise > 0) { 352c72fcc34Sopenharmony_ci fprintf(bat->err, _("Noise detected at %d points.\n"), 353c72fcc34Sopenharmony_ci cnt_noise); 354c72fcc34Sopenharmony_ci err = -cnt_noise; 355c72fcc34Sopenharmony_ci if (cnt_clean == 0) 356c72fcc34Sopenharmony_ci goto out3; 357c72fcc34Sopenharmony_ci } else { 358c72fcc34Sopenharmony_ci fprintf(bat->log, _("No noise detected.\n")); 359c72fcc34Sopenharmony_ci } 360c72fcc34Sopenharmony_ci 361c72fcc34Sopenharmony_ci avg_snr_pc = sum_snr_pc / cnt_clean; 362c72fcc34Sopenharmony_ci avg_snr_db = 20.0 * log10f(100.0 / avg_snr_pc); 363c72fcc34Sopenharmony_ci fprintf(bat->log, _("Average SNR is %.2f dB (%.2f %%) at %d points.\n"), 364c72fcc34Sopenharmony_ci avg_snr_db, avg_snr_pc, cnt_clean); 365c72fcc34Sopenharmony_ci 366c72fcc34Sopenharmony_ciout3: 367c72fcc34Sopenharmony_ci free(na.target); 368c72fcc34Sopenharmony_ciout2: 369c72fcc34Sopenharmony_ci free(na.source); 370c72fcc34Sopenharmony_ciout1: 371c72fcc34Sopenharmony_ci return err; 372c72fcc34Sopenharmony_ci} 373c72fcc34Sopenharmony_ci 374c72fcc34Sopenharmony_cistatic int find_and_check_noise(struct bat *bat, void *buf, int channel) 375c72fcc34Sopenharmony_ci{ 376c72fcc34Sopenharmony_ci int err = 0; 377c72fcc34Sopenharmony_ci float *source; 378c72fcc34Sopenharmony_ci 379c72fcc34Sopenharmony_ci source = (float *)malloc(sizeof(float) * bat->frames); 380c72fcc34Sopenharmony_ci if (!source) 381c72fcc34Sopenharmony_ci return -ENOMEM; 382c72fcc34Sopenharmony_ci 383c72fcc34Sopenharmony_ci /* convert source PCM to floats */ 384c72fcc34Sopenharmony_ci bat->convert_sample_to_float(buf, source, bat->frames); 385c72fcc34Sopenharmony_ci 386c72fcc34Sopenharmony_ci /* adjust waveform and calculate noise */ 387c72fcc34Sopenharmony_ci err = calculate_noise(bat, source, channel); 388c72fcc34Sopenharmony_ci 389c72fcc34Sopenharmony_ci free(source); 390c72fcc34Sopenharmony_ci return err; 391c72fcc34Sopenharmony_ci} 392c72fcc34Sopenharmony_ci 393c72fcc34Sopenharmony_ci/** 394c72fcc34Sopenharmony_ci * Convert interleaved samples from channels in samples from a single channel 395c72fcc34Sopenharmony_ci */ 396c72fcc34Sopenharmony_cistatic int reorder_data(struct bat *bat) 397c72fcc34Sopenharmony_ci{ 398c72fcc34Sopenharmony_ci char *p, *new_bat_buf; 399c72fcc34Sopenharmony_ci int ch, i, j; 400c72fcc34Sopenharmony_ci 401c72fcc34Sopenharmony_ci if (bat->channels == 1) 402c72fcc34Sopenharmony_ci return 0; /* No need for reordering */ 403c72fcc34Sopenharmony_ci 404c72fcc34Sopenharmony_ci p = malloc(bat->frames * bat->frame_size); 405c72fcc34Sopenharmony_ci new_bat_buf = p; 406c72fcc34Sopenharmony_ci if (p == NULL) 407c72fcc34Sopenharmony_ci return -ENOMEM; 408c72fcc34Sopenharmony_ci 409c72fcc34Sopenharmony_ci for (ch = 0; ch < bat->channels; ch++) { 410c72fcc34Sopenharmony_ci for (j = 0; j < bat->frames; j++) { 411c72fcc34Sopenharmony_ci for (i = 0; i < bat->sample_size; i++) { 412c72fcc34Sopenharmony_ci *p++ = ((char *) (bat->buf))[j * bat->frame_size 413c72fcc34Sopenharmony_ci + ch * bat->sample_size + i]; 414c72fcc34Sopenharmony_ci } 415c72fcc34Sopenharmony_ci } 416c72fcc34Sopenharmony_ci } 417c72fcc34Sopenharmony_ci 418c72fcc34Sopenharmony_ci free(bat->buf); 419c72fcc34Sopenharmony_ci bat->buf = new_bat_buf; 420c72fcc34Sopenharmony_ci 421c72fcc34Sopenharmony_ci return 0; 422c72fcc34Sopenharmony_ci} 423c72fcc34Sopenharmony_ci 424c72fcc34Sopenharmony_ci/* truncate sample frames for faster FFT analysis process */ 425c72fcc34Sopenharmony_cistatic int truncate_frames(struct bat *bat) 426c72fcc34Sopenharmony_ci{ 427c72fcc34Sopenharmony_ci int shift = SHIFT_MAX; 428c72fcc34Sopenharmony_ci 429c72fcc34Sopenharmony_ci for (; shift > SHIFT_MIN; shift--) 430c72fcc34Sopenharmony_ci if (bat->frames & (1 << shift)) { 431c72fcc34Sopenharmony_ci bat->frames = 1 << shift; 432c72fcc34Sopenharmony_ci return 0; 433c72fcc34Sopenharmony_ci } 434c72fcc34Sopenharmony_ci 435c72fcc34Sopenharmony_ci return -EINVAL; 436c72fcc34Sopenharmony_ci} 437c72fcc34Sopenharmony_ci 438c72fcc34Sopenharmony_ciint analyze_capture(struct bat *bat) 439c72fcc34Sopenharmony_ci{ 440c72fcc34Sopenharmony_ci int err = 0; 441c72fcc34Sopenharmony_ci size_t items; 442c72fcc34Sopenharmony_ci int c; 443c72fcc34Sopenharmony_ci struct analyze a; 444c72fcc34Sopenharmony_ci 445c72fcc34Sopenharmony_ci err = truncate_frames(bat); 446c72fcc34Sopenharmony_ci if (err < 0) { 447c72fcc34Sopenharmony_ci fprintf(bat->err, _("Invalid frame number for analysis: %d\n"), 448c72fcc34Sopenharmony_ci bat->frames); 449c72fcc34Sopenharmony_ci return err; 450c72fcc34Sopenharmony_ci } 451c72fcc34Sopenharmony_ci 452c72fcc34Sopenharmony_ci fprintf(bat->log, _("\nBAT analysis: signal has %d frames at %d Hz,"), 453c72fcc34Sopenharmony_ci bat->frames, bat->rate); 454c72fcc34Sopenharmony_ci fprintf(bat->log, _(" %d channels, %d bytes per sample.\n"), 455c72fcc34Sopenharmony_ci bat->channels, bat->sample_size); 456c72fcc34Sopenharmony_ci 457c72fcc34Sopenharmony_ci bat->buf = malloc(bat->frames * bat->frame_size); 458c72fcc34Sopenharmony_ci if (bat->buf == NULL) 459c72fcc34Sopenharmony_ci return -ENOMEM; 460c72fcc34Sopenharmony_ci 461c72fcc34Sopenharmony_ci bat->fp = fopen(bat->capture.file, "rb"); 462c72fcc34Sopenharmony_ci err = -errno; 463c72fcc34Sopenharmony_ci if (bat->fp == NULL) { 464c72fcc34Sopenharmony_ci fprintf(bat->err, _("Cannot open file: %s %d\n"), 465c72fcc34Sopenharmony_ci bat->capture.file, err); 466c72fcc34Sopenharmony_ci goto exit1; 467c72fcc34Sopenharmony_ci } 468c72fcc34Sopenharmony_ci 469c72fcc34Sopenharmony_ci /* Skip header */ 470c72fcc34Sopenharmony_ci err = read_wav_header(bat, bat->capture.file, bat->fp, true); 471c72fcc34Sopenharmony_ci if (err != 0) 472c72fcc34Sopenharmony_ci goto exit2; 473c72fcc34Sopenharmony_ci 474c72fcc34Sopenharmony_ci items = fread(bat->buf, bat->frame_size, bat->frames, bat->fp); 475c72fcc34Sopenharmony_ci if (items != bat->frames) { 476c72fcc34Sopenharmony_ci err = -EIO; 477c72fcc34Sopenharmony_ci goto exit2; 478c72fcc34Sopenharmony_ci } 479c72fcc34Sopenharmony_ci 480c72fcc34Sopenharmony_ci err = reorder_data(bat); 481c72fcc34Sopenharmony_ci if (err != 0) 482c72fcc34Sopenharmony_ci goto exit2; 483c72fcc34Sopenharmony_ci 484c72fcc34Sopenharmony_ci for (c = 0; c < bat->channels; c++) { 485c72fcc34Sopenharmony_ci fprintf(bat->log, _("\nChannel %i - "), c + 1); 486c72fcc34Sopenharmony_ci fprintf(bat->log, _("Checking for target frequency %2.2f Hz\n"), 487c72fcc34Sopenharmony_ci bat->target_freq[c]); 488c72fcc34Sopenharmony_ci a.buf = bat->buf + 489c72fcc34Sopenharmony_ci c * bat->frames * bat->frame_size 490c72fcc34Sopenharmony_ci / bat->channels; 491c72fcc34Sopenharmony_ci if (!bat->standalone) { 492c72fcc34Sopenharmony_ci err = find_and_check_harmonics(bat, &a, c); 493c72fcc34Sopenharmony_ci if (err != 0) 494c72fcc34Sopenharmony_ci goto exit2; 495c72fcc34Sopenharmony_ci } 496c72fcc34Sopenharmony_ci 497c72fcc34Sopenharmony_ci if (snr_is_valid(bat->snr_thd_db)) { 498c72fcc34Sopenharmony_ci fprintf(bat->log, _("\nChecking for SNR: ")); 499c72fcc34Sopenharmony_ci fprintf(bat->log, _("Threshold is %.2f dB (%.2f%%)\n"), 500c72fcc34Sopenharmony_ci bat->snr_thd_db, 100.0 501c72fcc34Sopenharmony_ci / powf(10.0, bat->snr_thd_db / 20.0)); 502c72fcc34Sopenharmony_ci err = find_and_check_noise(bat, a.buf, c); 503c72fcc34Sopenharmony_ci if (err != 0) 504c72fcc34Sopenharmony_ci goto exit2; 505c72fcc34Sopenharmony_ci } 506c72fcc34Sopenharmony_ci } 507c72fcc34Sopenharmony_ci 508c72fcc34Sopenharmony_ciexit2: 509c72fcc34Sopenharmony_ci fclose(bat->fp); 510c72fcc34Sopenharmony_ciexit1: 511c72fcc34Sopenharmony_ci free(bat->buf); 512c72fcc34Sopenharmony_ci 513c72fcc34Sopenharmony_ci return err; 514c72fcc34Sopenharmony_ci} 515