Version 1.0
Added: Configuration Editor, which allows to edit configurations in a graphical user interface. Contains GUIs for most commands supported by E-APO, but as lines can also be edited directly, all commands can be used. Added: Command "GraphicEQ", which can act as a regular, fixed-band graphic equalizer (via the GUI) but also supports variable bands so that any desired frequency response can be specified. Internally, it is implemented via convolution with a generated IR. Added: Command "Convolution", which allows to convolve the signal with a user-provided impulse response to achieve e.g. equalization or reverberation effects. Improved: Configurator performs checks for registry values that are needed for the operation of E-APO, which may be changed by driver installations, fixing the values if necessary. Improved: Configurator shows which is the default device as a hint to the user.
This commit is contained in:
1 parent
d68b958bc8
commit
b8cdd47f71
284 files changed
+17622
-322
No files matched your search
@@ -0,0 +1,830 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Christian Borss *
|
||||
* christian.borss@rub.de *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Library General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 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 Library General Public *
|
||||
* License along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
// Adapted version for Equalizer APO. For original version see libHybridConv.c
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <xmmintrin.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <math.h>
|
||||
#include <fftw3.h>
|
||||
#include "libHybridConv.h"
|
||||
|
||||
|
||||
double hcTime(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
DWORD t;
|
||||
|
||||
t = GetTickCount();
|
||||
return (double)t * 0.001;
|
||||
#else
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
return tv.tv_sec + tv.tv_usec * 0.000001;
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
double getProcTime(int flen, int num, double dur)
|
||||
{
|
||||
HConvSingle filter;
|
||||
float *x;
|
||||
float *h;
|
||||
float *y;
|
||||
int xlen, hlen, ylen;
|
||||
int size, n;
|
||||
int pos;
|
||||
double t_start, t_diff;
|
||||
double counter = 0.0;
|
||||
double proc_time;
|
||||
double lin, mul;
|
||||
|
||||
xlen = 2048*2048;
|
||||
size = sizeof(float) * xlen;
|
||||
x = (float *)fftwf_malloc(size);
|
||||
lin = pow(10.0, -100.0 / 20.0); // 0.00001 = -100dB
|
||||
mul = pow(lin, 1.0 / (double)xlen);
|
||||
x[0] = 1.0;
|
||||
for (n = 1; n < xlen; n++)
|
||||
x[n] = float(-mul * x[n - 1]);
|
||||
|
||||
hlen = flen * num;
|
||||
size = sizeof(float) * hlen;
|
||||
h = (float *)fftwf_malloc(size);
|
||||
lin = pow(10.0, -60.0 / 20.0); // 0.001 = -60dB
|
||||
mul = pow(lin, 1.0 / (double)hlen);
|
||||
h[0] = 1.0;
|
||||
for (n = 1; n < hlen; n++)
|
||||
h[n] = float(mul * h[n - 1]);
|
||||
|
||||
ylen = flen;
|
||||
size = sizeof(float) * ylen;
|
||||
y = (float *)fftwf_malloc(size);
|
||||
|
||||
hcInitSingle(&filter, h, hlen, flen, 1);
|
||||
|
||||
t_diff = 0.0;
|
||||
t_start = hcTime();
|
||||
pos = 0;
|
||||
while (t_diff < dur)
|
||||
{
|
||||
hcPutSingle(&filter, &x[pos]);
|
||||
hcProcessSingle(&filter);
|
||||
hcGetSingle(&filter, y);
|
||||
pos += flen;
|
||||
if (pos >= xlen)
|
||||
pos = 0;
|
||||
counter += 1.0;
|
||||
t_diff = hcTime() - t_start;
|
||||
}
|
||||
proc_time = t_diff / counter;
|
||||
printf("Processing time: %7.3f us\n", 1000000.0 * proc_time);
|
||||
|
||||
hcCloseSingle(&filter);
|
||||
fftwf_free(x);
|
||||
fftwf_free(h);
|
||||
fftwf_free(y);
|
||||
|
||||
return proc_time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void hcPutSingle(HConvSingle *filter, float *x)
|
||||
{
|
||||
int j, flen, size;
|
||||
|
||||
flen = filter->framelength;
|
||||
size = sizeof(float) * flen;
|
||||
memcpy(filter->dft_time, x, size);
|
||||
memset(&(filter->dft_time[flen]), 0, size);
|
||||
fftwf_execute(filter->fft);
|
||||
for (j = 0; j < flen + 1; j++)
|
||||
{
|
||||
filter->in_freq_real[j] = filter->dft_freq[j][0];
|
||||
filter->in_freq_imag[j] = filter->dft_freq[j][1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hcProcessSingle(HConvSingle *filter)
|
||||
{
|
||||
#if 0
|
||||
int s, n, start, stop, flen;
|
||||
float *x_real;
|
||||
float *x_imag;
|
||||
float *h_real;
|
||||
float *h_imag;
|
||||
float *y_real;
|
||||
float *y_imag;
|
||||
|
||||
flen = filter->framelength;
|
||||
x_real = filter->in_freq_real;
|
||||
x_imag = filter->in_freq_imag;
|
||||
start = filter->steptask[filter->step];
|
||||
stop = filter->steptask[filter->step + 1];
|
||||
for (s = start; s < stop; s++)
|
||||
{
|
||||
n = (s + filter->mixpos) % filter->num_mixbuf;
|
||||
y_real = filter->mixbuf_freq_real[n];
|
||||
y_imag = filter->mixbuf_freq_imag[n];
|
||||
h_real = filter->filterbuf_freq_real[s];
|
||||
h_imag = filter->filterbuf_freq_imag[s];
|
||||
for (n = 0; n < flen + 1; n++)
|
||||
{
|
||||
y_real[n] += x_real[n] * h_real[n] -
|
||||
x_imag[n] * h_imag[n];
|
||||
y_imag[n] += x_real[n] * h_imag[n] +
|
||||
x_imag[n] * h_real[n];
|
||||
}
|
||||
}
|
||||
filter->step = (filter->step + 1) % filter->maxstep;
|
||||
#endif
|
||||
|
||||
int s, n, start, stop, flen, flen4;
|
||||
__m128 *x4_real;
|
||||
__m128 *x4_imag;
|
||||
__m128 *h4_real;
|
||||
__m128 *h4_imag;
|
||||
__m128 *y4_real;
|
||||
__m128 *y4_imag;
|
||||
float *x_real;
|
||||
float *x_imag;
|
||||
float *h_real;
|
||||
float *h_imag;
|
||||
float *y_real;
|
||||
float *y_imag;
|
||||
|
||||
flen = filter->framelength;
|
||||
x_real = filter->in_freq_real;
|
||||
x_imag = filter->in_freq_imag;
|
||||
x4_real = (__m128*)x_real;
|
||||
x4_imag = (__m128*)x_imag;
|
||||
start = filter->steptask[filter->step];
|
||||
stop = filter->steptask[filter->step + 1];
|
||||
for (s = start; s < stop; s++)
|
||||
{
|
||||
n = (s + filter->mixpos) % filter->num_mixbuf;
|
||||
y_real = filter->mixbuf_freq_real[n];
|
||||
y_imag = filter->mixbuf_freq_imag[n];
|
||||
y4_real = (__m128*)y_real;
|
||||
y4_imag = (__m128*)y_imag;
|
||||
h_real = filter->filterbuf_freq_real[s];
|
||||
h_imag = filter->filterbuf_freq_imag[s];
|
||||
h4_real = (__m128*)h_real;
|
||||
h4_imag = (__m128*)h_imag;
|
||||
flen4 = flen / 4;
|
||||
for (n = 0; n < flen4; n++)
|
||||
{
|
||||
#ifdef WIN32
|
||||
__m128 a = _mm_mul_ps(x4_real[n], h4_real[n]);
|
||||
__m128 b = _mm_mul_ps(x4_imag[n], h4_imag[n]);
|
||||
__m128 c = _mm_sub_ps(a, b);
|
||||
y4_real[n] = _mm_add_ps(y4_real[n], c);
|
||||
a = _mm_mul_ps(x4_real[n], h4_imag[n]);
|
||||
b = _mm_mul_ps(x4_imag[n], h4_real[n]);
|
||||
c = _mm_add_ps(a, b);
|
||||
y4_imag[n] = _mm_add_ps(y4_imag[n], c);
|
||||
#else
|
||||
y4_real[n] += x4_real[n] * h4_real[n] -
|
||||
x4_imag[n] * h4_imag[n];
|
||||
y4_imag[n] += x4_real[n] * h4_imag[n] +
|
||||
x4_imag[n] * h4_real[n];
|
||||
#endif
|
||||
}
|
||||
y_real[flen] += x_real[flen] * h_real[flen] -
|
||||
x_imag[flen] * h_imag[flen];
|
||||
y_imag[flen] += x_real[flen] * h_imag[flen] +
|
||||
x_imag[flen] * h_real[flen];
|
||||
}
|
||||
filter->step = (filter->step + 1) % filter->maxstep;
|
||||
}
|
||||
|
||||
|
||||
void hcGetSingle(HConvSingle *filter, float *y)
|
||||
{
|
||||
int flen, mpos;
|
||||
float *out;
|
||||
float *hist;
|
||||
int size, n, j;
|
||||
|
||||
flen = filter->framelength;
|
||||
mpos = filter->mixpos;
|
||||
out = filter->dft_time;
|
||||
hist = filter->history_time;
|
||||
for (j = 0; j < flen + 1; j++)
|
||||
{
|
||||
filter->dft_freq[j][0] = filter->mixbuf_freq_real[mpos][j];
|
||||
filter->dft_freq[j][1] = filter->mixbuf_freq_imag[mpos][j];
|
||||
filter->mixbuf_freq_real[mpos][j] = 0.0;
|
||||
filter->mixbuf_freq_imag[mpos][j] = 0.0;
|
||||
}
|
||||
fftwf_execute(filter->ifft);
|
||||
for (n = 0; n < flen; n++)
|
||||
{
|
||||
y[n] = out[n] + hist[n];
|
||||
}
|
||||
size = sizeof(float) * flen;
|
||||
memcpy(hist, &(out[flen]), size);
|
||||
filter->mixpos = (filter->mixpos + 1) % filter->num_mixbuf;
|
||||
}
|
||||
|
||||
|
||||
void hcGetAddSingle(HConvSingle *filter, float *y)
|
||||
{
|
||||
int flen, mpos;
|
||||
float *out;
|
||||
float *hist;
|
||||
int size, n, j;
|
||||
|
||||
flen = filter->framelength;
|
||||
mpos = filter->mixpos;
|
||||
out = filter->dft_time;
|
||||
hist = filter->history_time;
|
||||
for (j = 0; j < flen + 1; j++)
|
||||
{
|
||||
filter->dft_freq[j][0] = filter->mixbuf_freq_real[mpos][j];
|
||||
filter->dft_freq[j][1] = filter->mixbuf_freq_imag[mpos][j];
|
||||
filter->mixbuf_freq_real[mpos][j] = 0.0;
|
||||
filter->mixbuf_freq_imag[mpos][j] = 0.0;
|
||||
}
|
||||
fftwf_execute(filter->ifft);
|
||||
for (n = 0; n < flen; n++)
|
||||
{
|
||||
y[n] += out[n] + hist[n];
|
||||
}
|
||||
size = sizeof(float) * flen;
|
||||
memcpy(hist, &(out[flen]), size);
|
||||
filter->mixpos = (filter->mixpos + 1) % filter->num_mixbuf;
|
||||
}
|
||||
|
||||
|
||||
void hcInitSingle(HConvSingle *filter, float *h, int hlen, int flen, int steps)
|
||||
{
|
||||
int i, j, size, num, pos;
|
||||
float gain;
|
||||
|
||||
// processing step counter
|
||||
filter->step = 0;
|
||||
|
||||
// number of processing steps per audio frame
|
||||
filter->maxstep = steps;
|
||||
|
||||
// current frame index
|
||||
filter->mixpos = 0;
|
||||
|
||||
// number of samples per audio frame
|
||||
filter->framelength = flen;
|
||||
|
||||
// DFT buffer (time domain)
|
||||
size = sizeof(float) * 2 * flen;
|
||||
filter->dft_time = (float *)fftwf_malloc(size);
|
||||
|
||||
// DFT buffer (frequency domain)
|
||||
size = sizeof(fftwf_complex) * (flen + 1);
|
||||
filter->dft_freq = (fftwf_complex*)fftwf_malloc(size);
|
||||
|
||||
// input buffer (frequency domain)
|
||||
size = sizeof(float) * (flen + 1);
|
||||
filter->in_freq_real = (float*)fftwf_malloc(size);
|
||||
filter->in_freq_imag = (float*)fftwf_malloc(size);
|
||||
|
||||
// number of filter segments
|
||||
filter->num_filterbuf = (hlen + flen - 1) / flen;
|
||||
|
||||
// processing tasks per step
|
||||
size = sizeof(int) * (steps + 1);
|
||||
filter->steptask = (int *)malloc(size);
|
||||
num = filter->num_filterbuf / steps;
|
||||
for (i = 0; i <= steps; i++)
|
||||
filter->steptask[i] = i * num;
|
||||
if (filter->steptask[1] == 0)
|
||||
pos = 1;
|
||||
else
|
||||
pos = 2;
|
||||
num = filter->num_filterbuf % steps;
|
||||
for (j = pos; j < pos + num; j++)
|
||||
{
|
||||
for (i = j; i <= steps; i++)
|
||||
filter->steptask[i]++;
|
||||
}
|
||||
|
||||
// filter segments (frequency domain)
|
||||
size = sizeof(float*) * filter->num_filterbuf;
|
||||
filter->filterbuf_freq_real = (float**)fftwf_malloc(size);
|
||||
filter->filterbuf_freq_imag = (float**)fftwf_malloc(size);
|
||||
for (i = 0; i < filter->num_filterbuf; i++)
|
||||
{
|
||||
size = sizeof(float) * (flen + 1);
|
||||
filter->filterbuf_freq_real[i] = (float*)fftwf_malloc(size);
|
||||
filter->filterbuf_freq_imag[i] = (float*)fftwf_malloc(size);
|
||||
}
|
||||
|
||||
// number of mixing segments
|
||||
filter->num_mixbuf = filter->num_filterbuf + 1;
|
||||
|
||||
// mixing segments (frequency domain)
|
||||
size = sizeof(float*) * filter->num_mixbuf;
|
||||
filter->mixbuf_freq_real = (float**)fftwf_malloc(size);
|
||||
filter->mixbuf_freq_imag = (float**)fftwf_malloc(size);
|
||||
for (i = 0; i < filter->num_mixbuf; i++)
|
||||
{
|
||||
size = sizeof(float) * (flen + 1);
|
||||
filter->mixbuf_freq_real[i] = (float*)fftwf_malloc(size);
|
||||
filter->mixbuf_freq_imag[i] = (float*)fftwf_malloc(size);
|
||||
memset(filter->mixbuf_freq_real[i], 0, size);
|
||||
memset(filter->mixbuf_freq_imag[i], 0, size);
|
||||
}
|
||||
|
||||
// history buffer (time domain)
|
||||
size = sizeof(float) * flen;
|
||||
filter->history_time = (float *)fftwf_malloc(size);
|
||||
memset(filter->history_time, 0, size);
|
||||
|
||||
// FFT transformation plan
|
||||
filter->fft = fftwf_plan_dft_r2c_1d(2 * flen, filter->dft_time, filter->dft_freq, FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
|
||||
|
||||
// IFFT transformation plan
|
||||
filter->ifft = fftwf_plan_dft_c2r_1d(2 * flen, filter->dft_freq, filter->dft_time, FFTW_ESTIMATE|FFTW_PRESERVE_INPUT);
|
||||
|
||||
// generate filter segments
|
||||
gain = 0.5f / flen;
|
||||
size = sizeof(float) * 2 * flen;
|
||||
memset(filter->dft_time, 0, size);
|
||||
for (i = 0; i < filter->num_filterbuf - 1; i++)
|
||||
{
|
||||
for (j = 0; j < flen; j++)
|
||||
filter->dft_time[j] = gain * h[i * flen + j];
|
||||
fftwf_execute(filter->fft);
|
||||
for (j = 0; j < flen + 1; j++)
|
||||
{
|
||||
filter->filterbuf_freq_real[i][j] = filter->dft_freq[j][0];
|
||||
filter->filterbuf_freq_imag[i][j] = filter->dft_freq[j][1];
|
||||
}
|
||||
}
|
||||
for (j = 0; j < hlen - i * flen; j++)
|
||||
filter->dft_time[j] = gain * h[i * flen + j];
|
||||
size = sizeof(float) * ((i + 1) * flen - hlen);
|
||||
memset(&(filter->dft_time[hlen - i * flen]), 0, size);
|
||||
fftwf_execute(filter->fft);
|
||||
for (j = 0; j < flen + 1; j++)
|
||||
{
|
||||
filter->filterbuf_freq_real[i][j] = filter->dft_freq[j][0];
|
||||
filter->filterbuf_freq_imag[i][j] = filter->dft_freq[j][1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hcCloseSingle(HConvSingle *filter)
|
||||
{
|
||||
int i;
|
||||
|
||||
fftwf_destroy_plan(filter->ifft);
|
||||
fftwf_destroy_plan(filter->fft);
|
||||
fftwf_free(filter->history_time);
|
||||
for (i = 0; i < filter->num_mixbuf; i++)
|
||||
{
|
||||
fftwf_free(filter->mixbuf_freq_real[i]);
|
||||
fftwf_free(filter->mixbuf_freq_imag[i]);
|
||||
}
|
||||
fftwf_free(filter->mixbuf_freq_real);
|
||||
fftwf_free(filter->mixbuf_freq_imag);
|
||||
for (i = 0; i < filter->num_filterbuf; i++)
|
||||
{
|
||||
fftwf_free(filter->filterbuf_freq_real[i]);
|
||||
fftwf_free(filter->filterbuf_freq_imag[i]);
|
||||
}
|
||||
fftwf_free(filter->filterbuf_freq_real);
|
||||
fftwf_free(filter->filterbuf_freq_imag);
|
||||
fftwf_free(filter->in_freq_real);
|
||||
fftwf_free(filter->in_freq_imag);
|
||||
fftwf_free(filter->dft_freq);
|
||||
fftwf_free(filter->dft_time);
|
||||
free(filter->steptask);
|
||||
memset(filter, 0, sizeof(HConvSingle));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void hcBenchmarkDual(int sflen, int lflen)
|
||||
{
|
||||
HConvDual filter;
|
||||
float *x;
|
||||
float *h;
|
||||
float *y;
|
||||
int xlen, hlen, ylen;
|
||||
int size, n;
|
||||
int pos;
|
||||
double t_start, t_diff;
|
||||
double counter = 0.0;
|
||||
double signal_time;
|
||||
double cpu_load;
|
||||
double lin, mul;
|
||||
|
||||
// xlen = sflen;
|
||||
xlen = 2048*2048;
|
||||
size = sizeof(float) * xlen;
|
||||
x = (float *)fftwf_malloc(size);
|
||||
lin = pow(10.0, -100.0 / 20.0); // 0.00001 = -100dB
|
||||
mul = pow(lin, 1.0 / (double)xlen);
|
||||
x[0] = 1.0;
|
||||
for (n = 1; n < xlen; n++)
|
||||
x[n] = float(-mul * x[n - 1]);
|
||||
|
||||
hlen = 96000;
|
||||
size = sizeof(float) * hlen;
|
||||
h = (float *)fftwf_malloc(size);
|
||||
lin = pow(10.0, -60.0 / 20.0); // 0.001 = -60dB
|
||||
mul = pow(lin, 1.0 / (double)hlen);
|
||||
h[0] = 1.0;
|
||||
for (n = 1; n < hlen; n++)
|
||||
h[n] = float(mul * h[n - 1]);
|
||||
|
||||
ylen = sflen;
|
||||
size = sizeof(float) * ylen;
|
||||
y = (float *)fftwf_malloc(size);
|
||||
|
||||
hcInitDual(&filter, h, hlen, sflen, lflen);
|
||||
|
||||
t_diff = 0.0;
|
||||
t_start = hcTime();
|
||||
pos = 0;
|
||||
while (t_diff < 10.0)
|
||||
{
|
||||
hcProcessDual(&filter, &(x[pos]), y);
|
||||
pos += sflen;
|
||||
if (pos >= xlen)
|
||||
pos = 0;
|
||||
counter += 1.0;
|
||||
t_diff = hcTime() - t_start;
|
||||
}
|
||||
signal_time = counter * sflen / 48000.0;
|
||||
cpu_load = 100.0 * t_diff / signal_time;
|
||||
printf("Estimated CPU load: %5.2f %%\n", cpu_load);
|
||||
|
||||
hcCloseDual(&filter);
|
||||
fftwf_free(x);
|
||||
fftwf_free(h);
|
||||
fftwf_free(y);
|
||||
}
|
||||
|
||||
|
||||
void hcProcessDual(HConvDual *filter, float *in, float *out)
|
||||
{
|
||||
int lpos, size, i;
|
||||
|
||||
// convolution with short segments
|
||||
hcPutSingle(filter->f_short, in);
|
||||
hcProcessSingle(filter->f_short);
|
||||
hcGetSingle(filter->f_short, out);
|
||||
|
||||
// add contribution from last long frame
|
||||
lpos = filter->step * filter->flen_short;
|
||||
for (i = 0; i < filter->flen_short; i++)
|
||||
out[i] += filter->out_long[lpos + i];
|
||||
|
||||
// convolution with long segments
|
||||
if (filter->step == 0)
|
||||
hcPutSingle(filter->f_long, filter->in_long);
|
||||
hcProcessSingle(filter->f_long);
|
||||
if (filter->step == filter->maxstep - 1)
|
||||
hcGetSingle(filter->f_long, filter->out_long);
|
||||
|
||||
// add current frame to long input buffer
|
||||
lpos = filter->step * filter->flen_short;
|
||||
size = sizeof(float) * filter->flen_short;
|
||||
memcpy(&(filter->in_long[lpos]), in, size);
|
||||
|
||||
// increase step counter
|
||||
filter->step = (filter->step + 1) % filter->maxstep;
|
||||
}
|
||||
|
||||
|
||||
void hcProcessAddDual(HConvDual *filter, float *in, float *out)
|
||||
{
|
||||
int lpos, size, i;
|
||||
|
||||
// convolution with short segments
|
||||
hcPutSingle(filter->f_short, in);
|
||||
hcProcessSingle(filter->f_short);
|
||||
hcGetAddSingle(filter->f_short, out);
|
||||
|
||||
// add contribution from last long frame
|
||||
lpos = filter->step * filter->flen_short;
|
||||
for (i = 0; i < filter->flen_short; i++)
|
||||
out[i] += filter->out_long[lpos + i];
|
||||
|
||||
// convolution with long segments
|
||||
if (filter->step == 0)
|
||||
hcPutSingle(filter->f_long, filter->in_long);
|
||||
hcProcessSingle(filter->f_long);
|
||||
if (filter->step == filter->maxstep - 1)
|
||||
hcGetSingle(filter->f_long, filter->out_long);
|
||||
|
||||
// add current frame to long input buffer
|
||||
lpos = filter->step * filter->flen_short;
|
||||
size = sizeof(float) * filter->flen_short;
|
||||
memcpy(&(filter->in_long[lpos]), in, size);
|
||||
|
||||
// increase step counter
|
||||
filter->step = (filter->step + 1) % filter->maxstep;
|
||||
}
|
||||
|
||||
|
||||
void hcInitDual(HConvDual *filter, float *h, int hlen, int sflen, int lflen)
|
||||
{
|
||||
int size;
|
||||
float *h2 = NULL;
|
||||
int h2len;
|
||||
|
||||
// sanity check: minimum impulse response length
|
||||
h2len = 2 * lflen + 1;
|
||||
if (hlen < h2len)
|
||||
{
|
||||
size = sizeof(float) * h2len;
|
||||
h2 = (float*)fftwf_malloc(size);
|
||||
memset(h2, 0, size);
|
||||
size = sizeof(float) * hlen;
|
||||
memcpy(h2, h, size);
|
||||
h = h2;
|
||||
hlen = h2len;
|
||||
}
|
||||
|
||||
// processing step counter
|
||||
filter->step = 0;
|
||||
|
||||
// number of processing steps per long audio frame
|
||||
filter->maxstep = lflen / sflen;
|
||||
|
||||
// number of samples per long audio frame
|
||||
filter->flen_long = lflen;
|
||||
|
||||
// number of samples per short audio frame
|
||||
filter->flen_short = sflen;
|
||||
|
||||
// input buffer (long frame)
|
||||
size = sizeof(float) * lflen;
|
||||
filter->in_long = (float *)fftwf_malloc(size);
|
||||
memset(filter->in_long, 0, size);
|
||||
|
||||
// output buffer (long frame)
|
||||
size = sizeof(float) * lflen;
|
||||
filter->out_long = (float *)fftwf_malloc(size);
|
||||
memset(filter->out_long, 0, size);
|
||||
|
||||
// convolution filter (short segments)
|
||||
size = sizeof(HConvSingle);
|
||||
filter->f_short = (HConvSingle *)malloc(size);
|
||||
hcInitSingle(filter->f_short, h, 2 * lflen, sflen, 1);
|
||||
|
||||
// convolution filter (long segments)
|
||||
size = sizeof(HConvSingle);
|
||||
filter->f_long = (HConvSingle *)malloc(size);
|
||||
hcInitSingle(filter->f_long, &(h[2 * lflen]), hlen - 2 * lflen, lflen, lflen / sflen);
|
||||
|
||||
if (h2 != NULL)
|
||||
{
|
||||
fftwf_free(h2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hcCloseDual(HConvDual *filter)
|
||||
{
|
||||
hcCloseSingle(filter->f_short);
|
||||
free(filter->f_short);
|
||||
hcCloseSingle(filter->f_long);
|
||||
free(filter->f_long);
|
||||
fftwf_free(filter->out_long);
|
||||
fftwf_free(filter->in_long);
|
||||
memset(filter, 0, sizeof(HConvDual));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void hcBenchmarkTripple(int sflen, int mflen, int lflen)
|
||||
{
|
||||
HConvTripple filter;
|
||||
float *x;
|
||||
float *h;
|
||||
float *y;
|
||||
int xlen, hlen, ylen;
|
||||
int size, n;
|
||||
int pos;
|
||||
double t_start, t_diff;
|
||||
double counter = 0.0;
|
||||
double signal_time;
|
||||
double cpu_load;
|
||||
double lin, mul;
|
||||
|
||||
// xlen = sflen;
|
||||
xlen = 2048*2048;
|
||||
size = sizeof(float) * xlen;
|
||||
x = (float *)fftwf_malloc(size);
|
||||
lin = pow(10.0, -100.0 / 20.0); // 0.00001 = -100dB
|
||||
mul = pow(lin, 1.0 / (double)xlen);
|
||||
x[0] = 1.0;
|
||||
for (n = 1; n < xlen; n++)
|
||||
x[n] = float(-mul * x[n - 1]);
|
||||
|
||||
hlen = 96000;
|
||||
size = sizeof(float) * hlen;
|
||||
h = (float *)fftwf_malloc(size);
|
||||
lin = pow(10.0, -60.0 / 20.0); // 0.001 = -60dB
|
||||
mul = pow(lin, 1.0 / (double)hlen);
|
||||
h[0] = 1.0;
|
||||
for (n = 1; n < hlen; n++)
|
||||
h[n] = float(mul * h[n - 1]);
|
||||
|
||||
ylen = sflen;
|
||||
size = sizeof(float) * ylen;
|
||||
y = (float *)fftwf_malloc(size);
|
||||
|
||||
hcInitTripple(&filter, h, hlen, sflen, mflen, lflen);
|
||||
|
||||
t_diff = 0.0;
|
||||
t_start = hcTime();
|
||||
size = mflen / sflen;
|
||||
pos = 0;
|
||||
while (t_diff < 10.0)
|
||||
{
|
||||
for (n = 0; n < size; n++)
|
||||
{
|
||||
// hcProcessTripple(&filter, x, y);
|
||||
hcProcessTripple(&filter, &(x[pos]), y);
|
||||
pos += sflen;
|
||||
if (pos >= xlen)
|
||||
pos = 0;
|
||||
}
|
||||
counter += 1.0;
|
||||
t_diff = hcTime() - t_start;
|
||||
}
|
||||
signal_time = counter * (double)mflen / 48000.0;
|
||||
cpu_load = 100.0 * t_diff / signal_time;
|
||||
printf("Estimated CPU load: %5.2f %%\n", cpu_load);
|
||||
|
||||
hcCloseTripple(&filter);
|
||||
fftwf_free(x);
|
||||
fftwf_free(h);
|
||||
fftwf_free(y);
|
||||
}
|
||||
|
||||
|
||||
void hcProcessTripple(HConvTripple *filter, float *in, float *out)
|
||||
{
|
||||
int lpos, size, i;
|
||||
|
||||
// convolution with short segments
|
||||
hcPutSingle(filter->f_short, in);
|
||||
hcProcessSingle(filter->f_short);
|
||||
hcGetSingle(filter->f_short, out);
|
||||
|
||||
// add contribution from last medium frame
|
||||
lpos = filter->step * filter->flen_short;
|
||||
for (i = 0; i < filter->flen_short; i++)
|
||||
out[i] += filter->out_medium[lpos + i];
|
||||
|
||||
// add current frame to medium input buffer
|
||||
lpos = filter->step * filter->flen_short;
|
||||
size = sizeof(float) * filter->flen_short;
|
||||
memcpy(&(filter->in_medium[lpos]), in, size);
|
||||
|
||||
// convolution with medium segments
|
||||
if (filter->step == filter->maxstep - 1)
|
||||
hcProcessDual(filter->f_medium,
|
||||
filter->in_medium,
|
||||
filter->out_medium);
|
||||
|
||||
// increase step counter
|
||||
filter->step = (filter->step + 1) % filter->maxstep;
|
||||
}
|
||||
|
||||
|
||||
void hcProcessAddTripple(HConvTripple *filter, float *in, float *out)
|
||||
{
|
||||
int lpos, size, i;
|
||||
|
||||
// convolution with short segments
|
||||
hcPutSingle(filter->f_short, in);
|
||||
hcProcessSingle(filter->f_short);
|
||||
hcGetAddSingle(filter->f_short, out);
|
||||
|
||||
// add contribution from last medium frame
|
||||
lpos = filter->step * filter->flen_short;
|
||||
for (i = 0; i < filter->flen_short; i++)
|
||||
out[i] += filter->out_medium[lpos + i];
|
||||
|
||||
// add current frame to medium input buffer
|
||||
lpos = filter->step * filter->flen_short;
|
||||
size = sizeof(float) * filter->flen_short;
|
||||
memcpy(&(filter->in_medium[lpos]), in, size);
|
||||
|
||||
// convolution with medium segments
|
||||
if (filter->step == filter->maxstep - 1)
|
||||
hcProcessDual(filter->f_medium,
|
||||
filter->in_medium,
|
||||
filter->out_medium);
|
||||
|
||||
// increase step counter
|
||||
filter->step = (filter->step + 1) % filter->maxstep;
|
||||
}
|
||||
|
||||
|
||||
void hcInitTripple(HConvTripple *filter, float *h, int hlen, int sflen, int mflen, int lflen)
|
||||
{
|
||||
int size;
|
||||
float *h2 = NULL;
|
||||
int h2len;
|
||||
|
||||
// sanity check: minimum impulse response length
|
||||
h2len = mflen + 2 * lflen + 1;
|
||||
if (hlen < h2len)
|
||||
{
|
||||
size = sizeof(float) * h2len;
|
||||
h2 = (float*)fftwf_malloc(size);
|
||||
memset(h2, 0, size);
|
||||
size = sizeof(float) * hlen;
|
||||
memcpy(h2, h, size);
|
||||
h = h2;
|
||||
hlen = h2len;
|
||||
}
|
||||
|
||||
// processing step counter
|
||||
filter->step = 0;
|
||||
|
||||
// number of processing steps per medium audio frame
|
||||
filter->maxstep = mflen / sflen;
|
||||
|
||||
// number of samples per medium audio frame
|
||||
filter->flen_medium = mflen;
|
||||
|
||||
// number of samples per short audio frame
|
||||
filter->flen_short = sflen;
|
||||
|
||||
// input buffer (medium frame)
|
||||
size = sizeof(float) * mflen;
|
||||
filter->in_medium = (float *)fftwf_malloc(size);
|
||||
memset(filter->in_medium, 0, size);
|
||||
|
||||
// output buffer (medium frame)
|
||||
size = sizeof(float) * mflen;
|
||||
filter->out_medium = (float *)fftwf_malloc(size);
|
||||
memset(filter->out_medium, 0, size);
|
||||
|
||||
// convolution filter (short segments)
|
||||
size = sizeof(HConvSingle);
|
||||
filter->f_short = (HConvSingle *)malloc(size);
|
||||
hcInitSingle(filter->f_short, h, mflen, sflen, 1);
|
||||
|
||||
// convolution filter (medium segments)
|
||||
size = sizeof(HConvDual);
|
||||
filter->f_medium = (HConvDual *)malloc(size);
|
||||
hcInitDual(filter->f_medium, &(h[mflen]), hlen - mflen, mflen, lflen);
|
||||
|
||||
if (h2 != NULL)
|
||||
{
|
||||
fftwf_free(h2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hcCloseTripple(HConvTripple *filter)
|
||||
{
|
||||
hcCloseSingle(filter->f_short);
|
||||
free(filter->f_short);
|
||||
hcCloseDual(filter->f_medium);
|
||||
free(filter->f_medium);
|
||||
fftwf_free(filter->out_medium);
|
||||
fftwf_free(filter->in_medium);
|
||||
memset(filter, 0, sizeof(HConvTripple));
|
||||
}
|
||||
Reference in new issue
Block a user