From d9b1edadfe33ca49f22fa7f52b4bfcc2d326b154 Mon Sep 17 00:00:00 2001 From: Anthony Rabine Date: Thu, 10 Aug 2023 09:00:45 +0200 Subject: [PATCH] (wip) mono and dynamic sample rate support --- .../raspberry-pico-w/pico_hal_wrapper.c | 20 ++--- software/platform/raspberry-pico-w/pico_i2s.c | 45 +---------- software/platform/raspberry-pico-w/pico_i2s.h | 5 +- software/system/audio_player.c | 81 +++++++++++-------- software/system/audio_player.h | 5 +- software/system/filesystem.c | 1 + software/system/fs_task.c | 12 ++- software/system/vm_task.c | 24 ++++-- 8 files changed, 93 insertions(+), 100 deletions(-) diff --git a/software/platform/raspberry-pico-w/pico_hal_wrapper.c b/software/platform/raspberry-pico-w/pico_hal_wrapper.c index aba5c35..799027a 100644 --- a/software/platform/raspberry-pico-w/pico_hal_wrapper.c +++ b/software/platform/raspberry-pico-w/pico_hal_wrapper.c @@ -77,12 +77,18 @@ static uint32_t ButtonsStatePrev = 0; // Rotary encoder // pio 0 is used -PIO pio = pio1; +static PIO pio = pio1; // state machine 0 -uint8_t sm = 0; +static uint8_t sm = 0; static int new_value, delta, old_value = 0; +static audio_i2s_config_t config = { + .freq = 44100, + .bps = 32, + .data_pin = 28, + .clock_pin_base = 26}; + // =========================================================================================================== // PROTOTYPES // =========================================================================================================== @@ -261,14 +267,7 @@ void ost_system_initialize() gpio_set_function(SDCARD_MISO, GPIO_FUNC_SPI); //------------------- Init Sound - static const audio_i2s_config_t config = { - .freq = 44100, - .bps = 32, - .data_pin = 28, - .clock_pin_base = 26}; - i2s_program_setup(pio0, audio_i2s_dma_irq_handler, &i2s, &config); - audio_init(&audio_ctx); // ------------ Everything is initialized, print stuff here @@ -425,6 +424,9 @@ void ost_display_transfer_multi(uint8_t *buff, uint32_t btr) void ost_audio_play(const char *filename) { audio_play(&audio_ctx, filename); + config.freq = audio_ctx.audio_info.sample_rate; + config.channels = audio_ctx.audio_info.channels; + pico_i2s_set_frequency(&i2s, &config); i2s.buffer_index = 0; diff --git a/software/platform/raspberry-pico-w/pico_i2s.c b/software/platform/raspberry-pico-w/pico_i2s.c index c44a0b7..68a66da 100644 --- a/software/platform/raspberry-pico-w/pico_i2s.c +++ b/software/platform/raspberry-pico-w/pico_i2s.c @@ -18,50 +18,13 @@ void pico_i2s_set_frequency(const pio_i2s *i2s, const audio_i2s_config_t *config) { - float bitClk = config->freq * config->bps * 2.0 /* channels */ * 2.0 /* edges per clock */; + // Pour le calcul de la fréquence, le nombre de canaux est toujours fixé à 2 + // car c'est notre format de sortie I2S + // Dans le cas du mono, on l'a détecté en amont et on a copié l'échantillon dans la voie de droite + float bitClk = config->freq * config->bps * config->channels /* channels */ * 2.0 /* edges per clock */; pio_sm_set_clkdiv(i2s->pio, i2s->sm_dout, (float)clock_get_hz(clk_sys) / bitClk); } -#if 0 - -static bool audio_enabled; - -void audio_i2s_set_enabled(bool enabled) -{ - if (enabled != audio_enabled) - { -#ifndef NDEBUG - if (enabled) - { - puts("Enabling PIO I2S audio\n"); - printf("(on core %d\n", get_core_num()); - } -#endif - irq_set_enabled(DMA_IRQ_0 + PICO_AUDIO_I2S_DMA_IRQ, enabled); - - if (enabled) - { - // audio_start_dma_transfer(); - } - else - { - /* - // if there was a buffer in flight, it will not be freed by DMA IRQ, let's do it manually - if (shared_state.playing_buffer) - { - give_audio_buffer(audio_i2s_consumer, shared_state.playing_buffer); - shared_state.playing_buffer = NULL; - } - */ - } - - pio_sm_set_enabled(audio_pio, shared_state.pio_sm, enabled); - - audio_enabled = enabled; - } -} -#endif - //--------------------------------------------------------------------------------------------------------------------------- static void dma_double_buffer_init(pio_i2s *i2s) diff --git a/software/platform/raspberry-pico-w/pico_i2s.h b/software/platform/raspberry-pico-w/pico_i2s.h index 257bdb0..10d4403 100644 --- a/software/platform/raspberry-pico-w/pico_i2s.h +++ b/software/platform/raspberry-pico-w/pico_i2s.h @@ -20,13 +20,11 @@ extern "C" { #endif -#define AUDIO_BUFFER_FRAMES SIZE_OF_SAMPLES -#define STEREO_BUFFER_SIZE AUDIO_BUFFER_FRAMES * 2 // for left + right - typedef struct { uint32_t freq; uint32_t bps; + uint16_t channels; uint8_t data_pin; uint8_t clock_pin_base; @@ -48,6 +46,7 @@ extern "C" void i2s_program_setup(PIO pio, void (*dma_handler)(void), pio_i2s *i2s, const audio_i2s_config_t *config); + void pico_i2s_set_frequency(const pio_i2s *i2s, const audio_i2s_config_t *config); void i2s_start(pio_i2s *i2s); void i2s_stop(pio_i2s *i2s); diff --git a/software/system/audio_player.c b/software/system/audio_player.c index b77e096..3fb6292 100644 --- a/software/system/audio_player.c +++ b/software/system/audio_player.c @@ -10,11 +10,10 @@ #include "ost_hal.h" #include "serializers.h" -// Audio Double Buffer for DMA transfer -int32_t audio_buf[SIZE_OF_SAMPLES * 2]; // x2 because we store L+R +int32_t audio_buf[STEREO_BUFFER_SIZE]; // x2 because we store L+R // Audio Buffer for File Read -uint8_t raw_buf[SIZE_OF_SAMPLES * 2 * 2]; // x2 for 16-bit, and x2 for L+R +uint8_t raw_buf[AUDIO_BUFFER_FRAMES * 2 * 2]; // x2 for 16-bit, and x2 for L+R int32_t DAC_ZERO_VALUE = 1; // @@ -59,12 +58,12 @@ void audio_init(audio_ctx_t *ctx) ctx->volume = 65; ctx->count = 0; - for (int i = 0; i < SIZE_OF_SAMPLES; i++) + for (int i = 0; i < STEREO_BUFFER_SIZE; i++) { audio_buf[i] = DAC_ZERO_VALUE; } - ctx->transfer_size = SIZE_OF_SAMPLES / 4; + ctx->transfer_size = STEREO_BUFFER_SIZE; } static int list_chunk_is_info_type(audio_ctx_t *ctx) @@ -95,12 +94,14 @@ static int load_next_file(audio_ctx_t *ctx, const char *fname_ptr) fr = f_open(&ctx->fil, ctx->audio_info.filename, FA_READ); if (fr != FR_OK) { - debug_printf("ERROR: f_open %d\n\r", (int)fr); + debug_printf("ERROR: f_open %d for file: %s\n\r", (int)fr, fname_ptr); } ctx->idx_play++; FRESULT res = f_read(&ctx->fil, ctx->header, sizeof(ctx->header), &br); - // Find 'data' chunk + ctx->audio_info.channels = leu16_get(&ctx->header[22]); + ctx->audio_info.sample_rate = leu32_get(&ctx->header[24]); + // Find 'data' chunk offset = 0; while (1) { @@ -116,17 +117,29 @@ static int load_next_file(audio_ctx_t *ctx, const char *fname_ptr) } else { + debug_printf("[AUDIO_PLAYER] Data not found, invalid file\r\n"); + return 0; break; } } - ctx->audio_info.data_size = size; - // printf("Audio data size = %d\n\r", (int) audio_info.data_size); - ctx->audio_info.data_start = offset; - ctx->audio_info.data_offset = 0; - return 1; - } - return 0; + if (size == 0) + { + debug_printf("[AUDIO_PLAYER] Empty audio file\r\n"); + return 0; + } + else + { + debug_printf("[AUDIO_PLAYER] Load WAV: \r\n - Channels: %d\r\n - Sample rate: %d\r\n", ctx->audio_info.channels, ctx->audio_info.sample_rate); + ctx->audio_info.data_size = size; + // printf("Audio data size = %d\n\r", (int) audio_info.data_size); + ctx->audio_info.data_start = offset; + ctx->audio_info.data_offset = 0; + return 1; + } + + return 0; + } } static int get_level(uint32_t val) @@ -164,6 +177,7 @@ static int get_audio_buf(audio_ctx_t *ctx, int32_t *buf_32b) uint32_t lvl_r = 0; number = 0; // number to transfer (en octets) + while (number < sizeof(raw_buf)) { file_rest = ctx->audio_info.data_size - ctx->audio_info.data_offset; @@ -192,18 +206,31 @@ static int get_audio_buf(audio_ctx_t *ctx, int32_t *buf_32b) } } - static bool onetime = true; + bool mono = ctx->audio_info.channels == 1; + uint32_t index = 4; + if (mono) + { + index = 2; + } // samples : total bytes devided by 2 (16 bits) and by two again (2 channels) - for (i = 0; i < number / 4; i++) + for (i = 0; i < number / index; i++) { // buf_32b[i * 2 + 0] = (int32_t)swap16b((int32_t)buf_16b[i * 2 + 0] * vol_table[ctx->volume]) + DAC_ZERO_VALUE; // L // buf_32b[i * 2 + 1] = (int32_t)swap16b((int32_t)buf_16b[i * 2 + 1] * vol_table[ctx->volume]) + DAC_ZERO_VALUE; // R // Avec le AUDIO PICO de waveshare, on entend un truc - buf_32b[i * 2] = ((int32_t)((int16_t)leu16_get(&raw_buf[i * 4]))) << 16; - buf_32b[i * 2 + 1] = ((int32_t)((int16_t)leu16_get(&raw_buf[i * 4 + 2]))) << 16; + buf_32b[i * 2] = ((int32_t)((int16_t)leu16_get(&raw_buf[i * index]))) << 16; + + if (mono) + { + buf_32b[i * 2 + 1] = buf_32b[i * 2]; + } + else + { + buf_32b[i * 2 + 1] = ((int32_t)((int16_t)leu16_get(&raw_buf[i * index + 2]))) << 16; + } // buf_32b[i * 2] = 1; // buf_32b[i * 2 + 1] = 4; @@ -211,21 +238,9 @@ static int get_audio_buf(audio_ctx_t *ctx, int32_t *buf_32b) // lvl_l += ((int32_t)buf_16b[i * 2 + 0] * buf_16b[i * 2 + 0]) / 32768; // lvl_r += ((int32_t)buf_16b[i * 2 + 1] * buf_16b[i * 2 + 1]) / 32768; } - /* - if (onetime) - { - onetime = false; - - for (int i = 0; i < 10; i++) - { - debug_printf("Sample left: %d\r\n", buf_32b[i * 2]); - debug_printf("Sample right: %d\r\n", buf_32b[i * 2 + 1]); - } - } - */ // ctx->audio_info.lvl_l = get_level(lvl_l / (number / 4)); // ctx->audio_info.lvl_r = get_level(lvl_r / (number / 4)); - ctx->transfer_size = (number / 2); // 32 bytes tranfers + ctx->transfer_size = number / 2; // 32 bytes tranfers return _next_is_end; } @@ -245,11 +260,11 @@ int audio_process(audio_ctx_t *ctx) } else { - for (int i = 0; i < SIZE_OF_SAMPLES; i++) + for (int i = 0; i < STEREO_BUFFER_SIZE; i++) { audio_buf[i] = DAC_ZERO_VALUE; } - ctx->transfer_size = SIZE_OF_SAMPLES / 4; + ctx->transfer_size = STEREO_BUFFER_SIZE; } ctx->count++; diff --git a/software/system/audio_player.h b/software/system/audio_player.h index 9699441..5783241 100644 --- a/software/system/audio_player.h +++ b/software/system/audio_player.h @@ -6,7 +6,8 @@ #include -#define SIZE_OF_SAMPLES (128) // in bytes +#define AUDIO_BUFFER_FRAMES (128) // in bytes +#define STEREO_BUFFER_SIZE AUDIO_BUFFER_FRAMES * 2 // for left + right #define FILENAME_MAX_SIZE 260 typedef struct @@ -18,6 +19,8 @@ typedef struct uint32_t data_start; uint32_t data_size; uint32_t data_offset; + uint32_t sample_rate; + uint16_t channels; char artist[256]; char title[256]; char album[256]; diff --git a/software/system/filesystem.c b/software/system/filesystem.c index 1240bc1..efe67a3 100644 --- a/software/system/filesystem.c +++ b/software/system/filesystem.c @@ -109,6 +109,7 @@ void filesystem_mount() } scan_files(""); + scan_files("/ba869e4b-03d6-4249-9202-85b4cec767a7/assets"); } uint32_t filesystem_get_capacity() diff --git a/software/system/fs_task.c b/software/system/fs_task.c index a3cb512..4061187 100644 --- a/software/system/fs_task.c +++ b/software/system/fs_task.c @@ -50,7 +50,8 @@ typedef struct fs_result_cb_t cb; } ost_fs_event_t; -#define STORY_DIR_OFFSET (UUID_SIZE + 1) +#define ASSETS_DIR "/assets/" +#define STORY_DIR_OFFSET (UUID_SIZE + 1) // +1 for the first '/' (filesystem root) // =========================================================================================================== // PRIVATE GLOBAL VARIABLES @@ -68,9 +69,6 @@ static int PacketCounter = 0; static char ScratchFile[260]; -static const char *ImagesDir = "/images/"; -static const char *SoundsDir = "/sounds/"; - static uint8_t LedState = 0; // =========================================================================================================== @@ -119,7 +117,7 @@ void FsTask(void *args) if (OstContext.sound != NULL) { ScratchFile[STORY_DIR_OFFSET] = 0; - strcat(ScratchFile, SoundsDir); + strcat(ScratchFile, ASSETS_DIR); strcat(ScratchFile, message->sound); debug_printf("\r\n-------------------------------------------------------\r\nPlaying: %s\r\n", ScratchFile); @@ -151,7 +149,7 @@ void FsTask(void *args) if (OstContext.image != NULL) { ScratchFile[STORY_DIR_OFFSET] = 0; - strcat(ScratchFile, ImagesDir); + strcat(ScratchFile, ASSETS_DIR); strcat(ScratchFile, message->image); filesystem_display_image(ScratchFile); @@ -168,7 +166,7 @@ void FsTask(void *args) // Init current directory ScratchFile[0] = '/'; memcpy(&ScratchFile[1], OstContext.uuid, UUID_SIZE); - ScratchFile[1 + UUID_SIZE] = 0; + ScratchFile[STORY_DIR_OFFSET] = 0; success = true; } diff --git a/software/system/vm_task.c b/software/system/vm_task.c index ea22822..7270f38 100644 --- a/software/system/vm_task.c +++ b/software/system/vm_task.c @@ -164,6 +164,7 @@ void VmTask(void *args) ost_vm_state_t VmState = OST_VM_STATE_HOME; fs_task_scan_index(read_index_callback); bool run_script = false; + bool block_keys = false; while (1) { @@ -176,17 +177,28 @@ void VmTask(void *args) case OST_VM_STATE_HOME: switch (message->ev) { + case VM_EV_END_OF_SOUND: + block_keys = false; + break; + case VM_EV_EXEC_HOME_INDEX: // La lecture de l'index est terminée, on demande l'affichage des médias - fs_task_play_index(); + if (!block_keys) + { + block_keys = true; + fs_task_play_index(); + } break; case VM_EV_BUTTON_EVENT: - // debug_printf("B: %x", message->button_mask); - if ((message->button_mask & OST_BUTTON_OK) == OST_BUTTON_OK) + if (!block_keys) { - VmState = OST_VM_STATE_HOME_WAIT_LOAD_STORY; - debug_printf("OK\r\n"); - fs_task_load_story(m_rom_data); + // debug_printf("B: %x", message->button_mask); + if ((message->button_mask & OST_BUTTON_OK) == OST_BUTTON_OK) + { + VmState = OST_VM_STATE_HOME_WAIT_LOAD_STORY; + debug_printf("OK\r\n"); + fs_task_load_story(m_rom_data); + } } break; case VM_EV_ERROR: