From 48b36c4de497551baedc533cd2ef37e402dc2fb3 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Wed, 13 Jan 2016 00:54:59 +0100 Subject: [PATCH] Add missing file. --- correlation_measurer.cpp | 67 ++++++++++++++++++++++++++++++++++++++++ correlation_measurer.h | 55 +++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 correlation_measurer.cpp create mode 100644 correlation_measurer.h diff --git a/correlation_measurer.cpp b/correlation_measurer.cpp new file mode 100644 index 0000000..888ebff --- /dev/null +++ b/correlation_measurer.cpp @@ -0,0 +1,67 @@ +// Adapted from Adriaensen's project Zita-mu1 (as of January 2016). +// Original copyright follows: +// +// Copyright (C) 2008-2015 Fons Adriaensen +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "correlation_measurer.h" + +#include +#include +#include + +using namespace std; + +CorrelationMeasurer::CorrelationMeasurer(unsigned sample_rate, + float lowpass_cutoff_hz, + float falloff_seconds) + : w1(2.0 * M_PI * lowpass_cutoff_hz / sample_rate), + w2(1.0 / (falloff_seconds * sample_rate)) +{ +} + +void CorrelationMeasurer::process_samples(const std::vector &samples) +{ + assert(samples.size() % 2 == 0); + + // The compiler isn't always happy about modifying members, + // since it doesn't always know they can't alias on . + // Help it out a bit. + float l = zl, r = zr, ll = zll, lr = zlr, rr = zrr; + const float w1c = w1, w2c = w2; + + for (size_t i = 0; i < samples.size(); i += 2) { + // The 1e-15f epsilon is to avoid denormals. + // TODO: Just set the SSE flush-to-zero flags instead. + l += w1c * (samples[i + 0] - l) + 1e-15f; + r += w1c * (samples[i + 1] - r) + 1e-15f; + lr += w2c * (l * r - lr); + ll += w2c * (l * l - ll); + rr += w2c * (r * r - rr); + } + + zl = l; + zr = r; + zll = ll; + zlr = lr; + zrr = rr; +} + +float CorrelationMeasurer::get_correlation() const +{ + // The 1e-12f epsilon is to avoid division by zero. + // zll and zrr are both always non-negative, so we do not risk negative values. + return zlr / sqrt(zll * zrr + 1e-12f); +} diff --git a/correlation_measurer.h b/correlation_measurer.h new file mode 100644 index 0000000..6d84340 --- /dev/null +++ b/correlation_measurer.h @@ -0,0 +1,55 @@ +#ifndef _CORRELATION_MEASURER_H +#define _CORRELATION_MEASURER_H 1 + +// Measurement of left/right stereo correlation. +1 is pure mono +// (okay but not ideal), 0 is no correlation (usually bad, unless +// it is due to silence), strongly negative values means inverted +// phase (bad). Typical values for e.g. music would be somewhere +// around +0.7, although you can expect it to vary a bit. +// +// This is, of course, based on the regular Pearson correlation, +// where µ_L and µ_R is taken to be 0 (ie., no DC offset). It is +// filtered through a simple IIR filter so that older values are +// weighed less than newer, depending on . +// +// +// Adapted from Adriaensen's project Zita-mu1 (as of January 2016). +// Original copyright follows: +// +// Copyright (C) 2008-2015 Fons Adriaensen +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include + +class CorrelationMeasurer { +public: + CorrelationMeasurer(unsigned sample_rate, float lowpass_cutoff_hz = 1000.0f, + float falloff_seconds = 0.150f); + void process_samples(const std::vector &samples); // Taken to be stereo, interleaved. + float get_correlation() const; + +private: + float w1, w2; + + // Filtered values of left and right channel, respectively. + float zl = 0.0f, zr = 0.0f; + + // Filtered values of l², r² and lr (where l and r are the filtered + // versions, given by zl and zr). Together, they make up what we need + // to calculate the correlation. + float zll = 0.0f, zlr = 0.0f, zrr = 0.0f; +}; + +#endif // !defined(_CORRELATION_MEASURER_H) -- 2.39.2