Arduino FLITE
All Classes Files Functions Pages
flite_out_arduino.h
Go to the documentation of this file.
1 
11 #include "Arduino.h"
12 #include "flite.h"
13 #include "config.h"
14 
15 #ifdef ESP32
16 #include "driver/i2s.h"
17 #include "freertos/queue.h"
18 #endif
19 
20 // API callback
21 typedef void (*flite_callback)(size_t size, int16_t *values);
22 
23 // define streaming callback used by Arduino
24 extern "C" int arduino_audio_stream_chunk(const cst_wave *w, int start, int size, int last, cst_audio_streaming_info_struct *user);
25 
26 
32  public:
33  virtual ~FliteOutputBase(){
34  }
35 
36  virtual cst_audiodev * open(int sps, int channels, cst_audiofmt fmt) {
37  LOG("FliteOutputBase::open: %d, %d, %d", sps, channels, fmt);
38  is_open = true;
39  audiodev = cst_alloc(cst_audiodev, 1);
40  audiodev->real_sps = audiodev->sps = sps;
41  audiodev->real_channels = audiodev->channels = channels;
42  audiodev->real_fmt = audiodev->fmt = fmt;
43  audiodev->platform_data = (void *) this;
44 
45  return audiodev;
46  };
47 
48  virtual int close() {
49  is_open = false;
50  return 0;
51  }
52 
53  virtual int drain(){
54  return 0;
55  }
56 
57  virtual int flush(){
58  return 0;
59  }
60 
61  virtual int write(void *buff,int sample_count) = 0;
62 
63  int channels() {
64  return audiodev!=nullptr ? audiodev->channels : 0;
65  }
66 
67  int sampleRate() {
68  return audiodev!=nullptr ? audiodev->real_sps : 0;
69  }
70 
71  int bitsPerSample() {
72  int result = 0;
73  if (audiodev!=nullptr){
74  switch(audiodev->real_fmt){
75  case 0: result = 16;
76  break;
77  case 1: result = 8;
78  break;
79  default:
80  Serial.println("Unsupported Audio Format");
81 
82  }
83  }
84  return result;
85  }
86 
87  bool isOpen() {
88  return is_open;
89  }
90 
91  cst_audiodev* info() {
92  return audiodev;
93  }
94 
95  protected:
96  bool is_open = false;
97  cst_audiodev *audiodev = nullptr;
98 };
99 
105  public:
106  FliteOutputCallback(flite_callback cb){
107  callback = cb;
108  }
109 
110  virtual int write(void *buffer,int sample_count) {
111  LOG("FliteOutputCallback::write: %d", sample_count);
112  int size = sample_count;
113  callback(size, (int16_t*) buffer);
114  return 0;
115  }
116 
117  protected:
118  flite_callback callback;
119 };
120 
121 #ifdef ESP32
127  public:
128  FliteOutputI2S( i2s_port_t i2s_num=I2S_NUM_0){
129  this->i2s_num = i2s_num;
130  setupDefaultConfig();
131  setupDefaultPins();
132  }
133 
134  FliteOutputI2S( i2s_port_t i2s_num, i2s_config_t cfg){
135  this->i2s_num = i2s_num;
136  this->i2s_config = cfg;
137  setupDefaultPins();
138  }
139 
140  FliteOutputI2S( i2s_port_t i2s_num, i2s_config_t cfg, i2s_pin_config_t pins ){
141  this->i2s_num = i2s_num;
142  this->i2s_config = cfg;
143  this->pin_config = pins;
144  }
145 
146  virtual cst_audiodev * open(int sample_rate, int channels, cst_audiofmt fmt) {
147  // update sample sample_rate
148  LOG("setting sample rate for I2S: %d", sample_rate);
149  i2s_config.sample_rate = sample_rate;
150  // install driver
151  if (i2s_driver_install(i2s_num, &i2s_config, 0, NULL)!=ESP_OK){
152  ESP_LOGE(TAG,"Failed to install i2s");
153  }
154  if (i2s_config.mode & I2S_MODE_DAC_BUILT_IN) {
155  //for internal DAC, this will enable both of the internal channels
156  LOG("i2s_set_pin: %s","internal DAC");
157  if (i2s_set_pin(i2s_num, NULL)!=ESP_OK){
158  ESP_LOGE(TAG,"Failed to set i2s pins");
159  }
160  } else {
161  // define pins for external DAC
162  LOG("i2s_set_pin: %s","external DAC");
163  if (i2s_set_pin(i2s_num, &pin_config)!=ESP_OK){
164  ESP_LOGE(TAG,"Failed to set i2s pins");
165  }
166  }
167  return FliteOutputBase::open(sample_rate, channels, fmt);
168  };
169 
170  virtual int close() {
171  if (i2s_driver_uninstall(i2s_num) != ESP_OK){
172  ESP_LOGE(TAG,"Failed to uninstall i2s");
173  }
174 
175  return FliteOutputBase::close();
176  }
177 
178  virtual int drain(){
179  i2s_zero_dma_buffer(i2s_num);
180  return 0;
181  }
182 
183  virtual int write(void *buffer,int sample_count) {
184  LOG("FliteOutputI2S::write: %d", sample_count);
185  size_t i2s_bytes_write;
186  if (channels()==2){
187  LOG("i2s_write: %s","simple call");
188  if (i2s_write(i2s_num, buffer, sample_count*sizeof(int16_t), &i2s_bytes_write, portMAX_DELAY)!=ESP_OK){
189  ESP_LOGE(TAG,"i2s_write failed!");
190  }
191  } else {
192  LOG("i2s_write: %s","generate data for 2 channels");
193  // copy from 1 to 2 channels
194  int total = 0;
195  int16_t *ptr = (int16_t *) buffer;
196  for (int j=0;j<sample_count;j++){
197  int16_t data[2] = {ptr[j], ptr[j]};
198  if (i2s_write(i2s_num, data, sizeof(int16_t)*2, &i2s_bytes_write, portMAX_DELAY)==ESP_OK){
199  total += i2s_bytes_write;
200  } else {
201  ESP_LOGE(TAG,"i2s_write failed!");
202  }
203  }
204  LOG("i2s_write - bytes written: %d",total);
205  }
206  return 0;
207  }
208 
209  protected:
210  i2s_port_t i2s_num;
211  i2s_config_t i2s_config;
212  i2s_pin_config_t pin_config;
213  const char *TAG = "FliteOutputI2S";
214 
215  void setupDefaultConfig() {
216  const i2s_config_t i2s_config_default = {
217  .mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_TX),
218  .sample_rate = this->sampleRate(),
219  .bits_per_sample = (i2s_bits_per_sample_t)16,
220  .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
221  .communication_format = (i2s_comm_format_t) (I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
222  .intr_alloc_flags = 0, // default interrupt priority
223  .dma_buf_count = 8,
224  .dma_buf_len = 64,
225  .use_apll = false
226  };
227  this->i2s_config = i2s_config_default;
228  }
229 
230  void setupDefaultPins() {
231  static const i2s_pin_config_t pin_config_default = {
232  .bck_io_num = 26,
233  .ws_io_num = 25,
234  .data_out_num = 22,
235  .data_in_num = I2S_PIN_NO_CHANGE
236  };
237  this->pin_config = pin_config_default;
238  }
239 
240 };
241 #endif
242 
247 class FliteOutput : public FliteOutputBase {
248  public:
249  FliteOutput(Print &out){
250  this->out_ptr = &out;
251  }
252 
253  virtual int drain(){
254  // while(out_ptr->available()>0){
255  // out_ptr->read();
256  // }
257  return 0;
258  }
259 
260  virtual int flush(){
261  //out_ptr->flush();
262  return 0;
263  };
264 
265  virtual int write(void *buffer, int sample_count) {
266  LOG("FliteOutput::write: %d", sample_count);
267  out_ptr->write((const uint8_t *) buffer, sample_count*sizeof(int16_t));
268  return 0;
269  }
270 
271  protected:
272  Print *out_ptr;
273 };
274 
280  public:
281  FlitePrintStream( Print &out) : FliteOutput(out) {
282  }
283 
284  virtual int write(void *buffer,int sample_count) {
285  LOG("FlitePrintStream::write: %d", sample_count);
286  // copy from 1 to 2 channels
287  int16_t *ptr = (int16_t *) buffer;
288  for (int j=0;j<sample_count;j++){
289  out_ptr->println(ptr[j]);
290  }
291  return 0;
292  }
293 
294 };
295 
Base Output Class with common functionality.
Definition: flite_out_arduino.h:31
Output via Callback method.
Definition: flite_out_arduino.h:104
Output using Arduino Print class.
Definition: flite_out_arduino.h:247
Output to I2S for ESP32.
Definition: flite_out_arduino.h:126
Write readable string to Arduino Print class.
Definition: flite_out_arduino.h:279
Configuration settings for Arduino.
int arduino_audio_stream_chunk(const cst_wave *w, int start, int size, int last, cst_audio_streaming_info_struct *user)
flite streaming callback method
Definition: flite_out_arduino.cpp:21