arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
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
7namespace audio_tools {
8
17 public:
19 MetaDataFilter() = default;
20
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 LOGI("write: %u", (unsigned)len);
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 size_t to_write = tmp.available();
78 if (to_write > 0) {
79 LOGI("output: %u", (unsigned)to_write);
80 size_t written = 0;
81 if (p_out) written = p_out->write(tmp.data(), to_write);
82 if (p_writer) written = p_writer->write(tmp.data(), to_write);
83 assert(to_write == written);
84 metadata_range.clear();
85 } else {
86 LOGI("output ignored");
87 }
88
89 // reset for next run
90 if (current_pos > metadata_range.to) {
91 current_pos = 0;
92 metadata_range.clear();
93 }
94
95 return result;
96 }
97
98 protected:
99 Print *p_out = nullptr;
100 AudioWriter *p_writer = nullptr;
101 int current_pos = 0;
102 enum MetaType { TAG, TAG_PLUS, ID3 };
103 int start = 0;
105 struct Range {
106 int from = -1;
107 int to = -1;
108
109 bool inRange(int pos) { return pos >= from && pos < to; }
110 void setLen(int len) { to = from + len; }
111
112 void clear() {
113 from = -1;
114 to = -1;
115 }
116 bool isDefined() { return from != -1; }
117 } metadata_range;
118
120 struct ID3v2 {
121 uint8_t header[3]; // ID3
122 uint8_t version[2];
123 uint8_t flags;
124 uint8_t size[4];
125 } tagv2;
126
128 bool findTag(const uint8_t *data, size_t len, int &pos_tag, int &meta_len) {
129 MetaType tag_type;
130 if (find((const char *)data, len, pos_tag, tag_type)) {
131 switch (tag_type) {
132 case TAG:
133 LOGD("TAG");
134 meta_len = 128;
135 break;
136 case TAG_PLUS:
137 LOGD("TAG+");
138 meta_len = 227;
139 break;
140 case ID3:
141 LOGD("ID3");
142 memcpy(&tagv2, data + pos_tag, sizeof(ID3v2));
143 meta_len = calcSizeID3v2(tagv2.size);
144 break;
145 }
146 return true;
147 }
148 return false;
149 }
150
151 // calculate the synch save size for ID3v2
152 uint32_t calcSizeID3v2(uint8_t chars[4]) {
153 uint32_t byte0 = chars[0];
154 uint32_t byte1 = chars[1];
155 uint32_t byte2 = chars[2];
156 uint32_t byte3 = chars[3];
157 return byte0 << 21 | byte1 << 14 | byte2 << 7 | byte3;
158 }
159
161 bool find(const char *str, size_t len, int &pos, MetaType &type) {
162 if (str == nullptr || len <= 0) return false;
163 for (size_t j = 0; j <= len - 3; j++) {
164 if (str[j] == 'T' && str[j + 1] == 'A' && str[j + 2] == 'G') {
165 type = str[j + 3] == '+' ? TAG_PLUS : TAG;
166 pos = j;
167 return true;
168 } else if (str[j] == 'I' && str[j + 1] == 'D' && str[j + 2] == '3') {
169 type = ID3;
170 pos = j;
171 return true;
172 }
173 }
174 return false;
175 }
176};
177
178/***
179 * MetaDataFiler applied to the indicated decoder: Class which filters out ID3v1
180 * and ID3v2 Metadata and provides only the audio data to the decoder
181 * @ingroup metadata
182 * @ingroup codecs
183 * @author Phil Schatzmann
184 * @copyright GPLv3
185 */
187 public:
189 p_decoder = &decoder;
190 filter.setOutput(decoder);
191 }
192
193 bool begin() override {
194 is_active = true;
195 filter.begin();
196 p_decoder->begin();
197 return AudioDecoder::begin();
198 }
199
200 void end() override {
201 is_active = false;
202 filter.end();
203 AudioDecoder::end();
204 }
205
206 size_t write(const uint8_t *data, size_t len) override {
207 return filter.write(data, len);
208 }
209
210 void setOutput(AudioStream &out_stream) override {
211 p_decoder->setOutput(out_stream);
212 addNotifyAudioChange(out_stream);
213 }
214
215 virtual void setOutput(AudioOutput &out_stream) override {
216 p_decoder->setOutput(out_stream);
217 addNotifyAudioChange(out_stream);
218 }
219
221 virtual void setOutput(Print &out_stream) override {
222 p_decoder->setOutput(out_stream);
223 }
224
225 operator bool() override { return p_print != nullptr && is_active; }
226
227 protected:
228 AudioDecoder *p_decoder = nullptr;
229 MetaDataFilter filter;
230 bool is_active = false;
231};
232
233} // namespace audio_tools
Decoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:18
virtual void setOutput(AudioStream &out_stream)
Defines where the decoded result is written to.
Definition AudioCodecsBase.h:36
virtual void addNotifyAudioChange(AudioInfoSupport &bi)
Adds target to be notified about audio changes.
Definition AudioTypes.h:151
Abstract Audio Ouptut class.
Definition AudioOutput.h:22
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:119
E.g. used by Encoders and Decoders.
Definition AudioTypes.h:207
Definition MetaDataFilter.h:186
virtual void setOutput(AudioOutput &out_stream) override
Defines where the decoded result is written to.
Definition MetaDataFilter.h:215
void setOutput(AudioStream &out_stream) override
Defines where the decoded result is written to.
Definition MetaDataFilter.h:210
virtual void setOutput(Print &out_stream) override
Defines where the decoded result is written to.
Definition MetaDataFilter.h:221
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:161
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:128
void setOutput(Print &out)
Defines the decoder to which we write the data.
Definition MetaDataFilter.h:27
Definition NoArduino.h:62
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:175
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:200
int available() override
provides the number of entries that are available to read
Definition Buffers.h:227
T * data()
Provides address of actual data.
Definition Buffers.h:261
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
ID3 verion 2 TAG Header (10 bytes)
Definition MetaDataFilter.h:120
Metadata range.
Definition MetaDataFilter.h:105