arduino-audio-tools
Loading...
Searching...
No Matches
Q1_14.h
Go to the documentation of this file.
1#pragma once
2#include <stdint.h>
4
5namespace audio_tools {
6
16class q1_14_t {
17 public:
18 static constexpr int kFractionalBits = 14;
19 static constexpr int32_t kScale = 1 << kFractionalBits; // 16384
20
21 q1_14_t() = default;
22 q1_14_t(const q1_14_t &in) = default;
23 q1_14_t(float in) { value = fromFloat(in); }
24 q1_14_t(double in) { value = fromFloat((float)in); }
25 q1_14_t(int in) {
26 value = (int16_t)clampRange64((int64_t)in * kScale, -32768, 32767);
27 }
28
29 q1_14_t &operator=(const q1_14_t &other) = default;
30 q1_14_t &operator=(float other) {
31 value = fromFloat(other);
32 return *this;
33 }
34
35 operator float() const { return toFloat(); }
37 explicit operator int() const {
38 int32_t iv = value;
39 return iv < 0 ? -((-iv) >> kFractionalBits) : (iv >> kFractionalBits);
40 }
41
43 int16_t raw() const { return value; }
45 static q1_14_t fromRaw(int16_t raw) {
46 q1_14_t result;
47 result.value = raw;
48 return result;
49 }
50
51 // PCM samples are treated as fixed-point with (bit_depth - 1) fractional
52 // bits (Q1.15 for 16-bit, Q1.23 for 24-bit, Q1.31 for 32-bit), so
53 // converting to/from Q1.14 (14 fractional bits) is just a left/right shift
54 // by the difference in fractional bits -- integer-only, no FPU needed.
55
57 int16_t toInt16() const {
58 return (int16_t)clampRange32((int32_t)value << 1, -32768, 32767);
59 }
61 int24_t toInt24() const {
62 return clampRange32((int32_t)value << 9, -8388608, 8388607);
63 }
65 int32_t toInt32() const {
66 return (int32_t)clampRange64((int64_t)value << 17, INT32_MIN, INT32_MAX);
67 }
68
70 static q1_14_t fromInt16(int16_t sample) { return fromRaw((int16_t)(sample >> 1)); }
72 static q1_14_t fromInt24(int24_t sample) {
73 return fromRaw((int16_t)(((int32_t)sample) >> 9));
74 }
76 static q1_14_t fromInt32(int32_t sample) { return fromRaw((int16_t)(sample >> 17)); }
77
78 // Applies this Q1.14 value as a gain/volume factor to a full-scale PCM
79 // sample (sample * factor), clipping on overflow -- integer-only, no FPU
80 // needed. Unlike operator*, the sample here is NOT itself Q1.14-scaled.
81
83 int16_t scale(int16_t sample) const {
84 int32_t prod = ((int32_t)sample * value) >> kFractionalBits;
85 return (int16_t)clampRange32(prod, -32768, 32767);
86 }
88 int24_t scale(int24_t sample) const {
89 int64_t prod = ((int64_t)(int32_t)sample * value) >> kFractionalBits;
90 return (int32_t)clampRange64(prod, -8388608, 8388607);
91 }
93 int32_t scale(int32_t sample) const {
94 int64_t prod = ((int64_t)sample * value) >> kFractionalBits;
95 return (int32_t)clampRange64(prod, INT32_MIN, INT32_MAX);
96 }
97
99 return fromRaw(clamp((int32_t)value + o.value));
100 }
102 return fromRaw(clamp((int32_t)value - o.value));
103 }
104 q1_14_t operator-() const { return fromRaw(clamp(-(int32_t)value)); }
105
107 int32_t prod = ((int32_t)value * (int32_t)o.value) >> kFractionalBits;
108 return fromRaw(clamp(prod));
109 }
110
112 if (o.value == 0) {
113 // saturate instead of dividing by zero
114 return fromRaw(value < 0 ? INT16_MIN : INT16_MAX);
115 }
116 int32_t quotient = (((int32_t)value) << kFractionalBits) / o.value;
117 return fromRaw(clamp(quotient));
118 }
119
120 q1_14_t &operator+=(q1_14_t o) { return *this = *this + o; }
121 q1_14_t &operator-=(q1_14_t o) { return *this = *this - o; }
122 q1_14_t &operator*=(q1_14_t o) { return *this = *this * o; }
123 q1_14_t &operator/=(q1_14_t o) { return *this = *this / o; }
124
125 bool operator<(q1_14_t o) const { return value < o.value; }
126 bool operator<=(q1_14_t o) const { return value <= o.value; }
127 bool operator>(q1_14_t o) const { return value > o.value; }
128 bool operator>=(q1_14_t o) const { return value >= o.value; }
129 bool operator==(q1_14_t o) const { return value == o.value; }
130 bool operator!=(q1_14_t o) const { return value != o.value; }
131
132 // q1_14_t/float mixed overloads: q1_14_t has both a converting
133 // constructor from float and a conversion operator to float, so
134 // `q1_14Value * 0.7f` would otherwise be ambiguous between converting the
135 // float to q1_14_t or the q1_14_t to float. These exact-match overloads
136 // resolve that.
137 q1_14_t operator+(float o) const { return *this + q1_14_t(o); }
138 q1_14_t operator-(float o) const { return *this - q1_14_t(o); }
139 q1_14_t operator*(float o) const { return *this * q1_14_t(o); }
140 q1_14_t operator/(float o) const { return *this / q1_14_t(o); }
141 bool operator<(float o) const { return *this < q1_14_t(o); }
142 bool operator<=(float o) const { return *this <= q1_14_t(o); }
143 bool operator>(float o) const { return *this > q1_14_t(o); }
144 bool operator>=(float o) const { return *this >= q1_14_t(o); }
145 bool operator==(float o) const { return *this == q1_14_t(o); }
146 bool operator!=(float o) const { return *this != q1_14_t(o); }
147
148 protected:
149 int16_t value = 0;
150
151 float toFloat() const { return (float)value / (float)kScale; }
152
153 static int16_t fromFloat(float in) {
154 float scaled = in * (float)kScale;
155 scaled += (scaled >= 0.0f ? 0.5f : -0.5f); // round to nearest
156 if (scaled >= 32767.0f) return 32767;
157 if (scaled <= -32768.0f) return -32768;
158 return (int16_t)scaled;
159 }
160
161 static int16_t clamp(int32_t v) {
162 if (v > 32767) return 32767;
163 if (v < -32768) return -32768;
164 return (int16_t)v;
165 }
166
167 static int32_t clampRange32(int32_t v, int32_t lo, int32_t hi) {
168 if (v > hi) return hi;
169 if (v < lo) return lo;
170 return v;
171 }
172
173 static int64_t clampRange64(int64_t v, int64_t lo, int64_t hi) {
174 if (v > hi) return hi;
175 if (v < lo) return lo;
176 return v;
177 }
178};
179
180// Free-function overloads for `float op q1_14_t` (float on the left), for
181// the same exact-match-ambiguity reason as the member float overloads above.
182inline q1_14_t operator+(float a, q1_14_t b) { return q1_14_t(a) + b; }
183inline q1_14_t operator-(float a, q1_14_t b) { return q1_14_t(a) - b; }
184inline q1_14_t operator*(float a, q1_14_t b) { return q1_14_t(a) * b; }
185inline q1_14_t operator/(float a, q1_14_t b) { return q1_14_t(a) / b; }
186inline bool operator<(float a, q1_14_t b) { return q1_14_t(a) < b; }
187inline bool operator<=(float a, q1_14_t b) { return q1_14_t(a) <= b; }
188inline bool operator>(float a, q1_14_t b) { return q1_14_t(a) > b; }
189inline bool operator>=(float a, q1_14_t b) { return q1_14_t(a) >= b; }
190inline bool operator==(float a, q1_14_t b) { return q1_14_t(a) == b; }
191inline bool operator!=(float a, q1_14_t b) { return q1_14_t(a) != b; }
192
193} // namespace audio_tools
24bit integer which is used for I2S sound processing. The values are represented as int32_t,...
Definition Int24_4bytes_t.h:22
Fixed-point Q1.14 number: a plain 16-bit signed integer holding 1 integer bit and 14 fractional bits ...
Definition Q1_14.h:16
static int16_t fromFloat(float in)
Definition Q1_14.h:153
q1_14_t & operator-=(q1_14_t o)
Definition Q1_14.h:121
bool operator<=(float o) const
Definition Q1_14.h:142
bool operator>(q1_14_t o) const
Definition Q1_14.h:127
bool operator>(float o) const
Definition Q1_14.h:143
int32_t toInt32() const
converts to a 32-bit PCM sample (-2147483648..2147483647)
Definition Q1_14.h:65
static int32_t clampRange32(int32_t v, int32_t lo, int32_t hi)
Definition Q1_14.h:167
q1_14_t & operator+=(q1_14_t o)
Definition Q1_14.h:120
q1_14_t & operator*=(q1_14_t o)
Definition Q1_14.h:122
int24_t toInt24() const
converts to a 24-bit PCM sample (-8388608..8388607)
Definition Q1_14.h:61
int24_t scale(int24_t sample) const
scales a 24-bit PCM sample by this Q1.14 factor
Definition Q1_14.h:88
bool operator==(float o) const
Definition Q1_14.h:145
static q1_14_t fromRaw(int16_t raw)
builds a q1_14_t directly from a raw Q1.14 value (no scaling)
Definition Q1_14.h:45
q1_14_t operator-(q1_14_t o) const
Definition Q1_14.h:101
q1_14_t operator/(float o) const
Definition Q1_14.h:140
q1_14_t & operator/=(q1_14_t o)
Definition Q1_14.h:123
static int16_t clamp(int32_t v)
Definition Q1_14.h:161
int32_t scale(int32_t sample) const
scales a 32-bit PCM sample by this Q1.14 factor
Definition Q1_14.h:93
static q1_14_t fromInt16(int16_t sample)
builds a q1_14_t from a 16-bit PCM sample (-32768..32767)
Definition Q1_14.h:70
q1_14_t operator-(float o) const
Definition Q1_14.h:138
q1_14_t(double in)
Definition Q1_14.h:24
q1_14_t operator*(q1_14_t o) const
Definition Q1_14.h:106
int16_t value
Definition Q1_14.h:149
int16_t scale(int16_t sample) const
scales a 16-bit PCM sample by this Q1.14 factor
Definition Q1_14.h:83
bool operator==(q1_14_t o) const
Definition Q1_14.h:129
bool operator<(float o) const
Definition Q1_14.h:141
q1_14_t & operator=(float other)
Definition Q1_14.h:30
bool operator<(q1_14_t o) const
Definition Q1_14.h:125
int16_t toInt16() const
converts to a 16-bit PCM sample (-32768..32767)
Definition Q1_14.h:57
static q1_14_t fromInt24(int24_t sample)
builds a q1_14_t from a 24-bit PCM sample (-8388608..8388607)
Definition Q1_14.h:72
q1_14_t & operator=(const q1_14_t &other)=default
q1_14_t operator/(q1_14_t o) const
Definition Q1_14.h:111
q1_14_t(int in)
Definition Q1_14.h:25
bool operator>=(float o) const
Definition Q1_14.h:144
q1_14_t operator*(float o) const
Definition Q1_14.h:139
q1_14_t operator+(float o) const
Definition Q1_14.h:137
static constexpr int kFractionalBits
Definition Q1_14.h:18
static int64_t clampRange64(int64_t v, int64_t lo, int64_t hi)
Definition Q1_14.h:173
q1_14_t(const q1_14_t &in)=default
bool operator!=(q1_14_t o) const
Definition Q1_14.h:130
q1_14_t operator-() const
Definition Q1_14.h:104
float toFloat() const
Definition Q1_14.h:151
static constexpr int32_t kScale
Definition Q1_14.h:19
int16_t raw() const
raw underlying Q1.14 representation
Definition Q1_14.h:43
static q1_14_t fromInt32(int32_t sample)
builds a q1_14_t from a 32-bit PCM sample (-2147483648..2147483647)
Definition Q1_14.h:76
q1_14_t(float in)
Definition Q1_14.h:23
q1_14_t operator+(q1_14_t o) const
Definition Q1_14.h:98
bool operator<=(q1_14_t o) const
Definition Q1_14.h:126
bool operator>=(q1_14_t o) const
Definition Q1_14.h:128
bool operator!=(float o) const
Definition Q1_14.h:146
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
PseudoFloat operator-(float a, PseudoFloat b)
Definition PseudoFloat.h:188
bool operator==(float a, PseudoFloat b)
Definition PseudoFloat.h:195
bool operator<=(float a, PseudoFloat b)
Definition PseudoFloat.h:193
PseudoFloat operator*(float a, PseudoFloat b)
Definition PseudoFloat.h:189
bool operator>(float a, PseudoFloat b)
Definition PseudoFloat.h:192
bool operator!=(float a, PseudoFloat b)
Definition PseudoFloat.h:196
bool operator<(float a, PseudoFloat b)
Definition PseudoFloat.h:191
PseudoFloat operator/(float a, PseudoFloat b)
Definition PseudoFloat.h:190
bool operator>=(float a, PseudoFloat b)
Definition PseudoFloat.h:194
PseudoFloat operator+(float a, PseudoFloat b)
Definition PseudoFloat.h:187