1
/****************************************************************************************
2
 * Copyright (c) 2004 Melchior FRANZ <mfranz@kde.org>                                   *
3
 *                                                                                      *
4
 * This program is free software; you can redistribute it and/or modify it under        *
5
 * the terms of the GNU General Public License as published by the Free Software        *
6
 * Foundation; either version 2 of the License, or (at your option) any later           *
7
 * version.                                                                             *
8
 *                                                                                      *
9
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
10
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
11
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
12
 *                                                                                      *
13
 * You should have received a copy of the GNU General Public License along with         *
14
 * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
15
 ****************************************************************************************/
16
17
#include "fht.h"
18
19
#include <math.h>
20
#include <string.h>
21
22
FHT::FHT(int n) :
23
    m_buf(0),
24
    m_tab(0),
25
    m_log(0)
26
{
27
    if (n < 3) {
28
        m_num = 0;
29
        m_exp2 = -1;
30
        return;
31
    }
32
    m_exp2 = n;
33
    m_num = 1 << n;
34
    if (n > 3) {
35
        m_buf = new float[m_num];
36
        m_tab = new float[m_num * 2];
37
        makeCasTable();
38
    }
39
}
40
41
42
FHT::~FHT()
43
{
44
    delete[] m_buf;
45
    delete[] m_tab;
46
    delete[] m_log;
47
}
48
49
50
void FHT::makeCasTable(void)
51
{
52
    float d, *costab, *sintab;
53
    int ul, ndiv2 = m_num / 2;
54
55
    for (costab = m_tab, sintab = m_tab + m_num / 2 + 1, ul = 0; ul < m_num; ul++) {
56
        d = M_PI * ul / ndiv2;
57
        *costab = *sintab = cos(d);
58
59
        costab += 2, sintab += 2;
60
        if (sintab > m_tab + m_num * 2)
61
            sintab = m_tab + 1;
62
    }
63
}
64
65
66
float* FHT::copy(float *d, float *s)
67
{
68
    return (float *)memcpy(d, s, m_num * sizeof(float));
69
}
70
71
72
float* FHT::clear(float *d)
73
{
74
    return (float *)memset(d, 0, m_num * sizeof(float));
75
}
76
77
78
void FHT::scale(float *p, float d)
79
{
80
    for (int i = 0; i < (m_num / 2); i++)
81
        *p++ *= d;
82
}
83
84
85
void FHT::ewma(float *d, float *s, float w)
86
{
87
    for (int i = 0; i < (m_num / 2); i++, d++, s++)
88
        *d = *d * w + *s * (1 - w);
89
}
90
91
92
void FHT::logSpectrum(float *out, float *p)
93
{
94
    int n = m_num / 2, i, j, k, *r;
95
    if (!m_log) {
96
        m_log = new int[n];
97
        float f = n / log10((double)n);
98
        for (i = 0, r = m_log; i < n; i++, r++) {
99
            j = int(rint(log10(i + 1.0) * f));
100
            *r = j >= n ? n - 1 : j;
101
        }
102
    }
103
    semiLogSpectrum(p);
104
    *out++ = *p = *p / 100;
105
    for (k = i = 1, r = m_log; i < n; ++i) {
106
        j = *r++;
107
        if (i == j)
108
            *out++ = p[i];
109
        else {
110
            float base = p[k - 1];
111
            float step = (p[j] - base) / (j - (k - 1));
112
            for (float corr = 0; k <= j; k++, corr += step)
113
                *out++ = base + corr;
114
        }
115
    }
116
}
117
118
119
void FHT::semiLogSpectrum(float *p)
120
{
121
    float e;
122
    power2(p);
123
    for (int i = 0; i < (m_num / 2); i++, p++) {
124
        e = 10.0 * log10(sqrt(*p * .5));
125
        *p = e < 0 ? 0 : e;
126
    }
127
}
128
129
130
void FHT::spectrum(float *p)
131
{
132
    power2(p);
133
    for (int i = 0; i < (m_num / 2); i++, p++)
134
        *p = (float)sqrt(*p * .5);
135
}
136
137
138
void FHT::power(float *p)
139
{
140
    power2(p);
141
    for (int i = 0; i < (m_num / 2); i++)
142
        *p++ *= .5;
143
}
144
145
146
void FHT::power2(float *p)
147
{
148
    int i;
149
    float *q;
150
    _transform(p, m_num, 0);
151
152
    *p = (*p * *p), *p += *p, p++;
153
154
    for (i = 1, q = p + m_num - 2; i < (m_num / 2); i++, --q)
155
        *p = (*p * *p) + (*q * *q), p++;
156
}
157
158
159
void FHT::transform(float *p)
160
{
161
    if (m_num == 8)
162
        transform8(p);
163
    else
164
        _transform(p, m_num, 0);
165
}
166
167
168
void FHT::transform8(float *p)
169
{
170
    float a, b, c, d, e, f, g, h, b_f2, d_h2;
171
    float a_c_eg, a_ce_g, ac_e_g, aceg, b_df_h, bdfh;
172
173
    a = *p++, b = *p++, c = *p++, d = *p++;
174
    e = *p++, f = *p++, g = *p++, h = *p;
175
    b_f2 = (b - f) * M_SQRT2;
176
    d_h2 = (d - h) * M_SQRT2;
177
178
    a_c_eg = a - c - e + g;
179
    a_ce_g = a - c + e - g;
180
    ac_e_g = a + c - e - g;
181
    aceg = a + c + e + g;
182
183
    b_df_h = b - d + f - h;
184
    bdfh = b + d + f + h;
185
186
    *p = a_c_eg - d_h2;
187
    *--p = a_ce_g - b_df_h;
188
    *--p = ac_e_g - b_f2;
189
    *--p = aceg - bdfh;
190
    *--p = a_c_eg + d_h2;
191
    *--p = a_ce_g + b_df_h;
192
    *--p = ac_e_g + b_f2;
193
    *--p = aceg + bdfh;
194
}
195
196
197
void FHT::_transform(float *p, int n, int k)
198
{
199
    if (n == 8) {
200
        transform8(p + k);
201
        return;
202
    }
203
204
    int i, j, ndiv2 = n / 2;
205
    float a, *t1, *t2, *t3, *t4, *ptab, *pp;
206
207
    for (i = 0, t1 = m_buf, t2 = m_buf + ndiv2, pp = &p[k]; i < ndiv2; i++)
208
        *t1++ = *pp++, *t2++ = *pp++;
209
210
    memcpy(p + k, m_buf, sizeof(float) * n);
211
212
    _transform(p, ndiv2, k);
213
    _transform(p, ndiv2, k + ndiv2);
214
215
    j = m_num / ndiv2 - 1;
216
    t1 = m_buf;
217
    t2 = t1 + ndiv2;
218
    t3 = p + k + ndiv2;
219
    ptab = m_tab;
220
    pp = p + k;
221
222
    a = *ptab++ * *t3++;
223
    a += *ptab * *pp;
224
    ptab += j;
225
226
    *t1++ = *pp + a;
227
    *t2++ = *pp++ - a;
228
229
    for (i = 1, t4 = p + k + n; i < ndiv2; i++, ptab += j) {
230
        a = *ptab++ * *t3++;
231
        a += *ptab * *--t4;
232
233
        *t1++ = *pp + a;
234
        *t2++ = *pp++ - a;
235
    }
236
    memcpy(p + k, m_buf, sizeof(float) * n);
237
}