103 lines
3.6 KiB
C
103 lines
3.6 KiB
C
#include <stdio.h>
|
|
#include "audio.h"
|
|
#include <stdio.h>
|
|
#include <inttypes.h>
|
|
#include <sdkconfig.h>
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "freertos/queue.h"
|
|
#include "esp_log.h"
|
|
#include "bsp/esp-bsp.h"
|
|
|
|
/* Buffer for reading/writing to I2S driver. Same length as SPIFFS buffer and I2S buffer, for optimal read/write performance.
|
|
Recording audio data path:
|
|
I2S peripheral -> I2S buffer (DMA) -> App buffer (RAM) -> SPIFFS buffer -> External SPI Flash.
|
|
Vice versa for playback. */
|
|
#define BUFFER_SIZE (1024)
|
|
#define SAMPLE_RATE (16000) // For recording
|
|
#define DEFAULT_VOLUME (25)
|
|
|
|
/* Globals */
|
|
static const char *TAG = "audio";
|
|
TaskHandle_t audio_task_handle;
|
|
|
|
|
|
// Very simple WAV header, ignores most fields
|
|
typedef struct __attribute__((packed))
|
|
{
|
|
uint8_t ignore_0[22];
|
|
uint16_t num_channels;
|
|
uint32_t sample_rate;
|
|
uint8_t ignore_1[6];
|
|
uint16_t bits_per_sample;
|
|
uint8_t ignore_2[4];
|
|
uint32_t data_size;
|
|
uint8_t data[];
|
|
} dumb_wav_header_t;
|
|
|
|
static void audio_task(void *arg)
|
|
{
|
|
esp_codec_dev_handle_t spk_codec_dev = bsp_audio_codec_speaker_init();
|
|
assert(spk_codec_dev);
|
|
esp_codec_dev_set_out_vol(spk_codec_dev, DEFAULT_VOLUME);
|
|
|
|
/* Pointer to a file that is going to be played */
|
|
const char music_filename[] = "/littlefs/sounds/imperial_march.wav";
|
|
const char *play_filename = music_filename;
|
|
|
|
while (1) {
|
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
|
|
|
int16_t *wav_bytes = malloc(BUFFER_SIZE);
|
|
assert(wav_bytes != NULL);
|
|
|
|
/* Open WAV file */
|
|
ESP_LOGI(TAG, "Playing file %s", play_filename);
|
|
FILE *play_file = fopen(play_filename, "rb");
|
|
if (play_file == NULL) {
|
|
ESP_LOGW(TAG, "%s file does not exist!", play_filename);
|
|
break;
|
|
}
|
|
|
|
/* Read WAV header file */
|
|
dumb_wav_header_t wav_header;
|
|
if (fread((void *)&wav_header, 1, sizeof(wav_header), play_file) != sizeof(wav_header)) {
|
|
ESP_LOGW(TAG, "Error in reading file");
|
|
break;
|
|
}
|
|
ESP_LOGI(TAG, "Number of channels: %" PRIu16 "", wav_header.num_channels);
|
|
ESP_LOGI(TAG, "Bits per sample: %" PRIu16 "", wav_header.bits_per_sample);
|
|
ESP_LOGI(TAG, "Sample rate: %" PRIu32 "", wav_header.sample_rate);
|
|
ESP_LOGI(TAG, "Data size: %" PRIu32 "", wav_header.data_size);
|
|
|
|
esp_codec_dev_sample_info_t fs = {
|
|
.sample_rate = wav_header.sample_rate,
|
|
.channel = wav_header.num_channels,
|
|
.bits_per_sample = wav_header.bits_per_sample,
|
|
};
|
|
esp_codec_dev_open(spk_codec_dev, &fs);
|
|
|
|
uint32_t bytes_send_to_i2s = 0;
|
|
while (bytes_send_to_i2s < wav_header.data_size) {
|
|
/* Get data from SPIFFS and send it to codec */
|
|
size_t bytes_read_from_spiffs = fread(wav_bytes, 1, BUFFER_SIZE, play_file);
|
|
esp_codec_dev_write(spk_codec_dev, wav_bytes, bytes_read_from_spiffs);
|
|
bytes_send_to_i2s += bytes_read_from_spiffs;
|
|
}
|
|
fclose(play_file);
|
|
free(wav_bytes);
|
|
esp_codec_dev_close(spk_codec_dev);
|
|
}
|
|
}
|
|
|
|
void playSound(void)
|
|
{
|
|
if(audio_task_handle==NULL){
|
|
BaseType_t ret = xTaskCreate(audio_task, "audio_task", 4096, NULL, 6, &audio_task_handle);
|
|
assert(ret == pdPASS);
|
|
}
|
|
xTaskNotifyGive(audio_task_handle);
|
|
}
|
|
|
|
|