added audioio to espressif
This commit is contained in:
parent
65556b42a5
commit
6f4f57e7e7
9 changed files with 779 additions and 4 deletions
|
|
@ -739,6 +739,10 @@ msgstr ""
|
|||
msgid "Can only alarm on two low pins from deep sleep."
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/audioio/AudioOut.c
|
||||
msgid "Can't construct AudioOut because continuous channel already open"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/_bleio/Characteristic.c
|
||||
#: ports/nordic/common-hal/_bleio/Characteristic.c
|
||||
msgid "Can't set CCCD on local Characteristic"
|
||||
|
|
@ -1001,15 +1005,43 @@ msgstr ""
|
|||
msgid "Failed to connect: timeout"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/audioio/AudioOut.c
|
||||
msgid "Failed to create continuous channels: invalid arg"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/audioio/AudioOut.c
|
||||
msgid "Failed to create continuous channels: invalid state"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/audioio/AudioOut.c
|
||||
msgid "Failed to create continuous channels: no mem"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/audioio/AudioOut.c
|
||||
msgid "Failed to create continuous channels: not found"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/audioio/AudioOut.c
|
||||
msgid "Failed to enable continuous"
|
||||
msgstr ""
|
||||
|
||||
#: shared-module/audiomp3/MP3Decoder.c
|
||||
msgid "Failed to parse MP3 file"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/audioio/AudioOut.c
|
||||
msgid "Failed to register continuous events callback"
|
||||
msgstr ""
|
||||
|
||||
#: ports/nordic/sd_mutex.c
|
||||
#, c-format
|
||||
msgid "Failed to release mutex, err 0x%04x"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/audioio/AudioOut.c
|
||||
msgid "Failed to start async audio"
|
||||
msgstr ""
|
||||
|
||||
#: supervisor/shared/safe_mode.c
|
||||
msgid "Failed to write internal flash."
|
||||
msgstr ""
|
||||
|
|
@ -2400,6 +2432,10 @@ msgstr ""
|
|||
msgid "addresses is empty"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/audioio/AudioOut.c
|
||||
msgid "already playing"
|
||||
msgstr ""
|
||||
|
||||
#: py/compile.c
|
||||
msgid "annotation must be an identifier"
|
||||
msgstr ""
|
||||
|
|
@ -2478,6 +2514,10 @@ msgstr ""
|
|||
msgid "attributes not supported"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/audioio/AudioOut.c
|
||||
msgid "audio format not supported"
|
||||
msgstr ""
|
||||
|
||||
#: extmod/ulab/code/ulab_tools.c
|
||||
msgid "axis is out of bounds"
|
||||
msgstr ""
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = {
|
|||
|
||||
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO25) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO25) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_GPIO25) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO34) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D34), MP_ROM_PTR(&pin_GPIO34) },
|
||||
|
|
|
|||
561
ports/espressif/common-hal/audioio/AudioOut.c
Normal file
561
ports/espressif/common-hal/audioio/AudioOut.c
Normal file
|
|
@ -0,0 +1,561 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "common-hal/audioio/AudioOut.h"
|
||||
#include "shared-bindings/audioio/AudioOut.h"
|
||||
#include "shared-bindings/microcontroller/__init__.h"
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
#include "shared-module/audiocore/__init__.h"
|
||||
|
||||
|
||||
#ifdef SOC_DAC_SUPPORTED
|
||||
|
||||
#include "driver/dac_continuous.h"
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32)
|
||||
#define pin_CHANNEL_0 pin_GPIO25
|
||||
#define pin_CHANNEL_1 pin_GPIO26
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#define pin_CHANNEL_0 pin_GPIO17
|
||||
#define pin_CHANNEL_1 pin_GPIO18
|
||||
#endif
|
||||
|
||||
static dac_continuous_handle_t _active_handle;
|
||||
|
||||
#define INCREMENT_BUF_IDX(idx) ((idx + 1) % (NUM_DMA_BUFFERS + 1))
|
||||
|
||||
|
||||
static void audioout_convert_noop(
|
||||
void *in_buffer,
|
||||
size_t in_buffer_size,
|
||||
uint8_t *out_buffer,
|
||||
uint32_t *out_buffer_size) {
|
||||
|
||||
assert(in_buffer_size <= *out_buffer_size);
|
||||
memcpy(out_buffer, in_buffer, in_buffer_size);
|
||||
*out_buffer_size = in_buffer_size;
|
||||
}
|
||||
|
||||
static void audioout_convert_u8s_u8m(
|
||||
void *in_buffer,
|
||||
size_t in_buffer_size,
|
||||
uint8_t *out_buffer,
|
||||
uint32_t *out_buffer_size) {
|
||||
|
||||
assert(in_buffer_size / 2 <= *out_buffer_size);
|
||||
audiosample_convert_u8s_u8m(out_buffer, (uint8_t *)in_buffer, in_buffer_size / 2);
|
||||
*out_buffer_size = in_buffer_size / 2;
|
||||
}
|
||||
|
||||
static void audioout_convert_u8m_u8s(
|
||||
void *in_buffer,
|
||||
size_t in_buffer_size,
|
||||
uint8_t *out_buffer,
|
||||
uint32_t *out_buffer_size) {
|
||||
|
||||
assert(in_buffer_size * 2 <= *out_buffer_size);
|
||||
audiosample_convert_u8m_u8s(out_buffer, (uint8_t *)in_buffer, in_buffer_size);
|
||||
*out_buffer_size = in_buffer_size * 2;
|
||||
}
|
||||
|
||||
static void audioout_convert_s8m_u8m(
|
||||
void *in_buffer,
|
||||
size_t in_buffer_size,
|
||||
uint8_t *out_buffer,
|
||||
uint32_t *out_buffer_size) {
|
||||
|
||||
assert(in_buffer_size <= *out_buffer_size);
|
||||
audiosample_convert_s8m_u8m(out_buffer, (int8_t *)in_buffer, in_buffer_size);
|
||||
*out_buffer_size = in_buffer_size;
|
||||
}
|
||||
|
||||
static void audioout_convert_s8s_u8m(
|
||||
void *in_buffer,
|
||||
size_t in_buffer_size,
|
||||
uint8_t *out_buffer,
|
||||
uint32_t *out_buffer_size) {
|
||||
|
||||
assert(in_buffer_size / 2 <= *out_buffer_size);
|
||||
audiosample_convert_s8s_u8m(out_buffer, (int8_t *)in_buffer, in_buffer_size / 2);
|
||||
*out_buffer_size = in_buffer_size / 2;
|
||||
}
|
||||
|
||||
static void audioout_convert_s8m_u8s(
|
||||
void *in_buffer,
|
||||
size_t in_buffer_size,
|
||||
uint8_t *out_buffer,
|
||||
uint32_t *out_buffer_size) {
|
||||
|
||||
assert(in_buffer_size * 2 <= *out_buffer_size);
|
||||
audiosample_convert_s8m_u8s(out_buffer, (int8_t *)in_buffer, in_buffer_size);
|
||||
*out_buffer_size = in_buffer_size * 2;
|
||||
}
|
||||
|
||||
static void audioout_convert_s8s_u8s(
|
||||
void *in_buffer,
|
||||
size_t in_buffer_size,
|
||||
uint8_t *out_buffer,
|
||||
uint32_t *out_buffer_size) {
|
||||
|
||||
assert(in_buffer_size <= *out_buffer_size);
|
||||
audiosample_convert_s8s_u8s(out_buffer, (int8_t *)in_buffer, in_buffer_size);
|
||||
*out_buffer_size = in_buffer_size;
|
||||
}
|
||||
|
||||
static void audioout_convert_u16m_u8m(
|
||||
void *in_buffer,
|
||||
size_t in_buffer_size,
|
||||
uint8_t *out_buffer,
|
||||
uint32_t *out_buffer_size) {
|
||||
|
||||
assert(in_buffer_size / 2 <= *out_buffer_size);
|
||||
audiosample_convert_u16m_u8m(out_buffer, (uint16_t *)in_buffer, in_buffer_size / 2);
|
||||
*out_buffer_size = in_buffer_size / 2;
|
||||
}
|
||||
|
||||
static void audioout_convert_u16m_u8s(
|
||||
void *in_buffer,
|
||||
size_t in_buffer_size,
|
||||
uint8_t *out_buffer,
|
||||
uint32_t *out_buffer_size) {
|
||||
|
||||
assert(in_buffer_size <= *out_buffer_size);
|
||||
audiosample_convert_u16m_u8s(out_buffer, (uint16_t *)in_buffer, in_buffer_size / 2);
|
||||
*out_buffer_size = in_buffer_size;
|
||||
}
|
||||
|
||||
static void audioout_convert_u16s_u8m(
|
||||
void *in_buffer,
|
||||
size_t in_buffer_size,
|
||||
uint8_t *out_buffer,
|
||||
uint32_t *out_buffer_size) {
|
||||
|
||||
assert(in_buffer_size / 4 <= *out_buffer_size);
|
||||
audiosample_convert_u16s_u8m(out_buffer, (uint16_t *)in_buffer, in_buffer_size / 4);
|
||||
*out_buffer_size = in_buffer_size / 4;
|
||||
}
|
||||
|
||||
static void audioout_convert_u16s_u8s(
|
||||
void *in_buffer,
|
||||
size_t in_buffer_size,
|
||||
uint8_t *out_buffer,
|
||||
uint32_t *out_buffer_size) {
|
||||
|
||||
assert(in_buffer_size / 2 <= *out_buffer_size);
|
||||
audiosample_convert_u16s_u8s(out_buffer, (uint16_t *)in_buffer, in_buffer_size / 4);
|
||||
*out_buffer_size = in_buffer_size / 2;
|
||||
}
|
||||
|
||||
static void audioout_convert_s16m_u8m(
|
||||
void *in_buffer,
|
||||
size_t in_buffer_size,
|
||||
uint8_t *out_buffer,
|
||||
uint32_t *out_buffer_size) {
|
||||
|
||||
assert(in_buffer_size / 2 <= *out_buffer_size);
|
||||
audiosample_convert_s16m_u8m(out_buffer, (int16_t *)in_buffer, in_buffer_size / 2);
|
||||
*out_buffer_size = in_buffer_size / 2;
|
||||
}
|
||||
|
||||
static void audioout_convert_s16m_u8s(
|
||||
void *in_buffer,
|
||||
size_t in_buffer_size,
|
||||
uint8_t *out_buffer,
|
||||
uint32_t *out_buffer_size) {
|
||||
|
||||
assert(in_buffer_size <= *out_buffer_size);
|
||||
audiosample_convert_s16m_u8s(out_buffer, (int16_t *)in_buffer, in_buffer_size / 2);
|
||||
*out_buffer_size = in_buffer_size;
|
||||
}
|
||||
|
||||
static void audioout_convert_s16s_u8m(
|
||||
void *in_buffer,
|
||||
size_t in_buffer_size,
|
||||
uint8_t *out_buffer,
|
||||
uint32_t *out_buffer_size) {
|
||||
|
||||
assert(in_buffer_size / 4 <= *out_buffer_size);
|
||||
audiosample_convert_s16s_u8m(out_buffer, (int16_t *)in_buffer, in_buffer_size / 4);
|
||||
*out_buffer_size = in_buffer_size / 4;
|
||||
}
|
||||
|
||||
static void audioout_convert_s16s_u8s(
|
||||
void *in_buffer,
|
||||
size_t in_buffer_size,
|
||||
uint8_t *out_buffer,
|
||||
uint32_t *out_buffer_size) {
|
||||
|
||||
assert(in_buffer_size / 2 <= *out_buffer_size);
|
||||
audiosample_convert_s16s_u8s(out_buffer, (int16_t *)in_buffer, in_buffer_size / 4);
|
||||
*out_buffer_size = in_buffer_size / 2;
|
||||
}
|
||||
|
||||
#define CONV_MATCH(bps, sign, ichans, ochans) ((bps & 0xf) | ((sign & 0x1) << 4) | ((ichans & 0x3) << 5) | ((ochans & 0x3) << 7))
|
||||
|
||||
static audioout_sample_convert_func_t audioout_get_samples_convert_func(
|
||||
size_t in_bits_per_sample,
|
||||
int in_channels,
|
||||
bool in_signed,
|
||||
int out_channels) {
|
||||
|
||||
switch CONV_MATCH(in_bits_per_sample, in_signed, in_channels, out_channels) {
|
||||
case CONV_MATCH(8, false, 1, 1):
|
||||
case CONV_MATCH(8, false, 2, 2):
|
||||
return audioout_convert_noop;
|
||||
case CONV_MATCH(8, false, 2, 1):
|
||||
return audioout_convert_u8s_u8m;
|
||||
case CONV_MATCH(8, false, 1, 2):
|
||||
return audioout_convert_u8m_u8s;
|
||||
case CONV_MATCH(8, true, 1, 1):
|
||||
return audioout_convert_s8m_u8m;
|
||||
case CONV_MATCH(8, true, 2, 1):
|
||||
return audioout_convert_s8s_u8m;
|
||||
case CONV_MATCH(8, true, 1, 2):
|
||||
return audioout_convert_s8m_u8s;
|
||||
case CONV_MATCH(8, true, 2, 2):
|
||||
return audioout_convert_s8s_u8s;
|
||||
case CONV_MATCH(16, false, 1, 1):
|
||||
return audioout_convert_u16m_u8m;
|
||||
case CONV_MATCH(16, false, 1, 2):
|
||||
return audioout_convert_u16m_u8s;
|
||||
case CONV_MATCH(16, false, 2, 1):
|
||||
return audioout_convert_u16s_u8m;
|
||||
case CONV_MATCH(16, false, 2, 2):
|
||||
return audioout_convert_u16s_u8s;
|
||||
case CONV_MATCH(16, true, 1, 1):
|
||||
return audioout_convert_s16m_u8m;
|
||||
case CONV_MATCH(16, true, 1, 2):
|
||||
return audioout_convert_s16m_u8s;
|
||||
case CONV_MATCH(16, true, 2, 1):
|
||||
return audioout_convert_s16s_u8m;
|
||||
case CONV_MATCH(16, true, 2, 2):
|
||||
return audioout_convert_s16s_u8s;
|
||||
default:
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("audio format not supported"));
|
||||
}
|
||||
}
|
||||
|
||||
static bool audioout_fill_buffer(audioio_audioout_obj_t *self) {
|
||||
if (!self->playing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
audioio_get_buffer_result_t get_buffer_result;
|
||||
|
||||
uint8_t dma_buf_idx = self->get_buffer_index;
|
||||
|
||||
if (dma_buf_idx == self->put_buffer_index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self->get_buffer_index = INCREMENT_BUF_IDX(dma_buf_idx);
|
||||
|
||||
uint8_t *dma_buf = self->dma_buffers[dma_buf_idx].ptr;
|
||||
size_t dma_buf_size = self->dma_buffers[dma_buf_idx].size;
|
||||
|
||||
bool single_channel_output = true; // whether or not we have 1 or 2 output channels
|
||||
uint8_t channel = 0; // which channel right now?
|
||||
uint8_t *raw_sample_buf; // raw audio sample buffer
|
||||
uint32_t raw_sample_buf_size; // raw audio sample buffer len
|
||||
uint8_t *sample_buf = self->scratch_buffer; // converted audio sample buffer
|
||||
uint32_t sample_buf_size = sizeof(self->scratch_buffer); // converted audio sample buffer len
|
||||
size_t bytes_loaded;
|
||||
esp_err_t ret;
|
||||
|
||||
if (self->sample_buffer != NULL && self->sample_buffer_size > 0) {
|
||||
sample_buf = self->sample_buffer;
|
||||
sample_buf_size = self->sample_buffer_size;
|
||||
get_buffer_result = self->sample_buffer_result;
|
||||
} else {
|
||||
get_buffer_result = audiosample_get_buffer(self->sample,
|
||||
single_channel_output,
|
||||
channel,
|
||||
&raw_sample_buf, &raw_sample_buf_size);
|
||||
|
||||
if (get_buffer_result == GET_BUFFER_ERROR) {
|
||||
common_hal_audioio_audioout_stop(self);
|
||||
return false;
|
||||
}
|
||||
|
||||
self->samples_convert(
|
||||
raw_sample_buf,
|
||||
raw_sample_buf_size,
|
||||
sample_buf,
|
||||
&sample_buf_size);
|
||||
}
|
||||
|
||||
if (sample_buf_size > 0) {
|
||||
ret = dac_continuous_write_asynchronously(self->handle,
|
||||
dma_buf, dma_buf_size,
|
||||
sample_buf, sample_buf_size,
|
||||
&bytes_loaded);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (get_buffer_result == GET_BUFFER_DONE) {
|
||||
if (self->looping) {
|
||||
audiosample_reset_buffer(self->sample, true, 0);
|
||||
} else {
|
||||
common_hal_audioio_audioout_stop(self);
|
||||
}
|
||||
}
|
||||
|
||||
sample_buf_size -= bytes_loaded;
|
||||
if (sample_buf_size == 0) {
|
||||
sample_buf = NULL;
|
||||
} else {
|
||||
sample_buf += bytes_loaded;
|
||||
}
|
||||
|
||||
self->sample_buffer = sample_buf;
|
||||
self->sample_buffer_size = sample_buf_size;
|
||||
self->sample_buffer_result = get_buffer_result;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void audioout_fill_buffers(audioio_audioout_obj_t *self) {
|
||||
while (audioout_fill_buffer(self)) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static void audioout_buf_callback_fun(void *user_data) {
|
||||
audioio_audioout_obj_t *self = (audioio_audioout_obj_t *)user_data;
|
||||
audioout_fill_buffers(self);
|
||||
}
|
||||
|
||||
static bool IRAM_ATTR handle_convert_done(dac_continuous_handle_t handle, const dac_event_data_t *event, void *user_data) {
|
||||
audioio_audioout_obj_t *self = (audioio_audioout_obj_t *)user_data;
|
||||
|
||||
uint8_t *newly_freed_dma_buf = event->buf;
|
||||
size_t newly_freed_dma_buf_size = event->buf_size;
|
||||
|
||||
uint8_t get_buf_idx = self->get_buffer_index;
|
||||
uint8_t put_buf_idx = self->put_buffer_index;
|
||||
uint8_t new_put_buf_idx = INCREMENT_BUF_IDX(put_buf_idx);
|
||||
|
||||
// if the ring buffer of dma buffers is full then drop this one
|
||||
if (get_buf_idx == new_put_buf_idx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self->dma_buffers[put_buf_idx].ptr = newly_freed_dma_buf;
|
||||
self->dma_buffers[put_buf_idx].size = newly_freed_dma_buf_size;
|
||||
|
||||
self->put_buffer_index = new_put_buf_idx;
|
||||
|
||||
background_callback_add(&self->callback, audioout_buf_callback_fun, user_data);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void audioout_init(audioio_audioout_obj_t *self) {
|
||||
dac_continuous_config_t cfg = {
|
||||
.chan_mask = self->channel_mask,
|
||||
.desc_num = NUM_DMA_BUFFERS,
|
||||
.buf_size = DMA_BUFFER_SIZE,
|
||||
.freq_hz = self->freq_hz,
|
||||
.offset = 0,
|
||||
.clk_src = DAC_DIGI_CLK_SRC_APLL,
|
||||
.chan_mode = self->channel_mode,
|
||||
};
|
||||
|
||||
esp_err_t ret;
|
||||
|
||||
ret = dac_continuous_new_channels(&cfg, &self->handle);
|
||||
if (ret == ESP_ERR_INVALID_ARG) {
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to create continuous channels: invalid arg"));
|
||||
} else if (ret == ESP_ERR_INVALID_STATE) {
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to create continuous channels: invalid state"));
|
||||
} else if (ret == ESP_ERR_NOT_FOUND) {
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to create continuous channels: not found"));
|
||||
} else if (ret == ESP_ERR_NO_MEM) {
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to create continuous channels: no mem"));
|
||||
}
|
||||
|
||||
_active_handle = self->handle;
|
||||
|
||||
dac_event_callbacks_t callbacks = {
|
||||
.on_convert_done = handle_convert_done,
|
||||
.on_stop = NULL,
|
||||
};
|
||||
|
||||
ret = dac_continuous_register_event_callback(self->handle, &callbacks, (void *)self);
|
||||
if (ret != ESP_OK) {
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to register continuous events callback"));
|
||||
}
|
||||
|
||||
ret = dac_continuous_enable(self->handle);
|
||||
if (ret != ESP_OK) {
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to enable continuous"));
|
||||
}
|
||||
}
|
||||
|
||||
void common_hal_audioio_audioout_construct(audioio_audioout_obj_t *self,
|
||||
const mcu_pin_obj_t *left_channel_pin, const mcu_pin_obj_t *right_channel_pin, uint16_t quiescent_value) {
|
||||
|
||||
if (_active_handle != NULL) {
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("Can't construct AudioOut because continuous channel already open"));
|
||||
}
|
||||
|
||||
self->playing = false;
|
||||
self->paused = false;
|
||||
self->freq_hz = DEFAULT_SAMPLE_RATE;
|
||||
|
||||
/* espressif has two dac channels and it can support true stereo or
|
||||
* outputting the same signal to both channels (dual mono).
|
||||
* if different pins are supplied for left and right then use true stereo.
|
||||
* if the same pin is supplied for left and right then use dual mono.
|
||||
*/
|
||||
if ((left_channel_pin == &pin_CHANNEL_0 &&
|
||||
right_channel_pin == &pin_CHANNEL_1) ||
|
||||
(left_channel_pin == &pin_CHANNEL_1 &&
|
||||
right_channel_pin == &pin_CHANNEL_0)) {
|
||||
self->channel_mask = DAC_CHANNEL_MASK_ALL;
|
||||
self->num_channels = 2;
|
||||
self->channel_mode = DAC_CHANNEL_MODE_ALTER;
|
||||
} else if ((left_channel_pin == &pin_CHANNEL_0 ||
|
||||
left_channel_pin == &pin_CHANNEL_1) &&
|
||||
right_channel_pin == left_channel_pin) {
|
||||
self->channel_mask = DAC_CHANNEL_MASK_ALL;
|
||||
self->num_channels = 1;
|
||||
self->channel_mode = DAC_CHANNEL_MODE_SIMUL;
|
||||
} else if (left_channel_pin == &pin_CHANNEL_0 &&
|
||||
right_channel_pin == NULL) {
|
||||
self->channel_mask = DAC_CHANNEL_MASK_CH0;
|
||||
self->num_channels = 1;
|
||||
self->channel_mode = DAC_CHANNEL_MODE_SIMUL;
|
||||
} else if (left_channel_pin == &pin_CHANNEL_1 &&
|
||||
right_channel_pin == NULL) {
|
||||
self->channel_mask = DAC_CHANNEL_MASK_CH1;
|
||||
self->num_channels = 1;
|
||||
self->channel_mode = DAC_CHANNEL_MODE_SIMUL;
|
||||
} else {
|
||||
raise_ValueError_invalid_pin();
|
||||
}
|
||||
|
||||
audioout_init(self);
|
||||
}
|
||||
|
||||
bool common_hal_audioio_audioout_deinited(audioio_audioout_obj_t *self) {
|
||||
return self->handle == NULL;
|
||||
}
|
||||
|
||||
void common_hal_audioio_audioout_deinit(audioio_audioout_obj_t *self) {
|
||||
if (common_hal_audioio_audioout_deinited(self)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->playing) {
|
||||
common_hal_audioio_audioout_stop(self);
|
||||
}
|
||||
dac_continuous_disable(self->handle);
|
||||
dac_continuous_del_channels(self->handle);
|
||||
self->handle = NULL;
|
||||
_active_handle = NULL;
|
||||
}
|
||||
|
||||
static void audioio_audioout_start(audioio_audioout_obj_t *self) {
|
||||
esp_err_t ret;
|
||||
|
||||
self->playing = true;
|
||||
self->paused = false;
|
||||
|
||||
ret = dac_continuous_start_async_writing(self->handle);
|
||||
if (ret != ESP_OK) {
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to start async audio"));
|
||||
}
|
||||
}
|
||||
|
||||
static void audioio_audioout_stop(audioio_audioout_obj_t *self, bool full_stop) {
|
||||
dac_continuous_stop_async_writing(self->handle);
|
||||
if (full_stop) {
|
||||
self->get_buffer_index = 0;
|
||||
self->put_buffer_index = 0;
|
||||
self->sample_buffer = NULL;
|
||||
self->sample = NULL;
|
||||
self->playing = false;
|
||||
self->paused = false;
|
||||
} else {
|
||||
self->paused = true;
|
||||
}
|
||||
}
|
||||
|
||||
void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self,
|
||||
mp_obj_t sample, bool loop) {
|
||||
|
||||
if (self->playing) {
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("already playing"));
|
||||
}
|
||||
|
||||
size_t samples_size;
|
||||
uint8_t channel_count;
|
||||
bool samples_signed;
|
||||
bool _single_buffer;
|
||||
uint32_t _max_buffer_length;
|
||||
uint8_t _spacing;
|
||||
uint32_t freq_hz;
|
||||
|
||||
audiosample_reset_buffer(sample, true, 0);
|
||||
|
||||
self->sample = sample;
|
||||
self->looping = loop;
|
||||
freq_hz = audiosample_sample_rate(self->sample);
|
||||
|
||||
if (freq_hz != self->freq_hz) {
|
||||
common_hal_audioio_audioout_deinit(self);
|
||||
self->freq_hz = freq_hz;
|
||||
audioout_init(self);
|
||||
}
|
||||
|
||||
samples_size = audiosample_bits_per_sample(self->sample);
|
||||
channel_count = audiosample_channel_count(self->sample);
|
||||
audiosample_get_buffer_structure(self->sample, false,
|
||||
&_single_buffer, &samples_signed,
|
||||
&_max_buffer_length, &_spacing);
|
||||
|
||||
self->samples_convert = audioout_get_samples_convert_func(
|
||||
samples_size,
|
||||
channel_count,
|
||||
samples_signed,
|
||||
self->num_channels);
|
||||
|
||||
audioio_audioout_start(self);
|
||||
}
|
||||
|
||||
void common_hal_audioio_audioout_pause(audioio_audioout_obj_t *self) {
|
||||
if (!self->playing || self->paused) {
|
||||
return;
|
||||
}
|
||||
audioio_audioout_stop(self, false);
|
||||
}
|
||||
|
||||
void common_hal_audioio_audioout_resume(audioio_audioout_obj_t *self) {
|
||||
if (!self->playing || !self->paused) {
|
||||
return;
|
||||
}
|
||||
audioio_audioout_start(self);
|
||||
}
|
||||
|
||||
bool common_hal_audioio_audioout_get_paused(audioio_audioout_obj_t *self) {
|
||||
return self->playing && self->paused;
|
||||
}
|
||||
|
||||
void common_hal_audioio_audioout_stop(audioio_audioout_obj_t *self) {
|
||||
if (!self->playing) {
|
||||
return;
|
||||
}
|
||||
audioio_audioout_stop(self, true);
|
||||
}
|
||||
|
||||
bool common_hal_audioio_audioout_get_playing(audioio_audioout_obj_t *self) {
|
||||
return self->playing && !self->paused;
|
||||
}
|
||||
|
||||
#endif
|
||||
46
ports/espressif/common-hal/audioio/AudioOut.h
Normal file
46
ports/espressif/common-hal/audioio/AudioOut.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "common-hal/microcontroller/Pin.h"
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
#include "supervisor/background_callback.h"
|
||||
#include "shared-module/audiocore/__init__.h"
|
||||
|
||||
#include "driver/dac_continuous.h"
|
||||
|
||||
|
||||
#define NUM_DMA_BUFFERS 6
|
||||
#define DMA_BUFFER_SIZE 512
|
||||
|
||||
#define DEFAULT_SAMPLE_RATE 32000
|
||||
|
||||
typedef void (*audioout_sample_convert_func_t)(void *in_buffer, size_t in_buffer_size, uint8_t *out_buffer, uint32_t *out_buffer_size);
|
||||
|
||||
typedef struct {
|
||||
uint8_t *ptr;
|
||||
size_t size;
|
||||
} buf_info_t;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
dac_continuous_handle_t handle;
|
||||
dac_channel_mask_t channel_mask;
|
||||
uint32_t freq_hz;
|
||||
uint8_t num_channels;
|
||||
dac_continuous_channel_mode_t channel_mode;
|
||||
mp_obj_t sample;
|
||||
bool playing;
|
||||
bool paused;
|
||||
bool looping;
|
||||
uint8_t *sample_buffer;
|
||||
size_t sample_buffer_size;
|
||||
audioio_get_buffer_result_t sample_buffer_result;
|
||||
uint8_t get_buffer_index;
|
||||
uint8_t put_buffer_index;
|
||||
buf_info_t dma_buffers[NUM_DMA_BUFFERS + 1];
|
||||
background_callback_t callback;
|
||||
uint8_t scratch_buffer[DMA_BUFFER_SIZE];
|
||||
audioout_sample_convert_func_t samples_convert;
|
||||
} audioio_audioout_obj_t;
|
||||
2
ports/espressif/common-hal/audioio/__init__.c
Normal file
2
ports/espressif/common-hal/audioio/__init__.c
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
#include "common-hal/audioio/__init__.h"
|
||||
0
ports/espressif/common-hal/audioio/__init__.h
Normal file
0
ports/espressif/common-hal/audioio/__init__.h
Normal file
|
|
@ -85,6 +85,7 @@ CIRCUITPY__EVE ?= 1
|
|||
ifeq ($(IDF_TARGET),esp32)
|
||||
# Modules
|
||||
CIRCUITPY_ALARM_TOUCH = 1
|
||||
CIRCUITPY_AUDIOIO = 1
|
||||
CIRCUITPY_RGBMATRIX = 0
|
||||
|
||||
# SDMMC not supported yet
|
||||
|
|
@ -244,6 +245,7 @@ CIRCUITPY_ESPCAMERA = 0
|
|||
else ifeq ($(IDF_TARGET),esp32s2)
|
||||
# Modules
|
||||
CIRCUITPY_ALARM_TOUCH = 1
|
||||
CIRCUITPY_AUDIOIO = 1
|
||||
# No BLE in hw
|
||||
CIRCUITPY_BLEIO = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ void audiosample_convert_u8m_s16s(int16_t *buffer_out, const uint8_t *buffer_in,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void audiosample_convert_u8s_s16s(int16_t *buffer_out, const uint8_t *buffer_in, size_t nframes) {
|
||||
size_t nsamples = 2 * nframes;
|
||||
for (; nsamples--;) {
|
||||
|
|
@ -76,7 +75,6 @@ void audiosample_convert_s8m_s16s(int16_t *buffer_out, const int8_t *buffer_in,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void audiosample_convert_s8s_s16s(int16_t *buffer_out, const int8_t *buffer_in, size_t nframes) {
|
||||
size_t nsamples = 2 * nframes;
|
||||
for (; nsamples--;) {
|
||||
|
|
@ -85,7 +83,6 @@ void audiosample_convert_s8s_s16s(int16_t *buffer_out, const int8_t *buffer_in,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void audiosample_convert_u16m_s16s(int16_t *buffer_out, const uint16_t *buffer_in, size_t nframes) {
|
||||
for (; nframes--;) {
|
||||
int16_t sample = *buffer_in++ - 0x8000;
|
||||
|
|
@ -94,7 +91,6 @@ void audiosample_convert_u16m_s16s(int16_t *buffer_out, const uint16_t *buffer_i
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void audiosample_convert_u16s_s16s(int16_t *buffer_out, const uint16_t *buffer_in, size_t nframes) {
|
||||
size_t nsamples = 2 * nframes;
|
||||
for (; nsamples--;) {
|
||||
|
|
@ -110,3 +106,114 @@ void audiosample_convert_s16m_s16s(int16_t *buffer_out, const int16_t *buffer_in
|
|||
*buffer_out++ = sample;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void audiosample_convert_u8s_u8m(uint8_t *buffer_out, const uint8_t *buffer_in, size_t nframes) {
|
||||
for (; nframes--;) {
|
||||
uint8_t sample = *buffer_in++ + 0x80;
|
||||
*buffer_out++ = sample;
|
||||
buffer_in++;
|
||||
}
|
||||
}
|
||||
|
||||
void audiosample_convert_s8m_u8m(uint8_t *buffer_out, const int8_t *buffer_in, size_t nframes) {
|
||||
for (; nframes--;) {
|
||||
uint8_t sample = *buffer_in++ + 0x80;
|
||||
*buffer_out++ = sample;
|
||||
}
|
||||
}
|
||||
|
||||
void audiosample_convert_s8s_u8m(uint8_t *buffer_out, const int8_t *buffer_in, size_t nframes) {
|
||||
for (; nframes--;) {
|
||||
uint8_t sample = *buffer_in++ + 0x80;
|
||||
*buffer_out++ = sample;
|
||||
buffer_in++;
|
||||
}
|
||||
}
|
||||
|
||||
void audiosample_convert_u16m_u8m(uint8_t *buffer_out, const uint16_t *buffer_in, size_t nframes) {
|
||||
for (; nframes--;) {
|
||||
uint8_t sample = (*buffer_in++) >> 8;
|
||||
*buffer_out++ = sample;
|
||||
}
|
||||
}
|
||||
|
||||
void audiosample_convert_u16s_u8m(uint8_t *buffer_out, const uint16_t *buffer_in, size_t nframes) {
|
||||
for (; nframes--;) {
|
||||
uint8_t sample = (*buffer_in++) >> 8;
|
||||
*buffer_out++ = sample;
|
||||
buffer_in++;
|
||||
}
|
||||
}
|
||||
|
||||
void audiosample_convert_s16m_u8m(uint8_t *buffer_out, const int16_t *buffer_in, size_t nframes) {
|
||||
for (; nframes--;) {
|
||||
uint8_t sample = (*buffer_in++ + 0x8000) >> 8;
|
||||
*buffer_out++ = sample;
|
||||
}
|
||||
}
|
||||
|
||||
void audiosample_convert_s16s_u8m(uint8_t *buffer_out, const int16_t *buffer_in, size_t nframes) {
|
||||
for (; nframes--;) {
|
||||
uint8_t sample = (*buffer_in++ + 0x8000) >> 8;
|
||||
*buffer_out++ = sample;
|
||||
buffer_in++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void audiosample_convert_u8m_u8s(uint8_t *buffer_out, const uint8_t *buffer_in, size_t nframes) {
|
||||
for (; nframes--;) {
|
||||
uint8_t sample = *buffer_in++;
|
||||
*buffer_out++ = sample;
|
||||
*buffer_out++ = sample;
|
||||
}
|
||||
}
|
||||
|
||||
void audiosample_convert_s8m_u8s(uint8_t *buffer_out, const int8_t *buffer_in, size_t nframes) {
|
||||
for (; nframes--;) {
|
||||
uint8_t sample = *buffer_in++ + 0x80;
|
||||
*buffer_out++ = sample;
|
||||
*buffer_out++ = sample;
|
||||
}
|
||||
}
|
||||
|
||||
void audiosample_convert_s8s_u8s(uint8_t *buffer_out, const int8_t *buffer_in, size_t nframes) {
|
||||
size_t nsamples = 2 * nframes;
|
||||
for (; nsamples--;) {
|
||||
uint8_t sample = *buffer_in++ + 0x80;
|
||||
*buffer_out++ = sample;
|
||||
}
|
||||
}
|
||||
|
||||
void audiosample_convert_u16m_u8s(uint8_t *buffer_out, const uint16_t *buffer_in, size_t nframes) {
|
||||
for (; nframes--;) {
|
||||
uint8_t sample = (*buffer_in++) >> 8;
|
||||
*buffer_out++ = sample;
|
||||
*buffer_out++ = sample;
|
||||
}
|
||||
}
|
||||
|
||||
void audiosample_convert_u16s_u8s(uint8_t *buffer_out, const uint16_t *buffer_in, size_t nframes) {
|
||||
size_t nsamples = 2 * nframes;
|
||||
for (; nsamples--;) {
|
||||
uint8_t sample = (*buffer_in++) >> 8;
|
||||
*buffer_out++ = sample;
|
||||
}
|
||||
}
|
||||
|
||||
void audiosample_convert_s16m_u8s(uint8_t *buffer_out, const int16_t *buffer_in, size_t nframes) {
|
||||
for (; nframes--;) {
|
||||
uint8_t sample = (*buffer_in++ + 0x8000) >> 8;
|
||||
*buffer_out++ = sample;
|
||||
*buffer_out++ = sample;
|
||||
}
|
||||
}
|
||||
|
||||
void audiosample_convert_s16s_u8s(uint8_t *buffer_out, const int16_t *buffer_in, size_t nframes) {
|
||||
size_t nsamples = 2 * nframes;
|
||||
for (; nsamples--;) {
|
||||
uint8_t sample = (*buffer_in++ + 0x8000) >> 8;
|
||||
*buffer_out++ = sample;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,3 +60,19 @@ void audiosample_convert_s8s_s16s(int16_t *buffer_out, const int8_t *buffer_in,
|
|||
void audiosample_convert_u16m_s16s(int16_t *buffer_out, const uint16_t *buffer_in, size_t nframes);
|
||||
void audiosample_convert_u16s_s16s(int16_t *buffer_out, const uint16_t *buffer_in, size_t nframes);
|
||||
void audiosample_convert_s16m_s16s(int16_t *buffer_out, const int16_t *buffer_in, size_t nframes);
|
||||
|
||||
void audiosample_convert_u8s_u8m(uint8_t *buffer_out, const uint8_t *buffer_in, size_t nframes);
|
||||
void audiosample_convert_s8m_u8m(uint8_t *buffer_out, const int8_t *buffer_in, size_t nframes);
|
||||
void audiosample_convert_s8s_u8m(uint8_t *buffer_out, const int8_t *buffer_in, size_t nframes);
|
||||
void audiosample_convert_u16m_u8m(uint8_t *buffer_out, const uint16_t *buffer_in, size_t nframes);
|
||||
void audiosample_convert_u16s_u8m(uint8_t *buffer_out, const uint16_t *buffer_in, size_t nframes);
|
||||
void audiosample_convert_s16m_u8m(uint8_t *buffer_out, const int16_t *buffer_in, size_t nframes);
|
||||
void audiosample_convert_s16s_u8m(uint8_t *buffer_out, const int16_t *buffer_in, size_t nframes);
|
||||
|
||||
void audiosample_convert_u8m_u8s(uint8_t *buffer_out, const uint8_t *buffer_in, size_t nframes);
|
||||
void audiosample_convert_s8m_u8s(uint8_t *buffer_out, const int8_t *buffer_in, size_t nframes);
|
||||
void audiosample_convert_s8s_u8s(uint8_t *buffer_out, const int8_t *buffer_in, size_t nframes);
|
||||
void audiosample_convert_u16m_u8s(uint8_t *buffer_out, const uint16_t *buffer_in, size_t nframes);
|
||||
void audiosample_convert_u16s_u8s(uint8_t *buffer_out, const uint16_t *buffer_in, size_t nframes);
|
||||
void audiosample_convert_s16m_u8s(uint8_t *buffer_out, const int16_t *buffer_in, size_t nframes);
|
||||
void audiosample_convert_s16s_u8s(uint8_t *buffer_out, const int16_t *buffer_in, size_t nframes);
|
||||
|
|
|
|||
Loading…
Reference in a new issue