15 #include "sam_config.h"
17 #if defined(ESP32) && LEGACY_ESP_I2S
18 #include "driver/i2s.h"
19 #include "freertos/queue.h"
23 typedef void (*sam_callback)(
size_t size, int16_t *values);
26 static void OutputByteCallback(
void *cbdata,
unsigned char b);
27 static uint32_t SAM_sample_rate = 22050;
37 SAM_LOG(
"SAMOutputBase::open");
46 virtual int drain() {
return 0; }
48 virtual int channels() {
return channel_count; }
50 virtual void setChannels(
int channels) { channel_count = channels; }
52 virtual int bitsPerSample() {
return 16; }
54 virtual bool isOpen() {
return is_open; }
56 static uint32_t sampleRate() {
57 return SAM_sample_rate;
60 static void setSampleRate(uint32_t rate) {
61 SAM_sample_rate = rate;
64 virtual const char *name() = 0;
66 virtual bool write(
byte *buff,
int bytes_count) = 0;
70 int channel_count = -1;
71 int bits_per_sample = -1;
82 virtual bool write(
byte *buffer,
int bytes_count) {
83 SAM_LOG(
"SAMOutputCallback::write: %d", bytes_count);
84 int size = bytes_count;
85 callback(size, (int16_t *)buffer);
89 const char *name() {
return "SAMOutputCallback"; }
92 sam_callback callback;
95 #if defined(ESP32) && LEGACY_ESP_I2S
96 #if __has_include("esp_arduino_version.h")
97 #include "esp_arduino_version.h"
100 #if !defined(ESP_IDF_VERSION_MAJOR)
101 #define ESP_IDF_VERSION_MAJOR 2
104 #if ESP_IDF_VERSION_MAJOR < 4
105 #define I2S_COMM_FORMAT_STAND_I2S \
106 (I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB)
119 this->i2s_num = i2s_num;
120 setupDefaultConfig();
125 this->i2s_num = i2s_num;
126 this->i2s_config = cfg;
130 SAMOutputI2S(i2s_port_t i2s_num, i2s_config_t cfg, i2s_pin_config_t pins) {
131 this->i2s_num = i2s_num;
132 this->i2s_config = cfg;
133 this->pin_config = pins;
142 const char *name() {
return "SAMOutputI2S"; }
144 int channels() {
return 2; }
146 virtual void open() {
148 i2s_config.sample_rate = SAMOutputBase::sampleRate();
149 SAM_LOG(
"setting sample rate for I2S: %d", i2s_config.sample_rate);
151 if (i2s_driver_install(i2s_num, &i2s_config, 0, NULL) != ESP_OK) {
152 ESP_LOGE(TAG,
"Failed to install i2s");
154 if (i2s_config.mode & I2S_MODE_DAC_BUILT_IN) {
156 SAM_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");
162 SAM_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");
167 SAMOutputBase::open();
170 virtual int close() {
171 if (i2s_driver_uninstall(i2s_num) != ESP_OK) {
172 ESP_LOGE(TAG,
"Failed to uninstall i2s");
175 return SAMOutputBase::close();
178 virtual int drain() {
179 i2s_zero_dma_buffer(i2s_num);
183 virtual bool write(
byte *buffer,
int bytes_count) {
184 SAM_LOG(
"SAMOutputI2S::write: %d", bytes_count);
185 size_t i2s_bytes_write;
187 if (this->i2s_config.mode & I2S_MODE_DAC_BUILT_IN) {
188 for (
int i = 0; i < bytes_count; i++) {
189 buffer[i] = buffer[i] + 0x8000;
193 if (i2s_write(i2s_num, buffer, bytes_count,
194 &i2s_bytes_write, portMAX_DELAY) != ESP_OK) {
195 ESP_LOGE(TAG,
"i2s_write failed!");
202 void setChannels(
int ch) {
203 if (ch != 2) SAM_LOG(
"Channels is not supported for this output type");
206 void setBitsPerSample(
int bps) {
207 if (bps != 16) SAM_LOG(
"Channels is not supported for this output type");
212 i2s_config_t i2s_config;
213 i2s_pin_config_t pin_config;
214 const char *TAG =
"SAMOutputI2S";
216 void setupDefaultConfig() {
217 const i2s_config_t i2s_config_default = {
218 .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
219 .sample_rate = this->sampleRate(),
220 .bits_per_sample = (i2s_bits_per_sample_t)16,
221 .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
222 .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_I2S,
223 .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
227 .tx_desc_auto_clear =
230 this->i2s_config = i2s_config_default;
233 void setupDefaultPins() {
234 static const i2s_pin_config_t pin_config_default = {
238 .data_in_num = I2S_PIN_NO_CHANGE};
239 this->pin_config = pin_config_default;
251 const char *name() {
return "SAMOutputStream"; }
253 virtual int drain() {
return 0; }
255 virtual bool write(
byte *buffer,
int bytes_count) {
256 SAM_LOG(
"SAMOutputStream::write: %d", bytes_count);
257 size_t len = bytes_count;
259 size_t len_written = out_ptr->write((
const uint8_t *)buffer, len);
260 if (len != len_written) {
261 SAM_LOG(
"Error - Could not write all data: %d of %d", len_written, len);
280 const char *name() {
return "SAMPrintStream"; }
282 virtual bool write(
byte *buffer,
int bytes_count) {
284 int16_t *buffer16 = (int16_t *)buffer;
285 for (
int j = 0; j < bytes_count / 2; j++) {
286 out_ptr->print(buffer16[j]);
287 if (j < channels() - 1) {
290 if (j == channels() - 1) {
Base Output Class with common functionality.
Definition: sam_arduino_out.h:32
Output via Callback method.
Definition: sam_arduino_out.h:78
Output to I2S for ESP32: This class is obsolete and has been deactivated in the sam_config....
Definition: sam_arduino_out.h:116
Output to Arduino Stream.
Definition: sam_arduino_out.h:248
Write readable string to Arduino Stream.
Definition: sam_arduino_out.h:276