arduino-audio-tools
CodecMP3Mini.h
1 #pragma once
2 
3 #define MINIMP3_NO_STDIO
4 //#define MINIMP3_NO_SIMD
5 //#define MINIMP3_IMPLEMENTATION
6 //#define MINIMP3_ONLY_MP3
7 //#define MINIMP3_FLOAT_OUTPUT
8 
9 #ifndef MINIMP3_MAX_SAMPLE_RATE
10 #define MINIMP3_MAX_SAMPLE_RATE 44100
11 #endif
12 
13 #include "AudioCodecs/AudioEncoded.h"
14 #include "minimp3.h"
15 
16 
17 namespace audio_tools {
18 
28 class MP3DecoderMini : public AudioDecoder {
29  public:
30  MP3DecoderMini() = default;
31 
34  if (active) {
35  end();
36  }
37  }
38 
39  void setBufferLength(int len) { buffer_size = len; }
40 
42  audioBaseInfoSupport = &bi;
43  }
44 
46  void begin() {
47  TRACED();
48  //esp_task_wdt_delete(nullptr);
49  ::mp3dec_init(&mp3d);
50  buffer.resize(buffer_size);
51  pcm.resize(MINIMP3_MAX_SAMPLES_PER_FRAME);
52  buffer_pos = 0;
53  active = true;
54  }
55 
57  void end() {
58  TRACED();
59  flush();
60  active = false;
61  }
62 
64  void setOutput(Print &outStream) { this->out = &outStream; }
65 
67  AudioInfo audioInfo() { return audio_info; }
68 
70  size_t write(const void *data, size_t len) {
71  LOGD("write: %zu", len);
72  if (active) {
73  if (buffer_pos+len>=buffer.size()){
74  decode(len);
75  }
76  assert(buffer_pos+len<buffer.size());
77  memcpy(buffer.data()+buffer_pos, data, len);
78  buffer_pos += len;
79  }
80  return len;
81  }
82 
84  void flush() {
85  // decode the full buffer
86  decode(0);
87  buffer_pos = 0;
88  }
89 
91  virtual operator bool() { return active; }
92 
93  void setSampleRateLimit(int limit){
94  sample_rate_limit = limit;
95  }
96 
97  protected:
98  AudioInfo audio_info;
99  AudioInfoSupport *audioBaseInfoSupport = nullptr;
100  Print *out = nullptr;
101  mp3dec_t mp3d;
102  mp3dec_frame_info_t mp3dec_info;
103  size_t buffer_size = 5 * 1024;
104  size_t buffer_pos = 0;
105  Vector<uint8_t> buffer;
106  Vector<mp3d_sample_t> pcm;
107  #ifdef MINIMP3_FLOAT_OUTPUT
108  Vector<int16_t> pcm16;
109  #endif
110  bool active;
111  int sample_rate_limit = MINIMP3_MAX_SAMPLE_RATE; //32000;
112 
114  void decode(int write_len) {
115  LOGD("decode: %zd ", buffer_pos);
116  int open = buffer_pos;
117  int processed = 0;
118  int samples;
119  do {
120  // decode data
121  samples = ::mp3dec_decode_frame(&mp3d, buffer.data()+processed, open,
122  pcm.data(), &mp3dec_info);
123  LOGD("frame_offset: %d - frame_bytes: %d -> samples %d", mp3dec_info.frame_offset, mp3dec_info.frame_bytes, samples);
124  open -= mp3dec_info.frame_bytes;
125  processed += mp3dec_info.frame_bytes;
126  // output decoding result
127  if (samples > 0) {
128  provideResult(samples);
129  }
130  // process until we have space for the next write
131  } while(processed < write_len);
132 
133  // save unprocessed data
134  buffer_pos = open;
135  memmove(buffer.data(),buffer.data()+processed, open);
136  }
137 
139  void provideResult(int samples) {
140  LOGD("provideResult: %d samples", samples);
141  AudioInfo info;
142  info.sample_rate = mp3dec_info.hz>sample_rate_limit ? sample_rate_limit : mp3dec_info.hz;
143  info.channels = mp3dec_info.channels;
144  info.bits_per_sample = 16;
145 
146  // notify about audio changes
147  if (audioBaseInfoSupport != nullptr && info != audio_info) {
148  info.logInfo();
149  audioBaseInfoSupport->setAudioInfo(info);
150  }
151  // store last audio_info so that we can detect any changes
152  audio_info = info;
153 
154  // provide result pwm data
155  if (out != nullptr) {
156  #ifdef MINIMP3_FLOAT_OUTPUT
157  pcm16.resize(samples);
158  f32_to_s16(pcm.data(), pcm16.data(), samples);
159  out->write((uint8_t *)pcm16.data(), samples * sizeof(int16_t));
160  #else
161  out->write((uint8_t *)pcm.data(), samples * sizeof(mp3d_sample_t));
162  #endif
163  }
164  }
165 
166  void f32_to_s16(float *in, int16_t *out, int num_samples) {
167  int i = 0;
168  for(; i < num_samples; i++){
169  float sample = in[i] * 32768.0f;
170  if (sample >= 32766.5f)
171  out[i] = (int16_t) 32767;
172  else if (sample <= -32767.5f)
173  out[i] = (int16_t)-32768;
174  else {
175  int16_t s = (int16_t)(sample + .5f);
176  s -= (s < 0); /* away from zero, to be compliant */
177  out[i] = s;
178  }
179  }
180  }
181 
182 
183 };
184 
185 } // namespace audio_tools
Docoding of encoded audio into PCM data.
Definition: AudioEncoded.h:17
Supports changes to the sampling rate, bits and channels.
Definition: AudioTypes.h:117
MP3 Decoder using https://github.com/pschatzmann/minimp3. This decoder does not provide any good resu...
Definition: CodecMP3Mini.h:28
size_t write(const void *data, size_t len)
Write mp3 data to decoder.
Definition: CodecMP3Mini.h:70
void setOutput(Print &outStream)
Defines the output Stream.
Definition: CodecMP3Mini.h:64
void setNotifyAudioChange(AudioInfoSupport &bi)
Registers an object that is notified if the audio format is changing.
Definition: CodecMP3Mini.h:41
AudioInfo audioInfo()
Provides the last available MP3FrameInfo.
Definition: CodecMP3Mini.h:67
~MP3DecoderMini()
Destroy the MP3DecoderMini object.
Definition: CodecMP3Mini.h:33
void provideResult(int samples)
Provides Metadata and PCM data.
Definition: CodecMP3Mini.h:139
void end()
Releases the reserved memory.
Definition: CodecMP3Mini.h:57
void begin()
Starts the processing.
Definition: CodecMP3Mini.h:46
void flush()
Decodes the last outstanding data.
Definition: CodecMP3Mini.h:84
void decode(int write_len)
Process single bytes so that we can decode a full frame when it is available.
Definition: CodecMP3Mini.h:114
Definition: NoArduino.h:58
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AnalogAudio.h:10
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:48
int channels
Number of channels: 2=stereo, 1=mono.
Definition: AudioTypes.h:53
int bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition: AudioTypes.h:55
int sample_rate
Sample Rate: e.g 44100.
Definition: AudioTypes.h:51