Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 9Rmain
  • anon/gpndemo
  • anon/update-sim
  • anon/webflasher
  • audio_input
  • audio_io
  • bl00mbox
  • bl00mbox_old
  • captouch-threshold
  • ch3/bl00mbox_docs
  • ci-1690580595
  • compressor
  • dev_p4
  • dev_p4-iggy
  • dev_p4-iggy-rebased
  • dos
  • dos-main-patch-50543
  • events
  • fm_fix
  • fm_fix2
  • fpletz/flake
  • history-rewrite
  • icon-flower
  • iggy/stemming
  • iggy/stemming_merge
  • json-error
  • main
  • main+schneider
  • media-buf
  • micropython_api
  • moon2_applications
  • moon2_demo_temp
  • moon2_gay_drums
  • passthrough
  • phhw
  • pippin/display-python-errors-on-display
  • pippin/make_empty_drawlists_skip_render_and_blit
  • pippin/media_framework
  • pippin/uhm_flash_access_bust
  • pressable_bugfix
  • q3k/doom-poc
  • rahix/big-flow3r
  • rahix/flow3rseeds
  • raw_captouch_new
  • raw_captouch_old
  • release/1.0.0
  • release/1.1.0
  • release/1.1.1
  • rev4_micropython
  • schneider/application-remove-name
  • schneider/bhi581
  • schneider/factory_test
  • schneider/recovery
  • scope
  • scope_hack
  • sdkconfig-spiram-tinyusb
  • sec/auto-nick
  • sec/blinky
  • simtest
  • slewtest
  • t
  • test
  • test2
  • uctx-wip
  • view-think
  • vm-pending
  • vsync
  • wave
  • wip-docs
  • wip-tinyusb
  • v1.0.0
  • v1.0.0+rc1
  • v1.0.0+rc2
  • v1.0.0+rc3
  • v1.0.0+rc4
  • v1.0.0+rc5
  • v1.0.0+rc6
  • v1.1.0
  • v1.1.0+rc1
  • v1.1.1
  • v1.2.0
  • v1.2.0+rc1
  • v1.3.0
83 results

Target

Select target project
  • flow3r/flow3r-firmware
  • Vespasian/flow3r-firmware
  • alxndr42/flow3r-firmware
  • pl/flow3r-firmware
  • Kari/flow3r-firmware
  • raimue/flow3r-firmware
  • grandchild/flow3r-firmware
  • mu5tach3/flow3r-firmware
  • Nervengift/flow3r-firmware
  • arachnist/flow3r-firmware
  • TheNewCivilian/flow3r-firmware
  • alibi/flow3r-firmware
  • manuel_v/flow3r-firmware
  • xeniter/flow3r-firmware
  • maxbachmann/flow3r-firmware
  • yGifoom/flow3r-firmware
  • istobic/flow3r-firmware
  • EiNSTeiN_/flow3r-firmware
  • gnudalf/flow3r-firmware
  • 999eagle/flow3r-firmware
  • toerb/flow3r-firmware
  • pandark/flow3r-firmware
  • teal/flow3r-firmware
  • x42/flow3r-firmware
  • alufers/flow3r-firmware
  • dos/flow3r-firmware
  • yrlf/flow3r-firmware
  • LuKaRo/flow3r-firmware
  • ThomasElRubio/flow3r-firmware
  • ai/flow3r-firmware
  • T_X/flow3r-firmware
  • highTower/flow3r-firmware
  • beanieboi/flow3r-firmware
  • Woazboat/flow3r-firmware
  • gooniesbro/flow3r-firmware
  • marvino/flow3r-firmware
  • kressnerd/flow3r-firmware
  • quazgar/flow3r-firmware
  • aoid/flow3r-firmware
  • jkj/flow3r-firmware
  • naomi/flow3r-firmware
41 results
Select Git revision
  • 89-apps-should-be-able-to-specify-if-they-want-wifi-to-be-disabled-when-entering-them
  • 9Rmain
  • allow-reloading-sunmenu
  • always-have-a-wifi-instance
  • anon/gpndemo
  • anon/update-sim
  • anon/webflasher
  • app_text_viewer
  • audio_input
  • audio_io
  • blm_dev_chan
  • ch3/bl00mbox_docs
  • ci-1690580595
  • dev_p4
  • dev_p4-iggy
  • dev_p4-iggy-rebased
  • dx/dldldld
  • dx/fb-save-restore
  • dx/hint-hint
  • dx/jacksense-headset-mic-only
  • events
  • fil3s-limit-filesize
  • fil3s-media
  • fpletz/flake
  • gr33nhouse-improvements
  • history-rewrite
  • icon-flower
  • iggy/stemming
  • iggy/stemming_merge
  • led_fix_fix
  • main
  • main+schneider
  • media_has_video_has_audio
  • micropython_api
  • mixer2
  • moon2_demo_temp
  • moon2_migrate_apps
  • more-accurate-battery
  • pippin/ctx_sprite_sheet_support
  • pippin/display-python-errors-on-display
  • pippin/make_empty_drawlists_skip_render_and_blit
  • pippin/more-accurate-battery
  • pippin/tcp_redirect_hack
  • pippin/tune_ctx_config_update_from_upstream
  • pippin/uhm_flash_access_bust
  • pressable_bugfix
  • py_only_update_fps_overlay_when_changing
  • q3k/doom-poc
  • q3k/render-to-texture
  • rahix/flow3rseeds
  • raw_captouch_new
  • raw_captouch_old
  • release/1.0.0
  • release/1.1.0
  • release/1.1.1
  • release/1.2.0
  • release/1.3.0
  • release/1.4.0
  • restore_blit
  • return_of_melodic_demo
  • rev4_micropython
  • schneider/application-remove-name
  • schneider/bhi581
  • schneider/factory_test
  • schneider/recovery
  • scope_hack
  • sdkconfig-spiram-tinyusb
  • sec/auto-nick
  • sec/blinky
  • sector_size_512
  • shoegaze-fps
  • smaller_gradient_lut
  • store_delta_ms_and_ins_as_class_members
  • task_cleanup
  • uctx-wip
  • w1f1-in-sim
  • widgets_draw
  • wifi-json-error-handling
  • wip-docs
  • wip-tinyusb
  • v1.0.0
  • v1.0.0+rc1
  • v1.0.0+rc2
  • v1.0.0+rc3
  • v1.0.0+rc4
  • v1.0.0+rc5
  • v1.0.0+rc6
  • v1.1.0
  • v1.1.0+rc1
  • v1.1.1
  • v1.2.0
  • v1.2.0+rc1
  • v1.3.0
  • v1.4.0
94 results
Show changes
Showing
with 1005 additions and 0 deletions
idf_component_register(
SRCS
apa102LEDStrip.c
audio.c
captouch.c
display.c
espan.c
leds.c
scope.c
synth.c
spio.c
INCLUDE_DIRS
include
REQUIRES
badge23_hwconfig
gc9a01
espressif__led_strip
)
menu "Badge23 Config"
choice BADGE23_HW_GEN
prompt "Badge23 Hardware Generation"
default BADGE23_HW_GEN_P4
config BADGE23_HW_GEN_P1
help
Protoype version 1, a.k.a. proto1. Very early protoype.
Visual identifiers:
- No line in/out jacks
- White bottom board
- USB-C jack points side of leaf
bool "Prototype 1"
config BADGE23_HW_GEN_P3
help
Prototype version 3, a.k.a. proto3
Visual identifiers:
- Sticker with B3xx (xx being arbitrary digits) on the back
bool "Prototype 3"
config BADGE23_HW_GEN_P4
help
Prototype version 4, a.k.a. proto4
Visual identifiers:
- Sticker with B4xx (xx being arbitrary digits) on the back
bool "Prototype 4"
config BADGE23_HW_GEN_ADILESS
help
Prototype version 5, a.k.a. adi-less
Visual identifiers:
- Sticker with B5xx (xx being arbitrary digits) on the back
bool "Prototype 5 / ADI-less"
endchoice
endmenu
badge23/espan
===
Transitional component containing all custom C code for badge23, including drivers for peripherals and 'espan' application leftovers.
This will be likely split up into sub-components.
#include "badge23/apa102LEDStrip.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
void initLEDs(struct apa102LEDStrip *ledObject, short int numLEDs, unsigned char bytesPerLED, unsigned char globalBrightness)
{
ledObject->_numLEDs = numLEDs;
ledObject->_bytesPerLED = bytesPerLED;
ledObject->_endFrameLength = 1;//round( (numLEDs/2)/8 );
ledObject->_frameLength = (1+numLEDs+ledObject->_endFrameLength)*bytesPerLED;
ledObject->_globalBrightness = globalBrightness;
ledObject->LEDs = (unsigned char *)malloc(ledObject->_frameLength*sizeof(unsigned char));
//Start Frame
ledObject->LEDs[0] = 0;
ledObject->LEDs[1] = 0;
ledObject->LEDs[2] = 0;
ledObject->LEDs[3] = 0;
//Driver frame+PIXEL frames
for(ledObject->_counter=ledObject->_bytesPerLED; ledObject->_counter<ledObject->_frameLength-(ledObject->_endFrameLength*ledObject->_bytesPerLED); ledObject->_counter+=ledObject->_bytesPerLED)
{
ledObject->LEDs[ledObject->_counter] = ledObject->_globalBrightness;
ledObject->LEDs[ledObject->_counter+1] = 0;
ledObject->LEDs[ledObject->_counter+2] = 0;
ledObject->LEDs[ledObject->_counter+3] = 0;
}
//END frames
for(ledObject->_counter=ledObject->_frameLength-(ledObject->_endFrameLength*ledObject->_bytesPerLED); ledObject->_counter<ledObject->_frameLength; ledObject->_counter+=ledObject->_bytesPerLED)
{
ledObject->LEDs[ledObject->_counter] = 255;
ledObject->LEDs[ledObject->_counter+1] = 255;
ledObject->LEDs[ledObject->_counter+2] = 255;
ledObject->LEDs[ledObject->_counter+3] = 255;
}
}
void setPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour)
{
ledObject->_counter = 4*(pixelIndex+1);
ledObject->LEDs[ ledObject->_counter + 1 ] = pixelColour[2];
ledObject->LEDs[ ledObject->_counter + 2 ] = pixelColour[1];
ledObject->LEDs[ ledObject->_counter + 3 ] = pixelColour[0];
}
void getPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour)
{
ledObject->_counter = 4*(pixelIndex+1);
pixelColour[2] = ledObject->LEDs[ ledObject->_counter + 1 ];
pixelColour[1] = ledObject->LEDs[ ledObject->_counter + 2 ];
pixelColour[0] = ledObject->LEDs[ ledObject->_counter + 3 ];
}
#include "badge23/audio.h"
#include "badge23/synth.h"
#include "badge23/scope.h"
#include "badge23_hwconfig.h"
#include "driver/i2s.h"
#include "driver/i2c.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#define TIMEOUT_MS 1000
#define I2C_MASTER_NUM 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
static void audio_player_task(void* arg);
#define DMA_BUFFER_SIZE 64
#define DMA_BUFFER_COUNT 2
#define I2S_PORT 0
#if defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4)
static uint8_t max98091_i2c_read(const uint8_t reg)
{
const uint8_t tx[] = {reg};
uint8_t rx[1];
esp_err_t ret = i2c_master_write_read_device(I2C_MASTER_NUM, 0x10, tx, sizeof(tx), rx, sizeof(rx), TIMEOUT_MS / portTICK_PERIOD_MS);
return rx[0];
}
static esp_err_t max98091_i2c_write(const uint8_t reg, const uint8_t data)
{
const uint8_t tx[] = {reg, data};
esp_err_t ret = i2c_master_write_to_device(I2C_MASTER_NUM, 0x10, tx, sizeof(tx), TIMEOUT_MS / portTICK_PERIOD_MS);
if(max98091_i2c_read(reg) != data) printf("Write of %04X to %02X apparently failed\n", data, reg);
return ret;
}
static void init_codec()
{
// Enable CODEC
vTaskDelay(10 / portTICK_PERIOD_MS);
ESP_ERROR_CHECK(max98091_i2c_write(0x00, 0x80)); // shutdown
vTaskDelay(10 / portTICK_PERIOD_MS);
ESP_ERROR_CHECK(max98091_i2c_write(0x45, 0)); // shutdown
ESP_ERROR_CHECK(max98091_i2c_write(0x1b, 1 << 4)); // pclk = mclk / 1
ESP_ERROR_CHECK(max98091_i2c_write(0x26, (1 << 7) | (1 << 6))); // music, dc filter in record
ESP_ERROR_CHECK(max98091_i2c_write(0x06, 1 << 2)); // Sets up DAI for left-justified slave mode operation.
ESP_ERROR_CHECK(max98091_i2c_write(0x07, 1 << 5)); // Sets up the DAC to speaker path
// Somehow this was needed to get an input signal to the ADC, even though
// all other registers should be taken care of later. Don't know why.
ESP_ERROR_CHECK(max98091_i2c_write(0x09, 1 << 6)); // Sets up the line in to adc path
ESP_ERROR_CHECK(max98091_i2c_write(0x25, (1 << 1) | (1 << 0))); // SDOUT, SDIN enabled
ESP_ERROR_CHECK(max98091_i2c_write(0x42, 1 << 0)); // bandgap bias
ESP_ERROR_CHECK(max98091_i2c_write(0x43, 1 << 0)); // high performane mode
// Table 51. Digital Audio Interface (DAI) Format Configuration Register
ESP_ERROR_CHECK(max98091_i2c_write(0x2E, 1)); // Left DAC -> Left Speaker
ESP_ERROR_CHECK(max98091_i2c_write(0x2F, 2)); // Right DAC -> Right Speaker
//max98091_i2c_write(0x2E, (1<<2) | (1<<1)); // Line A -> Left Speaker
//max98091_i2c_write(0x2F, (1<<3) | (1<<0)); // LIne B -> Right Speaker
ESP_ERROR_CHECK(max98091_i2c_write(0x29, 1)); // Left DAC -> Left HP
ESP_ERROR_CHECK(max98091_i2c_write(0x2A, 2)); // Right DAC -> Right HP
// Mic bias is off
ESP_ERROR_CHECK(max98091_i2c_write(0x3E, (1<<4) |(1<<3) | (1<<2) | (1<<1) | (1<<0))); // enable micbias, line input amps, ADCs
ESP_ERROR_CHECK(max98091_i2c_write(0x0D, (1<<3) | (1<<2))); // IN3 SE -> Line A, IN4 SE -> Line B
ESP_ERROR_CHECK(max98091_i2c_write(0x15, (1<<4) )); // line B -> left ADC
ESP_ERROR_CHECK(max98091_i2c_write(0x16, (1<<3) )); // line A -> right ADC
ESP_ERROR_CHECK(max98091_i2c_write(0x44, (1<<2) | (1<<1) | (1<<0) )); // 128x oversampling, dithering, high performance ADC
max98091_i2c_write(0x13, (1<<4) | (1<<5) | (1<<1) | (1<<0) ); // enable digital mic
// Enable headset mic
#if 0
max98091_i2c_write(0x13, 0);
ESP_ERROR_CHECK(max98091_i2c_write(0x0F, (0<<1) | (1<<0) )); // IN5/IN6 to MIC1
ESP_ERROR_CHECK(max98091_i2c_write(0x10, (1<<6) | (1<<4) | (1<<2) )); // 20 dB gain on MIC1
ESP_ERROR_CHECK(max98091_i2c_write(0x15, (1<<5) )); // MIC1 -> left ADC
ESP_ERROR_CHECK(max98091_i2c_write(0x16, (1<<5) )); // MIC1 -> right ADC
#endif
ESP_ERROR_CHECK(max98091_i2c_write(0x3F, (1<<1) | (1<<0))); // output enable: enable dacs
ESP_ERROR_CHECK(max98091_i2c_write(0x45, 1<<7)); // power up
//max98091_i2c_write(0x31, 0x2c); // 0db, no mute
//max98091_i2c_write(0x32, 0x2c); // 0db, no mute
ESP_ERROR_CHECK(max98091_i2c_write(0x3F, (1<<7) | (1<<6) | (1<<5) | (1<<4) | (1<<1) | (1<<0))); // enable outputs, dacs
//max98091_i2c_write(0x27, (1<<4) | (1<<5)); // full playback gain
//max98091_i2c_write(0x31, 0x3f); // +14 db speaker
//max98091_i2c_write(0x32, 0x3f); // +14 db speaker
ESP_ERROR_CHECK(max98091_i2c_write(0x41, 0x0));
ESP_ERROR_CHECK(max98091_i2c_write(0x3D, 1<<7)); // jack detect enable
}
static void i2s_init(void){
init_codec();
vTaskDelay(100 / portTICK_PERIOD_MS); // dunno if necessary
static const i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = 16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
//.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_LSB,
//^...technically wrong but works...? in idf v5 it's msb but don't try that late at night
.intr_alloc_flags = 0, // default interrupt priority
.dma_buf_count = DMA_BUFFER_COUNT,
.dma_buf_len = DMA_BUFFER_SIZE,
.use_apll = false
};
static const i2s_pin_config_t pin_config = {
.bck_io_num = 10,
.mck_io_num = 18,
.ws_io_num = 11,
.data_out_num = 12,
.data_in_num = I2S_PIN_NO_CHANGE
};
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
i2s_set_pin(I2S_PORT, &pin_config);
}
#elif defined(CONFIG_BADGE23_HW_GEN_P1)
static void i2s_init(void){
static const i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = 16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
//.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags = 0, // default interrupt priority
.dma_buf_count = DMA_BUFFER_COUNT,
.dma_buf_len = DMA_BUFFER_SIZE,
.use_apll = false
};
static const i2s_pin_config_t pin_config = {
.bck_io_num = 13,
.mck_io_num = 11,
.ws_io_num = 12,
.data_out_num = 14,
.data_in_num = I2S_PIN_NO_CHANGE
};
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
i2s_set_pin(I2S_PORT, &pin_config);
}
#else
#error "audio not implemented for this badge generation"
#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){
//construct audio source struct
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;
//handle empty list special case
if(_audio_sources == NULL){
_audio_sources = src;
return 0; //only nonempty lists from here on out!
}
//searching for lowest unused index
audio_source_t * index_source = _audio_sources;
while(1){
if(src->index == (index_source->index)){
src->index++; //someone else has index already, try next
index_source = _audio_sources; //start whole list for new index
} else {
index_source = index_source->next;
}
if(index_source == NULL){ //traversed the entire list
break;
}
}
audio_source_t * audio_source = _audio_sources;
//append new source to linked list
while(audio_source != NULL){
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;
}
vTaskDelay(20 / portTICK_PERIOD_MS); //give other tasks time to stop using
free(audio_source); //terrible hack tbh
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();
//ESP_ERROR_CHECK(i2s_channel_enable(tx_chan));
TaskHandle_t handle;
xTaskCreate(&audio_player_task, "Audio player", 3000, NULL, configMAX_PRIORITIES - 1, &handle);
}
#define LR_PHASE 1
#define NAT_LOG_DB 0.1151292546497023
static uint16_t _global_vol = 3000;
void set_global_vol_dB(int8_t vol_dB){
if(vol_dB < (BADGE_MIN_VOLUME_DB)){
_global_vol = 0;
} else {
if(vol_dB > (BADGE_MAX_VOLUME_DB)) vol_dB = (BADGE_MAX_VOLUME_DB);
uint16_t buf = 3000 * exp(vol_dB * NAT_LOG_DB);
if(buf > (BADGE_VOLUME_LIMIT)) buf = (BADGE_VOLUME_LIMIT);
_global_vol = buf;
}
}
static void audio_player_task(void* arg) {
int16_t buffer[DMA_BUFFER_SIZE * 2];
memset(buffer, 0, sizeof(buffer));
while(true) {
for(int i = 0; i < (DMA_BUFFER_SIZE * 2); i += 2){
float sample = 0;
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;
if(sample < -32767) sample = -32767;
buffer[i] = (int16_t) sample;
buffer[i+1] = LR_PHASE * buffer[i];
}
size_t count = 0;
i2s_write(I2S_PORT, buffer, sizeof(buffer), &count, 1000);
if (count != sizeof(buffer)) {
printf("i2s_write_bytes: count (%d) != length (%d)\n", count, sizeof(buffer));
abort();
}
}
}
void audio_init() { _audio_init(); }
/*
#define NAT_LOG_SEMITONE 0.05776226504666215
void synth_set_bend(int i, float bend){
if(bend != bend) return;
if((bend > -0.0001) && (bend < 0.0001)){
synths[i].bend = 1;
} else {
synths[i].bend = exp(bend * NAT_LOG_SEMITONE);
}
}
*/
/*
void synth_stop(int i){
if(synths[i].env_phase){
synths[i].env_phase = 3;
}
}
void synth_fullstop(int i){
synths[i].env_phase = 0;
}
void synth_start(int i){
synths[i].env_phase = 1; //put into attack phase;
}
float synth_get_env(int i){
return synths[i].env;
}
*/
This diff is collapsed.
#include "badge23/display.h"
#include "gc9a01.h"
#include "esp_log.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/timers.h>
#include <freertos/queue.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "badge23/scope.h"
#include "esp_system.h"
uint16_t *pixels;
typedef struct leds_cfg {
bool active_paddles[10];
} display_cfg_t;
static QueueHandle_t display_queue = NULL;
static void display_task(TimerHandle_t aaaaa);
//static void display_task(void* arg);
static void _display_init() {
GC9A01_Init();
// GC9A01_Screen_Load(0,0,240,240,pixels);
GC9A01_Update();
/*
display_queue = xQueueCreate(1, sizeof(display_cfg_t));
TaskHandle_t handle;
xTaskCreate(&display_task, "Display", 4096, NULL, configMAX_PRIORITIES - 3, &handle);
*/
/* SCOPE TASK
TimerHandle_t aa = xTimerCreate("Display", pdMS_TO_TICKS(100), pdTRUE, (void *) 0, *display_task);
if( xTimerStart(aa, 0 ) != pdPASS )
{
}
*/
}
void display_update(){
GC9A01_Update();
}
void display_draw_pixel(uint8_t x, uint8_t y, uint16_t col){
GC9A01_DrawPixel(x, y, col);
}
uint16_t display_get_pixel(uint8_t x, uint8_t y){
return GC9A01_GetPixel(x,y);
}
void display_fill(uint16_t col){
GC9A01_FillRect(0, 0, 240, 240, col);
}
void display_draw_scope(){
//display_cfg_t display_;
uint16_t line[240];
/*
printf("waiting...\n");
xQueueReceive(display_queue, &display_, portMAX_DELAY);
printf("go...\n");
*/
//uint32_t t0 = esp_log_timestamp();
begin_scope_read();
for(int y=0; y<240; y++){
read_line_from_scope(&(line[0]), y);
memcpy(&ScreenBuff[y * 240], line, sizeof(line));
}
end_scope_read();
//uint32_t td = esp_log_timestamp() - t0;
// printf("it took %lu\n", td);
display_update();
}
//static void display_task(void* arg) {
static void display_task(TimerHandle_t aaaaa) {
display_draw_scope();
}
void display_init() { _display_init(); }
#include "badge23/captouch.h"
#include "badge23/audio.h"
#include "badge23/leds.h"
#include "badge23/display.h"
#include "badge23/spio.h"
#include "badge23_hwconfig.h"
#include "esp_log.h"
#include "driver/i2c.h"
#include "driver/spi_master.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdint.h>
static const char *TAG = "espan";
#define I2C_MASTER_NUM 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
#define I2C_MASTER_FREQ_HZ 400000 /*!< I2C master clock frequency */
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#if defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4)
#define CONFIG_I2C_MASTER_SDA 2
#define CONFIG_I2C_MASTER_SCL 1
#elif defined(CONFIG_BADGE23_HW_GEN_P1)
#define CONFIG_I2C_MASTER_SDA 10
#define CONFIG_I2C_MASTER_SCL 9
#else
#error "i2c not implemented for this badge generation"
#endif
static esp_err_t i2c_master_init(void)
{
int i2c_master_port = I2C_MASTER_NUM;
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = CONFIG_I2C_MASTER_SDA,
.scl_io_num = CONFIG_I2C_MASTER_SCL,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
};
i2c_param_config(i2c_master_port, &conf);
return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}
#define CAPTOUCH_POLLING_PERIOD 10
void os_app_main(void)
{
ESP_LOGI(TAG, "Starting on %s...", badge23_hw_name);
ESP_ERROR_CHECK(i2c_master_init());
ESP_LOGI(TAG, "I2C initialized successfully");
set_global_vol_dB(-90);
audio_init();
leds_init();
init_buttons();
captouch_init();
vTaskDelay(2000 / portTICK_PERIOD_MS);
set_global_vol_dB(0);
display_init();
while(1) {
manual_captouch_readout(1);
vTaskDelay((CAPTOUCH_POLLING_PERIOD) / portTICK_PERIOD_MS);
manual_captouch_readout(0);
vTaskDelay((CAPTOUCH_POLLING_PERIOD) / portTICK_PERIOD_MS);
update_button_state();
vTaskDelay((CAPTOUCH_POLLING_PERIOD) / portTICK_PERIOD_MS);
//display_draw_scope();
}
ESP_ERROR_CHECK(i2c_driver_delete(I2C_MASTER_NUM));
ESP_LOGI(TAG, "I2C de-initialized successfully");
}
#ifndef DEF_apa102LEDStrip
#define DEF_apa102LEDStrip
struct apa102LEDStrip
{
unsigned char *LEDs;
short int _frameLength;
short int _endFrameLength;
short int _numLEDs;
unsigned char _bytesPerLED;
short int _counter;
unsigned char _globalBrightness;
};
void initLEDs(struct apa102LEDStrip *ledObject, short int numLEDs, unsigned char bytesPerLED, unsigned char globalBrightness);
void setPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour);
void getPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour);
#endif
#pragma once
#include <stdint.h>
#define SAMPLE_RATE 16000
#define BADGE_MAX_VOLUME_DB 20
#define BADGE_MIN_VOLUME_DB (-80)
#define BADGE_VOLUME_LIMIT 30000
void audio_init();
void set_global_vol_dB(int8_t vol_dB);
uint16_t count_audio_sources();
uint16_t add_audio_source(void * render_data, void * render_function);
void remove_audio_source(uint16_t index);
#pragma once
#include <stdint.h>
void captouch_init(void);
void captouch_print_debug_info(void);
void gpio_event_handler(void * arg);
void manual_captouch_readout(uint8_t top);
void captouch_get_cross(int paddle, int * x, int * y);
void captouch_force_calibration();
uint16_t read_captouch();
/*
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.
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
#define IMAGE_W 240
#define IMAGE_H 240
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Decode the jpeg ``image.jpg`` embedded into the program file into pixel data.
*
* @param pixels A pointer to a pointer for an array of rows, which themselves are an array of pixels.
* Effectively, you can get the pixel data by doing ``decode_image(&myPixels); pixelval=myPixels[ypos][xpos];``
* @return - ESP_ERR_NOT_SUPPORTED if image is malformed or a progressive jpeg file
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on succesful decode
*/
esp_err_t decode_image(uint16_t **pixels);
#ifdef __cplusplus
}
#endif
#pragma once
#include <stdbool.h>
#include <stdint.h>
void display_init();
void display_draw_scope();
void display_update();
void display_draw_pixel(uint8_t x, uint8_t y, uint16_t col);
uint16_t display_get_pixel(uint8_t x, uint8_t y);
void display_fill(uint16_t col);
#pragma once
void os_app_main(void);
#pragma once
#include <stdint.h>
void leds_init();
void leds_set_single_rgb(uint8_t index, uint8_t red, uint8_t green, uint8_t blue);
void leds_set_single_hsv(uint8_t index, float hue, float sat, float value);
void leds_update();
#pragma once
#include <stdint.h>
typedef struct {
int16_t * buffer;
int16_t buffer_size;
int16_t write_head_position; // last written value
volatile uint8_t is_being_read;
} scope_t;
void init_scope(uint16_t size);
void write_to_scope(int16_t value);
void begin_scope_read();
void end_scope_read();
void read_line_from_scope(uint16_t * line, int16_t point);
#pragma once
#include <stdint.h>
int8_t get_button_state(bool leftbutton);
void update_button_state();
void init_buttons();
#pragma once
#include <stdint.h>
#include <stdio.h>
#define TRAD_OSC_DECAY_STEP 0.01
#define TRAD_OSC_ATTACK_STEP 0.01
#define TRAD_OSC_MIN_ATTACK_ENV 0.01
#define TRAD_OSC_ATTACK_POP_BLOCK 16
typedef struct {
//user variables
float freq; //in hertz, negative frequencies for linFM allowed
float bend;
float vol; //output volume
float env;
uint8_t env_phase; //0: off, 1: attack, 2: hold, 3: decay
uint8_t skip_hold;
float gate; //below what volume the oscillator stops and returns 0
uint16_t decay_steps; //after how many sample rate steps the volume reduces
//by factor TRAD_OSC_DECAY_STEP, set 0 for no decay
uint16_t attack_steps;
uint8_t waveform; //0: sine, 1: fast sine, 2: tri, 3: saw,
//4: square, 5: 33% pulse, 6: 25% pulse
//internal data storage, not for user access
float counter; //state of central sawtooth oscillator, [-1..1] typ.
uint16_t env_counter;
int8_t overflow_event; //set to -1 when counter underflows (below -1),
//set to +1 when counter overflows (above 1)
//not reset or used by anything so far
uint16_t noise_reg;
} trad_osc_t;
//#define KS_BUFFER_SIZE (SAMPLE_RATE)/20
#define KS_BUFFER_SIZE 800
typedef struct {
//user variables
float freq; //frequency in hertz, negative frequencies are rectified,
//minimum freq determined by KS_BUFFER_SIZE
float feedback; //feedback value, will be compensated with frequency
//for equal decay across spectrum, [-1..1] without
//internal data storage, not for user access
float tape[KS_BUFFER_SIZE]; //the delay chain
float real_feedback; //compensated feedback value
} ks_osc_t; //karplus strong
float run_trad_osc(trad_osc_t * osc);
void trad_osc_set_freq_semitone(trad_osc_t * osc, float bend);
void trad_osc_set_freq_Hz(trad_osc_t * osc, float freq);
void trad_osc_set_waveform(trad_osc_t * osc, uint8_t waveform);
void trad_osc_set_attack(trad_osc_t * osc, uint16_t attack);
void trad_osc_set_decay(trad_osc_t * osc, uint16_t decay);
void trad_env_stop(trad_osc_t * osc);
void trad_env_fullstop(trad_osc_t * osc);
void trad_env_start(trad_osc_t * osc);
void render_audio(
instrument_descriptor_t instrument_descriptor,
instrument_t instance,
unsigned int sample_count,
float * output_vector
){
for(unsigned int i = 0; i < sample_count; i++){
instrument_descriptor->render_audio_sample(instance, sample_count, output_vector[2*i]);
}
}
void render_audio_adding(
instrument_descriptor_t instrument_descriptor,
instrument_t instance,
unsigned int sample_count,
float * output_vector,
float gain
){
if(gain <= 0.0000001) return;
float temp[2];
for(unsigned int i = 0; i < sample_count; i++){
instrument_descriptor->render_audio_sample(instance, sample_count, temp);
output_vector[2*i] += gain * buffer[0];
output_vector[2*i+1] += gain * buffer[1];
}
}
void append_instrument_descriptor(
instrument_descriptor_list_t * list,
void * construct_instrument_descriptor
){
lle_t * element = list;
while(element->next != NULL){
element = element->next;
}
element->next = malloc(sizeof(lle_t);
if(element->next == NULL) return;
element = element->next;
element->next = NULL;
element->content = construct_instrument_descriptor();
}
instrument_descriptor_list_t * list_builtin_instrument_descriptors(){
//really hope we can make this more elegant some day
instrument_descriptor_list_t * list = NULL;
//add your instrument here!
append_instrument_descriptor(list, &minimal_example_descriptor);
return list;
}
void instantiate_instrument(active_instrument_list_t instruments,
instrument_descriptor_t descriptor
){
descriptor->new_instrument
}
void mix_instruments_audio(active_instrument_list_t instruments,
unsigned int sample_count,
float * output_vector
){
active_instrument_t instrument = instruments;
while(instrument->next != NULL){
render_audio_adding(instrument->descriptor,
instrument->instrument,
sample_count,
output_vector,
instrument->gain)
instrument = instrument->next;
}
}
/* wip instrument api for badge23 (in large parts inspired by ladspa)
current status: none of this is hooked up or functional or compiles, just drafting things rn
some core concepts:
- several instruments can run at the same time (e.g., drum computer running in background),
with only one of them being in foreground and using buttons and display
- instruments are as "self contained" as possible, i.e. they access buttons and display with
minimal host involvement and pretty much just produce audio "on their own". aside from
scheduling the host mostly does some cap touch preprocessing and the audio output mixdown
- different timing requirements -> different "threads" for audio, buttons, display each
(leds: special case, see below)
open questions:
- led animations: instruments should be able to output led patterns. maybe keeping a dummy
led array in ram for each running instrument and allowing users to create and run "shaders"
would be a desirable functional mode; do we want this/does this need any extra api?
- for performance reasons: instruments are expected to behave themselves, i.e. not access hw
without permission or write to read-only locations, can we do better than that without
excessive overhead? and if we can, do we _want_ to? (devices that make electronic musical
instruments malfunction on purpose are not uncommon in general)
- badge link/cv data input/output: can probably be added to the descriptor easily? shouldn't
freeze api before tho
*/
//===========================================================================================
//some hardware dummy definitions, move somewhere else someday maybe
typedef struct {
int intensity; //touch strength, considered as no touch if below 0
int rad; //radial position
int az; //cw azimuthal position (only meaningful for top petals);
} petal_t;
typedef int button_t; //0: no press, -1: left, 1: right, 2: down
typedef struct { //read-only (shared between all instruments, unprotected)
petal_t petals[10]; //even: top, odd: bottom, 0 at usb-c jack, count ccw
button_t button; //can be either left or right, depending on host
//handedness settings. the other button is reserved for
//host use and is not exposed here.
} hardware_inputs_t;
//===========================================================================================
typedef void * instrument_t; //contains instrument instance data, not to be interpreted by host
typedef struct _instrument_descriptor_t {
unsigned int unique_id;
//null terminated instrument name
const char * name;
//allocates memory for new instance data and returns pointer to it (mandatory)
instrument_t (* new_instrument)(const struct _instrument_descriptor * descriptor,
unsigned int sample_rate,
hardware_inputs_t * hw);
//frees instance data memory (mandatory)
void (* delete_instrument) (instrument_t instance);
//renders a single stereo audio sample (optional, NULL if not supported)
void (* render_audio_sample) (instrument_t instance);
//handles petal/button/sensor input, ideally runs every 3-8ms (optional, NULL if not supported)
void (* process_user_input) (instrument_t instance);
//only runs when instrument is in foreground (optional, NULL if not supported)
void (* update_display) (instrument_t instance);
//(optional, NULL if not supported)
void (* update_leds) (instrument_t instance);
} instrument_descriptor_t;
// this function is called once per instrument type before use (i.e. around boot) and returns a
// filled out instrument descriptor struct to be used by the host for creating instrument instances
// returns null if allocation fails
const instrument_descriptor_t * contruct_instrument_descriptor();
//===========================================================================================
//host-side helper functions
void render_audio(
instrument_descriptor_t instrument_descriptor,
instrument_t instance,
unsigned int sample_count,
float * output_vector
);
void render_audio_adding(
instrument_descriptor_t instrument_descriptor,
instrument_t instance,
unsigned int sample_count,
float * output_vector,
float gain
);
typedef struct {
void * content;
lle_t * next;
} lle_t; //linked list element
typedef lle_t instrument_descriptor_list_t;
typedef struct {
instrument_t * instrument;
instrument_descriptor_t descriptor;
char is_foreground;
char is_rendering_leds;
float gain;
} active_instrument_t;
void append_instrument_descriptor(
instrument_descriptor_list_t * list,
void * construct_instrument_descriptor
);
instrument_descriptor_list_t * list_builtin_instrument_descriptors();
typedef lle_t active_instrument_list_t;
void mix_instruments_audio(active_instrument_list_t instruments,
unsigned int sample_count,
float * output_vector
);
//===========================================================================================