pd working using low-level i2s audio driver, output only so far.

This commit is contained in:
Miller Puckette 2021-07-10 21:37:02 -07:00
parent 44c02f82ac
commit fc1c3bce26
8 changed files with 395 additions and 660 deletions

View file

@ -4,4 +4,4 @@ cmake_minimum_required(VERSION 3.5)
include($ENV{ADF_PATH}/CMakeLists.txt)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(bt_spp_acceptor_demo)
project(espd)

View file

@ -1,16 +1,3 @@
qESP-IDF BT-SPP-ACCEPTOR demo
======================
enter menuconfig "Component config", choose "Bluetooth"
enter menu Bluetooth, choose "Classic Bluetooth" and "SPP Profile"
Demo of SPP acceptor role
This is the demo for user to use ESP_APIs to create a SPP acceptor.
Options choose step:
1. make menuconfig.
2. enter menuconfig "Component config", choose "Bluetooth"
3. enter menu Bluetooth, choose "Classic Bluetooth" and "SPP Profile"
4. choose your options.
Then set SPP_SHOW_MODE as SPP_SHOW_DATA or SPP_SHOW_SPEED in code(should be same with bt_spp_initator).
After the program started, bt_spp_initator will connect it and send data.

View file

@ -1,4 +1,4 @@
set(COMPONENT_SRCS "weasel.c fifostream.c pdmain.c \
set(COMPONENT_SRCS "espd.c pdmain.c \
../pd/src/g_canvas.c \
../pd/src/g_graph.c \
../pd/src/g_text.c \
@ -25,7 +25,12 @@ set(COMPONENT_SRCS "weasel.c fifostream.c pdmain.c \
../pd/src/d_osc.c \
../pd/src/d_ctl.c \
../pd/src/d_arithmetic.c \
../pd/src/d_array.c \
../pd/src/d_dac.c \
../pd/src/d_delay.c \
../pd/src/d_filter.c \
../pd/src/d_math.c \
../pd/src/d_misc.c \
../pd/src/x_arithmetic.c \
../pd/src/x_connective.c \
../pd/src/x_interface.c \
@ -37,6 +42,9 @@ set(COMPONENT_SRCS "weasel.c fifostream.c pdmain.c \
../pd/src/x_scalar.c \
../pd/src/x_text.c \
../pd/src/x_list.c \
../pd/src/x_vexp.c \
../pd/src/x_vexp_fun.c \
../pd/src/x_vexp_if.c \
")

317
main/espd.c Normal file
View file

@ -0,0 +1,317 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "audio_element.h"
#include "audio_pipeline.h"
#include "audio_event_iface.h"
#include "audio_mem.h"
#include "audio_common.h"
#include "i2s_stream.h"
#include "mp3_decoder.h"
#include "filter_resample.h"
#include "board.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gap_bt_api.h"
#include "esp_bt_device.h"
#include "esp_spp_api.h"
#include "esp_peripherals.h"
#include "periph_sdcard.h"
#include "nvs.h"
#include "nvs_flash.h"
static const char *TAG = "ESPD";
#define TEST_I2S_NUM I2S_NUM_0
extern void pdmain_tick( void);
void pdmain_init( void);
void bt_init( void);
void sd_init( void);
#define INCHANS 1
#define OUTCHANS 1
#define BLKSIZE 64
float soundin[OUTCHANS * BLKSIZE], soundout[OUTCHANS * BLKSIZE];
void senddacs( void)
{
int i, ret;
size_t written;
short poodle[OUTCHANS * BLKSIZE];
for (i = 0; i < BLKSIZE; i+= OUTCHANS)
{
int ch1 = 32767*soundout[i];
if (ch1 > 32767)
ch1 = 32767;
else if (ch1 < -32768)
ch1 = -32768;
poodle[i] = ch1;
/*
ch1 = 32767*soundout[BLKSIZE+i];
if (ch1 > 32767)
ch1 = 32767;
else if (ch1 < -32768)
ch1 = -32768;
poodle[i+1] = ch2; */
soundout[i] = 0;
}
ret = i2s_write(TEST_I2S_NUM, poodle, sizeof(poodle), &written,
portMAX_DELAY);
if (ret != ESP_OK)
ESP_LOGE(TAG, "error writing");
}
void pdmain_print( const char *s)
{
char y[80];
strncpy(y, s, 79);
y[79]=0;
ESP_LOGI(TAG, "%s", y);
}
void trymem(int foo);
void app_main(void)
{
i2s_config_t i2s_cfg = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX,
.sample_rate = 48000,
.bits_per_sample = 16,
/* .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, */
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
.communication_format = I2S_COMM_FORMAT_I2S,
.dma_buf_count = 3,
.dma_buf_len = 300,
.use_apll = 1,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL2,
};
i2s_pin_config_t i2s_pin_cfg = {0};
int zz = 0, ret;
pdmain_init();
esp_log_level_set("*", ESP_LOG_WARN);
esp_log_level_set(TAG, ESP_LOG_INFO);
ESP_LOGI(TAG, "[ 1 ] Start audio codec chip");
audio_board_handle_t board_handle = audio_board_init();
audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START);
i2s_driver_install(I2S_NUM_0, &i2s_cfg, 0, NULL);
get_i2s_pins(I2S_NUM_0, &i2s_pin_cfg);
i2s_set_pin(I2S_NUM_0, &i2s_pin_cfg);
i2s_mclk_gpio_select(I2S_NUM_0, GPIO_NUM_0);
bt_init();
sd_init();
ESP_LOGI(TAG, "[ 2 ] now write some shit");
while (1)
{
/* if (!((zz++)%1000))
{
trymem(5);
ESP_LOGI(TAG, "tick");
} */
pdmain_tick();
senddacs();
}
}
/* -------------------- bluetooth and SD card ------------------ */
void pd_dispatch_bt(char *data, size_t size);
static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_CB;
static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_AUTHENTICATE;
static const esp_spp_role_t role_slave = ESP_SPP_ROLE_SLAVE;
static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
{
switch (event) {
case ESP_SPP_INIT_EVT:
ESP_LOGI(TAG, "ESP_SPP_INIT_EVT");
esp_bt_dev_set_device_name("pure_data");
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
esp_spp_start_srv(sec_mask,role_slave, 0, "pd_server");
break;
case ESP_SPP_DISCOVERY_COMP_EVT:
ESP_LOGI(TAG, "ESP_SPP_DISCOVERY_COMP_EVT");
break;
case ESP_SPP_OPEN_EVT:
ESP_LOGI(TAG, "ESP_SPP_OPEN_EVT");
break;
case ESP_SPP_CLOSE_EVT:
ESP_LOGI(TAG, "ESP_SPP_CLOSE_EVT");
break;
case ESP_SPP_START_EVT:
ESP_LOGI(TAG, "ESP_SPP_START_EVT");
break;
case ESP_SPP_CL_INIT_EVT:
ESP_LOGI(TAG, "ESP_SPP_CL_INIT_EVT");
break;
case ESP_SPP_DATA_IND_EVT:
if (param->data_ind.len > 2)
ESP_LOGI(TAG, "ESP_SPP_DATA_IND_EVT len=%d handle=%d",
param->data_ind.len, param->data_ind.handle);
pd_dispatch_bt((char *)(param->data_ind.data), param->data_ind.len);
break;
case ESP_SPP_CONG_EVT:
ESP_LOGI(TAG, "ESP_SPP_CONG_EVT");
break;
case ESP_SPP_WRITE_EVT:
ESP_LOGI(TAG, "ESP_SPP_WRITE_EVT");
break;
case ESP_SPP_SRV_OPEN_EVT:
ESP_LOGI(TAG, "ESP_SPP_SRV_OPEN_EVT");
break;
default:
break;
}
}
void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
{
switch (event) {
case ESP_BT_GAP_AUTH_CMPL_EVT:{
if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
ESP_LOGI(TAG, "authentication success: %s", param->auth_cmpl.device_name);
esp_log_buffer_hex(TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
} else {
ESP_LOGE(TAG, "authentication failed, status:%d", param->auth_cmpl.stat);
}
break;
}
case ESP_BT_GAP_PIN_REQ_EVT:{
ESP_LOGI(TAG, "ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
if (param->pin_req.min_16_digit) {
ESP_LOGI(TAG, "Input pin code: 0000 0000 0000 0000");
esp_bt_pin_code_t pin_code = {0};
esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
} else {
ESP_LOGI(TAG, "Input pin code: 1234");
esp_bt_pin_code_t pin_code;
pin_code[0] = '1';
pin_code[1] = '2';
pin_code[2] = '3';
pin_code[3] = '4';
esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
}
break;
}
#if (CONFIG_BT_SSP_ENABLED == true)
case ESP_BT_GAP_CFM_REQ_EVT:
ESP_LOGI(TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
break;
case ESP_BT_GAP_KEY_NOTIF_EVT:
ESP_LOGI(TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
break;
case ESP_BT_GAP_KEY_REQ_EVT:
ESP_LOGI(TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
break;
#endif
default: {
ESP_LOGI(TAG, "event: %d", event);
break;
}
}
return;
}
void bt_init( void)
{
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
ESP_LOGE(TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
ESP_LOGE(TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bluedroid_init()) != ESP_OK) {
ESP_LOGE(TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bluedroid_enable()) != ESP_OK) {
ESP_LOGE(TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bt_gap_register_callback(esp_bt_gap_cb)) != ESP_OK) {
ESP_LOGE(TAG, "%s gap register failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_spp_register_callback(esp_spp_cb)) != ESP_OK) {
ESP_LOGE(TAG, "%s spp register failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_spp_init(esp_spp_mode)) != ESP_OK) {
ESP_LOGE(TAG, "%s spp init failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
#if (CONFIG_BT_SSP_ENABLED == true)
/* Set default parameters for Secure Simple Pairing */
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
#endif
/*
* Set default parameters for Legacy Pairing
* Use variable pin, input pin code when pairing
*/
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
esp_bt_pin_code_t pin_code;
esp_bt_gap_set_pin(pin_type, 0, pin_code);
}
void sd_init( void)
{
/* initialize SD card */
ESP_LOGI(TAG, "[ 1 ] Mount sdcard");
// Initialize peripherals management
esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
esp_periph_set_handle_t set = esp_periph_set_init(&periph_cfg);
// Initialize SD Card peripheral
audio_board_sdcard_init(set, SD_MODE_1_LINE);
}

View file

@ -1,200 +0,0 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
// All rights reserved.
#include <string.h>
#include "esp_log.h"
#include "audio_error.h"
#include "audio_mem.h"
#include "audio_element.h"
#include "fifostream.h"
#include "audio_type_def.h"
static const char *TAG = "fifostream";
#define CHANS 2
#define INCHANS CHANS
#define OUTCHANS CHANS
#define BLKSIZE 64
#define BLK_BYTES (BLKSIZE*CHANS*sizeof(short))
extern void pdmain_tick( void);
typedef struct fifostream {
int samplerate;
int channel;
short *s_buf;
int byte_num;
int at_eof;
} fifostream_t;
static esp_err_t fifostream_destroy(audio_element_handle_t self)
{
fifostream_t *fifostream = (fifostream_t *)audio_element_getdata(self);
audio_free(fifostream);
return ESP_OK;
}
static esp_err_t fifostream_open(audio_element_handle_t self)
{
ESP_LOGD(TAG, "fifostream_open");
fifostream_t *fifostream = (fifostream_t *)audio_element_getdata(self);
audio_element_info_t info = {0};
audio_element_getinfo(self, &info);
if (info.sample_rates
&& info.channels) {
fifostream->samplerate = info.sample_rates;
fifostream->channel = info.channels;
}
fifostream->at_eof = 0;
fifostream->s_buf = (short *)calloc(sizeof(short), BLK_BYTES/sizeof(short));
if (fifostream->s_buf == NULL) {
ESP_LOGE(TAG, "calloc buffer failed. (line %d)", __LINE__);
return ESP_ERR_NO_MEM;
}
memset(fifostream->s_buf, 0, BLK_BYTES);
return ESP_OK;
}
static esp_err_t fifostream_close(audio_element_handle_t self)
{
ESP_LOGD(TAG, "fifostream_close");
fifostream_t *fifostream = (fifostream_t *)audio_element_getdata(self);
if (fifostream->s_buf == NULL) {
audio_free(fifostream->s_buf);
fifostream->s_buf = NULL;
}
return ESP_OK;
}
float soundin[OUTCHANS * BLKSIZE], soundout[OUTCHANS * BLKSIZE];
#if 0 /* better one that doesn't work for some reason */
static int fifostream_process(audio_element_handle_t self, char *in_buffer,
int in_len)
{
static int cumsamps = 0;
fifostream_t *fifostream = (fifostream_t *)audio_element_getdata(self);
int ret = 0;
int r_size = (fifostream->at_eof ? 0 :
audio_element_input(self, (char *)fifostream->s_buf, BLK_BYTES));
if (r_size >= BLK_BYTES)
{
int i, nsamps = BLKSIZE;
fifostream->byte_num += BLK_BYTES;
for (i = 0; i < BLKSIZE; i+= 2)
{
soundin[i] = fifostream->s_buf[i]/32768;;
soundin[BLKSIZE+i] = fifostream->s_buf[i+1]/32768;
}
pdmain_tick();
for (i = 0; i < BLKSIZE; i+= 2)
{
int ch1 = 32767*soundout[i], ch2 = 32767*soundout[BLKSIZE+i];
if (ch1 > 32767)
ch1 = 32767;
else if (ch1 < -32768)
ch1 = -32768;
if (ch2 > 32767)
ch2 = 32767;
else if (ch2 < -32768)
ch2 = -32768;
fifostream->s_buf[i] = (short)ch1;
fifostream->s_buf[i+1] = (short)ch2;
}
ret = audio_element_output(self, (char *)fifostream->s_buf, BLK_BYTES);
}
else
{
fifostream->at_eof = 1;
ret = 0;
}
return ret;
}
#endif
#if 1
static int fifostream_process(audio_element_handle_t self, char *in_buffer, int in_len)
{
static int cumsamps = 0;
fifostream_t *fifostream = (fifostream_t *)audio_element_getdata(self);
int ret = 0;
int r_size = 0;
if (fifostream->at_eof == 0) {
r_size = audio_element_input(self, (char *)fifostream->s_buf, BLK_BYTES);
}
if (r_size > 0) {
if (r_size != BLK_BYTES) {
fifostream->at_eof = 1;
}
fifostream->byte_num += r_size;
{
int i, nsamps = r_size/(2*sizeof(short));
static int phase;
if (nsamps * 2 * sizeof(short) != r_size)
ESP_LOGE("WOMBAT", "odd sample frame size %d", r_size);
for (i = 0; i < nsamps; i++)
{
int ch1 = 32767*soundout[i], ch2 = 32767*soundout[BLKSIZE+i];
if (ch1 > 32767)
ch1 = 32767;
else if (ch1 < -32768)
ch1 = -32768;
if (ch2 > 32767)
ch2 = 32767;
else if (ch2 < -32768)
ch2 = -32768;
soundin[phase] = fifostream->s_buf[2*i]/32768;
fifostream->s_buf[2*i] = ch1;
soundin[BLKSIZE+phase] = fifostream->s_buf[2*i+1]/32768;
fifostream->s_buf[2*i+1] = ch2;
phase++;
if (phase == BLKSIZE)
{
pdmain_tick();
phase = 0;
}
}
}
ret = audio_element_output(self, (char *)fifostream->s_buf, BLK_BYTES);
} else {
ret = r_size;
}
return ret;
}
#endif
audio_element_handle_t fifostream_init(fifostream_cfg_t *config)
{
if (config == NULL) {
ESP_LOGE(TAG, "config is NULL. (line %d)", __LINE__);
return NULL;
}
fifostream_t *fifostream = audio_calloc(1, sizeof(fifostream_t));
AUDIO_MEM_CHECK(TAG, fifostream, return NULL);
if (fifostream == NULL) {
ESP_LOGE(TAG, "audio_calloc failed for fifostream. (line %d)", __LINE__);
return NULL;
}
audio_element_cfg_t cfg = DEFAULT_AUDIO_ELEMENT_CONFIG();
cfg.destroy = fifostream_destroy;
cfg.process = fifostream_process;
cfg.open = fifostream_open;
cfg.close = fifostream_close;
cfg.buffer_len = 0;
cfg.tag = "fifostream";
cfg.task_stack = config->task_stack;
cfg.task_prio = config->task_prio;
cfg.task_core = config->task_core;
cfg.out_rb_size = config->out_rb_size;
cfg.stack_in_ext = config->stack_in_ext;
audio_element_handle_t el = audio_element_init(&cfg);
AUDIO_MEM_CHECK(TAG, el, {audio_free(fifostream); return NULL;});
fifostream->samplerate = config->samplerate;
fifostream->channel = config->channel;
audio_element_setdata(el, fifostream);
audio_element_info_t info = {0};
audio_element_setinfo(el, &info);
ESP_LOGD(TAG, "fifostream_init");
return el;
}

View file

@ -1,57 +0,0 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
// All rights reserved.
#ifndef _FIFOSTREAM_H_
#define _FIFOSTREAM_H_
#include "esp_err.h"
#include "audio_element.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Configuration
*/
typedef struct fifostream_cfg {
int samplerate; /*!< Audio sample rate (in Hz)*/
int channel; /*!< Number of audio channels (Mono=1, Dual=2) */
int *set_gain; /*!< Equalizer gain */
int out_rb_size; /*!< Size of output ring buffer */
int task_stack; /*!< Task stack size */
int task_core; /*!< Task running in core...*/
int task_prio; /*!< Task priority*/
bool stack_in_ext; /*!< Try to allocate stack in external memory */
} fifostream_cfg_t;
#define FIFOSTREAM_TASK_STACK (20000)
#define FIFOSTREAM_TASK_CORE (0)
#define FIFOSTREAM_TASK_PRIO (5)
#define FIFOSTREAM_RINGBUFFER_SIZE (8 * 1024)
/**
* @note `set_value_gain` is defined in c file.
* values is {-13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13};
*/
extern int set_value_gain[];
#define DEFAULT_FIFOSTREAM_CONFIG() { \
.samplerate = 48000, \
.channel = 1, \
.set_gain = set_value_gain, \
.out_rb_size = FIFOSTREAM_RINGBUFFER_SIZE, \
.task_stack = FIFOSTREAM_TASK_STACK, \
.task_core = FIFOSTREAM_TASK_CORE, \
.task_prio = FIFOSTREAM_TASK_PRIO, \
.stack_in_ext = true, \
}
audio_element_handle_t fifostream_init(fifostream_cfg_t *config);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -10,6 +10,7 @@
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
void pd_init(void);
void glob_open(t_pd *ignore, t_symbol *name, t_symbol *dir, t_floatarg f);
@ -29,22 +30,18 @@ canvas 274 279 752 643 12;\n\
#endif
static const char patchfile[] = "\
canvas 0 50 604 482 12;\n\
#X obj 179 99 r foo;\n\
#X obj 179 124 osc~ 880;\n\
#X obj 179 149 dac~ 1;\n\
#X obj 257 127 osc~ 880;\n\
#X obj 257 102 r foo2;\n\
#X obj 257 151 dac~ 2;\n\
canvas 0 50 450 300 12;\n\
#X obj 190 104 loadbang;\n\
#X msg 190 129 \; pd dsp 1;\n\
#X obj 118 123 dac~ 1;\n\
#X obj 118 98 osc~ 440;\n\
#X connect 0 0 1 0;\n\
#X connect 1 0 2 0;\n\
#X connect 3 0 5 0;\n\
#X connect 4 0 3 0;\n\
#X connect 3 0 2 0;\n\
";
static void trymem(int foo)
void trymem(int foo)
{
#if 0
#if 1
int i;
char msg[80];
for (i = 1; i < 500; i++)
@ -74,10 +71,19 @@ void pd_dispatch_bt(char *data, size_t size)
void pd_poll_bt( void)
{
int lastchar;
static t_binbuf *b;
if (!b)
{
b = binbuf_new();
if (pd_bt_size)
post("new binbuf %x", b);
}
/* only interpret this text if terminated by a semicolon */
lastchar = pd_bt_size-1;
while (lastchar >= 0 && isspace((int)(pd_bt_buf[lastchar])))
lastchar--;
if (lastchar >= 3 && pd_bt_buf[lastchar] == ';' &&
pd_bt_buf[lastchar-1] != '\\')
{
binbuf_text(b, pd_bt_buf, pd_bt_size);
binbuf_eval(b, 0, 0, 0);
@ -87,41 +93,35 @@ void pd_poll_bt( void)
}
extern float soundin[], soundout[];
void canvas_start_dsp( void);
void pdmain_init( void)
{
t_binbuf *b;
sys_printhook = pdmain_print;
trymem(1); // 111
trymem(1);
pd_init();
trymem(2); // 47
trymem(2);
STUFF->st_dacsr = sys_getsr();
STUFF->st_soundout = soundout;
STUFF->st_soundin = soundin;
#if 0
b = binbuf_new();
glob_setfilename(0, gensym("main-patch"), gensym("."));
binbuf_text(b, patchfile, strlen(patchfile));
binbuf_eval(b, &pd_canvasmaker, 0, 0);
canvas_loadbang((t_canvas *)s__X.s_thing);
vmess(s__X.s_thing, gensym("pop"), "i", 0);
glob_setfilename(0, &s_, &s_);
binbuf_free(b);
#endif
}
void pdmain_tick( void)
{
static int initted;
if (!initted)
{
pdmain_init();
initted = 1;
}
memset(soundout, 0, 128*sizeof(float));
memset(soundout, 0, 64*sizeof(float));
pd_poll_bt();
sched_tick();
}
@ -132,9 +132,34 @@ t_class *glob_pdobject;
static void glob_foo(void *dummy, t_floatarg f)
{
post("foo %f", f);
trymem(0);
}
static void glob_beginnew(void *dummy, t_symbol *pname, t_symbol *pdir)
{
glob_setfilename(0, pname, pdir);
pd_bind(&pd_canvasmaker, &s__N);
}
static void glob_endnew(void *dummy)
{
pd_unbind(&pd_canvasmaker, &s__N);
if ((t_canvas *)s__X.s_thing)
{
canvas_loadbang((t_canvas *)s__X.s_thing);
vmess(s__X.s_thing, gensym("pop"), "i", 0);
}
glob_setfilename(0, &s_, &s_);
}
static void glob_close(void *dummy, t_symbol *pname)
{
t_pd *c = pd_findbyclass(pname, canvas_class);
if (c)
pd_free(c);
}
void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv);
void glob_init( void)
@ -145,6 +170,12 @@ void glob_init( void)
A_GIMME, 0);
class_addmethod(glob_pdobject, (t_method)glob_foo, gensym("foo"),
A_DEFFLOAT, 0);
class_addmethod(glob_pdobject, (t_method)glob_beginnew, gensym("begin-new"),
A_SYMBOL, A_SYMBOL, 0);
class_addmethod(glob_pdobject, (t_method)glob_close, gensym("close"),
A_SYMBOL, 0);
class_addmethod(glob_pdobject, (t_method)glob_endnew, gensym("end-new"),
0);
pd_bind(&glob_pdobject, gensym("pd"));
}
@ -209,7 +240,6 @@ void conf_init(void)
g_guiconnect_setup();
g_scalar_setup();
g_template_setup();
clone_setup();
m_pd_setup();
x_acoustics_setup();
x_interface_setup();
@ -228,23 +258,25 @@ void conf_init(void)
d_dac_setup();
d_ctl_setup();
d_osc_setup();
trymem(11);
}
/*
d_arithmetic_setup();
d_array_setup();
clone_setup();
d_delay_setup();
d_filter_setup();
d_math_setup();
d_misc_setup();
expr_setup();
trymem(11);
}
/*
g_traversal_setup();
*/
/* ------- STUBS that do nothing ------------- */
int sys_get_outchannels(void) {return(2); }
int sys_get_inchannels(void) {return(2); }
float sys_getsr( void) {return (44100);}
float sys_getsr( void) {return (48000);}
int sys_getblksize(void) { return (DEFDACBLKSIZE); }
int pd_compatibilitylevel = 100;
@ -323,6 +355,8 @@ void x_midi_newpdinstance( void) {}
t_symbol *iemgui_raute2dollar(t_symbol *s) {return(s);}
t_symbol *iemgui_dollar2raute(t_symbol *s) {return(s);}
t_class *clone_class;
/* --------------- m_sched.c -------------------- */
#define TIMEUNITPERMSEC (32. * 441.)
#define TIMEUNITPERSECOND (TIMEUNITPERMSEC * 1000.)

View file

@ -1,354 +0,0 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "nvs.h"
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "audio_pipeline.h"
#include "i2s_stream.h"
#include "board.h"
#include "fifostream.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gap_bt_api.h"
#include "esp_bt_device.h"
#include "esp_spp_api.h"
#include "time.h"
#include "sys/time.h"
#define SPP_TAG "WOMBAT"
#define SPP_SERVER_NAME "SPP_SERVER"
#define EXCAMPLE_DEVICE_NAME "ESP_SPP_ACCEPTOR"
#define SPP_SHOW_DATA 0
#define SPP_SHOW_SPEED 1
#define SPP_SHOW_MODE SPP_SHOW_DATA /*Choose show mode: show data or speed*/
void pdmain_print( const char *s)
{
ESP_LOGI("PD", "%s" , s);
}
static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_CB;
static struct timeval time_new, time_old;
static long data_num = 0;
static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_AUTHENTICATE;
static const esp_spp_role_t role_slave = ESP_SPP_ROLE_SLAVE;
static void print_speed(void)
{
float time_old_s = time_old.tv_sec + time_old.tv_usec / 1000000.0;
float time_new_s = time_new.tv_sec + time_new.tv_usec / 1000000.0;
float time_interval = time_new_s - time_old_s;
float speed = data_num * 8 / time_interval / 1000.0;
ESP_LOGI(SPP_TAG, "speed(%fs ~ %fs): %f kbit/s" , time_old_s, time_new_s, speed);
data_num = 0;
time_old.tv_sec = time_new.tv_sec;
time_old.tv_usec = time_new.tv_usec;
}
extern int phaseinc;
void pd_dispatch_bt(char *data, size_t size);
static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
{
switch (event) {
case ESP_SPP_INIT_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT");
esp_bt_dev_set_device_name(EXCAMPLE_DEVICE_NAME);
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
esp_spp_start_srv(sec_mask,role_slave, 0, SPP_SERVER_NAME);
break;
case ESP_SPP_DISCOVERY_COMP_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT");
break;
case ESP_SPP_OPEN_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT");
break;
case ESP_SPP_CLOSE_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT");
break;
case ESP_SPP_START_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT");
break;
case ESP_SPP_CL_INIT_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT");
break;
case ESP_SPP_DATA_IND_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_DATA_IND_EVT len=%d handle=%d",
param->data_ind.len, param->data_ind.handle);
esp_log_buffer_hex("",param->data_ind.data,param->data_ind.len);
{
#if 1
pd_dispatch_bt((char *)(param->data_ind.data),
param->data_ind.len);
#else
char foo[80];
int nfoo = (param->data_ind.len > 78 ? 78 : param->data_ind.len), i;
for (i = 0; i < nfoo; i++)
foo[i] = param->data_ind.data[i];
foo[i] = 0;
ESP_LOGI(SPP_TAG, "%s", foo);
sscanf(foo, "%d%d", &i, &phaseinc);
#endif
}
break;
case ESP_SPP_CONG_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_CONG_EVT");
break;
case ESP_SPP_WRITE_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_WRITE_EVT");
break;
case ESP_SPP_SRV_OPEN_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT");
gettimeofday(&time_old, NULL);
break;
default:
break;
}
}
void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
{
switch (event) {
case ESP_BT_GAP_AUTH_CMPL_EVT:{
if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
ESP_LOGI(SPP_TAG, "authentication success: %s", param->auth_cmpl.device_name);
esp_log_buffer_hex(SPP_TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
} else {
ESP_LOGE(SPP_TAG, "authentication failed, status:%d", param->auth_cmpl.stat);
}
break;
}
case ESP_BT_GAP_PIN_REQ_EVT:{
ESP_LOGI(SPP_TAG, "ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
if (param->pin_req.min_16_digit) {
ESP_LOGI(SPP_TAG, "Input pin code: 0000 0000 0000 0000");
esp_bt_pin_code_t pin_code = {0};
esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
} else {
ESP_LOGI(SPP_TAG, "Input pin code: 1234");
esp_bt_pin_code_t pin_code;
pin_code[0] = '1';
pin_code[1] = '2';
pin_code[2] = '3';
pin_code[3] = '4';
esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
}
break;
}
#if (CONFIG_BT_SSP_ENABLED == true)
case ESP_BT_GAP_CFM_REQ_EVT:
ESP_LOGI(SPP_TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
break;
case ESP_BT_GAP_KEY_NOTIF_EVT:
ESP_LOGI(SPP_TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
break;
case ESP_BT_GAP_KEY_REQ_EVT:
ESP_LOGI(SPP_TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
break;
#endif
default: {
ESP_LOGI(SPP_TAG, "event: %d", event);
break;
}
}
return;
}
void audio_main(void)
{
audio_pipeline_handle_t pipeline;
audio_element_handle_t i2s_stream_writer, i2s_stream_reader, fifostream;
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set(SPP_TAG, ESP_LOG_DEBUG);
ESP_LOGI(SPP_TAG, "[ 1 ] Start codec chip");
audio_board_handle_t board_handle = audio_board_init();
audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START);
ESP_LOGI(SPP_TAG, "[ 2 ] Create audio pipeline for playback");
audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
pipeline = audio_pipeline_init(&pipeline_cfg);
ESP_LOGI(SPP_TAG, "[3.1] Create i2s stream to write data to codec chip");
i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();
i2s_cfg.type = AUDIO_STREAM_WRITER;
i2s_stream_writer = i2s_stream_init(&i2s_cfg);
ESP_LOGI(SPP_TAG, "[3.1b] fifostream");
fifostream_cfg_t eq_cfg = DEFAULT_FIFOSTREAM_CONFIG();
int set_gain[] = {0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,};
eq_cfg.set_gain = set_gain;
fifostream = fifostream_init(&eq_cfg);
ESP_LOGI(SPP_TAG, "[3.2] Create i2s stream to read data from codec chip");
i2s_stream_cfg_t i2s_cfg_read = I2S_STREAM_CFG_DEFAULT();
i2s_cfg_read.type = AUDIO_STREAM_READER;
i2s_stream_reader = i2s_stream_init(&i2s_cfg_read);
ESP_LOGI(SPP_TAG, "[3.3] Register all elements to audio pipeline");
audio_pipeline_register(pipeline, i2s_stream_reader, "i2s_read");
audio_pipeline_register(pipeline, fifostream, "wombat");
audio_pipeline_register(pipeline, i2s_stream_writer, "i2s_write");
ESP_LOGI(SPP_TAG, "[3.4] Link it together [codec_chip]-->i2s_stream_reader-->i2s_stream_writer-->[codec_chip]");
const char *link_tag[3] = {"i2s_read", "wombat", "i2s_write"};
audio_pipeline_link(pipeline, &link_tag[0], 3);
ESP_LOGI(SPP_TAG, "[ 4 ] Set up event listener");
audio_event_iface_cfg_t evt_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG();
audio_event_iface_handle_t evt = audio_event_iface_init(&evt_cfg);
ESP_LOGI(SPP_TAG, "[4.1] Listening event from all elements of pipeline");
audio_pipeline_set_listener(pipeline, evt);
ESP_LOGI(SPP_TAG, "[ 5 ] Start audio_pipeline");
audio_pipeline_run(pipeline);
ESP_LOGI(SPP_TAG, "[ 7 ] Listen for all pipeline events");
while (1) {
audio_event_iface_msg_t msg;
esp_err_t ret = audio_event_iface_listen(evt, &msg, portMAX_DELAY);
if (ret != ESP_OK) {
ESP_LOGE(SPP_TAG, "[ * ] Event interface error : %d", ret);
continue;
}
/* Stop when the last pipeline element (i2s_stream_writer in this case) receives stop event */
if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg.source == (void *) i2s_stream_writer
&& msg.cmd == AEL_MSG_CMD_REPORT_STATUS
&& (((int)msg.data == AEL_STATUS_STATE_STOPPED) || ((int)msg.data == AEL_STATUS_STATE_FINISHED))) {
ESP_LOGW(SPP_TAG, "[ * ] Stop event received");
break;
}
}
ESP_LOGI(SPP_TAG, "[ 8 ] Stop audio_pipeline");
audio_pipeline_stop(pipeline);
audio_pipeline_wait_for_stop(pipeline);
audio_pipeline_terminate(pipeline);
audio_pipeline_unregister(pipeline, i2s_stream_reader);
audio_pipeline_unregister(pipeline, i2s_stream_writer);
/* Terminate the pipeline before removing the listener */
audio_pipeline_remove_listener(pipeline);
/* Make sure audio_pipeline_remove_listener & audio_event_iface_remove_listener are called before destroying event_iface */
audio_event_iface_destroy(evt);
/* Release all resources */
audio_pipeline_deinit(pipeline);
audio_element_deinit(i2s_stream_reader);
audio_element_deinit(i2s_stream_writer);
}
void app_main()
{
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
ESP_LOGE(SPP_TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
ESP_LOGE(SPP_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bluedroid_init()) != ESP_OK) {
ESP_LOGE(SPP_TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bluedroid_enable()) != ESP_OK) {
ESP_LOGE(SPP_TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_bt_gap_register_callback(esp_bt_gap_cb)) != ESP_OK) {
ESP_LOGE(SPP_TAG, "%s gap register failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_spp_register_callback(esp_spp_cb)) != ESP_OK) {
ESP_LOGE(SPP_TAG, "%s spp register failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
if ((ret = esp_spp_init(esp_spp_mode)) != ESP_OK) {
ESP_LOGE(SPP_TAG, "%s spp init failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
#if (CONFIG_BT_SSP_ENABLED == true)
/* Set default parameters for Secure Simple Pairing */
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
#endif
/*
* Set default parameters for Legacy Pairing
* Use variable pin, input pin code when pairing
*/
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
esp_bt_pin_code_t pin_code;
esp_bt_gap_set_pin(pin_type, 0, pin_code);
audio_main();
}
#if 0 /* this will be more work than I thought */
void gettaskinfo(char *where)
{
TaskStatus_t xTaskDetails;
vTaskGetInfo( /* The handle of the task being queried. */
0,
/* The TaskStatus_t structure to complete with information
on xTask. */
&xTaskDetails,
/* Include the stack high water mark value in the
TaskStatus_t structure. */
pdTRUE,
/* Include the task state in the TaskStatus_t structure. */
eInvalid );
ESP_LOGE("PROC", "where: proc %s: %d %d", xTaskDetails.pcTaskName,
(int)((char *)(&xTaskDetails) - (char *)(pxStackBase)),
(int)usStackHighWaterMark);
}
#endif