arduino-audio-tools
MetaDataFilter.h
1 #pragma once
2 #include "AudioLogger.h"
3 #include "AudioTools/AudioCodecs/AudioCodecsBase.h"
4 #include "AudioTools/CoreAudio/AudioOutput.h"
5 #include "AudioTools/CoreAudio/Buffers.h"
6 
7 namespace audio_tools {
8 
16 class MetaDataFilter : public AudioOutput {
17  public:
19  MetaDataFilter() = default;
20 
22  MetaDataFilter(Print &out) { setOutput(out); }
25 
27  void setOutput(Print &out) { p_out = &out; }
29  void setOutput(AudioWriter &out) { p_writer = &out; }
30 
32  bool begin() override {
33  TRACED();
34  start = 0;
35  if (p_writer) p_writer->begin();
36  return true;
37  }
38 
39  void end() override {
40  if (p_writer) p_writer->end();
41  }
42 
44  size_t write(const uint8_t *data, size_t len) override {
45  TRACEI();
46  size_t result = len;
47  // prevent npe
48  if ((p_out == nullptr && p_writer == nullptr) || (data == nullptr) ||
49  (len == 0))
50  return 0;
51 
52  // find tag
53  int meta_len = 0;
54  if (findTag(data, len, metadata_range.from, meta_len)) {
55  current_pos = 0;
56  metadata_range.setLen(meta_len);
57  LOGI("ignoring metadata at pos: %d len: %d", metadata_range.from,
58  meta_len);
59  }
60 
61  // nothing to ignore
62  if (!metadata_range.isDefined()) {
63  if (p_out) return p_out->write(data, len);
64  if (p_writer) return p_writer->write(data, len);
65  }
66 
67  // ignore data in metadata range
68  SingleBuffer<uint8_t> tmp(len);
69  for (int j = 0; j < len; j++) {
70  if (!metadata_range.inRange(current_pos)) {
71  tmp.write(data[j]);
72  }
73  current_pos++;
74  }
75 
76  // write partial data
77  if (tmp.available() > 0) {
78  if (p_out) p_out->write(tmp.data(), tmp.available());
79  if (p_writer) p_writer->write(tmp.data(), tmp.available());
80  }
81 
82  // reset for next run
83  if (current_pos > metadata_range.to) {
84  current_pos = 0;
85  metadata_range.clear();
86  }
87 
88  return result;
89  }
90 
91  protected:
92  Print *p_out = nullptr;
93  AudioWriter *p_writer = nullptr;
94  int current_pos = 0;
95  enum MetaType { TAG, TAG_PLUS, ID3 };
96  int start = 0;
98  struct Range {
99  int from = -1;
100  int to = -1;
101 
102  bool inRange(int pos) { return pos >= from && pos < to; }
103  void setLen(int len) { to = from + len; }
104 
105  void clear() {
106  from = -1;
107  to = -1;
108  }
109  bool isDefined() { return from != -1; }
110  } metadata_range;
111 
113  struct ID3v2 {
114  uint8_t header[3]; // ID3
115  uint8_t version[2];
116  uint8_t flags;
117  uint8_t size[4];
118  } tagv2;
119 
121  bool findTag(const uint8_t *data, size_t len, int &pos_tag, int &meta_len) {
122  MetaType tag_type;
123  if (find((const char *)data, len, pos_tag, tag_type)) {
124  switch (tag_type) {
125  case TAG:
126  LOGD("TAG");
127  meta_len = 128;
128  break;
129  case TAG_PLUS:
130  LOGD("TAG+");
131  meta_len = 227;
132  break;
133  case ID3:
134  LOGD("ID3");
135  memcpy(&tagv2, data + pos_tag, sizeof(ID3v2));
136  meta_len = calcSizeID3v2(tagv2.size);
137  break;
138  }
139  return true;
140  }
141  return false;
142  }
143 
144  // calculate the synch save size for ID3v2
145  uint32_t calcSizeID3v2(uint8_t chars[4]) {
146  uint32_t byte0 = chars[0];
147  uint32_t byte1 = chars[1];
148  uint32_t byte2 = chars[2];
149  uint32_t byte3 = chars[3];
150  return byte0 << 21 | byte1 << 14 | byte2 << 7 | byte3;
151  }
152 
154  bool find(const char *str, size_t len, int &pos, MetaType &type) {
155  if (str == nullptr || len <= 0) return false;
156  for (size_t j = 0; j <= len - 3; j++) {
157  if (str[j] == 'T' && str[j + 1] == 'A' && str[j + 2] == 'G') {
158  type = str[j + 3] == '+' ? TAG_PLUS : TAG;
159  pos = j;
160  return true;
161  } else if (str[j] == 'I' && str[j + 1] == 'D' && str[j + 2] == '3') {
162  type = ID3;
163  pos = j;
164  return true;
165  }
166  }
167  return false;
168  }
169 };
170 
171 /***
172  * MetaDataFiler applied to the indicated decoder: Class which filters out ID3v1
173  * and ID3v2 Metadata and provides only the audio data to the decoder
174  * @ingroup metadata
175  * @ingroup codecs
176  * @author Phil Schatzmann
177  * @copyright GPLv3
178  */
180  public:
182  p_decoder = &decoder;
183  filter.setOutput(decoder);
184  }
185 
186  bool begin() override {
187  is_active = true;
188  filter.begin();
189  return AudioDecoder::begin();
190  }
191 
192  void end() override {
193  is_active = false;
194  filter.end();
195  AudioDecoder::end();
196  }
197 
198  size_t write(const uint8_t *data, size_t len) override {
199  return filter.write(data, len);
200  }
201 
202  operator bool() override { return p_print != nullptr && is_active; }
203 
204  protected:
205  AudioDecoder *p_decoder = nullptr;
206  MetaDataFilter filter;
207  bool is_active = false;
208 };
209 
210 } // namespace audio_tools
Docoding of encoded audio into PCM data.
Definition: AudioCodecsBase.h:16
Abstract Audio Ouptut class.
Definition: AudioOutput.h:22
E.g. used by Encoders and Decoders.
Definition: AudioTypes.h:224
Definition: MetaDataFilter.h:179
Class which filters out ID3v1 and ID3v2 Metadata and provides only the audio data to the decoder.
Definition: MetaDataFilter.h:16
MetaDataFilter(Print &out)
Constructor which assigns the decoder.
Definition: MetaDataFilter.h:22
void setOutput(AudioWriter &out)
Defines the decoder to which we write the data.
Definition: MetaDataFilter.h:29
bool find(const char *str, size_t len, int &pos, MetaType &type)
find the tag position in the string;
Definition: MetaDataFilter.h:154
size_t write(const uint8_t *data, size_t len) override
Writes the data to the decoder.
Definition: MetaDataFilter.h:44
MetaDataFilter(AudioWriter &out)
Constructor which assigns the decoder.
Definition: MetaDataFilter.h:24
MetaDataFilter()=default
Default Constructor.
bool begin() override
(Re)starts the processing
Definition: MetaDataFilter.h:32
bool findTag(const uint8_t *data, size_t len, int &pos_tag, int &meta_len)
determines if the data conatins a ID3v1 or ID3v2 tag
Definition: MetaDataFilter.h:121
void setOutput(Print &out)
Defines the decoder to which we write the data.
Definition: MetaDataFilter.h:27
Definition: NoArduino.h:58
T * data()
Provides address of actual data.
Definition: Buffers.h:252
bool write(T sample) override
write add an entry to the buffer
Definition: Buffers.h:194
int available() override
provides the number of entries that are available to read
Definition: Buffers.h:219
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:823
ID3 verion 2 TAG Header (10 bytes)
Definition: MetaDataFilter.h:113
Metadata range.
Definition: MetaDataFilter.h:98