1+ #pragma once
2+ #include " AMRNB.h" // https://github.com/pschatzmann/codec-amr
3+ #include " AudioTools/AudioCodecs/AudioCodecsBase.h"
4+
5+ namespace audio_tools {
6+
7+ /* *
8+ * @brief AMR Narrowband Decoder
9+ * See https://github.com/pschatzmann/codec-amr
10+ * @ingroup codecs
11+ * @ingroup decoder
12+ * @author Phil Schatzmann
13+ * @copyright GPLv3
14+ */
15+
16+ class AMRNBDecoder : public AudioDecoder {
17+ public:
18+ AMRNBDecoder (AMRNB::Mode mode) {
19+ setMode (mode);
20+ info.channels = 1 ;
21+ info.sample_rate = 8000 ;
22+ }
23+
24+ ~AMRNBDecoder () override = default ;
25+
26+ void setMode (AMRNB::Mode mode) {
27+ this ->mode = mode;
28+ amr.setMode (mode);
29+ }
30+
31+ bool begin () {
32+ notifyAudioChange (audioInfo ());
33+ buffer.resize (amr.getEncodedFrameSizeBytes ());
34+ return getOutput () != nullptr ;
35+ }
36+
37+ void setAudioInfo (AudioInfo from) {
38+ if (from.bits_per_sample != 16 ) {
39+ LOGE (" Invalid bits per sample: %d" , from.bits_per_sample );
40+ }
41+ if (from.sample_rate != 8000 ) {
42+ LOGE (" Invalid sample rate: %d" , from.sample_rate );
43+ }
44+ if (from.channels != 1 ) {
45+ LOGE (" Invalid channels: %d" , from.channels );
46+ }
47+ }
48+
49+ size_t write (const uint8_t *data, size_t len) override {
50+ for (size_t j = 0 ; j < len; j++) {
51+ buffer.write (data[j]);
52+ if (buffer.isFull ()) {
53+ int result_samples = amr.getFrameSizeSamples ();
54+ int16_t result[result_samples];
55+ int size =
56+ amr.decode (buffer.data (), buffer.size (), result, result_samples);
57+ if (size > 0 ) {
58+ if (getOutput () != nullptr ) {
59+ getOutput ()->write ((uint8_t *)result, size * sizeof (int16_t ));
60+ }
61+ }
62+ buffer.clear ();
63+ }
64+ }
65+ return len;
66+ }
67+
68+ // / Provides the block size (size of encoded frame)
69+ int blockSize () {
70+ amr.setMode (mode);
71+ return amr.getEncodedFrameSizeBytes ();
72+ }
73+
74+ // / Provides the frame size (size of decoded frame)
75+ int frameSize () { return amr.getFrameSizeSamples () * sizeof (int16_t ); }
76+
77+ protected:
78+ AMRNB amr;
79+ AMRNB::Mode mode;
80+ SingleBuffer<uint8_t > buffer{0 };
81+ };
82+
83+ /* *
84+ * @brief AMR NB Encoder
85+ * See https://github.com/pschatzmann/codec-amr
86+ * @ingroup codecs
87+ * @ingroup decoder
88+ * @author Phil Schatzmann
89+ * @copyright GPLv3
90+ */
91+
92+ class AMRNBEncoder : public AudioEncoder {
93+ public:
94+ AMRNBEncoder (AMRNB::Mode mode) {
95+ setMode (mode);
96+ info.channels = 1 ;
97+ info.sample_rate = 8000 ;
98+ }
99+
100+ ~AMRNBEncoder () override = default ;
101+
102+ void setMode (AMRNB::Mode mode) {
103+ this ->mode = mode;
104+ amr.setMode (mode);
105+ }
106+
107+ bool begin () {
108+ buffer.resize (frameSize ());
109+ return getOutput () != nullptr ;
110+ }
111+
112+ void setAudioInfo (AudioInfo from) {
113+ if (from.bits_per_sample != 16 ) {
114+ LOGE (" Invalid bits per sample: %d" , from.bits_per_sample );
115+ }
116+ if (from.sample_rate != 8000 ) {
117+ LOGE (" Invalid sample rate: %d" , from.sample_rate );
118+ }
119+ if (from.channels != 1 ) {
120+ LOGE (" Invalid channels: %d" , from.channels );
121+ }
122+ }
123+
124+ size_t write (const uint8_t *data, size_t len) override {
125+ for (size_t j = 0 ; j < len; j++) {
126+ buffer.write (data[j]);
127+ if (buffer.isFull ()) {
128+ int result_bytes = blockSize ();
129+ uint8_t result[result_bytes];
130+ int size =
131+ amr.encode ((int16_t *)buffer.data (),
132+ buffer.size () / sizeof (int16_t ), result, result_bytes);
133+ if (size > 0 ) {
134+ if (getOutput () != nullptr ) {
135+ getOutput ()->write (result, size);
136+ }
137+ }
138+ buffer.clear ();
139+ }
140+ }
141+ return len;
142+ }
143+
144+ // / Provides the block size (size of encoded frame)
145+ int blockSize () {
146+ amr.setMode (mode);
147+ return amr.getEncodedFrameSizeBytes ();
148+ }
149+
150+ // / Provides the frame size (size of decoded frame)
151+ int frameSize () { return amr.getFrameSizeSamples () * sizeof (int16_t ); }
152+
153+ const char *mime () { return " audio/amr" ; }
154+
155+ void setOutput (Print &out_stream) override { p_print = &out_stream; }
156+
157+ Print *getOutput () { return p_print; }
158+
159+ protected:
160+ AMRNB amr;
161+ AMRNB::Mode mode;
162+ SingleBuffer<uint8_t > buffer{0 };
163+ Print *p_print = nullptr ;
164+ };
165+
166+ } // namespace audio_tools
0 commit comments