arduino-audio-tools
Loading...
Searching...
No Matches
VS1053Stream.h
1#pragma once
2
3#include "AudioTools/AudioCodecs/AudioEncoded.h"
4#include "AudioTools/AudioCodecs/CodecCopy.h"
5#include "AudioTools/AudioCodecs/CodecWAV.h"
6#include "AudioTools/CoreAudio/AudioStreams.h"
7
8#if VS1053_EXT
9#include "VS1053Driver.h"
10#else
11#include "VS1053.h"
12#endif
13
14namespace audio_tools {
15
16enum VS1053Mode { ENCODED_MODE, PCM_MODE, MIDI_MODE };
17
23class VS1053Config : public AudioInfo {
24 public:
25 VS1053Config() {
26 sample_rate = 44100;
27 channels = 2;
28 bits_per_sample = 16;
29 }
31 RxTxMode mode = TX_MODE;
32
35 uint8_t cs_pin = VS1053_CS;
36
38 uint8_t dcs_pin = VS1053_DCS;
39
42 uint8_t dreq_pin = VS1053_DREQ;
43
46 int16_t reset_pin = VS1053_RESET; // -1 is undefined
47
49 int16_t cs_sd_pin = VS1053_CS_SD;
50
53 bool is_encoded_data = false;
54
56 bool is_midi = false;
57
60 bool is_start_spi = true;
61#if VS1053_EXT
62 VS1053_INPUT input_device = VS1053_MIC;
63#endif
64};
65
78class VS1053Stream : public AudioStream, public VolumeSupport {
82 class VS1053StreamOut : public AudioStream {
83 public:
84 VS1053StreamOut(VS1053* vs) { p_VS1053 = vs; }
85 size_t write(const uint8_t* data, size_t len) override {
86 if (p_VS1053 == nullptr) {
87 LOGE("NPE");
88 return 0;
89 }
90 TRACED();
91 p_VS1053->playChunk((uint8_t*)data, len);
92 return len;
93 }
94
95 protected:
96 VS1053* p_VS1053 = nullptr;
97 };
98
99 public:
100 VS1053Stream() = default;
101
102 ~VS1053Stream() { end(); }
103
106 TRACED();
107 VS1053Config c;
108 // recording is rather inefficient so we use a low sample rate as default
109 if (mode == RX_MODE) {
110 c.sample_rate = 8000;
111 }
112 c.mode = mode;
113 return c;
114 }
115
118 cfg = c;
120 }
121
124 cfg.copyFrom(c);
126 }
127
129 bool begin() { return begin(cfg); }
130
132 bool begin(VS1053Config cfg) {
133 TRACEI();
134 bool result = true;
135 // enfornce encoded data for midi mode
136 if (cfg.is_midi) {
137 cfg.is_encoded_data = true;
138 }
139 this->cfg = cfg;
140 setAudioInfo(cfg);
141 cfg.logInfo();
142 LOGI("is_encoded_data: %s", cfg.is_encoded_data ? "true" : "false");
143 LOGI("is_midi: %s", cfg.is_midi ? "true" : "false");
144 LOGI("cs_pin: %d", cfg.cs_pin);
145 LOGI("dcs_pin: %d", cfg.dcs_pin);
146 LOGI("dreq_pin: %d", cfg.dreq_pin);
147 LOGI("reset_pin: %d", cfg.reset_pin);
148 LOGI("cs_sd_pin: %d", cfg.cs_sd_pin);
149
150 if (p_vs1053 == nullptr) {
151 p_vs1053 = new VS1053(cfg.cs_pin, cfg.dcs_pin, cfg.dreq_pin);
152 p_vs1053_out = new VS1053StreamOut(p_vs1053);
153
154 if (cfg.is_start_spi) {
155 LOGI("SPI.begin()")
156 SPI.begin();
157 } else {
158 LOGI("SPI not started");
159 }
160
161 if (cfg.reset_pin != -1) {
162 LOGI("Setting reset pin to high: %d", cfg.reset_pin);
163 pinMode(cfg.reset_pin, OUTPUT);
164 digitalWrite(cfg.reset_pin, HIGH);
165 delay(800);
166 }
167 }
168
169 // Output Stream
170 if (p_out == nullptr) {
171 AudioEncoder* p_enc = cfg.is_encoded_data ? &copy : p_encoder;
172 p_out = new EncodedAudioStream(p_vs1053_out, p_enc);
173 }
174
175 // hack to treat midi as separate mode
176 const int MIDI_MODE = 100;
177 int mode = cfg.mode;
178 if (cfg.is_midi) {
179 mode = MIDI_MODE;
180 }
181
182 switch (mode) {
183 case TX_MODE:
184 result = beginTx();
185 break;
186#if VS1053_EXT
187 case MIDI_MODE:
188 result = beginMidi();
189 break;
190
191 case RX_MODE:
192 result = beginRx();
193 break;
194#endif
195 default:
196 LOGD("Mode not supported");
197 result = false;
198 break;
199 }
200
201 // log error on failure
202 if (!result) LOGE("begin failed");
203 return result;
204 }
205
207 void end() {
208 TRACEI();
209 if (p_out != nullptr) {
210 delete p_out;
211 p_out = nullptr;
212 }
213 // free the wrapper before freeing the underlying HW object to avoid
214 // leaving a wrapper with a dangling pointer
215 if (p_vs1053_out != nullptr) {
216 delete p_vs1053_out;
217 p_vs1053_out = nullptr;
218 }
219 if (p_vs1053 != nullptr) {
220 // p_driver->end();
221 p_vs1053->stopSong();
222 p_vs1053->softReset();
223 delete p_vs1053;
224 p_vs1053 = nullptr;
225 }
226 }
227
229 bool setVolume(float vol) override {
230 // make sure that value is between 0 and 1
231 float volume = vol;
232 if (volume > 1.0f) volume = 1.0f;
233 if (volume < 0.0f) volume = 0.0f;
234 LOGD("setVolume: %f", volume);
235 if (p_vs1053 != nullptr) {
236 // Set the player volume.Level from 0-100, higher is louder
237 p_vs1053->setVolume(volume * 100.0f);
238 }
239 return true;
240 }
241
243 float volume() override {
244 TRACED();
245 if (p_vs1053 == nullptr) return -1.0f;
246 return p_vs1053->getVolume() / 100.0f;
247 }
248
251 void setBalance(float bal) {
252 float balance = bal;
253 if (balance < -1.0f) balance = -1.0f;
254 if (balance > 1.0f) balance = 1.0f;
255 LOGD("setBalance: %f", balance);
256 if (p_vs1053 != nullptr) {
257 p_vs1053->setBalance(balance * 100.0f);
258 }
259 }
261 float balance() {
262 TRACED();
263 if (p_vs1053 == nullptr) return -1.0f;
264 return static_cast<float>(p_vs1053->getBalance()) / 100.0f;
265 }
266
268 virtual size_t write(const uint8_t* data, size_t len) override {
269 TRACED();
270 if (len == 0) return 0;
271 if (p_out == nullptr) {
272 LOGE("vs1053 is closed");
273 return 0;
274 }
275 return p_out->write(data, len);
276 }
277
279 VS1053& getVS1053() {
280 TRACED();
281 return *p_vs1053;
282 }
283
287 TRACEI();
288 if (p_out != nullptr) {
289 logError("setEncoder");
290 return false;
291 }
292 // If caller provides nullptr, fall back to the internal wav encoder.
293 // Note: ownership remains external (VS1053Stream does not delete the
294 // encoder pointer).
295 if (enc == nullptr) {
296 p_encoder = &wav;
297 } else {
298 p_encoder = enc;
299 }
300 return true;
301 }
302
303#if VS1053_EXT
304 int available() override {
305 int result = getVS1053().available();
306 LOGI("available: %d", result);
307 return result;
308 }
309 size_t readBytes(uint8_t* data, size_t len) override {
310 TRACED();
311 return getVS1053().readBytes(data, len);
312 }
313
315 float treble() {
316 TRACED();
317 return static_cast<float>(getVS1053().treble()) / 100.0;
318 }
319
321 void setTreble(float val) {
322 float value = val;
323 if (value < 0.0f) value = 0.0f;
324 if (value > 1.0f) value = 1.0f;
325 LOGD("setTreble: %f", value);
326 getVS1053().setTreble(value * 100.0f);
327 }
328
330 float bass() {
331 TRACED();
332 return static_cast<float>(getVS1053().bass()) / 100.0;
333 }
334
336 void setBass(float val) {
337 float value = val;
338 if (value < 0.0f) value = 0.0f;
339 if (value > 1.0f) value = 1.0f;
340 LOGD("setBass: %f", value);
341 getVS1053().setBass(value * 100.0f);
342 }
343
345 void setTrebleFrequencyLimit(uint16_t value) {
346 LOGD("setTrebleFrequencyLimit: %u", value);
347 getVS1053().setTrebleFrequencyLimit(value);
348 }
350 void setBassFrequencyLimit(uint16_t value) {
351 LOGD("setBassFrequencyLimit: %u", value);
352 getVS1053().setBassFrequencyLimit(value);
353 }
354
356 void sendMidiMessage(uint8_t cmd, uint8_t data1, uint8_t data2) {
357 TRACEI();
358#if USE_MIDI
359 if (!cfg.is_midi) {
360 LOGE("start with is_midi=true");
361 return;
362 }
363 if (p_vs1053 == nullptr) {
364 logError(__FUNCTION__);
365 return;
366 }
367 p_vs1053->sendMidiMessage(cmd, data1, data2);
368#endif
369 }
370
371#endif
372
373 protected:
374 VS1053Config cfg;
375 VS1053* p_vs1053 = nullptr;
376 VS1053StreamOut* p_vs1053_out = nullptr;
377 EncodedAudioStream* p_out = nullptr;
378 WAVEncoder wav;
379 AudioEncoder* p_encoder = &wav; // by default we send wav data
380 CopyEncoder copy; // used when is_encoded_data == true
381
382 bool beginTx() {
383 TRACEI();
384 p_out->begin(cfg);
385 bool result = p_vs1053->begin();
386 p_vs1053->startSong();
387 p_vs1053->switchToMp3Mode(); // optional, some boards require this
388 if (p_vs1053->getChipVersion() ==
389 4) { // Only perform an update if we really are using a VS1053, not.
390 // eg. VS1003
391 p_vs1053->loadDefaultVs1053Patches();
392 }
393 delay(500);
394 setVolume(VS1053_DEFAULT_VOLUME);
395 return result;
396 }
397
398#if VS1053_EXT
399
400 bool beginRx() {
401 TRACEI();
402 VS1053Recording rec;
403 rec.setSampleRate(cfg.sample_rate);
404 rec.setChannels(cfg.channels);
405 rec.setInput(cfg.input_device);
406 return p_vs1053->beginInput(rec);
407 }
408
409 bool beginMidi() {
410#if USE_MIDI
411 TRACEI();
412 p_out->begin(cfg);
413 bool result = p_vs1053->beginMidi();
414 delay(500);
415 setVolume(VS1053_DEFAULT_VOLUME);
416 return result;
417#else
418 return false;
419#endif
420 }
421
422#endif
423 void logError(const char* str) { LOGE("Call %s after begin()", str); }
424};
425
426} // namespace audio_tools
Encoding of PCM data.
Definition AudioCodecsBase.h:97
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:122
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition BaseStream.h:130
A more natural Stream class to process encoded data (aac, wav, mp3...) which also supports the decodi...
Definition AudioEncoded.h:271
Configuration for VS1053Stream.
Definition VS1053Stream.h:23
uint8_t dreq_pin
Definition VS1053Stream.h:42
int16_t cs_sd_pin
Optional chip-select pin for an attached SD card (if present).
Definition VS1053Stream.h:49
bool is_encoded_data
Definition VS1053Stream.h:53
bool is_start_spi
Definition VS1053Stream.h:60
uint8_t dcs_pin
Data/command select (DCS) pin used by some VS1053 modules.
Definition VS1053Stream.h:38
RxTxMode mode
Operation mode (transmit/receive). Default: TX_MODE (playback).
Definition VS1053Stream.h:31
int16_t reset_pin
Definition VS1053Stream.h:46
bool is_midi
When true enable MIDI streaming mode (this also forces encoded mode).
Definition VS1053Stream.h:56
uint8_t cs_pin
Definition VS1053Stream.h:35
Output Interface which processes PCM data by default using a VS1053 audio module. If you want to writ...
Definition VS1053Stream.h:78
void setBalance(float bal)
Definition VS1053Stream.h:251
void setAudioInfo(VS1053Config c)
defines the default configuration that is used with the next begin()
Definition VS1053Stream.h:117
VS1053 & getVS1053()
returns the VS1053 object
Definition VS1053Stream.h:279
virtual size_t write(const uint8_t *data, size_t len) override
Write audio data.
Definition VS1053Stream.h:268
VS1053Config defaultConfig(RxTxMode mode=TX_MODE)
Provides the default configuration for the indicated mod.
Definition VS1053Stream.h:105
bool setEncoder(AudioEncoder *enc)
Definition VS1053Stream.h:286
float balance()
Get the currenet balance setting (-1.0..1.0)
Definition VS1053Stream.h:261
void setAudioInfo(AudioInfo c)
Updates the AudioInfo (sample rate, bits, channels)
Definition VS1053Stream.h:123
bool begin()
Starts with the default config or restarts.
Definition VS1053Stream.h:129
float volume() override
provides the volume
Definition VS1053Stream.h:243
void end()
Stops the processing and releases the memory.
Definition VS1053Stream.h:207
bool setVolume(float vol) override
value from 0 to 1.0
Definition VS1053Stream.h:229
bool begin(VS1053Config cfg)
Starts with the indicated configuration.
Definition VS1053Stream.h:132
Supports the setting and getting of the volume.
Definition AudioTypes.h:191
RxTxMode
The Microcontroller is the Audio Source (TX_MODE) or Audio Sink (RX_MODE). RXTX_MODE is Source and Si...
Definition AudioTypes.h:30
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:55
void copyFrom(AudioInfo info)
Same as set.
Definition AudioTypes.h:105
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:57
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:59
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:61