arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
PDMStream.h
1#include "AudioToolsConfig.h"
2#include "Stream.h"
3
4#define DELAY(j) {for(volatile int i=0;i<j;i++);}
5
6namespace audio_tools {
7
18template <typename T>
20 public:
21 DecimationStreamExt() = default;
22 DecimationStreamExt(Stream &in) { setStream(in); }
23
24 void setStream(Stream &in) { p_in = &in; }
25
26 virtual bool begin(AudioInfo cfg) {
27 setAudioInfo(cfg);
28 return true;
29 }
30
31 // defines the decimation factor: as multiple of bits_per sample
32 void setDecimationFactor(int factor) { dec_factor = factor; }
33
34 size_t readBytes(uint8_t *data, size_t len) {
35 LOGD("readBytes:%d", len);
36 assert(data != nullptr);
37 // make sure that we read full samples
38 int samples = len / sizeof(T);
39 int result_bytes = samples * sizeof(T);
40
41 // calculated scaling factor and offset for unsigned to signed conversion
42 int max_value = sizeof(T) * 8 * dec_factor; // e.g. 16 * 32 = 512
43 int scaled_max = pow(2, sizeof(T) * 8); // e.g. 65536
44 int factor = scaled_max / max_value; // e.g. 128
45 int unsigned_to_signed = scaled_max / 2; // e.g. 32768
46
47 // provide subsequent samples
48 T *data_typed = (T *)data;
49 T tmp_in;
50 for (int idx = 0; idx < samples; idx++) {
51 // decimate subsequent samples
52 unsigned decimated = 0;
53 for (int dec = 0; dec < dec_factor; dec++) {
54 int sample_bytes = sizeof(T);
55 LOGD("readBytes: %d", sample_bytes);
56 if (p_in->readBytes((uint8_t *)&tmp_in, sample_bytes) != sample_bytes) {
57 LOGE("readBytes failed");
58 }
59 decimated += countSetBits(tmp_in);
60 }
61 // store scaled decimated as singned value
62 //data[idx] = (decimated * factor) - unsigned_to_signed;
63 data_typed[idx] = decimated;
64 }
65
66 return result_bytes;
67 }
68
69 int available() {
70 TRACED();
71 return 1024;
72 }
73
74 AudioInfo audioInfoPDM() {
75 AudioInfo result = audioInfo();
76 // sample_rate_pcm = sample_rate_pdm / decimation
77 result.sample_rate = info.sample_rate * dec_factor;
78 return result;
79 }
80
81 protected:
82 Stream *p_in = nullptr;
83 int dec_factor = 32; // usually set between 25 and 64×
84
85 unsigned countSetBits(unsigned n) {
86 TRACED();
87 T count = 0;
88 while (n) {
89 count += n & 1;
90 n >>= 1;
91 }
92 return count;
93 }
94};
95
96
97/*
98We read the raw PDM data with the help of the Arduino digitalRead(). The SEL pin
99needs to be connected to GND, so that the data is valid at clock pin low.
100
101COMMON CLOCK AND DECIMATION RATIO SETTINGS
102PDM Clock Frequency(fPDM)Decimation Ratio Baseband Sampling Rate (fs) Audio Signal Bandwidth (fs/2)Applications
1034.8 MHz 25× 192 kHz 96 kHz Ultrasound
1044.8 MHz 50× 96 kHz 48 kHz
1053.072 MHz 64× 48 kHz 24 kHz Full-bandwidth audio
1062.4 MHz 50× 48 kHz 24 kHz
1071.536 MHz 48× 32 kHz 16 kHz Wide-bandwidth audio
1081.024 MHz 64× 16 kHz 8 kHz High-quality voice
109768 kHz 48× 16 kHz 8 kHz
110512 kHz 32× 16 kHz 8 kHz
111512 kHz 64× 8 kHz 4 kHz Standard voice
112*/
113
114template <typename T>
116
117public:
118 bool begin(AudioInfo cfg) {
120 pinMode(pin_clock, OUTPUT);
121 pinMode(pin_data, INPUT);
122 return true;
123 }
124
125 size_t readBytes(uint8_t *data, size_t len) {
126 LOGD("readBytes:%d", len);
127 assert(data != nullptr);
128 // make sure that we read full samples
129 int samples = len / sizeof(T);
130 int result_bytes = samples * sizeof(T);
131
132 // calculated scaling factor and offset for unsigned to signed conversion
133 int max_value = sizeof(T) * 8 * DecimationStreamExt<T>::dec_factor; // e.g. 16 * 32 = 512
134 int scaled_max = pow(2, sizeof(T) * 8); // e.g. 65536
135 int factor = scaled_max / max_value; // e.g. 128
136 int unsigned_to_signed = scaled_max / 2; // e.g. 32768
137
138 // provide subsequent samples
139 T *data_typed = (T *)data;
140 T tmp_in;
141 for (int idx = 0; idx < samples; idx++) {
142 // decimate subsequent samples
143 unsigned decimated = 0;
144 for (int dec = 0; dec < DecimationStreamExt<T>::dec_factor * sizeof(T)*8; dec++) {
145 int sample_bytes = sizeof(T);
146 digitalWrite(pin_clock, HIGH);
147 DELAY(1);
148 digitalWrite(pin_clock, LOW);
149 bool bit = digitalRead(pin_data);
150 DELAY(1);
151 // sum up active bits
152 decimated += bit;
153 }
154 // store scaled decimated as singned value
155 //data[idx] = (decimated * factor) - unsigned_to_signed;
156 data_typed[idx] = decimated;
157 }
158
159 return result_bytes;
160 }
161
162protected:
163 int pin_clock = 14;
164 int pin_data = 32;
165};
166
175template <typename T>
177 public:
179 decimation_stream.setStream(in);
180 info.sample_rate = 44100;
181 info.channels = 1;
182 info.bits_per_sample = bitsPerSample();
183 }
184
185 // provides the audio info of the PDM stream (with the much higher sample
186 // rate)
187 AudioInfo audioInfoPDM() {
188 AudioInfo result = audioInfo();
189 // sample_rate_pcm = sample_rate_pdm / decimation
190 result.sample_rate = info.sample_rate * decimation();
191 return result;
192 }
193
194 // provides the decimation factor that was used in the processing
195 int decimation() { return decimation_factor; }
196
197 // defines the decimation factor: must be multiple of bits_per sample
198 void setDecimationFactor(int factor) {
199 decimation_factor = factor;
200 }
201
202 bool begin(AudioInfo info) {
203 setAudioInfo(info);
204 if (info.channels != 1) {
205 LOGE("channels must be 1");
206 }
207 // set the factor for the decimator
208 decimation_stream.setDecimationFactor(decimation_factor);
209 return begin();
210 }
211
212 bool begin() {
213 decimation_stream.begin(info);
214 bool rc = in_filtered.begin(info);
215 in_filtered.setFilter(0, fir);
216 return rc;
217 }
218
219 size_t readBytes(uint8_t *data, size_t len) {
220 LOGD("readBytes:%d", len);
221 assert(data != nullptr);
222 // make sure that we read full samples
223 int samples = len / sizeof(T);
224 int result_bytes = samples * sizeof(T);
225 assert(result_bytes <= len);
226
227 if (in_filtered.readBytes(data, result_bytes) != result_bytes) {
228 LOGE("readBytes failed");
229 }
230
231 return result_bytes;
232 }
233
234 int available() {
235 TRACED();
236 return in_filtered.available();
237 }
238
239 template <size_t B>
240 void setFilterValues(const T (&b)[B]) {
241 fir.setValues(b);
242 }
243
244 protected:
245 int decimation_factor = sizeof(T) * 2;
246 // 44100 hz FIR: cut off: 18040, transition bandwidth: 7380
247 float coef[19] = {
248 -0.000704420658475743, -0.000537879918926308, 0.004114637509913062,
249 -0.012685775806621488, 0.027889173789107543, -0.049285026985058301,
250 0.074005079283040689, -0.097330704866957815, 0.114052040962871595,
251 0.880965753382213723, 0.114052040962871595, -0.097330704866957843,
252 0.074005079283040717, -0.049285026985058301, 0.027889173789107550,
253 -0.012685775806621504, 0.004114637509913064, -0.000537879918926308,
254 -0.000704420658475743};
255 DecimationStreamExt<T> decimation_stream;
256 FilteredStream<T, float> in_filtered{decimation_stream, 1};
257 FIR<float> fir{coef};
258
259 constexpr int8_t bitsPerSample() { return sizeof(T) * 8; }
260};
261
262// Define PDMStream
264
265} // namespace audio_tools
int digitalRead(int pin)
e.g. for AudioActions
Definition NoArduino.h:200
virtual void setAudioInfo(AudioInfo info)=0
Defines the input AudioInfo.
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:119
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition BaseStream.h:127
virtual AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition BaseStream.h:150
Definition PDMStream.h:115
Deciates an sample stream by the indicated factor: Decimation counts the number of set bits....
Definition PDMStream.h:19
FIR Filter Converted from https://github.com/sebnil/FIR-filter-Arduino-Library/tree/master/src You ca...
Definition Filter.h:63
Stream to which we can apply Filters for each channel. The filter might change the result size!
Definition AudioStreams.h:1557
void setFilter(int channel, Filter< TF > *filter)
Definition AudioStreams.h:1637
Applies low pass filter to a decimated pdm signal to convert it to pcm.
Definition PDMStream.h:176
Definition NoArduino.h:142
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:53
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:55
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:57
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:59