(wip) mono and dynamic sample rate support

This commit is contained in:
Anthony Rabine 2023-08-10 09:00:45 +02:00
parent 620f06bf6c
commit d9b1edadfe
8 changed files with 93 additions and 100 deletions

View file

@ -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;

View file

@ -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)

View file

@ -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);

View file

@ -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++;

View file

@ -6,7 +6,8 @@
#include <ff.h>
#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];

View file

@ -109,6 +109,7 @@ void filesystem_mount()
}
scan_files("");
scan_files("/ba869e4b-03d6-4249-9202-85b4cec767a7/assets");
}
uint32_t filesystem_get_capacity()

View file

@ -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;
}

View file

@ -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: