move to new cspot

This commit is contained in:
philippe44
2023-03-25 16:48:41 -07:00
parent c712b78931
commit 008c36facf
2983 changed files with 465270 additions and 13569 deletions

View File

@@ -0,0 +1,46 @@
#include "AC101AudioSink.h"
#include "driver/i2s.h"
AC101AudioSink::AC101AudioSink()
{
// Disable software volume control, all handled by ::volumeChanged
softwareVolumeControl = false;
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX
.sample_rate = 44100,
.bits_per_sample = (i2s_bits_per_sample_t)16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
.communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_I2S,
.intr_alloc_flags = 0, //Default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 512,
.use_apll = true,
.tx_desc_auto_clear = true //Auto clear tx descriptor on underflow
};
i2s_pin_config_t pin_config = {
.bck_io_num = 27,
.ws_io_num = 26,
.data_out_num = 25,
.data_in_num = -1 //Not used
};
dac = &dac_a1s;
dac->init(0, 0, &i2s_config);
dac->speaker(false);
dac->power(ADAC_ON);
startI2sFeed();
}
AC101AudioSink::~AC101AudioSink()
{
}
void AC101AudioSink::volumeChanged(uint16_t volume) {
dac->volume(volume, volume);
}

View File

@@ -0,0 +1,47 @@
#include "BufferedAudioSink.h"
#include "driver/i2s.h"
#include "freertos/task.h"
#include "freertos/ringbuf.h"
RingbufHandle_t dataBuffer;
static void i2sFeed(void *pvParameters)
{
while (true)
{
size_t itemSize;
char *item = (char *)xRingbufferReceiveUpTo(dataBuffer, &itemSize, portMAX_DELAY, 512);
if (item != NULL)
{
size_t written = 0;
while (written < itemSize)
{
i2s_write((i2s_port_t)0, item, itemSize, &written, portMAX_DELAY);
}
vRingbufferReturnItem(dataBuffer, (void *)item);
}
}
}
void BufferedAudioSink::startI2sFeed(size_t buf_size)
{
dataBuffer = xRingbufferCreate(buf_size, RINGBUF_TYPE_BYTEBUF);
xTaskCreatePinnedToCore(&i2sFeed, "i2sFeed", 4096, NULL, 10, NULL, tskNO_AFFINITY);
}
void BufferedAudioSink::feedPCMFrames(const uint8_t *buffer, size_t bytes)
{
feedPCMFramesInternal(buffer, bytes);
}
void BufferedAudioSink::feedPCMFramesInternal(const void *pvItem, size_t xItemSize)
{
xRingbufferSend(dataBuffer, pvItem, xItemSize, portMAX_DELAY);
}
bool BufferedAudioSink::setParams(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) {
// TODO override this for sinks with custom mclk
i2s_set_clk((i2s_port_t)0, sampleRate, (i2s_bits_per_sample_t)bitDepth, (i2s_channel_t)channelCount);
return true;
}

View File

@@ -0,0 +1,106 @@
#include "ES8311AudioSink.h"
extern "C" {
#include "es8311.h"
}
ES8311AudioSink::ES8311AudioSink()
{
this->softwareVolumeControl = false;
esp_err_t ret_val = ESP_OK;
Es8311Config cfg = {
.esMode = ES_MODE_SLAVE,
.i2c_port_num = I2C_NUM_0,
.i2c_cfg = {
.mode = I2C_MODE_MASTER,
.sda_io_num = 1,
.scl_io_num = 2,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
},
.dacOutput = (DacOutput) (DAC_OUTPUT_LOUT1 | DAC_OUTPUT_LOUT2 | DAC_OUTPUT_ROUT1 | DAC_OUTPUT_ROUT2),
.adcInput = ADC_INPUT_LINPUT1_RINPUT1,
};
cfg.i2c_cfg.master.clk_speed = 100000;
Es8311Init(&cfg);
Es8311SetBitsPerSample(ES_MODULE_DAC, BIT_LENGTH_16BITS);
Es8311ConfigFmt(ES_MODULE_DAC, ES_I2S_NORMAL);
Es8311SetVoiceVolume(60);
Es8311Start(ES_MODULE_DAC);
ES8311WriteReg(ES8311_CLK_MANAGER_REG01, 0xbf);
ES8311WriteReg(ES8311_CLK_MANAGER_REG02, 0x18);
// .codec_mode = AUDIO_HAL_CODEC_MODE_DECODE,
// .i2s_iface = {
// .mode = AUDIO_HAL_MODE_SLAVE,
// .fmt = AUDIO_HAL_I2S_NORMAL,
// .samples = AUDIO_HAL_44K_SAMPLES,
// .bits = AUDIO_HAL_BIT_LENGTH_16BITS,
// },
// };
// ret_val |= es8311_codec_init(&cfg);
// ret_val |= es8311_set_bits_per_sample(cfg.i2s_iface.bits);
// ret_val |= es8311_config_fmt((es_i2s_fmt_t) cfg.i2s_iface.fmt);
// ret_val |= es8311_codec_set_voice_volume(60);
// ret_val |= es8311_codec_ctrl_state(cfg.codec_mode, AUDIO_HAL_CTRL_START);
// ret_val |= es8311_codec_set_clk();
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX
.sample_rate = 44100,
.bits_per_sample = (i2s_bits_per_sample_t)16,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // 2-channels
.communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = 0, // Default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 512,
.use_apll = false,
.tx_desc_auto_clear = true, // Auto clear tx descriptor on underflow
};
i2s_pin_config_t pin_config = {
.mck_io_num = 42,
.bck_io_num = 40,
.ws_io_num = 41,
.data_out_num = 39,
.data_in_num = -1,
};
int err;
err = i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL);
if (err != ESP_OK)
{
ESP_LOGE("OI", "i2s driver installation error: %d", err);
}
err = i2s_set_pin((i2s_port_t)0, &pin_config);
if (err != ESP_OK)
{
ESP_LOGE("OI", "i2s set pin error: %d", err);
}
// PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
// REG_SET_FIELD(PIN_CTRL, CLK_OUT1, 0);
// ESP_LOGI("OI", "MCLK output on CLK_OUT1");
startI2sFeed();
}
void ES8311AudioSink::volumeChanged(uint16_t volume)
{
Es8311SetVoiceVolume(volume);
}
void ES8311AudioSink::writeReg(uint8_t reg_add, uint8_t data)
{
}
void ES8311AudioSink::setSampleRate(uint32_t sampleRate) {
std::cout << "ES8311AudioSink::setSampleRate(" << sampleRate << ")" << std::endl;
// i2s set sample rate
es8311_Codec_Startup(0, sampleRate);
}
ES8311AudioSink::~ES8311AudioSink()
{
}

View File

@@ -0,0 +1,150 @@
#include "ES8388AudioSink.h"
struct es8388_cmd_s {
uint8_t reg;
uint8_t value;
};
ES8388AudioSink::ES8388AudioSink()
{
// configure i2c
i2c_config = {
.mode = I2C_MODE_MASTER,
.sda_io_num = 33,
.scl_io_num = 32,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
};
i2c_config.master.clk_speed = 100000;
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX
.sample_rate = 44100,
.bits_per_sample = (i2s_bits_per_sample_t)16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
.communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_MSB,
.intr_alloc_flags = 0, //Default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 512,
.use_apll = true,
.tx_desc_auto_clear = true, //Auto clear tx descriptor on underflow
.fixed_mclk = 256 * 44100
};
i2s_pin_config_t pin_config = {
.bck_io_num = 27,
.ws_io_num = 25,
.data_out_num = 26,
.data_in_num = -1 //Not used
};
int err;
err = i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL);
if (err != ESP_OK) {
ESP_LOGE("OI", "i2s driver installation error: %d", err);
}
err = i2s_set_pin((i2s_port_t)0, &pin_config);
if (err != ESP_OK) {
ESP_LOGE("OI", "i2s set pin error: %d", err);
}
err = i2c_param_config(0, &i2c_config);
if (err != ESP_OK) {
ESP_LOGE("OI", "i2c param config error: %d", err);
}
err = i2c_driver_install(0, I2C_MODE_MASTER, 0, 0, 0);
if (err != ESP_OK) {
ESP_LOGE("OI", "i2c driver installation error: %d", err);
}
i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
err = i2c_master_start(i2c_cmd);
if (err != ESP_OK) {
ESP_LOGE("OI", "i2c master start error: %d", err);
}
/* mute DAC during setup, power up all systems, slave mode */
writeReg(ES8388_DACCONTROL3, 0x04);
writeReg(ES8388_CONTROL2, 0x50);
writeReg(ES8388_CHIPPOWER, 0x00);
writeReg(ES8388_MASTERMODE, 0x00);
/* power up DAC and enable LOUT1+2 / ROUT1+2, ADC sample rate = DAC sample rate */
writeReg(ES8388_DACPOWER, 0x3e);
writeReg(ES8388_CONTROL1, 0x12);
/* DAC I2S setup: 16 bit word length, I2S format; MCLK / Fs = 256*/
writeReg(ES8388_DACCONTROL1, 0x18);
writeReg(ES8388_DACCONTROL2, 0x02);
/* DAC to output route mixer configuration: ADC MIX TO OUTPUT */
writeReg(ES8388_DACCONTROL16, 0x1B);
writeReg(ES8388_DACCONTROL17, 0x90);
writeReg(ES8388_DACCONTROL20, 0x90);
/* DAC and ADC use same LRCK, enable MCLK input; output resistance setup */
writeReg(ES8388_DACCONTROL21, 0x80);
writeReg(ES8388_DACCONTROL23, 0x00);
/* DAC volume control: 0dB (maximum, unattented) */
writeReg(ES8388_DACCONTROL5, 0x00);
writeReg(ES8388_DACCONTROL4, 0x00);
/* power down ADC while configuring; volume: +9dB for both channels */
writeReg(ES8388_ADCPOWER, 0xff);
writeReg(ES8388_ADCCONTROL1, 0x88); // +24db
/* select LINPUT2 / RINPUT2 as ADC input; stereo; 16 bit word length, format right-justified, MCLK / Fs = 256 */
writeReg(ES8388_ADCCONTROL2, 0xf0); // 50
writeReg(ES8388_ADCCONTROL3, 0x80); // 00
writeReg(ES8388_ADCCONTROL4, 0x0e);
writeReg(ES8388_ADCCONTROL5, 0x02);
/* set ADC volume */
writeReg(ES8388_ADCCONTROL8, 0x20);
writeReg(ES8388_ADCCONTROL9, 0x20);
/* set LOUT1 / ROUT1 volume: 0dB (unattenuated) */
writeReg(ES8388_DACCONTROL24, 0x1e);
writeReg(ES8388_DACCONTROL25, 0x1e);
/* set LOUT2 / ROUT2 volume: 0dB (unattenuated) */
writeReg(ES8388_DACCONTROL26, 0x1e);
writeReg(ES8388_DACCONTROL27, 0x1e);
/* power up and enable DAC; power up ADC (no MIC bias) */
writeReg(ES8388_DACPOWER, 0x3c);
writeReg(ES8388_DACCONTROL3, 0x00);
writeReg(ES8388_ADCPOWER, 0x00);
startI2sFeed();
}
void ES8388AudioSink::writeReg(uint8_t reg_add, uint8_t data)
{
int res = 0;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
res |= i2c_master_start(cmd);
res |= i2c_master_write_byte(cmd, ES8388_ADDR, ACK_CHECK_EN);
res |= i2c_master_write_byte(cmd, reg_add, ACK_CHECK_EN);
res |= i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
res |= i2c_master_stop(cmd);
res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (res != ESP_OK) {
ESP_LOGE("RR", "Unable to write to ES8388: %d", res);
}else{
ESP_LOGE("RR", "register successfull written.");
}
}
ES8388AudioSink::~ES8388AudioSink()
{
}

View File

@@ -0,0 +1,36 @@
#include "ES9018AudioSink.h"
#include "driver/i2s.h"
ES9018AudioSink::ES9018AudioSink()
{
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX
.sample_rate = 44100,
.bits_per_sample = (i2s_bits_per_sample_t)16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
.communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_MSB,
.intr_alloc_flags = 0, //Default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 512,
.use_apll = true,
.tx_desc_auto_clear = true, //Auto clear tx descriptor on underflow
.fixed_mclk = 384 * 44100
};
i2s_pin_config_t pin_config = {
.bck_io_num = 27,
.ws_io_num = 32,
.data_out_num = 25,
.data_in_num = -1 //Not used
};
i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL);
i2s_set_pin((i2s_port_t)0, &pin_config);
startI2sFeed();
}
ES9018AudioSink::~ES9018AudioSink()
{
}

View File

@@ -0,0 +1,35 @@
#include "InternalAudioSink.h"
#include "driver/i2s.h"
InternalAudioSink::InternalAudioSink()
{
softwareVolumeControl = true;
usign = true;
#ifdef I2S_MODE_DAC_BUILT_IN
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), // Only TX
.sample_rate = (i2s_bits_per_sample_t)44100,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = 0,//ESP_INTR_FLAG_LEVEL1
.dma_buf_count = 6,
.dma_buf_len = 512,
.use_apll = true,
.tx_desc_auto_clear = true, //Auto clear tx descriptor on underflow
.fixed_mclk=-1
};
//install and start i2s driver
i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL);
//init DAC
i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);
#endif
startI2sFeed();
}
InternalAudioSink::~InternalAudioSink()
{
}

View File

@@ -0,0 +1,36 @@
#include "PCM5102AudioSink.h"
#include "driver/i2s.h"
PCM5102AudioSink::PCM5102AudioSink()
{
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX
.sample_rate = 44100,
.bits_per_sample = (i2s_bits_per_sample_t)16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
.communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_I2S,
.intr_alloc_flags = 0, //Default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 512,
.use_apll = true,
.tx_desc_auto_clear = true, //Auto clear tx descriptor on underflow
.fixed_mclk = 384 * 44100
};
i2s_pin_config_t pin_config = {
.bck_io_num = 27,
.ws_io_num = 32,
.data_out_num = 25,
.data_in_num = -1 //Not used
};
i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL);
i2s_set_pin((i2s_port_t)0, &pin_config);
startI2sFeed();
}
PCM5102AudioSink::~PCM5102AudioSink()
{
}

View File

@@ -0,0 +1,186 @@
#include "SPDIFAudioSink.h"
#include "driver/i2s.h"
// See http://www.hardwarebook.info/S/PDIF for more info on this protocol
// Conversion table to biphase code mark (LSB first, ending in 1)
static const uint16_t bmc_convert[256] = {
0x3333, 0xb333, 0xd333, 0x5333, 0xcb33, 0x4b33, 0x2b33, 0xab33,
0xcd33, 0x4d33, 0x2d33, 0xad33, 0x3533, 0xb533, 0xd533, 0x5533,
0xccb3, 0x4cb3, 0x2cb3, 0xacb3, 0x34b3, 0xb4b3, 0xd4b3, 0x54b3,
0x32b3, 0xb2b3, 0xd2b3, 0x52b3, 0xcab3, 0x4ab3, 0x2ab3, 0xaab3,
0xccd3, 0x4cd3, 0x2cd3, 0xacd3, 0x34d3, 0xb4d3, 0xd4d3, 0x54d3,
0x32d3, 0xb2d3, 0xd2d3, 0x52d3, 0xcad3, 0x4ad3, 0x2ad3, 0xaad3,
0x3353, 0xb353, 0xd353, 0x5353, 0xcb53, 0x4b53, 0x2b53, 0xab53,
0xcd53, 0x4d53, 0x2d53, 0xad53, 0x3553, 0xb553, 0xd553, 0x5553,
0xcccb, 0x4ccb, 0x2ccb, 0xaccb, 0x34cb, 0xb4cb, 0xd4cb, 0x54cb,
0x32cb, 0xb2cb, 0xd2cb, 0x52cb, 0xcacb, 0x4acb, 0x2acb, 0xaacb,
0x334b, 0xb34b, 0xd34b, 0x534b, 0xcb4b, 0x4b4b, 0x2b4b, 0xab4b,
0xcd4b, 0x4d4b, 0x2d4b, 0xad4b, 0x354b, 0xb54b, 0xd54b, 0x554b,
0x332b, 0xb32b, 0xd32b, 0x532b, 0xcb2b, 0x4b2b, 0x2b2b, 0xab2b,
0xcd2b, 0x4d2b, 0x2d2b, 0xad2b, 0x352b, 0xb52b, 0xd52b, 0x552b,
0xccab, 0x4cab, 0x2cab, 0xacab, 0x34ab, 0xb4ab, 0xd4ab, 0x54ab,
0x32ab, 0xb2ab, 0xd2ab, 0x52ab, 0xcaab, 0x4aab, 0x2aab, 0xaaab,
0xcccd, 0x4ccd, 0x2ccd, 0xaccd, 0x34cd, 0xb4cd, 0xd4cd, 0x54cd,
0x32cd, 0xb2cd, 0xd2cd, 0x52cd, 0xcacd, 0x4acd, 0x2acd, 0xaacd,
0x334d, 0xb34d, 0xd34d, 0x534d, 0xcb4d, 0x4b4d, 0x2b4d, 0xab4d,
0xcd4d, 0x4d4d, 0x2d4d, 0xad4d, 0x354d, 0xb54d, 0xd54d, 0x554d,
0x332d, 0xb32d, 0xd32d, 0x532d, 0xcb2d, 0x4b2d, 0x2b2d, 0xab2d,
0xcd2d, 0x4d2d, 0x2d2d, 0xad2d, 0x352d, 0xb52d, 0xd52d, 0x552d,
0xccad, 0x4cad, 0x2cad, 0xacad, 0x34ad, 0xb4ad, 0xd4ad, 0x54ad,
0x32ad, 0xb2ad, 0xd2ad, 0x52ad, 0xcaad, 0x4aad, 0x2aad, 0xaaad,
0x3335, 0xb335, 0xd335, 0x5335, 0xcb35, 0x4b35, 0x2b35, 0xab35,
0xcd35, 0x4d35, 0x2d35, 0xad35, 0x3535, 0xb535, 0xd535, 0x5535,
0xccb5, 0x4cb5, 0x2cb5, 0xacb5, 0x34b5, 0xb4b5, 0xd4b5, 0x54b5,
0x32b5, 0xb2b5, 0xd2b5, 0x52b5, 0xcab5, 0x4ab5, 0x2ab5, 0xaab5,
0xccd5, 0x4cd5, 0x2cd5, 0xacd5, 0x34d5, 0xb4d5, 0xd4d5, 0x54d5,
0x32d5, 0xb2d5, 0xd2d5, 0x52d5, 0xcad5, 0x4ad5, 0x2ad5, 0xaad5,
0x3355, 0xb355, 0xd355, 0x5355, 0xcb55, 0x4b55, 0x2b55, 0xab55,
0xcd55, 0x4d55, 0x2d55, 0xad55, 0x3555, 0xb555, 0xd555, 0x5555,
};
#define I2S_BUG_MAGIC (26 * 1000 * 1000) // magic number for avoiding I2S bug
#define BITS_PER_SUBFRAME 64
#define FRAMES_PER_BLOCK 192
#define SPDIF_BUF_SIZE (BITS_PER_SUBFRAME/8 * 2 * FRAMES_PER_BLOCK)
#define SPDIF_BUF_ARRAY_SIZE (SPDIF_BUF_SIZE / sizeof(uint32_t))
#define BMC_B 0x33173333 // block start
#define BMC_M 0x331d3333 // left ch
#define BMC_W 0x331b3333 // right ch
#define BMC_MW_DIF (BMC_M ^ BMC_W)
static uint32_t spdif_buf[SPDIF_BUF_ARRAY_SIZE];
static uint32_t *spdif_ptr;
static void spdif_buf_init(void)
{
// first bllock has W preamble
spdif_buf[0] = BMC_B;
// all other blocks are alternating M, then W preamble
uint32_t bmc_mw = BMC_M;
for (int i = 2; i < SPDIF_BUF_ARRAY_SIZE; i += 2)
{
spdif_buf[i] = bmc_mw ^= BMC_MW_DIF;
}
}
SPDIFAudioSink::SPDIFAudioSink(uint8_t spdifPin)
{
// initialize S/PDIF buffer
spdif_buf_init();
spdif_ptr = spdif_buf;
this->spdifPin = spdifPin;
this->setParams(44100, 16, 2);
startI2sFeed(SPDIF_BUF_SIZE * 16);
}
bool SPDIFAudioSink::setParams(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) {
if (bitDepth != 16 || channelCount != 2) // TODO support mono playback and different bit widths
return false;
int sample_rate = (int)sampleRate * 2;
int bclk = sample_rate * 64 * 2;
int mclk = (I2S_BUG_MAGIC / bclk) * bclk;
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
.sample_rate = (uint32_t) sample_rate,
#else
.sample_rate = (int) sample_rate,
#endif
.bits_per_sample = (i2s_bits_per_sample_t)(bitDepth * 2),
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = 0,
.dma_buf_count = 8,
.dma_buf_len = 512,
.use_apll = true,
.tx_desc_auto_clear = true,
.fixed_mclk = mclk, // avoiding I2S bug
};
i2s_pin_config_t pin_config = {
.bck_io_num = -1,
.ws_io_num = -1,
.data_out_num = spdifPin,
.data_in_num = -1,
};
i2s_driver_uninstall((i2s_port_t)0);
int err = i2s_driver_install((i2s_port_t)0, &i2s_config, 0, nullptr);
i2s_set_pin((i2s_port_t)0, &pin_config);
return !err;
}
SPDIFAudioSink::~SPDIFAudioSink() {
i2s_driver_uninstall((i2s_port_t)0);
}
int num_frames = 0;
void SPDIFAudioSink::feedPCMFrames(const uint8_t *buffer, size_t bytes)
{
for (int i = 0; i < bytes; i += 2)
{
/**
* What is this, and why does it work?
*
* Rather than assemble all S/PDIF frames from scratch we want to do the
* minimum amount of work possible. To that extent, we fix the final four
* bits (VUCP) to be all-zero prior to BMC encoding (= valid, no subcode
* or channel-status bits set, even parity), and zero the lowest 8 sample
* bits (prior to BMC encoding). This is all done in spdif_buf_init(),
* aligning at word boundaries and setting alternating preambles as well
* as encoding 8 bits of zeros as 0x33, leaving the final bit high.
*
* We must therefore BMC encode our 16 bit PCM data in such a way that:
* - the first (least significant) bit is 0 (to fit with 0x33 zeros)
* - the final bit is 1 (so as to fit with the following 0x33 VUCP bits)
* - the result has even parity
*
* As biphase mark code retains parity (0 encodes as two 1s or two 0s),
* this is evidently not possible without loss of data, as the input PCM
* data isn't already even parity. We can use the first (least significant)
* bit as parity bit to achieve our desired encoding.
*
* The bmc_convert table converts the lower and upper 8 bit of our PCM
* frames into 16 bit biphase mark code patterns with the first two bits
* encoding the LSB and the final bit always high. We combine both 16bit
* patterns into a 32 bit encoding of our original input data by shifting
* the first (lower) 16 bit into position, then sign-extending the second
* (higher) 16bit pattern. If that pattern started with a 1, the resulting
* 32 bit pattern will now contain 1s in the first 16 bits.
*
* Keep in mind that the shifted value in the first (lower) 16 bits always
* ends in a 1 bit, so the entire pattern must be flipped in case the
* second (higher) 16 bit pattern starts with a 1 bit. XORing the sign-
* extended component to the first one achieves exactly that.
*
* Finally, we zero out the very first bit of the resulting value. This
* may change the lowest bit of our encoded value, but ensures that our
* newly encoded bits form a valid BMC pattern with the already zeroed out
* lower 8 bits in the pattern set up in spdif_buf_init().
*
* Further, this also happens to ensure even parity:
* All entries in the BMC table end in a 1, so an all-zero pattern would
* end (after encoding an even number of bits) in two 0 bits. Setting any
* bit will cause the BMC-encoded pattern to flip its first (lowest) bit,
* meaning we can use that bit to infer parity. Setting it to zero flips
* the first (lowest) bit such that we always have even parity.
*
* I did not come up with this, all credit goes to
* github.com/amedes/esp_a2dp_sink_spdif
*/
uint32_t lo = ((uint32_t)(bmc_convert[buffer[i]]) << 16);
uint32_t hi = (uint32_t)((int16_t)bmc_convert[buffer[i+1]]);
*(spdif_ptr + 1) = ((lo ^ hi) << 1) >> 1;
spdif_ptr += 2; // advance to next audio data
if (spdif_ptr >= &spdif_buf[SPDIF_BUF_ARRAY_SIZE]) {
feedPCMFramesInternal(spdif_buf, sizeof(spdif_buf));
spdif_ptr = spdif_buf;
}
}
}

View File

@@ -0,0 +1,117 @@
#include "TAS5711AudioSink.h"
struct tas5711_cmd_s {
uint8_t reg;
uint8_t value;
};
static const struct tas5711_cmd_s tas5711_init_sequence[] = {
{ 0x00, 0x6c }, // 0x6c - 256 x mclk
{ 0x04, 0x03 }, // 0x03 - 16 bit i2s
{ 0x05, 0x00 }, // system control 0x00 is audio playback
{ 0x06, 0x00 }, // disable mute
{ 0x07, 0x50 }, // volume register
{ 0xff, 0xff }
};
i2c_ack_type_t ACK_CHECK_EN = (i2c_ack_type_t)0x1;
TAS5711AudioSink::TAS5711AudioSink()
{
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX
.sample_rate = 44100,
.bits_per_sample = (i2s_bits_per_sample_t)16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
.communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_MSB,
.intr_alloc_flags = 0, //Default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 512,
.use_apll = true,
.tx_desc_auto_clear = true, //Auto clear tx descriptor on underflow
.fixed_mclk = 256 * 44100
};
i2s_pin_config_t pin_config = {
.bck_io_num = 5,
.ws_io_num = 25,
.data_out_num = 26,
.data_in_num = -1 //Not used
};
i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL);
i2s_set_pin((i2s_port_t)0, &pin_config);
// configure i2c
i2c_config = {
.mode = I2C_MODE_MASTER,
.sda_io_num = 21,
.scl_io_num = 23,
.sda_pullup_en = GPIO_PULLUP_DISABLE,
.scl_pullup_en = GPIO_PULLUP_DISABLE,
};
i2c_config.master.clk_speed = 250000;
i2c_param_config(i2c_port, &i2c_config);
i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
uint8_t data, addr = (0x1b);
i2c_master_start(i2c_cmd);
i2c_master_write_byte(i2c_cmd, (addr << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN);
i2c_master_write_byte(i2c_cmd, 00, ACK_CHECK_EN);
i2c_master_start(i2c_cmd);
i2c_master_write_byte(i2c_cmd, (addr << 1) | I2C_MASTER_READ, ACK_CHECK_EN);
i2c_master_read_byte(i2c_cmd, &data, ACK_CHECK_EN);
i2c_master_stop(i2c_cmd);
int ret = i2c_master_cmd_begin(i2c_port, i2c_cmd, 50 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(i2c_cmd);
if (ret == ESP_OK) {
ESP_LOGI("RR", "Detected TAS");
}
else {
ESP_LOGI("RR", "Unable to detect dac");
}
writeReg(0x1b, 0x00);
vTaskDelay(100 / portTICK_PERIOD_MS);
for (int i = 0; tas5711_init_sequence[i].reg != 0xff; i++) {
writeReg(tas5711_init_sequence[i].reg, tas5711_init_sequence[i].value);
vTaskDelay(1 / portTICK_PERIOD_MS);
}
startI2sFeed();
}
void TAS5711AudioSink::writeReg(uint8_t reg, uint8_t value)
{
i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
i2c_master_start(i2c_cmd);
i2c_master_write_byte(i2c_cmd, (0x1b << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN);
i2c_master_write_byte(i2c_cmd, reg, ACK_CHECK_EN);
i2c_master_write_byte(i2c_cmd, value, ACK_CHECK_EN);
i2c_master_stop(i2c_cmd);
esp_err_t res = i2c_master_cmd_begin(i2c_port, i2c_cmd, 500 / portTICK_PERIOD_MS);
if (res != ESP_OK) {
ESP_LOGE("RR", "Unable to write to TAS5711");
}
i2c_cmd_link_delete(i2c_cmd);
}
TAS5711AudioSink::~TAS5711AudioSink()
{
}

View File

@@ -0,0 +1,426 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <string.h>
#include <esp_log.h>
#include <esp_types.h>
#include <esp_system.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/i2c.h>
#include <driver/i2s.h>
#include "adac.h"
#include "ac101.h"
const static char TAG[] = "AC101";
#define SPKOUT_EN ((1 << 9) | (1 << 11) | (1 << 7) | (1 << 5))
#define EAROUT_EN ((1 << 11) | (1 << 12) | (1 << 13))
#define BIN(a, b, c, d) 0b##a##b##c##d
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define AC_ASSERT(a, format, b, ...) \
if ((a) != 0) \
{ \
ESP_LOGE(TAG, format, ##__VA_ARGS__); \
return b; \
}
static bool init(int i2c_port_num, int i2s_num, i2s_config_t *config);
static void deinit(void);
static void speaker(bool active);
static void headset(bool active);
static void volume(unsigned left, unsigned right);
static void power(adac_power_e mode);
struct adac_s dac_a1s = {init, deinit, power, speaker, headset, volume};
static esp_err_t i2c_write_reg(uint8_t reg, uint16_t val);
static uint16_t i2c_read_reg(uint8_t reg);
static void ac101_start(ac_module_t mode);
static void ac101_stop(void);
static void ac101_set_earph_volume(uint8_t volume);
static void ac101_set_spk_volume(uint8_t volume);
static int ac101_get_spk_volume(void);
static int i2c_port;
/****************************************************************************************
* init
*/
static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config)
{
esp_err_t res = ESP_OK;
i2c_port = i2c_port_num;
// configure i2c
i2c_config_t i2c_config = {
.mode = I2C_MODE_MASTER,
.sda_io_num = 33,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = 32,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 250000,
};
i2c_param_config(i2c_port, &i2c_config);
i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
res = i2c_read_reg(CHIP_AUDIO_RS);
if (!res)
{
ESP_LOGW(TAG, "No AC101 detected");
i2c_driver_delete(i2c_port);
return 0;
}
ESP_LOGI(TAG, "AC101 DAC using I2C sda:%u, scl:%u", i2c_config.sda_io_num, i2c_config.scl_io_num);
res = i2c_write_reg(CHIP_AUDIO_RS, 0x123);
// huh?
vTaskDelay(100 / portTICK_PERIOD_MS);
// enable the PLL from BCLK source
i2c_write_reg(PLL_CTRL1, BIN(0000, 0001, 0100, 1111)); // F=1,M=1,PLL,INT=31 (medium)
i2c_write_reg(PLL_CTRL2, BIN(1000, 0110, 0000, 0000)); // PLL, F=96,N_i=1024-96,F=0,N_f=0*0.2;
// i2c_write_reg(PLL_CTRL2, BIN(1000,0011,1100,0000));
// clocking system
i2c_write_reg(SYSCLK_CTRL, BIN(1010, 1010, 0000, 1000)); // PLLCLK, BCLK1, IS1CLK, PLL, SYSCLK
i2c_write_reg(MOD_CLK_ENA, BIN(1000, 0000, 0000, 1100)); // IS21, ADC, DAC
i2c_write_reg(MOD_RST_CTRL, BIN(1000, 0000, 0000, 1100)); // IS21, ADC, DAC
i2c_write_reg(I2S_SR_CTRL, BIN(0111, 0000, 0000, 0000)); // 44.1kHz
// analogue config
i2c_write_reg(I2S1LCK_CTRL, BIN(1000, 1000, 0101, 0000)); // Slave, BCLK=I2S/8,LRCK=32,16bits,I2Smode, Stereo
i2c_write_reg(I2S1_SDOUT_CTRL, BIN(1100, 0000, 0000, 0000)); // I2S1ADC (R&L)
i2c_write_reg(I2S1_SDIN_CTRL, BIN(1100, 0000, 0000, 0000)); // IS21DAC (R&L)
i2c_write_reg(I2S1_MXR_SRC, BIN(0010, 0010, 0000, 0000)); // ADCL, ADCR
i2c_write_reg(ADC_SRCBST_CTRL, BIN(0100, 0100, 0100, 0000)); // disable all boost (default)
#if ENABLE_ADC
i2c_write_reg(ADC_SRC, BIN(0000, 0100, 0000, 1000)); // source=linein(R/L)
i2c_write_reg(ADC_DIG_CTRL, BIN(1000, 0000, 0000, 0000)); // enable digital ADC
i2c_write_reg(ADC_ANA_CTRL, BIN(1011, 1011, 0000, 0000)); // enable analogue R/L, 0dB
#else
i2c_write_reg(ADC_SRC, BIN(0000, 0000, 0000, 0000)); // source=none
i2c_write_reg(ADC_DIG_CTRL, BIN(0000, 0000, 0000, 0000)); // disable digital ADC
i2c_write_reg(ADC_ANA_CTRL, BIN(0011, 0011, 0000, 0000)); // disable analogue R/L, 0dB
#endif
//Path Configuration
i2c_write_reg(DAC_MXR_SRC, BIN(1000, 1000, 0000, 0000)); // DAC from I2S
i2c_write_reg(DAC_DIG_CTRL, BIN(1000, 0000, 0000, 0000)); // enable DAC
i2c_write_reg(OMIXER_DACA_CTRL, BIN(1111, 0000, 0000, 0000)); // enable DAC/Analogue (see note on offset removal and PA)
i2c_write_reg(OMIXER_DACA_CTRL, BIN(1111, 1111, 0000, 0000)); // this toggle is needed for headphone PA offset
#if ENABLE_ADC
i2c_write_reg(OMIXER_SR, BIN(0000, 0001, 0000, 0010)); // source=DAC(R/L) (are DACR and DACL really inverted in bitmap?)
#else
i2c_write_reg(OMIXER_SR, BIN(0000, 0101, 0000, 1010)); // source=DAC(R/L) and LINEIN(R/L)
#endif
// configure I2S pins & install driver
i2s_pin_config_t i2s_pin_config = (i2s_pin_config_t){.bck_io_num = 27, .ws_io_num = 26, .data_out_num = 25, .data_in_num = -1};
res |= i2s_driver_install(i2s_num, i2s_config, 0, NULL);
res |= i2s_set_pin(i2s_num, &i2s_pin_config);
// enable earphone & speaker
i2c_write_reg(SPKOUT_CTRL, 0x0220);
i2c_write_reg(HPOUT_CTRL, 0xf801);
// set gain for speaker and earphone
ac101_set_spk_volume(70);
ac101_set_earph_volume(70);
ESP_LOGI(TAG, "DAC using I2S bck:%d, ws:%d, do:%d", i2s_pin_config.bck_io_num, i2s_pin_config.ws_io_num, i2s_pin_config.data_out_num);
return (res == ESP_OK);
}
/****************************************************************************************
* init
*/
static void deinit(void)
{
i2c_driver_delete(i2c_port);
}
/****************************************************************************************
* change volume
*/
static void volume(unsigned left, unsigned right)
{
ac101_set_earph_volume(left);
// nothing at that point, volume is handled by backend
}
/****************************************************************************************
* power
*/
static void power(adac_power_e mode)
{
switch (mode)
{
case ADAC_STANDBY:
case ADAC_OFF:
ac101_stop();
break;
case ADAC_ON:
ac101_start(AC_MODULE_DAC);
break;
default:
ESP_LOGW(TAG, "unknown power command");
break;
}
}
/****************************************************************************************
* speaker
*/
static void speaker(bool active)
{
uint16_t value = i2c_read_reg(SPKOUT_CTRL);
if (active)
i2c_write_reg(SPKOUT_CTRL, value | SPKOUT_EN);
else
i2c_write_reg(SPKOUT_CTRL, value & ~SPKOUT_EN);
}
/****************************************************************************************
* headset
*/
static void headset(bool active)
{
// there might be aneed to toggle OMIXER_DACA_CTRL 11:8, not sure
uint16_t value = i2c_read_reg(HPOUT_CTRL);
if (active)
i2c_write_reg(HPOUT_CTRL, value | EAROUT_EN);
else
i2c_write_reg(HPOUT_CTRL, value & ~EAROUT_EN);
}
/****************************************************************************************
*
*/
static esp_err_t i2c_write_reg(uint8_t reg, uint16_t val)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
esp_err_t ret = 0;
uint8_t send_buff[4];
send_buff[0] = (AC101_ADDR << 1);
send_buff[1] = reg;
send_buff[2] = (val >> 8) & 0xff;
send_buff[3] = val & 0xff;
ret |= i2c_master_start(cmd);
ret |= i2c_master_write(cmd, send_buff, 4, ACK_CHECK_EN);
ret |= i2c_master_stop(cmd);
ret |= i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
/****************************************************************************************
*
*/
static uint16_t i2c_read_reg(uint8_t reg)
{
uint8_t data[2] = {0};
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (AC101_ADDR << 1) | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (AC101_ADDR << 1) | READ_BIT, ACK_CHECK_EN); //check or not
i2c_master_read(cmd, data, 2, ACK_VAL);
i2c_master_stop(cmd);
i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
return (data[0] << 8) + data[1];
;
}
/****************************************************************************************
*
*/
void set_sample_rate(int rate)
{
if (rate == 8000)
rate = SAMPLE_RATE_8000;
else if (rate == 11025)
rate = SAMPLE_RATE_11052;
else if (rate == 12000)
rate = SAMPLE_RATE_12000;
else if (rate == 16000)
rate = SAMPLE_RATE_16000;
else if (rate == 22050)
rate = SAMPLE_RATE_22050;
else if (rate == 24000)
rate = SAMPLE_RATE_24000;
else if (rate == 32000)
rate = SAMPLE_RATE_32000;
else if (rate == 44100)
rate = SAMPLE_RATE_44100;
else if (rate == 48000)
rate = SAMPLE_RATE_48000;
else if (rate == 96000)
rate = SAMPLE_RATE_96000;
else if (rate == 192000)
rate = SAMPLE_RATE_192000;
else
{
ESP_LOGW(TAG, "Unknown sample rate %hu", rate);
rate = SAMPLE_RATE_44100;
}
i2c_write_reg(I2S_SR_CTRL, rate);
}
/****************************************************************************************
* Get normalized (0..100) speaker volume
*/
static int ac101_get_spk_volume(void)
{
return ((i2c_read_reg(SPKOUT_CTRL) & 0x1f) * 100) / 0x1f;
}
/****************************************************************************************
* Set normalized (0..100) volume
*/
static void ac101_set_spk_volume(uint8_t volume)
{
uint16_t value = min(volume, 100);
value = ((int)value * 0x1f) / 100;
value |= i2c_read_reg(SPKOUT_CTRL) & ~0x1f;
i2c_write_reg(SPKOUT_CTRL, value);
}
/****************************************************************************************
* Get normalized (0..100) earphone volume
*/
static int ac101_get_earph_volume(void)
{
return (((i2c_read_reg(HPOUT_CTRL) >> 4) & 0x3f) * 100) / 0x3f;
}
/****************************************************************************************
* Set normalized (0..100) earphone volume
*/
static void ac101_set_earph_volume(uint8_t volume)
{
uint16_t value = min(volume, 255);
value = (((int)value * 0x3f) / 255) << 4;
value |= i2c_read_reg(HPOUT_CTRL) & ~(0x3f << 4);
i2c_write_reg(HPOUT_CTRL, value);
}
/****************************************************************************************
*
*/
static void ac101_set_output_mixer_gain(ac_output_mixer_gain_t gain, ac_output_mixer_source_t source)
{
uint16_t regval, temp, clrbit;
regval = i2c_read_reg(OMIXER_BST1_CTRL);
switch (source)
{
case SRC_MIC1:
temp = (gain & 0x7) << 6;
clrbit = ~(0x7 << 6);
break;
case SRC_MIC2:
temp = (gain & 0x7) << 3;
clrbit = ~(0x7 << 3);
break;
case SRC_LINEIN:
temp = (gain & 0x7);
clrbit = ~0x7;
break;
default:
return;
}
regval &= clrbit;
regval |= temp;
i2c_write_reg(OMIXER_BST1_CTRL, regval);
}
/****************************************************************************************
*
*/
static void ac101_start(ac_module_t mode)
{
if (mode == AC_MODULE_LINE)
{
i2c_write_reg(0x51, 0x0408);
i2c_write_reg(0x40, 0x8000);
i2c_write_reg(0x50, 0x3bc0);
}
if (mode == AC_MODULE_ADC || mode == AC_MODULE_ADC_DAC || mode == AC_MODULE_LINE)
{
// I2S1_SDOUT_CTRL
// i2c_write_reg(PLL_CTRL2, 0x8120);
i2c_write_reg(0x04, 0x800c);
i2c_write_reg(0x05, 0x800c);
// res |= i2c_write_reg(0x06, 0x3000);
}
if (mode == AC_MODULE_DAC || mode == AC_MODULE_ADC_DAC || mode == AC_MODULE_LINE)
{
uint16_t value = i2c_read_reg(PLL_CTRL2);
value |= 0x8000;
i2c_write_reg(PLL_CTRL2, value);
}
}
/****************************************************************************************
*
*/
static void ac101_stop(void)
{
uint16_t value = i2c_read_reg(PLL_CTRL2);
value &= ~0x8000;
i2c_write_reg(PLL_CTRL2, value);
}
/****************************************************************************************
*
*/
static void ac101_deinit(void)
{
i2c_write_reg(CHIP_AUDIO_RS, 0x123); //soft reset
}
/****************************************************************************************
* Don't know when this one is supposed to be called
*/
static void ac101_i2s_config_clock(ac_i2s_clock_t *cfg)
{
uint16_t regval = 0;
regval = i2c_read_reg(I2S1LCK_CTRL);
regval &= 0xe03f;
regval |= (cfg->bclk_div << 9);
regval |= (cfg->lclk_div << 6);
i2c_write_reg(I2S1LCK_CTRL, regval);
}

View File

@@ -0,0 +1,796 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <string.h>
#include "esp_log.h"
#include "es8311.h"
// #include "board.h"
/* ES8311 address
* 0x32:CE=1;0x30:CE=0
*/
#define ES8311_ADDR 0x32
#define ES7243_ADDR 0x26
/*
* to define the clock soure of MCLK
*/
#define FROM_MCLK_PIN 0
#define FROM_SCLK_PIN 1
/*
* to define work mode(master or slave)
*/
#define MASTER_MODE 0
#define SLAVE_MODE 1
/*
* to define serial digital audio format
*/
#define I2S_FMT 0
#define LEFT_JUSTIFIED_FMT 1
#define DPS_PCM_A_FMT 2
#define DPS_PCM_B_FMT 3
/*
* to define resolution of PCM interface
*/
#define LENGTH_16BIT 0
#define LENGTH_24BIT 1
#define LENGTH_32BIT 2
/*
* codec private data
*/
struct es8311_private {
bool dmic_enable;
bool mclkinv;
bool sclkinv;
uint8_t master_slave_mode;
uint8_t pcm_format;
uint8_t pcm_resolution;
uint8_t mclk_src;
};
static struct es8311_private *es8311_priv;
/*
* Clock coefficient structer
*/
struct _coeff_div {
uint32_t mclk; /* mclk frequency */
uint32_t rate; /* sample rate */
uint8_t prediv; /* the pre divider with range from 1 to 8 */
uint8_t premulti; /* the pre multiplier with x1, x2, x4 and x8 selection */
uint8_t adcdiv; /* adcclk divider */
uint8_t dacdiv; /* dacclk divider */
uint8_t fsmode; /* double speed or single speed, =0, ss, =1, ds */
uint8_t lrck_h; /* adclrck divider and daclrck divider */
uint8_t lrck_l;
uint8_t bclkdiv; /* sclk divider */
uint8_t adcosr; /* adc osr */
uint8_t dacosr; /* dac osr */
};
/* codec hifi mclk clock divider coefficients */
static const struct _coeff_div coeff_div[] = {
//mclk rate prediv mult adcdiv dacdiv fsmode lrch lrcl bckdiv osr
/* 8k */
{12288000, 8000 , 0x06, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{18432000, 8000 , 0x03, 0x02, 0x03, 0x03, 0x00, 0x05, 0xff, 0x18, 0x10, 0x10},
{16384000, 8000 , 0x08, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{8192000 , 8000 , 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{6144000 , 8000 , 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{4096000 , 8000 , 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{3072000 , 8000 , 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{2048000 , 8000 , 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{1536000 , 8000 , 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{1024000 , 8000 , 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
/* 11.025k */
{11289600, 11025, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{5644800 , 11025, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{2822400 , 11025, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{1411200 , 11025, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
/* 12k */
{12288000, 12000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{6144000 , 12000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{3072000 , 12000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{1536000 , 12000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
/* 16k */
{12288000, 16000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{18432000, 16000, 0x03, 0x02, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, 0x10},
{16384000, 16000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{8192000 , 16000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{6144000 , 16000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{4096000 , 16000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{3072000 , 16000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{2048000 , 16000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{1536000 , 16000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{1024000 , 16000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
/* 22.05k */
{11289600, 22050, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{5644800 , 22050, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{2822400 , 22050, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{1411200 , 22050, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
/* 24k */
{12288000, 24000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{18432000, 24000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{6144000 , 24000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{3072000 , 24000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{1536000 , 24000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
/* 32k */
{12288000, 32000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{18432000, 32000, 0x03, 0x04, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, 0x10},
{16384000, 32000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{8192000 , 32000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{6144000 , 32000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{4096000 , 32000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{3072000 , 32000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{2048000 , 32000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{1536000 , 32000, 0x03, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10},
{1024000 , 32000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
/* 44.1k */
{11289600, 44100, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{5644800 , 44100, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{2822400 , 44100, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{1411200 , 44100, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
/* 48k */
{12288000, 48000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{18432000, 48000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{6144000 , 48000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{3072000 , 48000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{1536000 , 48000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
/* 64k */
{12288000, 64000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{18432000, 64000, 0x03, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10},
{16384000, 64000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{8192000 , 64000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{6144000 , 64000, 0x01, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10},
{4096000 , 64000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{3072000 , 64000, 0x01, 0x08, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10},
{2048000 , 64000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{1536000 , 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0xbf, 0x03, 0x18, 0x18},
{1024000 , 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10},
/* 88.2k */
{11289600, 88200, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{5644800 , 88200, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{2822400 , 88200, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{1411200 , 88200, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10},
/* 96k */
{12288000, 96000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{18432000, 96000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{6144000 , 96000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{3072000 , 96000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10},
{1536000 , 96000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10},
};
static char *TAG = "DRV8311";
#define ES_ASSERT(a, format, b, ...) \
if ((a) != 0) { \
ESP_LOGE(TAG, format, ##__VA_ARGS__); \
return b;\
}
static int Es8311WriteReg(uint8_t regAdd, uint8_t data)
{
int res = 0;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
res |= i2c_master_start(cmd);
res |= i2c_master_write_byte(cmd, ES8311_ADDR, 1 /*ACK_CHECK_EN*/);
res |= i2c_master_write_byte(cmd, regAdd, 1 /*ACK_CHECK_EN*/);
res |= i2c_master_write_byte(cmd, data, 1 /*ACK_CHECK_EN*/);
res |= i2c_master_stop(cmd);
res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
ES_ASSERT(res, "Es8311 Write Reg error", -1);
return res;
}
int Es8311ReadReg(uint8_t regAdd)
{
uint8_t data;
int res = 0;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
res |= i2c_master_start(cmd);
res |= i2c_master_write_byte(cmd, ES8311_ADDR, 1 /*ACK_CHECK_EN*/);
res |= i2c_master_write_byte(cmd, regAdd, 1 /*ACK_CHECK_EN*/);
res |= i2c_master_stop(cmd);
res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
cmd = i2c_cmd_link_create();
res |= i2c_master_start(cmd);
res |= i2c_master_write_byte(cmd, ES8311_ADDR | 0x01, 1 /*ACK_CHECK_EN*/);
res |= i2c_master_read_byte(cmd, &data, 0x01 /*NACK_VAL*/);
res |= i2c_master_stop(cmd);
res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
ES_ASSERT(res, "Es8311 Read Reg error", -1);
return (int)data;
}
static int Es7243WriteReg(uint8_t regAdd, uint8_t data)
{
int res = 0;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
res |= i2c_master_start(cmd);
res |= i2c_master_write_byte(cmd, ES7243_ADDR, 1 /*ACK_CHECK_EN*/);
res |= i2c_master_write_byte(cmd, regAdd, 1 /*ACK_CHECK_EN*/);
res |= i2c_master_write_byte(cmd, data, 1 /*ACK_CHECK_EN*/);
res |= i2c_master_stop(cmd);
res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
ES_ASSERT(res, "Es7243 Write Reg error", -1);
return res;
}
int Es7243ReadReg(uint8_t regAdd)
{
uint8_t data;
int res = 0;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
res |= i2c_master_start(cmd);
res |= i2c_master_write_byte(cmd, ES7243_ADDR, 1 /*ACK_CHECK_EN*/);
res |= i2c_master_write_byte(cmd, regAdd, 1 /*ACK_CHECK_EN*/);
res |= i2c_master_stop(cmd);
res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
cmd = i2c_cmd_link_create();
res |= i2c_master_start(cmd);
res |= i2c_master_write_byte(cmd, ES7243_ADDR | 0x01, 1 /*ACK_CHECK_EN*/);
res |= i2c_master_read_byte(cmd, &data, 0x01 /*NACK_VAL*/);
res |= i2c_master_stop(cmd);
res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
ES_ASSERT(res, "Es7243 Read Reg error", -1);
return (int)data;
}
esp_err_t Es7243Init(void)
{
esp_err_t ret = ESP_OK;
ret |= Es7243WriteReg(0x00, 0x01);
ret |= Es7243WriteReg(0x06, 0x00);
ret |= Es7243WriteReg(0x05, 0x1B);
ret |= Es7243WriteReg(0x01, 0x0C);
ret |= Es7243WriteReg(0x08, 0x43);
ret |= Es7243WriteReg(0x05, 0x13);
if (ret) {
ESP_LOGE(TAG, "Es7243 initialize failed!");
return ESP_FAIL;
}
return ret;
}
static int I2cInit(i2c_config_t *conf, int i2cMasterPort)
{
int res;
res = i2c_param_config(i2cMasterPort, conf);
res |= i2c_driver_install(i2cMasterPort, conf->mode, 0, 0, 0);
ES_ASSERT(res, "I2cInit error", -1);
return res;
}
/*
* look for the coefficient in coeff_div[] table
*/
static int get_coeff(uint32_t mclk, uint32_t rate)
{
for (int i = 0; i < (sizeof(coeff_div) / sizeof(coeff_div[0])); i++) {
if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
return i;
}
return -1;
}
/*
* set es8311 clock parameter and PCM/I2S interface
*/
static void es8311_pcm_hw_params(uint32_t mclk, uint32_t lrck)
{
int coeff;
uint8_t regv, datmp;
ESP_LOGI(TAG, "Enter into es8311_pcm_hw_params()\n");
coeff = get_coeff(mclk, lrck);
if (coeff < 0) {
ESP_LOGE(TAG, "Unable to configure sample rate %dHz with %dHz MCLK\n", lrck, mclk);
return;
}
/*
* set clock parammeters
*/
if (coeff >= 0) {
regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG02) & 0x07;
regv |= (coeff_div[coeff].prediv - 1) << 5;
datmp = 0;
switch (coeff_div[coeff].premulti) {
case 1:
datmp = 0;
break;
case 2:
datmp = 1;
break;
case 4:
datmp = 2;
break;
case 8:
datmp = 3;
break;
default:
break;
}
#if CONFIG_ESP32_KORVO_V1_1_BOARD
datmp = 3;
#endif
regv |= (datmp) << 3;
Es8311WriteReg(ES8311_CLK_MANAGER_REG02, regv);
regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG05) & 0x00;
regv |= (coeff_div[coeff].adcdiv - 1) << 4;
regv |= (coeff_div[coeff].dacdiv - 1) << 0;
Es8311WriteReg(ES8311_CLK_MANAGER_REG05, regv);
regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG03) & 0x80;
regv |= coeff_div[coeff].fsmode << 6;
regv |= coeff_div[coeff].adcosr << 0;
Es8311WriteReg(ES8311_CLK_MANAGER_REG03, regv);
regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG04) & 0x80;
regv |= coeff_div[coeff].dacosr << 0;
Es8311WriteReg(ES8311_CLK_MANAGER_REG04, regv);
regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG07) & 0xC0;
regv |= coeff_div[coeff].lrck_h << 0;
Es8311WriteReg(ES8311_CLK_MANAGER_REG07, regv);
regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG08) & 0x00;
regv |= coeff_div[coeff].lrck_l << 0;
Es8311WriteReg(ES8311_CLK_MANAGER_REG08, regv);
regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG06) & 0xE0;
if (coeff_div[coeff].bclkdiv < 19) {
regv |= (coeff_div[coeff].bclkdiv - 1) << 0;
} else {
regv |= (coeff_div[coeff].bclkdiv) << 0;
}
Es8311WriteReg(ES8311_CLK_MANAGER_REG06, regv);
}
}
/*
* set data and clock in tri-state mode
* if tristate = 0, tri-state is disabled for normal mode
* if tristate = 1, tri-state is enabled
*/
// static void es8311_set_tristate(int tristate)
// {
// uint8_t regv;
// ESP_LOGI(TAG, "Enter into es8311_set_tristate(), tristate = %d\n", tristate);
// regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG07) & 0xcf;
// if (tristate) {
// Es8311WriteReg(ES8311_CLK_MANAGER_REG07, regv | 0x30);
// } else {
// Es8311WriteReg(ES8311_CLK_MANAGER_REG07, regv);
// }
// }
/*
* set es8311 dac mute or not
* if mute = 0, dac un-mute
* if mute = 1, dac mute
*/
static void es8311_mute(int mute)
{
uint8_t regv;
ESP_LOGI(TAG, "Enter into es8311_mute(), mute = %d\n", mute);
regv = Es8311ReadReg(ES8311_DAC_REG31) & 0x9f;
if (mute) {
Es8311WriteReg(ES8311_SYSTEM_REG12, 0x02);
Es8311WriteReg(ES8311_DAC_REG31, regv | 0x60);
Es8311WriteReg(ES8311_DAC_REG32, 0x00);
Es8311WriteReg(ES8311_DAC_REG37, 0x08);
} else {
Es8311WriteReg(ES8311_DAC_REG31, regv);
Es8311WriteReg(ES8311_SYSTEM_REG12, 0x00);
}
}
/*
* set es8311 into suspend mode
*/
// static void es8311_suspend(void)
// {
// ESP_LOGI(TAG, "Enter into es8311_suspend()\n");
// Es8311WriteReg(ES8311_DAC_REG32, 0x00);
// Es8311WriteReg(ES8311_ADC_REG17, 0x00);
// Es8311WriteReg(ES8311_SYSTEM_REG0E, 0xFF);
// Es8311WriteReg(ES8311_SYSTEM_REG12, 0x02);
// Es8311WriteReg(ES8311_SYSTEM_REG14, 0x00);
// Es8311WriteReg(ES8311_SYSTEM_REG0D, 0xFA);
// Es8311WriteReg(ES8311_ADC_REG15, 0x00);
// Es8311WriteReg(ES8311_DAC_REG37, 0x08);
// Es8311WriteReg(ES8311_RESET_REG00, 0x00);
// Es8311WriteReg(ES8311_RESET_REG00, 0x1F);
// Es8311WriteReg(ES8311_CLK_MANAGER_REG01, 0x30);
// Es8311WriteReg(ES8311_CLK_MANAGER_REG01, 0x00);
// Es8311WriteReg(ES8311_GP_REG45, 0x01);
// }
/*
* initialize es8311 codec
*/
static void es8311_init(uint32_t mclk_freq, uint32_t lrck_freq)
{
int regv;
Es8311WriteReg(ES8311_GP_REG45, 0x00);
Es8311WriteReg(ES8311_CLK_MANAGER_REG01, 0x30);
Es8311WriteReg(ES8311_CLK_MANAGER_REG02, 0x00);
Es8311WriteReg(ES8311_CLK_MANAGER_REG03, 0x10);
Es8311WriteReg(ES8311_ADC_REG16, 0x24);
Es8311WriteReg(ES8311_CLK_MANAGER_REG04, 0x10);
Es8311WriteReg(ES8311_CLK_MANAGER_REG05, 0x00);
Es8311WriteReg(ES8311_SYSTEM_REG0B, 0x00);
Es8311WriteReg(ES8311_SYSTEM_REG0C, 0x00);
Es8311WriteReg(ES8311_SYSTEM_REG10, 0x1F);
Es8311WriteReg(ES8311_SYSTEM_REG11, 0x7F);
Es8311WriteReg(ES8311_RESET_REG00, 0x80);
/*
* Set Codec into Master or Slave mode
*/
regv = Es8311ReadReg(ES8311_RESET_REG00);
/* set master/slave audio interface */
switch (es8311_priv->master_slave_mode) {
case MASTER_MODE: /* MASTER MODE */
ESP_LOGI(TAG, "ES8311 in Master mode\n");
regv |= 0x40;
break;
case SLAVE_MODE: /* SLAVE MODE */
ESP_LOGI(TAG, "ES8311 in Slave mode\n");
regv &= 0xBF;
break;
default:
regv &= 0xBF;
}
Es8311WriteReg(ES8311_RESET_REG00, regv);
Es8311WriteReg(ES8311_SYSTEM_REG0D, 0x01);
Es8311WriteReg(ES8311_CLK_MANAGER_REG01, 0x3F);
/*
* select clock source for internal mclk
*/
switch (es8311_priv->mclk_src) {
case FROM_MCLK_PIN:
regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG01);
regv &= 0x7F;
Es8311WriteReg(ES8311_CLK_MANAGER_REG01, regv);
break;
case FROM_SCLK_PIN:
regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG01);
regv |= 0x80;
Es8311WriteReg(ES8311_CLK_MANAGER_REG01, regv);
break;
default:
regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG01);
regv &= 0x7F;
Es8311WriteReg(ES8311_CLK_MANAGER_REG01, regv);
break;
}
es8311_pcm_hw_params(lrck_freq * 256, lrck_freq);
/*
* mclk inverted or not
*/
if (es8311_priv->mclkinv == true) {
regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG01);
regv |= 0x40;
Es8311WriteReg(ES8311_CLK_MANAGER_REG01, regv);
} else {
regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG01);
regv &= ~(0x40);
Es8311WriteReg(ES8311_CLK_MANAGER_REG01, regv);
}
/*
* sclk inverted or not
*/
if (es8311_priv->sclkinv == true) {
regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG06);
regv |= 0x20;
Es8311WriteReg(ES8311_CLK_MANAGER_REG06, regv);
} else {
regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG06);
regv &= ~(0x20);
Es8311WriteReg(ES8311_CLK_MANAGER_REG06, regv);
}
Es8311WriteReg(ES8311_SYSTEM_REG14, 0x1A);
/*
* pdm dmic enable or disable
*/
if (es8311_priv->dmic_enable == true) {
regv = Es8311ReadReg(ES8311_SYSTEM_REG14);
regv |= 0x40;
Es8311WriteReg(ES8311_SYSTEM_REG14, regv);
} else {
regv = Es8311ReadReg(ES8311_SYSTEM_REG14);
regv &= ~(0x40);
Es8311WriteReg(ES8311_SYSTEM_REG14, regv);
}
Es8311WriteReg(ES8311_SYSTEM_REG13, 0x10);
Es8311WriteReg(ES8311_SYSTEM_REG0E, 0x02);
Es8311WriteReg(ES8311_ADC_REG15, 0x40);
Es8311WriteReg(ES8311_ADC_REG1B, 0x0A);
Es8311WriteReg(ES8311_ADC_REG1C, 0x6A);
Es8311WriteReg(ES8311_DAC_REG37, 0x48);
Es8311WriteReg(ES8311_GPIO_REG44, 0x08);
Es8311WriteReg(ES8311_DAC_REG32, 0xBF);
#ifdef CONFIG_USE_ES7243
Es7243Init();
#endif
}
/*
* set codec private data and initialize codec
*/
void es8311_Codec_Startup(uint32_t mclk_freq, uint32_t lrck_freq)
{
ESP_LOGI(TAG, "Enter into es8311_Codec_Startup()\n");
es8311_priv->dmic_enable = false;
es8311_priv->mclkinv = false;
es8311_priv->sclkinv = false;
es8311_priv->pcm_format = I2S_FMT;
es8311_priv->pcm_resolution = LENGTH_16BIT;
es8311_priv->master_slave_mode = SLAVE_MODE;
#ifdef CONFIG_ESP32_KORVO_V1_1_BOARD
es8311_priv->mclk_src = FROM_SCLK_PIN;
#else
es8311_priv->mclk_src = FROM_MCLK_PIN;
#endif
es8311_init(mclk_freq, lrck_freq);
ESP_LOGI(TAG, "Exit es8311_Codec_Startup()\n");
}
// static int Es8311SetAdcDacVolume(int mode, int volume, int dot)
// {
// int res = 0;
// if ( volume < -96 || volume > 0 ) {
// ESP_LOGI(TAG, "Warning: volume < -96! or > 0!\n");
// if (volume < -96) {
// volume = -96;
// } else {
// volume = 0;
// }
// }
// dot = (dot >= 5 ? 1 : 0);
// return res;
// }
esp_err_t Es8311GetRef(bool flag)
{
esp_err_t ret = ESP_OK;
uint8_t regv = 0;
if (flag) {
regv = Es8311ReadReg(ES8311_GPIO_REG44);
regv |= 0x50;
ret |= Es8311WriteReg(ES8311_GPIO_REG44, regv);
} else {
ret |= Es8311WriteReg(ES8311_GPIO_REG44, 0x08);
}
return ret;
}
int Es8311Init(Es8311Config *cfg)
{
es8311_priv = calloc(1, sizeof(struct es8311_private));
I2cInit(&cfg->i2c_cfg, cfg->i2c_port_num); // ESP32 in master mode
es8311_Codec_Startup(11289600, 44100);
return 0;
}
void Es8311Uninit()
{
Es8311WriteReg(ES8311_RESET_REG00, 0x3f);
free(es8311_priv);
es8311_priv = NULL;
}
int Es8311ConfigFmt(ESCodecModule mode, ESCodecI2SFmt fmt)
{
int res = 0;
uint8_t regAdc = 0, regDac = 0;
if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) {
res |= Es8311WriteReg(ES8311_ADC_REG17, 0xBF);
}
if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) {
res |= Es8311WriteReg(ES8311_SYSTEM_REG12, 0x00);
}
regAdc = Es8311ReadReg(ES8311_SDPIN_REG09);
regDac = Es8311ReadReg(ES8311_SDPOUT_REG0A);
switch (fmt) {
case ES_I2S_NORMAL:
ESP_LOGI(TAG, "ES8311 in I2S Format");
regAdc &= ~0x03;
regDac &= ~0x03;
break;
case ES_I2S_LEFT:
case ES_I2S_RIGHT:
ESP_LOGI(TAG, "ES8311 in LJ Format");
regAdc &= ~0x03;
regAdc |= 0x01;
regDac &= ~0x03;
regDac |= 0x01;
break;
case ES_I2S_DSP:
ESP_LOGI(TAG, "ES8311 in DSP Format");
regAdc |= 0x03;
regDac |= 0x03;
break;
default:
ESP_LOGE(TAG, "Not Supported Format");
break;
}
res |= Es8311WriteReg(ES8311_SDPIN_REG09, regAdc);
res |= Es8311WriteReg(ES8311_SDPOUT_REG0A, regDac);
return res;
}
int Es8311I2sConfigClock(ESCodecI2sClock cfg)
{
int res = 0;
return res;
}
int Es8311SetBitsPerSample(ESCodecModule mode, BitsLength bitPerSample)
{
int res = 0;
uint8_t reg = 0;
int bits = (int)bitPerSample;
if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) {
reg = Es8311ReadReg(ES8311_SDPIN_REG09);
reg = reg & 0xe3;
res |= Es8311WriteReg(ES8311_SDPIN_REG09, reg | (bits << 2));
}
if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) {
reg = Es8311ReadReg(ES8311_SDPOUT_REG0A);
reg = reg & 0xe3;
res |= Es8311WriteReg(ES8311_SDPOUT_REG0A, reg | (bits << 2));
}
return res;
}
int Es8311Start(ESCodecModule mode)
{
int res = 0;
if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) {
res |= Es8311WriteReg(ES8311_ADC_REG17, 0xBF);
}
if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) {
res |= Es8311WriteReg(ES8311_SYSTEM_REG12, Es8311ReadReg(ES8311_SYSTEM_REG12) & 0xfd);
}
return res;
}
int Es8311Stop(ESCodecModule mode)
{
int res = 0;
if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) {
res |= Es8311WriteReg(ES8311_ADC_REG17, 0x00);
}
if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) {
res |= Es8311WriteReg(ES8311_SYSTEM_REG12, Es8311ReadReg(ES8311_SYSTEM_REG12) | 0x02);
}
return res;
}
int Es8311SetVoiceVolume(int volume)
{
int res = 0;
if (volume == 0) {
volume = 1;
}
Es8311WriteReg(ES8311_DAC_REG32, volume);
return res;
}
int Es8311GetVoiceVolume(int *volume)
{
int res = ESP_OK;
int regv = Es8311ReadReg(ES8311_DAC_REG32);
if (regv == ESP_FAIL) {
*volume = 0;
res = ESP_FAIL;
} else {
*volume = regv * 100 / 256;
}
ESP_LOGI(TAG, "GET: res:%d, volume:%d\n", regv, *volume);
return res;
}
int Es8311SetVoiceMute(int enable)
{
int res = 0;
ESP_LOGI(TAG, "Es8311SetVoiceMute volume:%d\n", enable);
es8311_mute(enable);
return res;
}
int Es8311GetVoiceMute(int *mute)
{
int res = -1;
uint8_t reg = 0;
res = Es8311ReadReg(ES8311_DAC_REG31);
if (res != ESP_FAIL) {
reg = (res & 0x20) >> 5;
}
*mute = reg;
return res;
}
int Es8311SetMicGain(MicGain gain)
{
int res = 0;
uint8_t gain_n = Es8311ReadReg(ES8311_ADC_REG16) & 0x07;
gain_n |= gain / 6;
res = Es8311WriteReg(ES8311_ADC_REG16, gain_n); // MIC gain scale
return res;
}
int Es8311ConfigAdcInput(AdcInput input)
{
int res = 0;
return res;
}
int Es8311SetAdcVolume(uint8_t adc_vol)
{
int res = 0;
res = Es8311WriteReg(ES8311_ADC_REG17, adc_vol); // MIC ADC Volume
return res;
}
int ES8311WriteReg(uint8_t regAdd, uint8_t data)
{
return Es8311WriteReg(regAdd, data);
}
void Es8311ReadAll()
{
for (int i = 0; i < 0x4A; i++) {
uint8_t reg = Es8311ReadReg(i);
// ets_printf("REG:%02x, %02x\n", reg, i);
}
}

View File

@@ -0,0 +1,25 @@
#ifndef AUDIOSINK_H
#define AUDIOSINK_H
#include <cstdint>
#include <cstdlib>
#include <vector>
class AudioSink
{
public:
AudioSink() {}
virtual ~AudioSink() {}
virtual void feedPCMFrames(const uint8_t *buffer, size_t bytes) = 0;
virtual void volumeChanged(uint16_t volume) {}
// Return false if the sink doesn't support reconfiguration.
virtual bool setParams(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) { return false; }
// Deprecated. Implement/use setParams() instead.
virtual inline bool setRate(uint16_t sampleRate) {
return setParams(sampleRate, 2, 16);
}
bool softwareVolumeControl = true;
bool usign = false;
};
#endif

View File

@@ -0,0 +1,26 @@
#ifndef AC101AUDIOSINK_H
#define AC101AUDIOSINK_H
#include <vector>
#include <iostream>
#include "BufferedAudioSink.h"
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#include "ac101.h"
#include "adac.h"
class AC101AudioSink : public BufferedAudioSink
{
public:
AC101AudioSink();
~AC101AudioSink();
void volumeChanged(uint16_t volume);
private:
adac_s *dac;
};
#endif

View File

@@ -0,0 +1,25 @@
#ifndef BUFFEREDAUDIOSINK_H
#define BUFFEREDAUDIOSINK_H
#include <vector>
#include <iostream>
#include "AudioSink.h"
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
class BufferedAudioSink : public AudioSink
{
public:
void feedPCMFrames(const uint8_t *buffer, size_t bytes) override;
bool setParams(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) override;
protected:
void startI2sFeed(size_t buf_size = 4096 * 8);
void feedPCMFramesInternal(const void *pvItem, size_t xItemSize);
private:
};
#endif

View File

@@ -0,0 +1,28 @@
#ifndef ES8311AUDIOSINK_H
#define ES8311AUDIOSINK_H
#include "driver/i2s.h"
#include <vector>
#include <iostream>
#include "BufferedAudioSink.h"
#include <stdio.h>
#include <string.h>
#include "driver/gpio.h"
#include "driver/i2c.h"
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
class ES8311AudioSink : public BufferedAudioSink
{
public:
ES8311AudioSink();
~ES8311AudioSink();
void writeReg(uint8_t reg_add, uint8_t data);
void volumeChanged(uint16_t volume);
void setSampleRate(uint32_t sampleRate);
private:
};
#endif

View File

@@ -0,0 +1,105 @@
#ifndef ES8388AUDIOSINK_H
#define ES8388AUDIOSINK_H
#include "driver/i2s.h"
#include <driver/i2c.h>
#include <vector>
#include <iostream>
#include "BufferedAudioSink.h"
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#define ES8388_ADDR 0x20
#define ACK_CHECK_EN 0x1
/* ES8388 register */
#define ES8388_CONTROL1 0x00
#define ES8388_CONTROL2 0x01
#define ES8388_CHIPPOWER 0x02
#define ES8388_ADCPOWER 0x03
#define ES8388_DACPOWER 0x04
#define ES8388_CHIPLOPOW1 0x05
#define ES8388_CHIPLOPOW2 0x06
#define ES8388_ANAVOLMANAG 0x07
#define ES8388_MASTERMODE 0x08
/* ADC */
#define ES8388_ADCCONTROL1 0x09
#define ES8388_ADCCONTROL2 0x0a
#define ES8388_ADCCONTROL3 0x0b
#define ES8388_ADCCONTROL4 0x0c
#define ES8388_ADCCONTROL5 0x0d
#define ES8388_ADCCONTROL6 0x0e
#define ES8388_ADCCONTROL7 0x0f
#define ES8388_ADCCONTROL8 0x10
#define ES8388_ADCCONTROL9 0x11
#define ES8388_ADCCONTROL10 0x12
#define ES8388_ADCCONTROL11 0x13
#define ES8388_ADCCONTROL12 0x14
#define ES8388_ADCCONTROL13 0x15
#define ES8388_ADCCONTROL14 0x16
/* DAC */
#define ES8388_DACCONTROL1 0x17
#define ES8388_DACCONTROL2 0x18
#define ES8388_DACCONTROL3 0x19
#define ES8388_DACCONTROL4 0x1a
#define ES8388_DACCONTROL5 0x1b
#define ES8388_DACCONTROL6 0x1c
#define ES8388_DACCONTROL7 0x1d
#define ES8388_DACCONTROL8 0x1e
#define ES8388_DACCONTROL9 0x1f
#define ES8388_DACCONTROL10 0x20
#define ES8388_DACCONTROL11 0x21
#define ES8388_DACCONTROL12 0x22
#define ES8388_DACCONTROL13 0x23
#define ES8388_DACCONTROL14 0x24
#define ES8388_DACCONTROL15 0x25
#define ES8388_DACCONTROL16 0x26
#define ES8388_DACCONTROL17 0x27
#define ES8388_DACCONTROL18 0x28
#define ES8388_DACCONTROL19 0x29
#define ES8388_DACCONTROL20 0x2a
#define ES8388_DACCONTROL21 0x2b
#define ES8388_DACCONTROL22 0x2c
#define ES8388_DACCONTROL23 0x2d
#define ES8388_DACCONTROL24 0x2e
#define ES8388_DACCONTROL25 0x2f
#define ES8388_DACCONTROL26 0x30
#define ES8388_DACCONTROL27 0x31
#define ES8388_DACCONTROL28 0x32
#define ES8388_DACCONTROL29 0x33
#define ES8388_DACCONTROL30 0x34
class ES8388AudioSink : public BufferedAudioSink
{
public:
ES8388AudioSink();
~ES8388AudioSink();
bool begin(int sda = -1, int scl = -1, uint32_t frequency = 400000U);
enum ES8388_OUT
{
ES_MAIN, // this is the DAC output volume (both outputs)
ES_OUT1, // this is the additional gain for OUT1
ES_OUT2 // this is the additional gain for OUT2
};
void mute(const ES8388_OUT out, const bool muted);
void volume(const ES8388_OUT out, const uint8_t vol);
void writeReg(uint8_t reg_add, uint8_t data);
private:
i2c_config_t i2c_config;
i2c_port_t i2c_port = 0;
};
#endif

View File

@@ -0,0 +1,22 @@
#ifndef ES9018AUDIOSINK_H
#define ES9018AUDIOSINK_H
#include <vector>
#include <iostream>
#include "BufferedAudioSink.h"
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
class ES9018AudioSink : public BufferedAudioSink
{
public:
ES9018AudioSink();
~ES9018AudioSink();
private:
};
#endif

View File

@@ -0,0 +1,22 @@
#ifndef INTERNALAUDIOSINK_H
#define INTERNALAUDIOSINK_H
#include <vector>
#include <iostream>
#include "BufferedAudioSink.h"
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
class InternalAudioSink : public BufferedAudioSink
{
public:
InternalAudioSink();
~InternalAudioSink();
private:
};
#endif

View File

@@ -0,0 +1,22 @@
#ifndef PCM5102AUDIOSINK_H
#define PCM5102AUDIOSINK_H
#include <vector>
#include <iostream>
#include "BufferedAudioSink.h"
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
class PCM5102AudioSink : public BufferedAudioSink
{
public:
PCM5102AudioSink();
~PCM5102AudioSink();
private:
};
#endif

View File

@@ -0,0 +1,26 @@
#ifndef SPDIFAUDIOSINK_H
#define SPDIFAUDIOSINK_H
#include <vector>
#include <iostream>
#include "BufferedAudioSink.h"
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
class SPDIFAudioSink : public BufferedAudioSink
{
private:
uint8_t spdifPin;
public:
explicit SPDIFAudioSink(uint8_t spdifPin);
~SPDIFAudioSink() override;
void feedPCMFrames(const uint8_t *buffer, size_t bytes) override;
bool setParams(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) override;
private:
};
#endif

View File

@@ -0,0 +1,30 @@
#ifndef TAS5711AUDIOSINK_H
#define TAS5711AUDIOSINK_H
#include "driver/i2s.h"
#include <driver/i2c.h>
#include <vector>
#include <iostream>
#include "BufferedAudioSink.h"
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
class TAS5711AudioSink : public BufferedAudioSink
{
public:
TAS5711AudioSink();
~TAS5711AudioSink();
void writeReg(uint8_t reg, uint8_t value);
private:
i2c_config_t i2c_config;
i2c_port_t i2c_port = 0;
};
#endif

View File

@@ -0,0 +1,176 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __AC101_H__
#define __AC101_H__
#include "esp_types.h"
#define AC101_ADDR 0x1a /*!< Device address*/
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
#define ACK_VAL 0x0 /*!< I2C ack value */
#define NACK_VAL 0x1 /*!< I2C nack value */
#define CHIP_AUDIO_RS 0x00
#define PLL_CTRL1 0x01
#define PLL_CTRL2 0x02
#define SYSCLK_CTRL 0x03
#define MOD_CLK_ENA 0x04
#define MOD_RST_CTRL 0x05
#define I2S_SR_CTRL 0x06
#define I2S1LCK_CTRL 0x10
#define I2S1_SDOUT_CTRL 0x11
#define I2S1_SDIN_CTRL 0x12
#define I2S1_MXR_SRC 0x13
#define I2S1_VOL_CTRL1 0x14
#define I2S1_VOL_CTRL2 0x15
#define I2S1_VOL_CTRL3 0x16
#define I2S1_VOL_CTRL4 0x17
#define I2S1_MXR_GAIN 0x18
#define ADC_DIG_CTRL 0x40
#define ADC_VOL_CTRL 0x41
#define HMIC_CTRL1 0x44
#define HMIC_CTRL2 0x45
#define HMIC_STATUS 0x46
#define DAC_DIG_CTRL 0x48
#define DAC_VOL_CTRL 0x49
#define DAC_MXR_SRC 0x4c
#define DAC_MXR_GAIN 0x4d
#define ADC_ANA_CTRL 0x50
#define ADC_SRC 0x51
#define ADC_SRCBST_CTRL 0x52
#define OMIXER_DACA_CTRL 0x53
#define OMIXER_SR 0x54
#define OMIXER_BST1_CTRL 0x55
#define HPOUT_CTRL 0x56
#define SPKOUT_CTRL 0x58
#define AC_DAC_DAPCTRL 0xa0
#define AC_DAC_DAPHHPFC 0xa1
#define AC_DAC_DAPLHPFC 0xa2
#define AC_DAC_DAPLHAVC 0xa3
#define AC_DAC_DAPLLAVC 0xa4
#define AC_DAC_DAPRHAVC 0xa5
#define AC_DAC_DAPRLAVC 0xa6
#define AC_DAC_DAPHGDEC 0xa7
#define AC_DAC_DAPLGDEC 0xa8
#define AC_DAC_DAPHGATC 0xa9
#define AC_DAC_DAPLGATC 0xaa
#define AC_DAC_DAPHETHD 0xab
#define AC_DAC_DAPLETHD 0xac
#define AC_DAC_DAPHGKPA 0xad
#define AC_DAC_DAPLGKPA 0xae
#define AC_DAC_DAPHGOPA 0xaf
#define AC_DAC_DAPLGOPA 0xb0
#define AC_DAC_DAPOPT 0xb1
#define DAC_DAP_ENA 0xb5
typedef enum{
SAMPLE_RATE_8000 = 0x0000,
SAMPLE_RATE_11052 = 0x1000,
SAMPLE_RATE_12000 = 0x2000,
SAMPLE_RATE_16000 = 0x3000,
SAMPLE_RATE_22050 = 0x4000,
SAMPLE_RATE_24000 = 0x5000,
SAMPLE_RATE_32000 = 0x6000,
SAMPLE_RATE_44100 = 0x7000,
SAMPLE_RATE_48000 = 0x8000,
SAMPLE_RATE_96000 = 0x9000,
SAMPLE_RATE_192000 = 0xa000,
} ac_adda_fs_i2s1_t;
typedef enum{
BCLK_DIV_1 = 0x0,
BCLK_DIV_2 = 0x1,
BCLK_DIV_4 = 0x2,
BCLK_DIV_6 = 0x3,
BCLK_DIV_8 = 0x4,
BCLK_DIV_12 = 0x5,
BCLK_DIV_16 = 0x6,
BCLK_DIV_24 = 0x7,
BCLK_DIV_32 = 0x8,
BCLK_DIV_48 = 0x9,
BCLK_DIV_64 = 0xa,
BCLK_DIV_96 = 0xb,
BCLK_DIV_128 = 0xc,
BCLK_DIV_192 = 0xd,
} ac_i2s1_bclk_div_t;
typedef enum{
LRCK_DIV_16 =0x0,
LRCK_DIV_32 =0x1,
LRCK_DIV_64 =0x2,
LRCK_DIV_128 =0x3,
LRCK_DIV_256 =0x4,
} ac_i2s1_lrck_div_t;
typedef enum {
BIT_LENGTH_8_BITS = 0x00,
BIT_LENGTH_16_BITS = 0x01,
BIT_LENGTH_20_BITS = 0x02,
BIT_LENGTH_24_BITS = 0x03,
} ac_bits_length_t;
typedef enum {
AC_MODE_MIN = -1,
AC_MODE_SLAVE = 0x00,
AC_MODE_MASTER = 0x01,
AC_MODE_MAX,
} ac_mode_sm_t;
typedef enum {
AC_MODULE_MIN = -1,
AC_MODULE_ADC = 0x01,
AC_MODULE_DAC = 0x02,
AC_MODULE_ADC_DAC = 0x03,
AC_MODULE_LINE = 0x04,
AC_MODULE_MAX
} ac_module_t;
typedef enum{
SRC_MIC1 = 1,
SRC_MIC2 = 2,
SRC_LINEIN = 3,
}ac_output_mixer_source_t;
typedef enum {
GAIN_N45DB = 0,
GAIN_N30DB = 1,
GAIN_N15DB = 2,
GAIN_0DB = 3,
GAIN_15DB = 4,
GAIN_30DB = 5,
GAIN_45DB = 6,
GAIN_60DB = 7,
} ac_output_mixer_gain_t;
typedef struct {
ac_i2s1_bclk_div_t bclk_div; /*!< bits clock divide */
ac_i2s1_lrck_div_t lclk_div; /*!< WS clock divide */
} ac_i2s_clock_t;
#endif

View File

@@ -0,0 +1,28 @@
/*
* Squeezelite for esp32
*
* (c) Sebastien 2019
* Philippe G. 2019, philippe_44@outlook.com
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*
*/
#include "freertos/FreeRTOS.h"
#include "driver/i2s.h"
typedef enum { ADAC_ON = 0, ADAC_STANDBY, ADAC_OFF } adac_power_e;
struct adac_s {
bool (*init)(int i2c_port_num, int i2s_num, i2s_config_t *config);
void (*deinit)(void);
void (*power)(adac_power_e mode);
void (*speaker)(bool active);
void (*headset)(bool active);
void (*volume)(unsigned left, unsigned right);
};
extern struct adac_s dac_tas57xx;
extern struct adac_s dac_a1s;
extern struct adac_s dac_external;

View File

@@ -0,0 +1,122 @@
/*
* ES8311.h -- ES8311 ALSA SoC Audio Codec
*
* Authors:
*
* Based on ES8374.h by David Yang
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ES8311_H
#define _ES8311_H
#include "driver/i2c.h"
#include "esxxx_common.h"
/*
* ES8311_REGISTER NAME_REG_REGISTER ADDRESS
*/
#define ES8311_RESET_REG00 0x00 /*reset digital,csm,clock manager etc.*/
/*
* Clock Scheme Register definition
*/
#define ES8311_CLK_MANAGER_REG01 0x01 /* select clk src for mclk, enable clock for codec */
#define ES8311_CLK_MANAGER_REG02 0x02 /* clk divider and clk multiplier */
#define ES8311_CLK_MANAGER_REG03 0x03 /* adc fsmode and osr */
#define ES8311_CLK_MANAGER_REG04 0x04 /* dac osr */
#define ES8311_CLK_MANAGER_REG05 0x05 /* clk divier for adc and dac */
#define ES8311_CLK_MANAGER_REG06 0x06 /* bclk inverter and divider */
#define ES8311_CLK_MANAGER_REG07 0x07 /* tri-state, lrck divider */
#define ES8311_CLK_MANAGER_REG08 0x08 /* lrck divider */
#define ES8311_SDPIN_REG09 0x09 /* dac serial digital port */
#define ES8311_SDPOUT_REG0A 0x0A /* adc serial digital port */
#define ES8311_SYSTEM_REG0B 0x0B /* system */
#define ES8311_SYSTEM_REG0C 0x0C /* system */
#define ES8311_SYSTEM_REG0D 0x0D /* system, power up/down */
#define ES8311_SYSTEM_REG0E 0x0E /* system, power up/down */
#define ES8311_SYSTEM_REG0F 0x0F /* system, low power */
#define ES8311_SYSTEM_REG10 0x10 /* system */
#define ES8311_SYSTEM_REG11 0x11 /* system */
#define ES8311_SYSTEM_REG12 0x12 /* system, Enable DAC */
#define ES8311_SYSTEM_REG13 0x13 /* system */
#define ES8311_SYSTEM_REG14 0x14 /* system, select DMIC, select analog pga gain */
#define ES8311_ADC_REG15 0x15 /* ADC, adc ramp rate, dmic sense */
#define ES8311_ADC_REG16 0x16 /* ADC */
#define ES8311_ADC_REG17 0x17 /* ADC, volume */
#define ES8311_ADC_REG18 0x18 /* ADC, alc enable and winsize */
#define ES8311_ADC_REG19 0x19 /* ADC, alc maxlevel */
#define ES8311_ADC_REG1A 0x1A /* ADC, alc automute */
#define ES8311_ADC_REG1B 0x1B /* ADC, alc automute, adc hpf s1 */
#define ES8311_ADC_REG1C 0x1C /* ADC, equalizer, hpf s2 */
#define ES8311_DAC_REG31 0x31 /* DAC, mute */
#define ES8311_DAC_REG32 0x32 /* DAC, volume */
#define ES8311_DAC_REG33 0x33 /* DAC, offset */
#define ES8311_DAC_REG34 0x34 /* DAC, drc enable, drc winsize */
#define ES8311_DAC_REG35 0x35 /* DAC, drc maxlevel, minilevel */
#define ES8311_DAC_REG37 0x37 /* DAC, ramprate */
#define ES8311_GPIO_REG44 0x44 /* GPIO, dac2adc for test */
#define ES8311_GP_REG45 0x45 /* GP CONTROL */
#define ES8311_CHD1_REGFD 0xFD /* CHIP ID1 */
#define ES8311_CHD2_REGFE 0xFE /* CHIP ID2 */
#define ES8311_CHVER_REGFF 0xFF /* VERSION */
#define ES8311_CHD1_REGFD 0xFD /* CHIP ID1 */
#define ES8311_MAX_REGISTER 0xFF
typedef struct {
ESCodecMode esMode;
i2c_port_t i2c_port_num;
i2c_config_t i2c_cfg;
DacOutput dacOutput;
AdcInput adcInput;
} Es8311Config;
#define AUDIO_CODEC_ES8311_DEFAULT(){ \
.esMode = ES_MODE_SLAVE, \
.i2c_port_num = I2C_NUM_0, \
.i2c_cfg = { \
.mode = I2C_MODE_MASTER, \
.sda_io_num = IIC_DATA, \
.scl_io_num = IIC_CLK, \
.sda_pullup_en = GPIO_PULLUP_ENABLE,\
.scl_pullup_en = GPIO_PULLUP_ENABLE,\
.master.clk_speed = 100000\
}, \
.adcInput = ADC_INPUT_LINPUT1_RINPUT1,\
.dacOutput = DAC_OUTPUT_LOUT1 | DAC_OUTPUT_LOUT2 | DAC_OUTPUT_ROUT1 | DAC_OUTPUT_ROUT2,\
};
int Es8311Init(Es8311Config *cfg);
void Es8311Uninit();
esp_err_t Es8311GetRef(bool flag);
esp_err_t Es7243Init(void);
int Es7243ReadReg(uint8_t regAdd);
int Es8311ConfigFmt(ESCodecModule mode, ESCodecI2SFmt fmt);
int Es8311I2sConfigClock(ESCodecI2sClock cfg);
int Es8311SetBitsPerSample(ESCodecModule mode, BitsLength bitPerSample);
void es8311_Codec_Startup(uint32_t mclk_freq, uint32_t lrck_freq);
int Es8311Start(ESCodecModule mode);
int Es8311Stop(ESCodecModule mode);
int Es8311SetVoiceVolume(int volume);
int Es8311GetVoiceVolume(int *volume);
int Es8311SetVoiceMute(int enable);
int Es8311GetVoiceMute(int *mute);
int Es8311SetMicGain(MicGain gain);
int Es8311ConfigAdcInput(AdcInput input);
int Es8311ConfigDacOutput(DacOutput output);
int ES8311WriteReg(uint8_t regAdd, uint8_t data);
void Es8311ReadAll();
int Es8311ReadReg(uint8_t regAdd);
#endif

View File

@@ -0,0 +1,166 @@
#ifndef __ESCODEC_COMMON_H__
#define __ESCODEC_COMMON_H__
typedef enum BitsLength {
BIT_LENGTH_MIN = -1,
BIT_LENGTH_16BITS = 0x03,
BIT_LENGTH_18BITS = 0x02,
BIT_LENGTH_20BITS = 0x01,
BIT_LENGTH_24BITS = 0x00,
BIT_LENGTH_32BITS = 0x04,
BIT_LENGTH_MAX,
} BitsLength;
typedef enum {
SAMPLE_RATE_MIN = -1,
SAMPLE_RATE_16K,
SAMPLE_RATE_32K,
SAMPLE_RATE_44_1K,
SAMPLE_RATE_MAX,
} SampleRate;
typedef enum {
MclkDiv_MIN = -1,
MclkDiv_1 = 1,
MclkDiv_2 = 2,
MclkDiv_3 = 3,
MclkDiv_4 = 4,
MclkDiv_6 = 5,
MclkDiv_8 = 6,
MclkDiv_9 = 7,
MclkDiv_11 = 8,
MclkDiv_12 = 9,
MclkDiv_16 = 10,
MclkDiv_18 = 11,
MclkDiv_22 = 12,
MclkDiv_24 = 13,
MclkDiv_33 = 14,
MclkDiv_36 = 15,
MclkDiv_44 = 16,
MclkDiv_48 = 17,
MclkDiv_66 = 18,
MclkDiv_72 = 19,
MclkDiv_5 = 20,
MclkDiv_10 = 21,
MclkDiv_15 = 22,
MclkDiv_17 = 23,
MclkDiv_20 = 24,
MclkDiv_25 = 25,
MclkDiv_30 = 26,
MclkDiv_32 = 27,
MclkDiv_34 = 28,
MclkDiv_7 = 29,
MclkDiv_13 = 30,
MclkDiv_14 = 31,
MclkDiv_MAX,
} SclkDiv;
typedef enum {
LclkDiv_MIN = -1,
LclkDiv_128 = 0,
LclkDiv_192 = 1,
LclkDiv_256 = 2,
LclkDiv_384 = 3,
LclkDiv_512 = 4,
LclkDiv_576 = 5,
LclkDiv_768 = 6,
LclkDiv_1024 = 7,
LclkDiv_1152 = 8,
LclkDiv_1408 = 9,
LclkDiv_1536 = 10,
LclkDiv_2112 = 11,
LclkDiv_2304 = 12,
LclkDiv_125 = 16,
LclkDiv_136 = 17,
LclkDiv_250 = 18,
LclkDiv_272 = 19,
LclkDiv_375 = 20,
LclkDiv_500 = 21,
LclkDiv_544 = 22,
LclkDiv_750 = 23,
LclkDiv_1000 = 24,
LclkDiv_1088 = 25,
LclkDiv_1496 = 26,
LclkDiv_1500 = 27,
LclkDiv_MAX,
} LclkDiv;
typedef enum {
ADC_INPUT_MIN = -1,
ADC_INPUT_LINPUT1_RINPUT1 = 0x00,
ADC_INPUT_MIC1 = 0x05,
ADC_INPUT_MIC2 = 0x06,
ADC_INPUT_LINPUT2_RINPUT2 = 0x50,
ADC_INPUT_DIFFERENCE = 0xf0,
ADC_INPUT_MAX,
} AdcInput;
typedef enum {
DAC_OUTPUT_MIN = -1,
DAC_OUTPUT_LOUT1 = 0x04,
DAC_OUTPUT_LOUT2 = 0x08,
DAC_OUTPUT_SPK = 0x09,
DAC_OUTPUT_ROUT1 = 0x10,
DAC_OUTPUT_ROUT2 = 0x20,
DAC_OUTPUT_ALL = 0x3c,
DAC_OUTPUT_MAX,
} DacOutput;
typedef enum {
D2SE_PGA_GAIN_MIN = -1,
D2SE_PGA_GAIN_DIS = 0,
D2SE_PGA_GAIN_EN = 1,
D2SE_PGA_GAIN_MAX = 2,
} D2SEPGA;
typedef enum {
MIC_GAIN_MIN = -1,
MIC_GAIN_0DB = 0,
MIC_GAIN_3DB = 3,
MIC_GAIN_6DB = 6,
MIC_GAIN_9DB = 9,
MIC_GAIN_12DB = 12,
MIC_GAIN_15DB = 15,
MIC_GAIN_18DB = 18,
MIC_GAIN_21DB = 21,
MIC_GAIN_24DB = 24,
#if defined CONFIG_CODEC_CHIP_IS_ES8311
MIC_GAIN_30DB = 30,
MIC_GAIN_36DB = 36,
MIC_GAIN_42DB = 42,
#endif
MIC_GAIN_MAX,
} MicGain;
typedef enum {
ES_MODULE_MIN = -1,
ES_MODULE_ADC = 0x01,
ES_MODULE_DAC = 0x02,
ES_MODULE_ADC_DAC = 0x03,
ES_MODULE_LINE = 0x04,
ES_MODULE_MAX
} ESCodecModule;
typedef enum {
ES_MODE_MIN = -1,
ES_MODE_SLAVE = 0x00,
ES_MODE_MASTER = 0x01,
ES_MODE_MAX,
} ESCodecMode;
typedef enum {
ES_ = -1,
ES_I2S_NORMAL = 0,
ES_I2S_LEFT = 1,
ES_I2S_RIGHT = 2,
ES_I2S_DSP = 3,
ES_I2S_MAX
} ESCodecI2SFmt;
typedef struct {
SclkDiv sclkDiv;
LclkDiv lclkDiv;
} ESCodecI2sClock;
#endif //__ESCODEC_COMMON_H__

View File

@@ -0,0 +1,124 @@
#pragma once
#include <vector>
#include <fstream>
#include "AudioSink.h"
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <BellTask.h>
#include <unistd.h>
#include <memory>
#include <mutex>
#define PCM_DEVICE "default"
template <typename T, int SIZE>
class RingbufferPointer
{
typedef std::unique_ptr<T> TPointer;
public:
explicit RingbufferPointer()
{
// create objects
for (int i = 0; i < SIZE; i++)
{
buf_[i] = std::make_unique<T>();
}
}
bool push(TPointer &item)
{
std::lock_guard<std::mutex> lock(mutex_);
if (full())
return false;
std::swap(buf_[head_], item);
if (full_)
tail_ = (tail_ + 1) % max_size_;
head_ = (head_ + 1) % max_size_;
full_ = head_ == tail_;
return true;
}
bool pop(TPointer &item)
{
std::lock_guard<std::mutex> lock(mutex_);
if (empty())
return false;
std::swap(buf_[tail_], item);
full_ = false;
tail_ = (tail_ + 1) % max_size_;
return true;
}
void reset()
{
std::lock_guard<std::mutex> lock(mutex_);
head_ = tail_;
full_ = false;
}
bool empty() const
{
return (!full_ && (head_ == tail_));
}
bool full() const
{
return full_;
}
int capacity() const
{
return max_size_;
}
int size() const
{
int size = max_size_;
if (!full_)
{
if (head_ >= tail_)
size = head_ - tail_;
else
size = max_size_ + head_ - tail_;
}
return size;
}
private:
TPointer buf_[SIZE];
std::mutex mutex_;
int head_ = 0;
int tail_ = 0;
const int max_size_ = SIZE;
bool full_ = 0;
};
class ALSAAudioSink : public AudioSink, public bell::Task
{
public:
ALSAAudioSink();
~ALSAAudioSink();
void feedPCMFrames(const uint8_t *buffer, size_t bytes);
void runTask();
private:
RingbufferPointer<std::vector<uint8_t>, 3> ringbuffer;
unsigned int pcm;
snd_pcm_t *pcm_handle;
snd_pcm_hw_params_t *params;
snd_pcm_uframes_t frames;
int buff_size;
std::vector<uint8_t> buff;
};

View File

@@ -0,0 +1,16 @@
#pragma once
#include <vector>
#include <fstream>
#include "AudioSink.h"
class NamedPipeAudioSink : public AudioSink
{
public:
NamedPipeAudioSink();
~NamedPipeAudioSink();
void feedPCMFrames(const uint8_t *buffer, size_t bytes);
private:
std::ofstream namedPipeFile;
};

View File

@@ -0,0 +1,19 @@
#pragma once
#include <cstdint>
#include <iostream>
#include <vector>
#include "AudioSink.h"
#include "portaudio.h"
class PortAudioSink : public AudioSink {
public:
PortAudioSink();
~PortAudioSink() override;
void feedPCMFrames(const uint8_t* buffer, size_t bytes) override;
bool setParams(uint32_t sampleRate, uint8_t channelCount,
uint8_t bitDepth) override;
private:
PaStream* stream = nullptr;
};

View File

@@ -0,0 +1,101 @@
#include "ALSAAudioSink.h"
ALSAAudioSink::ALSAAudioSink() : Task("", 0, 0, 0)
{
/* Open the PCM device in playback mode */
if (pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE,
SND_PCM_STREAM_PLAYBACK, 0) < 0)
{
printf("ERROR: Can't open \"%s\" PCM device. %s\n",
PCM_DEVICE, snd_strerror(pcm));
}
/* Allocate parameters object and fill it with default values*/
snd_pcm_hw_params_alloca(&params);
snd_pcm_hw_params_any(pcm_handle, params);
/* Set parameters */
if (pcm = snd_pcm_hw_params_set_access(pcm_handle, params,
SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm));
if (pcm = snd_pcm_hw_params_set_format(pcm_handle, params,
SND_PCM_FORMAT_S16_LE) < 0)
printf("ERROR: Can't set format. %s\n", snd_strerror(pcm));
if (pcm = snd_pcm_hw_params_set_channels(pcm_handle, params, 2) < 0)
printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm));
unsigned int rate = 44100;
if (pcm = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0) < 0)
printf("ERROR: Can't set rate. %s\n", snd_strerror(pcm));
unsigned int periodTime = 800;
int dir = -1;
snd_pcm_hw_params_set_period_time_near(pcm_handle, params, &periodTime, &dir);
/* Write parameters */
if (pcm = snd_pcm_hw_params(pcm_handle, params) < 0)
printf("ERROR: Can't set harware parameters. %s\n", snd_strerror(pcm));
/* Resume information */
printf("PCM name: '%s'\n", snd_pcm_name(pcm_handle));
printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle)));
unsigned int tmp;
snd_pcm_hw_params_get_channels(params, &tmp);
printf("channels: %i ", tmp);
if (tmp == 1)
printf("(mono)\n");
else if (tmp == 2)
printf("(stereo)\n");
snd_pcm_hw_params_get_period_time(params, &tmp, NULL);
printf("period_time = %d\n", tmp);
snd_pcm_hw_params_get_period_size(params, &frames, 0);
this->buff_size = frames * 2 * 2 /* 2 -> sample size */;
printf("required buff_size: %d\n", buff_size);
this->startTask();
}
ALSAAudioSink::~ALSAAudioSink()
{
snd_pcm_drain(pcm_handle);
snd_pcm_close(pcm_handle);
}
void ALSAAudioSink::runTask()
{
std::unique_ptr<std::vector<uint8_t>> dataPtr;
while (true)
{
if (!this->ringbuffer.pop(dataPtr))
{
usleep(100);
continue;
}
if (pcm = snd_pcm_writei(pcm_handle, dataPtr->data(), this->frames) == -EPIPE)
{
snd_pcm_prepare(pcm_handle);
}
else if (pcm < 0)
{
printf("ERROR. Can't write to PCM device. %s\n", snd_strerror(pcm));
}
}
}
void ALSAAudioSink::feedPCMFrames(const uint8_t *buffer, size_t bytes)
{
buff.insert(buff.end(), buffer, buffer + bytes);
while (buff.size() > this->buff_size)
{
auto ptr = std::make_unique<std::vector<uint8_t>>(this->buff.begin(), this->buff.begin() + this->buff_size);
this->buff = std::vector<uint8_t>(this->buff.begin() + this->buff_size, this->buff.end());
while (!this->ringbuffer.push(ptr))
{
usleep(100);
};
}
}

View File

@@ -0,0 +1,21 @@
#include "NamedPipeAudioSink.h"
NamedPipeAudioSink::NamedPipeAudioSink()
{
printf("Start\n");
this->namedPipeFile = std::ofstream("outputFifo", std::ios::binary);
printf("stop\n");
}
NamedPipeAudioSink::~NamedPipeAudioSink()
{
this->namedPipeFile.close();
}
void NamedPipeAudioSink::feedPCMFrames(const uint8_t *buffer, size_t bytes)
{
// Write the actual data
this->namedPipeFile.write((char*)buffer, (long)bytes);
this->namedPipeFile.flush();
}

View File

@@ -0,0 +1,65 @@
#include "PortAudioSink.h"
PortAudioSink::PortAudioSink()
{
Pa_Initialize();
this->setParams(44100, 2, 16);
}
bool PortAudioSink::setParams(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) {
if (stream) {
Pa_StopStream(stream);
}
PaStreamParameters outputParameters;
outputParameters.device = Pa_GetDefaultOutputDevice();
if (outputParameters.device == paNoDevice) {
printf("PortAudio: Default audio device not found!\n");
// exit(0);
}
printf("PortAudio: Default audio device not found!\n");
outputParameters.channelCount = channelCount;
switch (bitDepth) {
case 32:
outputParameters.sampleFormat = paInt32;
break;
case 24:
outputParameters.sampleFormat = paInt24;
break;
case 16:
outputParameters.sampleFormat = paInt16;
break;
case 8:
outputParameters.sampleFormat = paInt8;
break;
default:
outputParameters.sampleFormat = paInt16;
break;
}
outputParameters.suggestedLatency = 0.050;
outputParameters.hostApiSpecificStreamInfo = NULL;
PaError err = Pa_OpenStream(
&stream,
NULL,
&outputParameters,
sampleRate,
4096 / (channelCount * bitDepth / 8),
paClipOff,
NULL, // blocking api
NULL
);
Pa_StartStream(stream);
return !err;
}
PortAudioSink::~PortAudioSink()
{
Pa_StopStream(stream);
Pa_Terminate();
}
void PortAudioSink::feedPCMFrames(const uint8_t *buffer, size_t bytes)
{
Pa_WriteStream(stream, buffer, bytes / 4);
}