Arduino LibHelix
MP3DecoderHelix.h
1 #pragma once
2 
3 #include "CommonHelix.h"
4 #include "libhelix-mp3/mp3common.h"
5 #include "libhelix-mp3/mp3dec.h"
6 
7 
8 namespace libhelix {
9 
10 typedef void (*MP3InfoCallback)(MP3FrameInfo &info, void *ref);
11 typedef void (*MP3DataCallback)(MP3FrameInfo &info, short *pcm_buffer,
12  size_t len, void *ref);
13 
14 enum MP3Type { MP3Normal = 0, MP3SelfContaind = 1 };
15 
23 class MP3DecoderHelix : public CommonHelix {
24  public:
25  MP3DecoderHelix() {
26  this->mp3_type = MP3Normal;
27  setMinFrameBufferSize(MP3_MIN_FRAME_SIZE);
28  }
29 
30 #if defined(ARDUINO) || defined(HELIX_PRINT)
31  MP3DecoderHelix(Print &output, MP3Type mp3Type = MP3Normal) {
32  this->out = &output;
33  this->mp3_type = mp3Type;
34  setMinFrameBufferSize(MP3_MIN_FRAME_SIZE);
35  }
36 #endif
37  MP3DecoderHelix(MP3DataCallback dataCallback, MP3Type mp3Type = MP3Normal) {
38  this->pcmCallback = dataCallback;
39  this->mp3_type = mp3Type;
40  setMinFrameBufferSize(MP3_MIN_FRAME_SIZE);
41  }
42 
43  MP3DecoderHelix(MP3Type mp3Type) {
44  this->mp3_type = mp3Type;
45  setMinFrameBufferSize(MP3_MIN_FRAME_SIZE);
46  }
47 
48  virtual ~MP3DecoderHelix() { end(); }
49 
50  void setInfoCallback(MP3InfoCallback cb, void *caller = nullptr) {
51  this->infoCallback = cb;
52  if (caller!=nullptr)
53  p_caller_ref = caller;
54  }
55 
56  void setDataCallback(MP3DataCallback cb) { this->pcmCallback = cb; }
57 
59  MP3FrameInfo audioInfo() { return mp3FrameInfo; }
60 
62  void end() override {
63  LOGD_HELIX( "end");
64 
65  if (decoder != nullptr) {
66  flush();
67  MP3FreeDecoder(decoder);
68  decoder = nullptr;
69  }
71  memset(&mp3FrameInfo, 0, sizeof(MP3FrameInfo));
72  }
73 
75  size_t maxFrameSize() override {
76  return max_frame_size == 0 ? MP3_MAX_FRAME_SIZE : max_frame_size;
77  }
78 
80  size_t maxPCMSize() override {
81  return max_pcm_size == 0 ? MP3_MAX_OUTPUT_SIZE : max_pcm_size;
82  }
83 
84  protected:
85  HMP3Decoder decoder = nullptr;
86  MP3DataCallback pcmCallback = nullptr;
87  MP3InfoCallback infoCallback = nullptr;
88  MP3Type mp3_type;
89  MP3FrameInfo mp3FrameInfo;
90  void *p_caller_data = nullptr;
91 
93  virtual bool allocateDecoder() override {
94  if (decoder == nullptr) {
95  decoder = MP3InitDecoder();
96  }
97  memset(&mp3FrameInfo, 0, sizeof(MP3FrameInfo));
98  return decoder != nullptr;
99  }
100 
103  int findSynchWord(int offset = 0) override {
104  if (offset > frame_buffer.available()) return -1;
105  int result = MP3FindSyncWord(frame_buffer.data() + offset,
106  frame_buffer.available() - offset);
107  if (result < 0) return result;
108  return offset == 0 ? result : result - offset;
109  }
110 
112  int decode() override {
113  int processed = 0;
114  int available = frame_buffer.available();
115  int bytes_left = frame_buffer.available();
116  LOGI_HELIX( "decode: %d (left:%d)", available, bytes_left);
117  uint8_t *data = frame_buffer.data();
118  int rc = MP3Decode(decoder, &data, &bytes_left, (short *)pcm_buffer.data(),
119  mp3_type);
120  if (rc == 0) {
121  processed = data - frame_buffer.data();
122  // return the decoded result
123  MP3FrameInfo info;
124  MP3GetLastFrameInfo(decoder, &info);
125  provideResult(info);
126  } else {
127  LOGI_HELIX( "MP3Decode rc: %d", rc);
128  }
129  return processed;
130  }
131 
132  // return the resulting PCM data
133  void provideResult(MP3FrameInfo &info) {
134  // increase PCM size if this fails
135  assert(info.outputSamps * sizeof(short) < maxPCMSize());
136 
137  LOGD_HELIX( "=> provideResult: %d", info.outputSamps);
138  if (info.outputSamps > 0) {
139  // provide result
140  if (pcmCallback != nullptr) {
141  // output via callback
142  pcmCallback(info, (short *)pcm_buffer.data(), info.outputSamps,
143  p_caller_data);
144  } else {
145  // output to stream
146  if (info.samprate != mp3FrameInfo.samprate && infoCallback != nullptr) {
147  infoCallback(info, p_caller_ref);
148  }
149 #if defined(ARDUINO) || defined(HELIX_PRINT)
150  if (out != nullptr){
151  int sampleSize = info.bitsPerSample / 8;
152  int toWrite = info.outputSamps * sampleSize;
153  int written = out->write((uint8_t *)pcm_buffer.data(), toWrite);
154  // assume blocking write
155  assert(written == toWrite);
156  }
157 #endif
158  }
159  mp3FrameInfo = info;
160  }
161  }
162 };
163 
164 } // namespace libhelix
Common Simple Arduino API.
Definition: CommonHelix.h:33
void flush()
Decode all open packets.
Definition: CommonHelix.h:104
virtual void end()
Releases the reserved memory.
Definition: CommonHelix.h:63
virtual void setMinFrameBufferSize(int size)
Defines the minimum frame buffer size which is required before starting the decoding.
Definition: CommonHelix.h:251
A simple Arduino API for the libhelix MP3 decoder. The data is provided with the help of write() call...
Definition: MP3DecoderHelix.h:23
void end() override
Releases the reserved memory.
Definition: MP3DecoderHelix.h:62
int findSynchWord(int offset=0) override
Definition: MP3DecoderHelix.h:103
size_t maxFrameSize() override
determines the frame buffer size that will be allocated
Definition: MP3DecoderHelix.h:75
MP3FrameInfo audioInfo()
Provides the last available MP3FrameInfo.
Definition: MP3DecoderHelix.h:59
int decode() override
decods the data and removes the decoded frame from the buffer
Definition: MP3DecoderHelix.h:112
size_t maxPCMSize() override
Determines the pcm buffer size that will be allocated.
Definition: MP3DecoderHelix.h:80
virtual bool allocateDecoder() override
Allocate the decoder.
Definition: MP3DecoderHelix.h:93