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 }
70 CommonHelix::end();
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
libhelix::CommonHelix
Common Simple Arduino API.
Definition: CommonHelix.h:33
libhelix::CommonHelix::flush
void flush()
Decode all open packets.
Definition: CommonHelix.h:104
libhelix::CommonHelix::end
virtual void end()
Releases the reserved memory.
Definition: CommonHelix.h:63
libhelix::CommonHelix::setMinFrameBufferSize
virtual void setMinFrameBufferSize(int size)
Defines the minimum frame buffer size which is required before starting the decoding.
Definition: CommonHelix.h:251
libhelix::MP3DecoderHelix
A simple Arduino API for the libhelix MP3 decoder. The data is provided with the help of write() call...
Definition: MP3DecoderHelix.h:23
libhelix::MP3DecoderHelix::end
void end() override
Releases the reserved memory.
Definition: MP3DecoderHelix.h:62
libhelix::MP3DecoderHelix::findSynchWord
int findSynchWord(int offset=0) override
Definition: MP3DecoderHelix.h:103
libhelix::MP3DecoderHelix::maxFrameSize
size_t maxFrameSize() override
determines the frame buffer size that will be allocated
Definition: MP3DecoderHelix.h:75
libhelix::MP3DecoderHelix::audioInfo
MP3FrameInfo audioInfo()
Provides the last available MP3FrameInfo.
Definition: MP3DecoderHelix.h:59
libhelix::MP3DecoderHelix::decode
int decode() override
decods the data and removes the decoded frame from the buffer
Definition: MP3DecoderHelix.h:112
libhelix::MP3DecoderHelix::maxPCMSize
size_t maxPCMSize() override
Determines the pcm buffer size that will be allocated.
Definition: MP3DecoderHelix.h:80
libhelix::MP3DecoderHelix::allocateDecoder
virtual bool allocateDecoder() override
Allocate the decoder.
Definition: MP3DecoderHelix.h:93