2019-02-04 21:34:12 +01:00
|
|
|
/*
|
|
|
|
Strawberry Music Player
|
|
|
|
This file was part of Clementine.
|
|
|
|
Copyright 2004, Melchior FRANZ <mfranz@kde.org>
|
|
|
|
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
|
|
|
|
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
|
|
|
Copyright 2017, Santiago Gil
|
|
|
|
|
|
|
|
Strawberry 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.
|
|
|
|
|
|
|
|
Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2018-05-01 00:41:33 +02:00
|
|
|
|
2018-02-27 18:06:05 +01:00
|
|
|
#include "fht.h"
|
|
|
|
|
2019-02-04 21:34:12 +01:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
#include <QVector>
|
|
|
|
|
|
|
|
FHT::FHT(int n) : num_((n < 3) ? 0 : 1 << n), exp2_((n < 3) ? -1 : n) {
|
2018-02-27 18:06:05 +01:00
|
|
|
if (n > 3) {
|
2019-02-04 21:34:12 +01:00
|
|
|
buf_vector_.resize(num_);
|
|
|
|
tab_vector_.resize(num_ * 2);
|
2018-02-27 18:06:05 +01:00
|
|
|
makeCasTable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-04 21:34:12 +01:00
|
|
|
FHT::~FHT() {}
|
|
|
|
|
|
|
|
int FHT::sizeExp() const { return exp2_; }
|
|
|
|
int FHT::size() const { return num_; }
|
|
|
|
|
|
|
|
float* FHT::buf_() { return buf_vector_.data(); }
|
|
|
|
float* FHT::tab_() { return tab_vector_.data(); }
|
|
|
|
int* FHT::log_() { return log_vector_.data(); }
|
2018-02-27 18:06:05 +01:00
|
|
|
|
|
|
|
void FHT::makeCasTable(void) {
|
2019-02-04 21:34:12 +01:00
|
|
|
float* costab = tab_();
|
|
|
|
float* sintab = tab_() + num_ / 2 + 1;
|
2018-02-27 18:06:05 +01:00
|
|
|
|
2019-02-04 21:34:12 +01:00
|
|
|
for (int ul = 0; ul < num_; ul++) {
|
|
|
|
float d = M_PI * ul / (num_ / 2);
|
2018-02-27 18:06:05 +01:00
|
|
|
*costab = *sintab = cos(d);
|
|
|
|
|
2019-02-04 21:34:12 +01:00
|
|
|
costab += 2;
|
|
|
|
sintab += 2;
|
|
|
|
if (sintab > tab_() + num_ * 2) sintab = tab_() + 1;
|
2018-02-27 18:06:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FHT::scale(float* p, float d) {
|
2019-02-04 21:34:12 +01:00
|
|
|
for (int i = 0; i < (num_ / 2); i++) *p++ *= d;
|
2018-02-27 18:06:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void FHT::ewma(float* d, float* s, float w) {
|
2019-02-04 21:34:12 +01:00
|
|
|
for (int i = 0; i < (num_ / 2); i++, d++, s++) *d = *d * w + *s * (1 - w);
|
2018-02-27 18:06:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void FHT::logSpectrum(float* out, float* p) {
|
2019-02-04 21:34:12 +01:00
|
|
|
|
2021-03-26 21:30:13 +01:00
|
|
|
int n = num_ / 2, i = 0, j = 0, k = 0, *r = nullptr;
|
2019-02-04 21:34:12 +01:00
|
|
|
if (log_vector_.size() < n) {
|
|
|
|
log_vector_.resize(n);
|
|
|
|
float f = n / log10(static_cast<double>(n));
|
|
|
|
for (i = 0, r = log_(); i < n; i++, r++) {
|
|
|
|
j = static_cast<int>(rint(log10(i + 1.0) * f));
|
2018-02-27 18:06:05 +01:00
|
|
|
*r = j >= n ? n - 1 : j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
semiLogSpectrum(p);
|
|
|
|
*out++ = *p = *p / 100;
|
2019-02-04 21:34:12 +01:00
|
|
|
for (k = i = 1, r = log_(); i < n; i++) {
|
2018-02-27 18:06:05 +01:00
|
|
|
j = *r++;
|
2019-02-04 21:34:12 +01:00
|
|
|
if (i == j) {
|
2018-02-27 18:06:05 +01:00
|
|
|
*out++ = p[i];
|
2019-02-04 21:34:12 +01:00
|
|
|
}
|
2018-02-27 18:06:05 +01:00
|
|
|
else {
|
|
|
|
float base = p[k - 1];
|
|
|
|
float step = (p[j] - base) / (j - (k - 1));
|
|
|
|
for (float corr = 0; k <= j; k++, corr += step) *out++ = base + corr;
|
|
|
|
}
|
|
|
|
}
|
2019-02-04 21:34:12 +01:00
|
|
|
|
2018-02-27 18:06:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void FHT::semiLogSpectrum(float* p) {
|
|
|
|
power2(p);
|
2019-02-04 21:34:12 +01:00
|
|
|
for (int i = 0; i < (num_ / 2); i++, p++) {
|
|
|
|
float e = 10.0 * log10(sqrt(*p / 2));
|
2018-02-27 18:06:05 +01:00
|
|
|
*p = e < 0 ? 0 : e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FHT::spectrum(float* p) {
|
|
|
|
power2(p);
|
2019-02-04 21:34:12 +01:00
|
|
|
for (int i = 0; i < (num_ / 2); i++, p++)
|
|
|
|
*p = static_cast<float>(sqrt(*p / 2));
|
2018-02-27 18:06:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void FHT::power(float* p) {
|
|
|
|
power2(p);
|
2019-02-04 21:34:12 +01:00
|
|
|
for (int i = 0; i < (num_ / 2); i++) *p++ /= 2;
|
2018-02-27 18:06:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void FHT::power2(float* p) {
|
2019-02-04 21:34:12 +01:00
|
|
|
_transform(p, num_, 0);
|
2018-02-27 18:06:05 +01:00
|
|
|
|
2019-02-04 21:34:12 +01:00
|
|
|
*p = static_cast<float>(2 * pow(*p, 2));
|
|
|
|
p++;
|
2018-02-27 18:06:05 +01:00
|
|
|
|
2019-02-04 21:34:12 +01:00
|
|
|
float* q = p + num_ - 2;
|
|
|
|
for (int i = 1; i < (num_ / 2); i++) {
|
|
|
|
*p = static_cast<float>(pow(*p, 2) + pow(*q, 2));
|
|
|
|
p++;
|
|
|
|
q--;
|
|
|
|
}
|
2018-02-27 18:06:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void FHT::transform(float* p) {
|
2019-02-04 21:34:12 +01:00
|
|
|
if (num_ == 8)
|
2018-02-27 18:06:05 +01:00
|
|
|
transform8(p);
|
|
|
|
else
|
2019-02-04 21:34:12 +01:00
|
|
|
_transform(p, num_, 0);
|
2018-02-27 18:06:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void FHT::transform8(float* p) {
|
2019-02-04 21:34:12 +01:00
|
|
|
|
2021-03-26 21:30:13 +01:00
|
|
|
float a = 0.0, b = 0.0, c = 0.0, d = 0.0, e = 0.0, f = 0.0, g = 0.0, h = 0.0, b_f2 = 0.0, d_h2 = 0.0;
|
|
|
|
float a_c_eg = 0.0, a_ce_g = 0.0, ac_e_g = 0.0, aceg = 0.0, b_df_h = 0.0, bdfh = 0.0;
|
2018-02-27 18:06:05 +01:00
|
|
|
|
|
|
|
a = *p++, b = *p++, c = *p++, d = *p++;
|
|
|
|
e = *p++, f = *p++, g = *p++, h = *p;
|
|
|
|
b_f2 = (b - f) * M_SQRT2;
|
|
|
|
d_h2 = (d - h) * M_SQRT2;
|
|
|
|
|
|
|
|
a_c_eg = a - c - e + g;
|
|
|
|
a_ce_g = a - c + e - g;
|
|
|
|
ac_e_g = a + c - e - g;
|
|
|
|
aceg = a + c + e + g;
|
|
|
|
|
|
|
|
b_df_h = b - d + f - h;
|
|
|
|
bdfh = b + d + f + h;
|
|
|
|
|
|
|
|
*p = a_c_eg - d_h2;
|
|
|
|
*--p = a_ce_g - b_df_h;
|
|
|
|
*--p = ac_e_g - b_f2;
|
|
|
|
*--p = aceg - bdfh;
|
|
|
|
*--p = a_c_eg + d_h2;
|
|
|
|
*--p = a_ce_g + b_df_h;
|
|
|
|
*--p = ac_e_g + b_f2;
|
|
|
|
*--p = aceg + bdfh;
|
2019-02-04 21:34:12 +01:00
|
|
|
|
2018-02-27 18:06:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void FHT::_transform(float* p, int n, int k) {
|
|
|
|
|
|
|
|
if (n == 8) {
|
|
|
|
transform8(p + k);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-26 21:30:13 +01:00
|
|
|
int i = 0, j = 0, ndiv2 = n / 2;
|
|
|
|
float a = 0.0, *t1 = nullptr, *t2 = nullptr, *t3 = nullptr, *t4 = nullptr, *ptab = nullptr, *pp = nullptr;
|
2018-02-27 18:06:05 +01:00
|
|
|
|
2019-02-04 21:34:12 +01:00
|
|
|
for (i = 0, t1 = buf_(), t2 = buf_() + ndiv2, pp = &p[k]; i < ndiv2; i++)
|
2018-02-27 18:06:05 +01:00
|
|
|
*t1++ = *pp++, *t2++ = *pp++;
|
|
|
|
|
2019-02-04 21:34:12 +01:00
|
|
|
std::copy(buf_(), buf_() + n, p + k);
|
2018-02-27 18:06:05 +01:00
|
|
|
|
|
|
|
_transform(p, ndiv2, k);
|
|
|
|
_transform(p, ndiv2, k + ndiv2);
|
|
|
|
|
2019-02-04 21:34:12 +01:00
|
|
|
j = num_ / ndiv2 - 1;
|
|
|
|
t1 = buf_();
|
2018-02-27 18:06:05 +01:00
|
|
|
t2 = t1 + ndiv2;
|
|
|
|
t3 = p + k + ndiv2;
|
2019-02-04 21:34:12 +01:00
|
|
|
ptab = tab_();
|
2018-02-27 18:06:05 +01:00
|
|
|
pp = p + k;
|
|
|
|
|
|
|
|
a = *ptab++ * *t3++;
|
|
|
|
a += *ptab * *pp;
|
|
|
|
ptab += j;
|
|
|
|
|
|
|
|
*t1++ = *pp + a;
|
|
|
|
*t2++ = *pp++ - a;
|
|
|
|
|
|
|
|
for (i = 1, t4 = p + k + n; i < ndiv2; i++, ptab += j) {
|
|
|
|
a = *ptab++ * *t3++;
|
|
|
|
a += *ptab * *--t4;
|
|
|
|
|
|
|
|
*t1++ = *pp + a;
|
|
|
|
*t2++ = *pp++ - a;
|
|
|
|
}
|
2019-02-04 21:34:12 +01:00
|
|
|
|
|
|
|
std::copy(buf_(), buf_() + n, p + k);
|
|
|
|
|
2018-02-27 18:06:05 +01:00
|
|
|
}
|