summaryrefslogtreecommitdiff
path: root/gfft.c
blob: fa21a111a12c5eb6c88e5fdd9ca54c134cca8bbc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>

#include "gfft.h"

void window_hard(sample *in, double *out, size_t size, int ch, int nch)
{
	for (size_t i = 0; i < size; i++) {
		sample val = in[i * nch + ch];
		out[i] = (1./32768.) * val;
	}
}

void window_hann(sample *in, double *out, size_t size, int ch, int nch)
{
	double cfac = 2. * M_PI / ((double) size - 1);
	for (size_t i = 0; i < size; i++) {
		sample val = in[i * nch + ch];
		out[i] = (1./32768.) * val
				* 0.5 * (1. - cos (cfac * (double)i));
	}
}

static gpointer fftrun_threadf(gpointer param)
{
	struct fft_runner *fftr = param;
	fftw_plan p;
	double *in;
	fftw_complex *out;
	struct qe *qe;
	struct fe *fe;
	int stopped = 0;
	sample *hist;
	size_t span = fftr->span;
	size_t pktsize = fftr->dev->pktsize;

	hist = malloc(sizeof(sample) * pktsize * span * fftr->dev->chan);
	in = fftw_malloc(sizeof(double) * pktsize * span);
	out = fftw_malloc(sizeof(fftw_complex) * pktsize * span);
	p = fftw_plan_dft_r2c_1d(pktsize * span, in, out,
			FFTW_MEASURE | FFTW_DESTROY_INPUT);
	free(out);

	while (!stopped) {
		qe = g_async_queue_pop(fftr->dev->queue);
		fe = calloc(sizeof(struct fe), 1);

		switch (qe->message) {
		case QE_STOPPED:
			fe->message = FE_STOPPED;
			stopped = 1;
			break;

		case QE_ERROR:
			fe->message = FE_DEV_ERROR;
			fe->errcode = qe->errcode;
			fe->errp = qe->errp;
			break;

		case QE_DATA:
			memmove(hist, hist + pktsize,
				pktsize * (span - 1) * fftr->dev->chan * sizeof(*hist));
			memmove(hist + pktsize * (span - 1), qe->samples,
				pktsize * fftr->dev->chan * sizeof(*hist));

			fe->message = FE_DATA;
			fe->data = fftw_malloc(sizeof(fftw_complex)
					* pktsize * span);
			fe->size = pktsize * span;
			fftr->winf(hist, in, pktsize * span, 0, fftr->dev->chan);
			fftw_execute_dft_r2c(p, in, fe->data);
			break;
		}
		free(qe);

		g_async_queue_push(fftr->queue, fe);
	}

	free(in);
	fftw_destroy_plan(p);
	return NULL;
}

struct fft_runner *fftrun_attach(struct device *device,
		window_func *winf, size_t span)
{
	GError *error = NULL;
	struct fft_runner *fftr;

	fftr = malloc(sizeof(*fftr));
	fftr->dev = device;
	fftr->queue = g_async_queue_new();
	fftr->thread = g_thread_create(fftrun_threadf, fftr, 0, &error);
	fftr->winf = winf;
	fftr->span = span;
	return fftr;
}