sort of working....

This commit is contained in:
Mitchell Marino 2025-03-26 01:52:42 -05:00
parent babe2f828e
commit 62b82eba2b
2 changed files with 152 additions and 15 deletions

View File

@ -1,8 +1,103 @@
#include "speaker.h" #include "speaker.h"
static const char *TAG = "speaker";
typedef struct {
/// The path to the file being played.
char* file_name;
/// The handle to the file being played.
FILE* file_handle;
/// A number that all samples will be shifted right by.
uint8_t prescaler;
/// A flag for repeating.
bool repeat;
} playing_audio_clip_t;
i2s_chan_handle_t tx_chan; i2s_chan_handle_t tx_chan;
static const char *TAG = "speaker"; /// A queue of `audio_clip_t`s to be played once there is nothing being played
QueueHandle_t sequential_clip_queue;
/// The clips that are currently playing
std::vector<playing_audio_clip_t> playing_clips;
static void speaker_task(void* arg) {
audio_clip_t next_clip;
playing_audio_clip_t playing_next_clip;
int16_t* audio_buf = (int16_t*) malloc(AUDIO_BLOCK_SIZE * sizeof(int16_t));
int16_t* file_buf = (int16_t*) malloc(AUDIO_BLOCK_SIZE * sizeof(int16_t));
// wait for a clip request.
while (!xQueueReceive(sequential_clip_queue, &next_clip, portMAX_DELAY));
ESP_LOGI(TAG, "opening %s", next_clip.file_name);
FILE* fh = fopen(next_clip.file_name, "rb");
if (fh != NULL) {
ESP_LOGI(TAG, "fh was not null!");
// skip the .wav header
fseek(fh, 44, SEEK_SET);
playing_next_clip = {
.file_name = next_clip.file_name,
.file_handle = fh,
.prescaler = next_clip.prescaler,
.repeat = next_clip.repeat,
};
playing_clips.push_back(playing_next_clip);
} else {
ESP_LOGI(TAG, "null :(");
}
i2s_channel_enable(tx_chan);
while (1) {
std::memset(audio_buf, 0, AUDIO_BLOCK_SIZE * sizeof(int16_t));
ESP_LOGI(TAG, "size: %d", playing_clips.size());
for (int clip_idx = playing_clips.size()-1; clip_idx >= 0; clip_idx--) {
ESP_LOGI(TAG, "i: %d", clip_idx);
playing_audio_clip_t& clip = playing_clips.at(clip_idx);
ESP_LOGI(TAG, "r %d", (size_t) clip.file_handle);
// ESP_LOGI(TAG, "reading from %s", clip.file_name);
size_t samples_read = fread(file_buf, sizeof(uint16_t), AUDIO_BLOCK_SIZE, clip.file_handle);
ESP_LOGI(TAG, "read! %d", samples_read);
if (samples_read == 0) {
if (clip.repeat) {
ESP_LOGI(TAG, "repeating...");
fseek(fh, 44, SEEK_SET);
} else {
ESP_LOGI(TAG, "deleting...");
fclose(clip.file_handle);
free(clip.file_name);
playing_clips.erase(playing_clips.begin() + clip_idx);
}
continue;
}
for (int i = 0; i < samples_read; i++) {
audio_buf[i] += (file_buf[i] >> clip.prescaler);
}
}
size_t bytes_written;
i2s_channel_write(tx_chan, audio_buf, AUDIO_BLOCK_SIZE * sizeof(int16_t), &bytes_written, portMAX_DELAY);
}
// xQueuePeek(sequential_clip_queue, &next_clip, 0);
// QueueHandle_t stop_music = xQueueCreate(2, sizeof (uint8_t));
// if (stop_music == 0) {
// ESP_LOGW(TAG, "Could not create stop_music queue!");
// vTaskDelete(NULL);
// }
// while (playing_music) {
// play_raw_stop_queue(MOUNT_POINT "/tetris.pcm", stop_music);
// }
vTaskDelete(NULL);
}
esp_err_t play_raw_stop_queue(const char *fp, QueueHandle_t stop_handle) { esp_err_t play_raw_stop_queue(const char *fp, QueueHandle_t stop_handle) {
FILE *fh = fopen(fp, "rb"); FILE *fh = fopen(fp, "rb");
@ -10,10 +105,11 @@ esp_err_t play_raw_stop_queue(const char *fp, QueueHandle_t stop_handle) {
ESP_LOGE(TAG, "Failed to open file"); ESP_LOGE(TAG, "Failed to open file");
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
// create a writer buffer // create a writer buffer
uint8_t *read_buf = (uint8_t*) calloc(AUDIO_BUFFER, sizeof(uint8_t)); uint8_t *read_buf = (uint8_t*) calloc(AUDIO_BLOCK_SIZE, sizeof(uint8_t));
uint16_t *write_buf = (uint16_t*) calloc(AUDIO_BUFFER, sizeof(uint16_t)); uint16_t *write_buf = (uint16_t*) calloc(AUDIO_BLOCK_SIZE, sizeof(uint16_t));
size_t bytes_read = 0; size_t bytes_read = 0;
size_t bytes_written = 0; size_t bytes_written = 0;
@ -23,7 +119,7 @@ esp_err_t play_raw_stop_queue(const char *fp, QueueHandle_t stop_handle) {
return channel_enable_result; return channel_enable_result;
} }
bytes_read = fread(read_buf, sizeof(uint8_t), AUDIO_BUFFER, fh); bytes_read = fread(read_buf, sizeof(uint8_t), AUDIO_BLOCK_SIZE, fh);
for (int i = 0; i < bytes_read; i++) { for (int i = 0; i < bytes_read; i++) {
write_buf[i] = read_buf[i] << 4; write_buf[i] = read_buf[i] << 4;
} }
@ -38,7 +134,7 @@ esp_err_t play_raw_stop_queue(const char *fp, QueueHandle_t stop_handle) {
// printf("%s0x%04X ", (val < 0 ? "-" : "+"), (val < 0 ? -val : val)); // printf("%s0x%04X ", (val < 0 ? "-" : "+"), (val < 0 ? -val : val));
// }> // }>
i2s_channel_write(tx_chan, write_buf, bytes_read * sizeof(int16_t), &bytes_written, portMAX_DELAY); i2s_channel_write(tx_chan, write_buf, bytes_read * sizeof(int16_t), &bytes_written, portMAX_DELAY);
bytes_read = fread(read_buf, sizeof(uint8_t), AUDIO_BUFFER, fh); bytes_read = fread(read_buf, sizeof(uint8_t), AUDIO_BLOCK_SIZE, fh);
for (int i = 0; i < bytes_read; i++) { for (int i = 0; i < bytes_read; i++) {
write_buf[i] = read_buf[i] << 4; write_buf[i] = read_buf[i] << 4;
} }
@ -67,11 +163,11 @@ esp_err_t play_wav(const char *fp) {
// skip the header... // skip the header...
fseek(fh, 44, SEEK_SET); fseek(fh, 44, SEEK_SET);
int16_t *buf = (int16_t*) calloc(AUDIO_BUFFER, sizeof(int16_t)); int16_t *buf = (int16_t*) calloc(AUDIO_BLOCK_SIZE, sizeof(int16_t));
size_t bytes_read = 0; size_t bytes_read = 0;
size_t bytes_written = 0; size_t bytes_written = 0;
bytes_read = fread(buf, sizeof(int16_t), AUDIO_BUFFER, fh); bytes_read = fread(buf, sizeof(int16_t), AUDIO_BLOCK_SIZE, fh);
for (int i = 0; i < bytes_read; i++) { for (int i = 0; i < bytes_read; i++) {
buf[i] = buf[i] >> 2; buf[i] = buf[i] >> 2;
} }
@ -81,7 +177,7 @@ esp_err_t play_wav(const char *fp) {
while (bytes_read > 0) while (bytes_read > 0)
{ {
bytes_read = fread(buf, sizeof(int16_t), AUDIO_BUFFER, fh); bytes_read = fread(buf, sizeof(int16_t), AUDIO_BLOCK_SIZE, fh);
for (int i = 0; i < bytes_read; i++) { for (int i = 0; i < bytes_read; i++) {
buf[i] = buf[i] >> 2; buf[i] = buf[i] >> 2;
} }
@ -104,12 +200,12 @@ esp_err_t play_raw(const char *fp) {
} }
// create a writer buffer // create a writer buffer
uint8_t *read_buf = (uint8_t*) calloc(AUDIO_BUFFER, sizeof(uint8_t)); uint8_t *read_buf = (uint8_t*) calloc(AUDIO_BLOCK_SIZE, sizeof(uint8_t));
uint16_t *write_buf = (uint16_t*) calloc(AUDIO_BUFFER, sizeof(uint16_t)); uint16_t *write_buf = (uint16_t*) calloc(AUDIO_BLOCK_SIZE, sizeof(uint16_t));
size_t bytes_read = 0; size_t bytes_read = 0;
size_t bytes_written = 0; size_t bytes_written = 0;
bytes_read = fread(read_buf, sizeof(uint8_t), AUDIO_BUFFER, fh); bytes_read = fread(read_buf, sizeof(uint8_t), AUDIO_BLOCK_SIZE, fh);
for (int i = 0; i < bytes_read; i++) { for (int i = 0; i < bytes_read; i++) {
write_buf[i] = read_buf[i] << 4; write_buf[i] = read_buf[i] << 4;
} }
@ -128,7 +224,7 @@ esp_err_t play_raw(const char *fp) {
// int16_t val = buf[i]; // int16_t val = buf[i];
// printf("%s0x%04X ", (val < 0 ? "-" : "+"), (val < 0 ? -val : val)); // printf("%s0x%04X ", (val < 0 ? "-" : "+"), (val < 0 ? -val : val));
// }> // }>
bytes_read = fread(read_buf, sizeof(uint8_t), AUDIO_BUFFER, fh); bytes_read = fread(read_buf, sizeof(uint8_t), AUDIO_BLOCK_SIZE, fh);
for (int i = 0; i < bytes_read; i++) { for (int i = 0; i < bytes_read; i++) {
write_buf[i] = read_buf[i] << 4; write_buf[i] = read_buf[i] << 4;
} }
@ -168,8 +264,28 @@ void init_speaker(void) {
}; };
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_chan, &tx_std_cfg)); ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_chan, &tx_std_cfg));
ESP_ERROR_CHECK_WITHOUT_ABORT(play_wav("/sdcard/startup.wav")); // init queues and list
ESP_ERROR_CHECK_WITHOUT_ABORT(play_raw("/sdcard/boot.pcm")); sequential_clip_queue = xQueueCreate(8, sizeof(audio_clip_t));
// start task
// TODO: make stack 4096 again :(
xTaskCreate(speaker_task, "play_audio", 16384, NULL, 5, NULL);
// ESP_ERROR_CHECK_WITHOUT_ABORT(play_wav(MOUNT_POINT "/startup.wav"));
// ESP_ERROR_CHECK_WITHOUT_ABORT(play_raw(MOUNT_POINT "/boot.pcm"));
char* file_name = (char*) malloc(sizeof(MOUNT_POINT "/startup.wav"));
memcpy(file_name, MOUNT_POINT "/startup.wav", sizeof(MOUNT_POINT "/startup.wav"));
audio_clip_t startup_clip = {
.file_name = file_name,
.prescaler = 1,
.repeat = false,
.play_immediatly = false,
};
xQueueSend(sequential_clip_queue, &startup_clip, 0);
vTaskDelay(pdMS_TO_TICKS(5000));
ESP_LOGI(TAG, "Speaker initialized!"); ESP_LOGI(TAG, "Speaker initialized!");
} }

View File

@ -3,6 +3,9 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string>
#include <cstring>
#include <vector>
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/queue.h" #include "freertos/queue.h"
#include "freertos/task.h" #include "freertos/task.h"
@ -16,10 +19,28 @@
#define SPEAKER_PIN_WS GPIO_NUM_9 #define SPEAKER_PIN_WS GPIO_NUM_9
#define SPEAKER_PIN_DOUT GPIO_NUM_3 #define SPEAKER_PIN_DOUT GPIO_NUM_3
#define SAMPLE_RATE 44100 #define SAMPLE_RATE 44100
#define AUDIO_BUFFER 2048 #define PLAY_QUEUE_SIZE 8
// The maximum number of clips that can be playing at one time.
#define PLAYING_CLIP_SIZE 8
// Audio will be processed in blocks of this many samples
#define AUDIO_BLOCK_SIZE 2048
extern i2s_chan_handle_t tx_chan; extern i2s_chan_handle_t tx_chan;
typedef struct {
/// A dynamically allocated string specifying the name of the
/// file to play. The speaker system will free this once it
/// is done.
char* file_name;
/// A number that all samples will be shifted right by.
uint8_t prescaler;
/// A flag for repeating.
bool repeat;
/// A flag for starting the clip immediatly,
/// even if there is another clip playing.
bool play_immediatly;
} audio_clip_t;
/// Plays a audio file stopping when something is received on `stop_handle` /// Plays a audio file stopping when something is received on `stop_handle`
/// ///
/// `stop_handle` should be of size `uint8_t`. /// `stop_handle` should be of size `uint8_t`.