-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutils.c
124 lines (107 loc) · 3.83 KB
/
utils.c
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
* Copyright (C) 2017 taylor.fish <[email protected]>
*
* This file is part of Fish Waveshaper.
*
* Fish Waveshaper 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.
*
* Fish Waveshaper 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 Fish Waveshaper. If not, see <http://www.gnu.org/licenses/>.
*/
#include "utils.h"
#define NUM_LOWPASS_STAGES 3
static int compare_points(const void *p1_ptr, const void *p2_ptr) {
const Point *point1 = (const Point *)p1_ptr;
const Point *point2 = (const Point *)p2_ptr;
int cmp = double_cmp(point1->x, point2->x);
if (cmp != 0) return cmp;
if (point1->index < point2->index) return 1;
if (point1->index > point2->index) return -1;
return 0;
}
void sort_points(Point *points, size_t count) {
qsort(points, count, sizeof(points[0]), &compare_points);
}
size_t make_points_unique(Point *points, size_t count) {
size_t offset = 0;
for (size_t i = 1; i < count;) {
points[i] = points[i + offset];
if (double_cmp(points[i].x, points[i - 1].x) == 0) {
offset++;
count--;
} else {
i++;
}
}
return count;
}
size_t sort_points_unique(Point *points, size_t count) {
sort_points(points, count);
return make_points_unique(points, count);
}
void init_lowpass(LowpassParams *params) {
params->gt = init_iir_stage(
IIR_STAGE_LOWPASS, NUM_LOWPASS_STAGES, 3, 2
);
params->iirf = init_iirf_t(params->gt);
}
void update_lowpass_coefficients(LowpassParams *params, float fc) {
chebyshev(
params->iirf, params->gt, NUM_LOWPASS_STAGES * 2, IIR_STAGE_LOWPASS,
fc, 0.5f
);
}
void run_lowpass(LowpassParams *params, const float *input, float *output,
uint32_t n_samples) {
iir_process_buffer_ns_5(
params->iirf, params->gt, input, output, n_samples
);
}
void reset_lowpass(LowpassParams *params) {
reset_iirf_t(params->iirf, params->gt, params->gt->availst);
}
void free_lowpass(LowpassParams *params) {
free_iirf_t(params->iirf, params->gt);
free_iir_stage(params->gt);
params->gt = NULL;
params->iirf = NULL;
}
void upsample_raw(const float *input, uint32_t n_samples,
uint_fast8_t multiplier, float *output) {
for (size_t pos = 0, base = 0; pos < n_samples; pos++) {
float val = input[pos];
for (size_t offset = 0; offset < multiplier; offset++) {
output[base + offset] = val;
}
base += multiplier;
}
}
void upsample(const float *input, uint32_t n_samples,
uint_fast8_t multiplier, float *output, LowpassParams *lp) {
float *upsamples = malloc(n_samples * multiplier * sizeof(float));
upsample_raw(input, n_samples, multiplier, upsamples);
run_lowpass(lp, upsamples, output, n_samples * multiplier);
free(upsamples);
}
void downsample_raw(const float *input, uint32_t n_samples,
uint_fast8_t multiplier, float *output) {
for (size_t pos = 0, new_pos = 0; pos < n_samples; pos += multiplier) {
output[new_pos] = input[pos];
new_pos++;
}
}
void downsample(const float *input, uint32_t n_samples,
uint_fast8_t multiplier, float *output, LowpassParams *lp) {
float *lpsamples = malloc(n_samples * sizeof(float));
run_lowpass(lp, input, lpsamples, n_samples);
downsample_raw(lpsamples, n_samples, multiplier, output);
free(lpsamples);
}