Skip to content
Snippets Groups Projects
Commit ba78bc5e authored by moon2's avatar moon2 :speech_balloon: Committed by q3k
Browse files

hooked up trad_osc to micropython

parent 46b8aa91
No related branches found
No related tags found
No related merge requests found
......@@ -2,6 +2,33 @@
plays an infinite scripted note sequence and provides a basic micropython repl
makes extra noise when Crtl+D'd in the repl (importing py libraries works too)
some fun commands to try:
'''
import badge_audio
#turn on sound
badge_audio.set_global_volume_dB(-10)
#turn off all demo oscillators
badge_audio.dump_all_sources()
import synth
a=synth.tinysynth(440,1);
a.start();
b=synth.tinysynth(660,0);
b.start();
b.stop();
#tiny issue with garbage collect:
badge_audio.count_sources();
a.__del__();
badge_audio.count_sources();
import gc
del b
gc.collect()
badge_audio.count_sources();
#...don't know how to hook up gc to __del__, maybe wrong approach
'''
## how to build
1. install esp-idf v4.4:
......@@ -51,7 +78,7 @@ $ picocom -b 115200 /dev/ttyACM0
## how to modify
general info
### general info
global + micropython entry point: app_main() in micropython/ports/esp32/main.c (includes badge23/espan.h)
c entry point, called by^: os_app_main() in badge23/espan.c
register new c files for compilation: add to set(BADGE23_LIB) in micropython/ports/esp32/main/CMakelists.txt
......
......@@ -10,6 +10,8 @@
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "../../py/mphal.h"
#define DRUMS_TOP 0
......@@ -22,51 +24,6 @@ static void audio_player_task(void* arg);
#define DMA_BUFFER_COUNT 2
#define I2S_PORT 0
#if 0
static i2s_chan_handle_t tx_chan; // I2S tx channel handler
static i2s_chan_handle_t rx_chan; // I2S rx channel handler
static void i2s_init_std_duplex(void)
{
/* Setp 1: Determine the I2S channel configuration and allocate both channels
* The default configuration can be generated by the helper macro,
* it only requires the I2S controller id and I2S role */
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
chan_cfg.dma_desc_num = DMA_BUFFER_COUNT;
chan_cfg.dma_frame_num = DMA_BUFFER_SIZE;
// Play silence after all DMA buffers are empty
chan_cfg.auto_clear = true;
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_chan, &rx_chan));
/* Step 2: Setting the configurations of standard mode, and initialize rx & tx channels
* The slot configuration and clock configuration can be generated by the macros
* These two helper macros is defined in 'i2s_std.h' which can only be used in STD mode.
* They can help to specify the slot and clock configurations for initialization or re-configuring */
i2s_std_config_t std_cfg = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
//.slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
.gpio_cfg = {
.mclk = 11,
.bclk = 13,
.ws = 12,
.dout = 14,
.din = I2S_GPIO_UNUSED,
.invert_flags = {
.mclk_inv = false,
.bclk_inv = false,
.ws_inv = false,
},
},
};
/* Initialize the channels */
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_chan, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_chan, &std_cfg));
}
#endif
static void i2s_init_idk_lol(void){
static const i2s_config_t i2s_config = {
......@@ -123,6 +80,69 @@ static float FREQ_TABLE[] = {
};
#endif
typedef struct _audio_source_t{
void * render_data;
float (* render_function)(void *);
uint16_t index;
struct _audio_source_t * next;
} audio_source_t;
static audio_source_t * _audio_sources = NULL;
uint16_t add_audio_source(void * render_data, void * render_function){
audio_source_t * src = malloc(sizeof(audio_source_t));
if(src == NULL) return;
src->render_data = render_data;
src->render_function = render_function;
src->next = NULL;
src->index = 0;
audio_source_t * audio_source = _audio_sources;
if(audio_source == NULL){
_audio_sources = src;
}
while(audio_source != NULL){
src->index++;
if(audio_source->next == NULL){
audio_source->next = src;
break;
} else {
audio_source = audio_source->next;
}
}
return src->index;
}
void remove_audio_source(uint16_t index){
audio_source_t * audio_source = _audio_sources;
audio_source_t * start_gap = NULL;
while(audio_source != NULL){
if(index == audio_source->index){
if(start_gap == NULL){
_audio_sources = audio_source->next;
} else {
start_gap->next = audio_source->next;
}
free(audio_source);
break;
}
start_gap = audio_source;
audio_source = audio_source->next;
}
}
uint16_t count_audio_sources(){
uint16_t ret = 0;
audio_source_t * audio_source = _audio_sources;
while(audio_source != NULL){
audio_source = audio_source->next;
ret++;
}
return ret;
}
static void _audio_init(void) {
init_scope(241);
//i2s_init_std_duplex();
......@@ -171,8 +191,8 @@ static void _audio_init(void) {
synths[i].waveform = 8;
synths[i].noise_reg = 1;
}
add_audio_source(&(synths[i]), trad_osc);
}
TaskHandle_t handle;
xTaskCreate(&audio_player_task, "Audio player", 20000, NULL, configMAX_PRIORITIES - 1, &handle);
}
......@@ -182,6 +202,7 @@ static void _audio_init(void) {
#define NAT_LOG_DB 0.1151292546497023
static uint16_t _global_vol = 3000;
static void * _extra_synth = NULL;
void set_global_vol_dB(int8_t vol_dB){
if(vol_dB < (BADGE_MIN_VOLUME_DB)){
......@@ -194,6 +215,14 @@ void set_global_vol_dB(int8_t vol_dB){
}
}
void set_extra_synth(void * synth){
_extra_synth = synth;
}
void clear_extra_synth(){
_extra_synth = NULL;
}
static void audio_player_task(void* arg) {
int16_t buffer[DMA_BUFFER_SIZE * 2];
//memset(buffer, 0, sizeof(buffer));
......@@ -202,9 +231,19 @@ static void audio_player_task(void* arg) {
for(int i = 0; i < (DMA_BUFFER_SIZE * 2); i += 2){
float sample = 0;
/*
for(int j = 0; j<NUM_SYNTH; j++){
sample += trad_osc(&(synths[j]));
}
if(_extra_synth != NULL){
sample += trad_osc((trad_osc_t * )_extra_synth);
}
*/
audio_source_t * audio_source = _audio_sources;
while(audio_source != NULL){
sample += (*(audio_source->render_function))(audio_source->render_data);
audio_source = audio_source->next;
}
write_to_scope((int16_t) (1600. * sample));
sample = _global_vol * sample;
if(sample > 32767) sample = 32767;
......
......@@ -17,4 +17,9 @@ void synth_fullstop(int i);
float synth_get_env(int i);
void set_global_vol_dB(int8_t vol_dB);
void set_extra_synth(void * synth);
void clear_extra_synth();
uint16_t count_audio_sources();
uint16_t add_audio_source(void * render_data, void * render_function);
void remove_audio_source(uint16_t index);
......@@ -95,7 +95,7 @@ void os_app_main(void)
ESP_LOGI(TAG, "I2C initialized successfully");
vTaskDelay(1000 / portTICK_PERIOD_MS);
set_global_vol_dB(0);
set_global_vol_dB(-90);
audio_init();
leds_init();
......
// probably doesn't need all of these idk
#include <stdio.h>
#include <string.h>
#include "py/runtime.h"
#include "py/mphal.h"
#include "mphalport.h"
#include "modmachine.h"
#include "extmod/virtpin.h"
#include "machine_rtc.h"
#include "py/builtin.h"
#include "py/runtime.h"
#include "../badge23/audio.h"
STATIC mp_obj_t mp_set_global_volume_dB(size_t n_args, const mp_obj_t *args) {
mp_float_t x = mp_obj_get_float(args[0]);
int8_t d = x;
set_global_vol_dB(d);
mp_float_t l = x;
return mp_obj_new_float(l);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_set_global_volume_dB_obj, 1, 2, mp_set_global_volume_dB);
STATIC mp_obj_t mp_count_sources(size_t n_args, const mp_obj_t *args) {
uint16_t d = count_audio_sources();
return mp_obj_new_int(d);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_count_sources_obj, 0, 2, mp_count_sources);
STATIC mp_obj_t mp_dump_all_sources(size_t n_args, const mp_obj_t *args) {
uint16_t d = count_audio_sources();
for(uint16_t i = 0; i < d; i++){
remove_audio_source(i);
}
return mp_obj_new_int(d);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_dump_all_sources_obj, 0, 2, mp_dump_all_sources);
STATIC const mp_rom_map_elem_t mp_module_badge_audio_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_badge_audio) },
{ MP_ROM_QSTR(MP_QSTR_set_global_volume_dB), MP_ROM_PTR(&mp_set_global_volume_dB_obj) },
{ MP_ROM_QSTR(MP_QSTR_count_sources), MP_ROM_PTR(&mp_count_sources_obj) },
{ MP_ROM_QSTR(MP_QSTR_dump_all_sources), MP_ROM_PTR(&mp_dump_all_sources_obj) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_badge_audio_globals, mp_module_badge_audio_globals_table);
const mp_obj_module_t mp_module_badge_audio = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&mp_module_badge_audio_globals,
};
MP_REGISTER_MODULE(MP_QSTR_badge_audio, mp_module_badge_audio);
#include <stdio.h>
#include "py/runtime.h"
#include "py/obj.h"
#include "../../../badge23/synth.h"
#include "../../../badge23/audio.h"
typedef struct _synth_tinysynth_obj_t {
mp_obj_base_t base;
trad_osc_t osc;
uint16_t source_index;
} synth_tinysynth_obj_t;
const mp_obj_type_t synth_tinysynth_type;
STATIC void tinysynth_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
synth_tinysynth_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_print_str(print, "tinysynth(");
mp_obj_print_helper(print, mp_obj_new_int(self->source_index), PRINT_REPR);
mp_print_str(print, ")");
}
STATIC mp_obj_t tinysynth_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 2, 2, true);
synth_tinysynth_obj_t *self = m_new_obj(synth_tinysynth_obj_t);
self->base.type = &synth_tinysynth_type;
self->osc.decay_steps = 50;
self->osc.attack_steps = 3;
self->osc.vol = 1.;
self->osc.gate = 0.01;
self->osc.freq = mp_obj_get_int(args[0]);
self->osc.counter = 0;
self->osc.bend = 1;
self->osc.noise_reg = 1;
self->osc.waveform = 1;
self->osc.skip_hold = mp_obj_get_int(args[1]);
//set_extra_synth(&(self->osc));
self->source_index = add_audio_source(&(self->osc), trad_osc);
return MP_OBJ_FROM_PTR(self);
}
// Class methods
STATIC mp_obj_t tinysynth_start(mp_obj_t self_in) {
synth_tinysynth_obj_t *self = MP_OBJ_TO_PTR(self_in);
self->osc.env_phase = 1;
return mp_obj_new_int(1);
}
MP_DEFINE_CONST_FUN_OBJ_1(tinysynth_start_obj, tinysynth_start);
STATIC mp_obj_t tinysynth_stop(mp_obj_t self_in) {
synth_tinysynth_obj_t *self = MP_OBJ_TO_PTR(self_in);
if(self->osc.env_phase){
self->osc.env_phase = 3;
}
return mp_obj_new_int(1);
}
MP_DEFINE_CONST_FUN_OBJ_1(tinysynth_stop_obj, tinysynth_stop);
STATIC mp_obj_t tinysynth_deinit(mp_obj_t self_in) {
synth_tinysynth_obj_t *self = MP_OBJ_TO_PTR(self_in);
remove_audio_source(self->source_index);
return mp_obj_new_int(1);
}
MP_DEFINE_CONST_FUN_OBJ_1(tinysynth_deinit_obj, tinysynth_deinit);
STATIC const mp_rom_map_elem_t tinysynth_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&tinysynth_start_obj) },
{ MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&tinysynth_stop_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&tinysynth_deinit_obj) },
};
STATIC MP_DEFINE_CONST_DICT(tinysynth_locals_dict, tinysynth_locals_dict_table);
MP_DEFINE_CONST_OBJ_TYPE(
synth_tinysynth_type,
MP_QSTR_synth,
MP_TYPE_FLAG_NONE,
make_new, tinysynth_make_new,
print, tinysynth_print,
locals_dict, &tinysynth_locals_dict
);
STATIC const mp_map_elem_t synth_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_synth) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_tinysynth), (mp_obj_t)&synth_tinysynth_type },
};
STATIC MP_DEFINE_CONST_DICT (
mp_module_synth_globals,
synth_globals_table
);
const mp_obj_module_t synth_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_synth_globals,
};
MP_REGISTER_MODULE(MP_QSTR_synth, synth_user_cmodule);
......@@ -60,6 +60,8 @@ set(MICROPY_SOURCE_DRIVERS
)
set(MICROPY_SOURCE_PORT
${PROJECT_DIR}/badge23_mp_audio.c
${PROJECT_DIR}/badge23_mp_tinysynth.c
${PROJECT_DIR}/main.c
${PROJECT_DIR}/uart.c
${PROJECT_DIR}/usb.c
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment