arduino-audio-tools
VS1053Stream.h
1 #pragma once
2 
3 #include "AudioTools/AudioStreams.h"
4 #include "AudioCodecs/CodecCopy.h"
5 #if VS1053_EXT
6 # include "VS1053Driver.h"
7 #else
8 # include "VS1053.h"
9 #endif
10 
11 namespace audio_tools {
12 
13 enum VS1053Mode {ENCODED_MODE, PCM_MODE, MIDI_MODE };
14 
20 class VS1053Config : public AudioInfo {
21  public:
22  VS1053Config(){
23  sample_rate = 44100;
24  channels = 2;
25  bits_per_sample = 16;
26  }
27  RxTxMode mode = TX_MODE;
29  uint8_t cs_pin = VS1053_CS;
30  uint8_t dcs_pin = VS1053_DCS;
31  uint8_t dreq_pin = VS1053_DREQ;
32  int16_t reset_pin = VS1053_RESET; // -1 is undefined
33  int16_t cs_sd_pin = VS1053_CS_SD;
35  bool is_encoded_data = false;
37  bool is_midi = false;
39  bool is_start_spi = true;
40 #if VS1053_EXT
41  VS1053_INPUT input_device = VS1053_MIC;
42 #endif
43 };
44 
52 class VS1053Stream : public AudioStream, public VolumeSupport {
53 
57  class VS1053StreamOut : public AudioStream {
58  public:
59  VS1053StreamOut(VS1053 *vs){
60  p_VS1053 = vs;
61  }
62  size_t write(const uint8_t *buffer, size_t size) override {
63  if (p_VS1053==nullptr) {
64  LOGE("NPE");
65  return 0;
66  }
67  TRACED();
68  p_VS1053->playChunk((uint8_t*)buffer, size);
69  return size;
70  }
71  protected:
72  VS1053 *p_VS1053=nullptr;
73  };
74 
75 public:
76 
77  VS1053Stream() = default;
78 
79  VS1053Config defaultConfig(RxTxMode mode=TX_MODE) {
80  TRACED();
81  VS1053Config c;
82  // recording is rather inefficient so we use a low sample rate as default
83  if (mode==RX_MODE){
84  c.sample_rate = 8000;
85  }
86  c.mode = mode;
87  return c;
88  }
89 
92  cfg = c;
93  }
94 
96  cfg.copyFrom(c);
97  }
98 
100  bool begin() {
101  return begin(cfg);
102  }
103 
105  bool begin(VS1053Config cfg) {
106  TRACEI();
107  bool result = true;
108  // enfornce encoded data for midi mode
109  if (cfg.is_midi){
110  cfg.is_encoded_data = true;
111  }
112  this->cfg = cfg;
113  setAudioInfo(cfg);
114  cfg.logInfo();
115  LOGI("is_encoded_data: %s", cfg.is_encoded_data?"true":"false");
116  LOGI("is_midi: %s", cfg.is_midi?"true":"false");
117  LOGI("cs_pin: %d", cfg.cs_pin);
118  LOGI("dcs_pin: %d", cfg.dcs_pin);
119  LOGI("dreq_pin: %d", cfg.dreq_pin);
120  LOGI("reset_pin: %d", cfg.reset_pin);
121  LOGI("cs_sd_pin: %d", cfg.cs_sd_pin);
122 
123  if (p_vs1053==nullptr){
124  p_vs1053 = new VS1053(cfg.cs_pin,cfg.dcs_pin,cfg.dreq_pin);
125  p_vs1053_out = new VS1053StreamOut(p_vs1053);
126 
127  if (cfg.is_start_spi) {
128  LOGI("SPI.begin()")
129  SPI.begin();
130  } else {
131  LOGI("SPI not started");
132  }
133 
134  if (cfg.reset_pin!=-1){
135  LOGI("Setting reset pin to high: %d", cfg.reset_pin);
136  pinMode(cfg.reset_pin, OUTPUT);
137  digitalWrite(cfg.reset_pin, HIGH);
138  delay(800);
139  }
140  }
141 
142  // Output Stream
143  if (p_out==nullptr){
144  AudioEncoder *p_enc = cfg.is_encoded_data ? &copy:p_encoder;
145  p_out = new EncodedAudioStream(p_vs1053_out, p_enc);
146  }
147 
148  // hack to treat midi as separate mode
149  const int MIDI_MODE = 100;
150  int mode = cfg.mode;
151  if (cfg.is_midi){
152  mode = MIDI_MODE;
153  }
154 
155  switch(mode){
156 
157  case TX_MODE:
158  result = beginTx();
159  break;
160 #if VS1053_EXT
161  case MIDI_MODE:
162  result = beginMidi();
163  break;
164 
165  case RX_MODE:
166  result = beginRx();
167  break;
168 #endif
169  default:
170  LOGD("Mode not supported");
171  result = false;
172  break;
173  }
174  return result;
175  }
176 
178  void end(){
179  TRACEI();
180  if (p_out!=nullptr){
181  delete p_out;
182  p_out = nullptr;
183  }
184  if (p_vs1053!=nullptr){
185  //p_driver->end();
186  p_vs1053->stopSong();
187  p_vs1053->softReset();
188  delete p_vs1053;
189  p_vs1053 = nullptr;
190  }
191  }
192 
194  bool setVolume(float vol) override {
195  // make sure that value is between 0 and 1
196  float volume = vol;
197  if (volume>1.0) volume = 1.0;
198  if (volume<0.0) volume = 0.0;
199  LOGD("setVolume: %f", volume);
200  if (p_vs1053!=nullptr){
201  // Set the player volume.Level from 0-100, higher is louder
202  p_vs1053->setVolume(volume*100.0);
203  }
204  return true;
205  }
206 
208  float volume() override {
209  TRACED();
210  if (p_vs1053==nullptr) return -1.0;
211  return p_vs1053->getVolume()/100.0;;
212  }
213 
215  void setBalance(float bal){
216  float balance = bal;
217  if (balance<-1.0) balance = -1;
218  if (balance>1.0) balance = 1;
219  LOGD("setBalance: %f", balance);
220  if (p_vs1053!=nullptr){
221  p_vs1053->setBalance(balance*100.0);
222  }
223  }
225  float balance(){
226  TRACED();
227  if (p_vs1053==nullptr) return -1.0;
228  return static_cast<float>(p_vs1053->getBalance())/100.0;
229  }
230 
232  virtual size_t write(const uint8_t *buffer, size_t size) override {
233  TRACED();
234  if (size==0) return 0;
235  if (p_out==nullptr) {
236  LOGE("vs1053 is closed");
237  return 0;
238  }
239  return p_out->write(buffer, size);
240  }
241 
243  VS1053 &getVS1053() {
244  TRACED();
245  return *p_vs1053;
246  }
247 
250  TRACEI();
251  if (p_out!=nullptr){
252  logError("setEncoder");
253  return false;
254  }
255  if (p_encoder!=nullptr){
256  delete p_encoder;
257  p_encoder = enc;
258  }
259  return true;
260  }
261 
262 #if VS1053_EXT
263  int available() override {
264  int result = getVS1053().available();
265  LOGI("available: %d", result);
266  return result;
267  }
268  size_t readBytes(uint8_t* data, size_t len) override {
269  TRACED();
270  return getVS1053().readBytes(data, len);
271  }
272 
274  float treble() {
275  TRACED();
276  return static_cast<float>(getVS1053().treble())/100.0;
277  }
278 
280  void setTreble(float val){
281  float value = val;
282  if (value<0.0) value = 0.0;
283  if (value>1.0) value = 1.0;
284  LOGD("setTreble: %f", value);
285  getVS1053().setTreble(value*100);
286  }
287 
289  float bass() {
290  TRACED();
291  return static_cast<float>(getVS1053().bass())/100.0;
292  }
293 
295  void setBass(float val){
296  float value = val;
297  if (value<0.0) value = 0.0;
298  if (value>1.0) value = 1.0;
299  LOGD("setBass: %f", value);
300  getVS1053().setBass(value*100.0);
301  }
302 
304  void setTrebleFrequencyLimit(uint16_t value){
305  LOGD("setTrebleFrequencyLimit: %u", value);
306  getVS1053().setTrebleFrequencyLimit(value);
307  }
309  void setBassFrequencyLimit(uint16_t value){
310  LOGD("setBassFrequencyLimit: %u", value);
311  getVS1053().setBassFrequencyLimit(value);
312  }
313 
315  void sendMidiMessage(uint8_t cmd, uint8_t data1, uint8_t data2) {
316  TRACEI();
317 #if USE_MIDI
318  if (!cfg.is_midi){
319  LOGE("start with is_midi=true");
320  return;
321  }
322  if (p_vs1053==nullptr) {
323  logError(__FUNCTION__);
324  return;
325  }
326  p_vs1053->sendMidiMessage(cmd, data1, data2);
327 #endif
328  }
329 
330 #endif
331 
332 protected:
333  VS1053Config cfg;
334  VS1053 *p_vs1053 = nullptr;
335  VS1053StreamOut *p_vs1053_out = nullptr;
336  EncodedAudioStream *p_out = nullptr;
337  AudioEncoder *p_encoder = new WAVEncoder(); // by default we send wav data
338  CopyEncoder copy; // used when is_encoded_data == true
339 
340  bool beginTx() {
341  TRACEI();
342  p_out->begin(cfg);
343  bool result = p_vs1053->begin();
344  p_vs1053->startSong();
345  p_vs1053->switchToMp3Mode(); // optional, some boards require this
346  if (p_vs1053->getChipVersion() == 4) { // Only perform an update if we really are using a VS1053, not. eg. VS1003
347  p_vs1053->loadDefaultVs1053Patches();
348  }
349  delay(500);
350  setVolume(VS1053_DEFAULT_VOLUME);
351  return result;
352  }
353 
354 #if VS1053_EXT
355 
356  bool beginRx() {
357  TRACEI();
358  VS1053Recording rec;
359  rec.setSampleRate(cfg.sample_rate);
360  rec.setChannels(cfg.channels);
361  rec.setInput(cfg.input_device);
362  return p_vs1053->beginInput(rec);
363  }
364 
365  bool beginMidi(){
366 #if USE_MIDI
367  TRACEI();
368  p_out->begin(cfg);
369  bool result = p_vs1053->beginMidi();
370  delay(500);
371  setVolume(VS1053_DEFAULT_VOLUME);
372  return result;
373 #else
374  return false;
375 #endif
376  }
377 
378 #endif
379  void logError(const char* str){
380  LOGE("Call %s after begin()", str);
381  }
382 
383 
384 };
385 
386 }
Encoding of PCM data.
Definition: AudioEncoded.h:88
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition: AudioStreams.h:24
A more natural Stream class to process encoded data (aac, wav, mp3...) which also supports the decodi...
Definition: AudioEncoded.h:488
Configuration for VS1053Stream.
Definition: VS1053Stream.h:20
bool is_encoded_data
The data is encoded as WAV, MPEG etc. By default this is false and supports PCM data.
Definition: VS1053Stream.h:35
bool is_start_spi
SPI.begin is called by the driver (default setting)
Definition: VS1053Stream.h:39
bool is_midi
set true for streaming midi
Definition: VS1053Stream.h:37
uint8_t cs_pin
set to false if it is a pcm stream
Definition: VS1053Stream.h:29
VS1053 Output Interface which processes PCM data by default. If you want to write encoded data set is...
Definition: VS1053Stream.h:52
void setBalance(float bal)
Adjusting the left and right volume balance, higher to enhance the right side, lower to enhance the l...
Definition: VS1053Stream.h:215
void setAudioInfo(VS1053Config c)
defines the default configuration that is used with the next begin()
Definition: VS1053Stream.h:91
bool setEncoder(AudioEncoder *enc)
Defines an alternative encoder that will be used (e.g. MP3Encoder). It must be allocated on the heap!
Definition: VS1053Stream.h:249
float balance()
Get the currenet balance setting (-1.0..1.0)
Definition: VS1053Stream.h:225
void setAudioInfo(AudioInfo c)
Defines the input AudioInfo.
Definition: VS1053Stream.h:95
bool begin()
Starts with the default config or restarts.
Definition: VS1053Stream.h:100
float volume() override
provides the volume
Definition: VS1053Stream.h:208
void end()
Stops the processing and releases the memory.
Definition: VS1053Stream.h:178
VS1053 & getVS1053()
returns the VS1053 object
Definition: VS1053Stream.h:243
bool setVolume(float vol) override
value from 0 to 1.0
Definition: VS1053Stream.h:194
virtual size_t write(const uint8_t *buffer, size_t size) override
Write audio data.
Definition: VS1053Stream.h:232
bool begin(VS1053Config cfg)
Starts with the indicated configuration.
Definition: VS1053Stream.h:105
Supports the setting and getting of the volume.
Definition: AudioTypes.h:210
RxTxMode
The Microcontroller is the Audio Source (TX_MODE) or Audio Sink (RX_MODE). RXTX_MODE is Source and Si...
Definition: AudioTypes.h:26
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AnalogAudio.h:10
void delay(uint32_t ms)
Waits for the indicated milliseconds.
Definition: Millis.h:11
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:50
void copyFrom(AudioInfo info)
Same as set.
Definition: AudioTypes.h:105
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition: AudioTypes.h:53
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition: AudioTypes.h:55
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition: AudioTypes.h:57