-
Notifications
You must be signed in to change notification settings - Fork 0
/
iirfilter.h
157 lines (122 loc) · 5.86 KB
/
iirfilter.h
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
This file is part of WaverIIR
Copyright (C) 2021 Peter Papp
Please visit https://launchpad.net/waveriir for details
*/
#ifndef IIRFILTER_H
#define IIRFILTER_H
#include <QtCore>
#include <QAudioFormat>
#include "coefficientlist.h"
#include "iirfiltercallback.h"
class IIRFilter {
public:
static const int MAX_ORDER = 12;
static const int MAX_CHANNELS = 8;
// filter types for coefficient calculation (BandStop is also called Notch, BandShelf is also called Peak)
enum FilterTypes { LowPass, HighPass, BandPass, BandStop, LowShelf, HighShelf, BandShelf };
// supported sample types
enum SampleTypes { Unknown, int8Sample, uint8Sample, int16Sample, uint16Sample, int32Sample, uint32Sample, floatSample };
// convenience
static CoefficientList calculateBiquadCoefficients(FilterTypes filterType, double Q, double K, double gainDecibel);
static CoefficientList calculateBiquadCoefficients(FilterTypes filterType, double centerFrequency, double bandwidth, int sampleRate, double gainDecibel);
static CoefficientList calculateBiquadCoefficients(FilterTypes filterType, double centerFrequency, double bandwidth, int sampleRate);
static SampleTypes getSampleTypeFromAudioFormat(QAudioFormat audioFormat);
// constructor and destructor
IIRFilter();
IIRFilter(CoefficientList coefficientList);
~IIRFilter();
// manage
void setCoefficients(CoefficientList coefficientList);
void disableUpdateData();
// callback functions
void setCallbackRaw(IIRFilterCallback *callbackRawObject, IIRFilterCallback::FilterCallbackPointer callbackRawMember);
void setCallbackFiltered(IIRFilterCallback *callbackFilteredObject, IIRFilterCallback::FilterCallbackPointer callbackFilteredMember);
// filtering
void processPCMData(void *data, int byteCount, SampleTypes sampleType, int channelCount);
void reset();
private:
// mode of operation
bool updateData;
// coefficients
double *a;
double *b;
int aLength;
// input and output buffers
double inputBuffer[MAX_CHANNELS][MAX_ORDER];
double outputBuffer[MAX_CHANNELS][MAX_ORDER];
int currentChannel;
// callback pointers (using callbacks here because they are faster than signals)
IIRFilterCallback *callbackRawObject;
IIRFilterCallback *callbackFilteredObject;
IIRFilterCallback::FilterCallbackPointer callbackRawMember;
IIRFilterCallback::FilterCallbackPointer callbackFilteredMember;
// manange
void applyCoefficients(CoefficientList coefficientList);
// filtering - template function works with all supported sample types
template <class T> void process(void *data, int byteCount, int channelCount)
{
// variables to hold the sample's value
T *temp;
double sample;
double filteredSample;
// minimum and maximum values
double minValue = std::numeric_limits<T>::min();
double maxValue = std::numeric_limits<T>::max();
// process each sample in buffer
int processedCount = 0;
while (processedCount < byteCount) {
// pointer to the sample
temp = (T *)((char *)data + processedCount);
// get the sample as double value
sample = *temp;
// callback
if ((callbackRawObject != nullptr) && (callbackRawMember != nullptr)) {
(callbackRawObject->*callbackRawMember)(&sample, currentChannel);
if (sample < minValue) {
sample = minValue;
}
if (sample > maxValue) {
sample = maxValue;
}
}
// calculation
filteredSample = 1e-10 + a[0] * sample;
for (int i = 1; i < aLength; i++) {
filteredSample = filteredSample + a[i] * inputBuffer[currentChannel][i - 1] - b[i] * outputBuffer[currentChannel][i - 1];
}
// input and output buffer for the next sample calculation
memmove(&inputBuffer[currentChannel][1], &inputBuffer[currentChannel][0], sizeof(double) * (aLength - 1));
memmove(&outputBuffer[currentChannel][1], &outputBuffer[currentChannel][0], sizeof(double) * (aLength - 1));
inputBuffer[currentChannel][0] = sample;
outputBuffer[currentChannel][0] = filteredSample;
// callback
if ((callbackFilteredObject != nullptr) && (callbackFilteredMember != nullptr)) {
if (filteredSample < minValue) {
filteredSample = minValue;
}
if (filteredSample > maxValue) {
filteredSample = maxValue;
}
(callbackFilteredObject->*callbackFilteredMember)(&filteredSample, currentChannel);
}
// put filtered sample back to buffer
if (updateData) {
if (filteredSample < minValue) {
filteredSample = minValue;
}
if (filteredSample > maxValue) {
filteredSample = maxValue;
}
*temp = static_cast<T>(filteredSample);
}
// on to the next sample
processedCount += sizeof(T);
currentChannel++;
if (currentChannel >= channelCount) {
currentChannel = 0;
}
}
}
};
#endif // IIRFILTER_H