arduino-audio-tools
FrequencyDetection.h
1 #include "AudioTools/CoreAudio/AudioStreams.h"
2 
3 namespace audio_tools {
4 
13  public:
15 
17  p_out = &out;
18  };
19 
21  p_out = ∈
22  p_in = ∈
23  };
24 
25  bool begin(AudioInfo info){
26  setAudioInfo(info);
27  return AudioStream::begin();
28  }
29 
30  int available()override{
31  if (p_in) return p_in->available();
32  return 0;
33  }
34 
35  int availableForWrite()override{
36  if (p_out) return p_out->availableForWrite();
37  return DEFAULT_BUFFER_SIZE;
38  }
39 
40  size_t readBytes(uint8_t *data, size_t len) override {
41  size_t result = p_in->readBytes(data, len);
42  switch(info.bits_per_sample){
43  case 16:
44  detect<int16_t>((int16_t*)data, len/sizeof(int16_t));
45  break;
46  case 24:
47  detect<int24_t>((int24_t*)data, len/sizeof(int24_t));
48  break;
49  case 32:
50  detect<int32_t>((int32_t*)data, len/sizeof(int32_t));
51  break;
52  }
53  return result;
54  }
55 
56  virtual size_t write(const uint8_t *data, size_t len) override {
57  switch(info.bits_per_sample){
58  case 16:
59  detect<int16_t>((int16_t*)data, len/sizeof(int16_t));
60  break;
61  case 24:
62  detect<int24_t>((int24_t*)data, len/sizeof(int24_t));
63  break;
64  case 32:
65  detect<int32_t>((int32_t*)data, len/sizeof(int32_t));
66  break;
67  }
68 
69  size_t result = len;
70  if (p_out!=nullptr) result = p_out->write(data, len);
71  return result;
72  }
73 
75  float frequency(int channel) {
76  if(channel>=info.channels) {
77  LOGE("Invalid channel: %d", channel);
78  return 0;
79  }
80  return freq[channel];
81  }
82 
83  protected:
84  Vector<float> freq;
85  Print *p_out=nullptr;
86  Stream *p_in = nullptr;
87  float sum=0, sum_old=0;
88 
89  template <class T>
90  void detect(T* samples, size_t len) {
91  freq.resize(info.channels);
92  for (int ch=0; ch<info.channels; ch++){
93  freq[ch] = detectChannel(ch, samples, len);
94  }
95  }
96 
97  template <class T>
98  float detectChannel(int channel, T* samples, size_t len) {
99  int thresh = 0;
100  uint8_t pd_state = 0;
101  int period = 0;
102  T max_value = NumberConverter::maxValue(info.bits_per_sample);
103  // Autocorrelation
104  for(int i = channel; i < len; i+=info.channels) {
105  sum_old = sum;
106  sum = 0;
107  for(int k = channel; k < len-i; k+=info.channels) {
108  sum += (samples[k])*(samples[k+i]); // / max_value;
109  }
110 
111  // Peak Detect State Machine
112  if (pd_state == 2 && (sum-sum_old) <=0) {
113  period = i;
114  pd_state = 3;
115  }
116  if (pd_state == 1 && (sum > thresh) && (sum-sum_old) > 0) {
117  pd_state = 2;
118  }
119  if (pd_state == 0) {
120  thresh = sum * 0.5;
121  pd_state = 1;
122  }
123  }
124  // Frequency identified in Hz
125  return static_cast<float>(info.sample_rate) / period;
126  }
127 };
128 
137  public:
138  FrequncyZeroCrossingStream() = default;
139 
141  p_out = &out;
142  };
143 
145  p_out = &in;
146  p_in = &in;
147  };
148 
149  bool begin(AudioInfo info){
150  setAudioInfo(info);
151  return AudioStream::begin();
152  }
153 
154  int available()override{
155  if (p_in) return p_in->available();
156  return 0;
157  }
158 
159  int availableForWrite()override{
160  if (p_out) return p_out->availableForWrite();
161  return DEFAULT_BUFFER_SIZE;
162  }
163 
164  size_t readBytes(uint8_t *data, size_t len) override {
165  size_t result = p_in->readBytes(data, len);
166  switch(info.bits_per_sample){
167  case 16:
168  detect<int16_t>((int16_t*)data, len/sizeof(int16_t));
169  break;
170  case 24:
171  detect<int24_t>((int24_t*)data, len/sizeof(int24_t));
172  break;
173  case 32:
174  detect<int32_t>((int32_t*)data, len/sizeof(int32_t));
175  break;
176  }
177  return result;
178  }
179 
180  virtual size_t write(const uint8_t *data, size_t len) override {
181  switch(info.bits_per_sample){
182  case 16:
183  detect<int16_t>((int16_t*)data, len/sizeof(int16_t));
184  break;
185  case 24:
186  detect<int24_t>((int24_t*)data, len/sizeof(int24_t));
187  break;
188  case 32:
189  detect<int32_t>((int32_t*)data, len/sizeof(int32_t));
190  break;
191  }
192 
193  size_t result = len;
194  if (p_out!=nullptr) result = p_out->write(data, len);
195  return result;
196  }
197 
199  float frequency(int channel) {
200  if(channel>=info.channels) {
201  LOGE("Invalid channel: %d", channel);
202  return 0;
203  }
204  return freq[channel];
205  }
206 
207  void setFrequencyCallback(void (*callback)(int channel, float freq)){
208  notify = callback;
209  }
210 
211  protected:
212  Vector<float> freq;
213  Print *p_out=nullptr;
214  Stream *p_in = nullptr;
215  int count = 0;
216  bool active = false;
217  void (*notify)(int channel, float freq);
218 
219  template <class T>
220  void detect(T* samples, size_t len) {
221  freq.resize(info.channels);
222  for (int ch=0; ch<info.channels; ch++){
223  detectChannel(ch, samples, len);
224  }
225  }
226 
227  template <class T>
228  void detectChannel(int channel, T* samples, size_t len) {
229  for(int i = channel; i < (len-info.channels); i+=info.channels) {
230  // start counter at first crossing
231  if (active) count++;
232  // update frequncy at each upward zero crossing
233  if (samples[i]<=0 && samples[i+info.channels]>0) {
234  freq[channel] = (1.0f * info.sample_rate) / count;
235  if (notify) notifyAudioChange(channel, freq[channel]);
236  count = 0;
237  active = true;
238  }
239  }
240  }
241 };
242 
243 
244 }
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition: BaseStream.h:109
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition: BaseStream.h:117
Determine Frequency using Audio Correlation. based on https://github.com/akellyirl/AutoCorr_Freq_dete...
Definition: FrequencyDetection.h:12
float frequency(int channel)
provides the determined frequncy
Definition: FrequencyDetection.h:75
Determine Frequency using upward 0 crossings.
Definition: FrequencyDetection.h:136
float frequency(int channel)
provides the determined frequncy
Definition: FrequencyDetection.h:199
static int64_t maxValue(int value_bits_per_sample)
provides the biggest number for the indicated number of bits
Definition: AudioTypes.h:325
Definition: NoArduino.h:58
Definition: NoArduino.h:125
24bit integer which is used for I2S sound processing. The values are represented as int32_t,...
Definition: Int24_4bytes_t.h:16
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:821
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:50
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition: AudioTypes.h:53
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition: AudioTypes.h:55
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition: AudioTypes.h:57