WE HAVE A GOOD SPEAKER DRIVER!!!!
This commit is contained in:
parent
62b82eba2b
commit
cc8dcfacb3
@ -8,7 +8,7 @@
|
||||
#include "sdmmc_cmd.h"
|
||||
#include "driver/sdmmc_host.h"
|
||||
|
||||
#define MOUNT_POINT "/sdcard"
|
||||
#define MOUNT_POINT "/sd"
|
||||
|
||||
extern sdmmc_card_t *card;
|
||||
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
static const char *TAG = "speaker";
|
||||
|
||||
static size_t audio_block_size = 4096;
|
||||
|
||||
typedef struct {
|
||||
/// The path to the file being played.
|
||||
char* file_name;
|
||||
@ -13,59 +15,119 @@ typedef struct {
|
||||
bool repeat;
|
||||
} playing_audio_clip_t;
|
||||
|
||||
// It's hard to get the tx_chan's internal state, so instead, we keep track of it here.
|
||||
bool channel_enabled = false;
|
||||
i2s_chan_handle_t tx_chan;
|
||||
|
||||
/// A queue of owned `char*` to be stopped from playing.
|
||||
///
|
||||
/// the speaker driver system will free the given char* when it is done with it.
|
||||
QueueHandle_t stop_clip_queue;
|
||||
/// A queue of `audio_clip_t`s to be played once there is nothing being played
|
||||
QueueHandle_t sequential_clip_queue;
|
||||
QueueHandle_t play_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!");
|
||||
static bool push_clip(audio_clip_t clip) {
|
||||
ESP_LOGD(TAG, "playing %s", clip.file_name);
|
||||
FILE* fh = fopen(clip.file_name, "rb");
|
||||
if (fh == NULL) {
|
||||
ESP_LOGW(TAG, "failed to open %s", clip.file_name);
|
||||
return false;
|
||||
} else {
|
||||
// skip the .wav header
|
||||
fseek(fh, 44, SEEK_SET);
|
||||
|
||||
playing_next_clip = {
|
||||
.file_name = next_clip.file_name,
|
||||
playing_audio_clip_t playing_clip = {
|
||||
.file_name = clip.file_name,
|
||||
.file_handle = fh,
|
||||
.prescaler = next_clip.prescaler,
|
||||
.repeat = next_clip.repeat,
|
||||
.prescaler = clip.prescaler,
|
||||
.repeat = clip.repeat,
|
||||
};
|
||||
playing_clips.push_back(playing_next_clip);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "null :(");
|
||||
playing_clips.push_back(playing_clip);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
i2s_channel_enable(tx_chan);
|
||||
while (1) {
|
||||
std::memset(audio_buf, 0, AUDIO_BLOCK_SIZE * sizeof(int16_t));
|
||||
/// @brief Disables the channel if neccesary.
|
||||
static void disable_channel() {
|
||||
if (channel_enabled) {
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(i2s_channel_disable(tx_chan));
|
||||
channel_enabled = false;
|
||||
}
|
||||
}
|
||||
/// @brief Enables the channel if neccesary
|
||||
static void enable_channel() {
|
||||
if (!channel_enabled) {
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(i2s_channel_enable(tx_chan));
|
||||
channel_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "size: %d", playing_clips.size());
|
||||
static void speaker_task(void* arg) {
|
||||
audio_clip_t next_clip;
|
||||
char* clip_to_stop;
|
||||
|
||||
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));
|
||||
|
||||
while (1) {
|
||||
// first, take all "play immediatly" clips from the queue.
|
||||
while (xQueuePeek(play_clip_queue, &next_clip, 0) == pdTRUE && next_clip.play_immediatly) {
|
||||
if (xQueueReceive(play_clip_queue, &next_clip, 0) == pdTRUE) {
|
||||
push_clip(next_clip);
|
||||
}
|
||||
}
|
||||
|
||||
// handle any stop requests
|
||||
while (xQueueReceive(stop_clip_queue, &clip_to_stop, 0) == pdTRUE) {
|
||||
// delete clip from list
|
||||
bool found = false;
|
||||
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 (strcmp(clip.file_name, clip_to_stop) == 0) {
|
||||
found = true;
|
||||
ESP_LOGV(TAG, "stopping %s", clip.file_name);
|
||||
fclose(clip.file_handle);
|
||||
free(clip.file_name);
|
||||
playing_clips.erase(playing_clips.begin() + clip_idx);
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
ESP_LOGW(TAG, "Could not find clip \"%s\" to stop", clip_to_stop);
|
||||
}
|
||||
// free the string that was passed into the queue
|
||||
free(clip_to_stop);
|
||||
}
|
||||
|
||||
// if we aren't playing any clips, wait for the next one.
|
||||
if (playing_clips.empty()) {
|
||||
if (xQueueReceive(play_clip_queue, &next_clip, 0) == pdTRUE) {
|
||||
push_clip(next_clip);
|
||||
} else {
|
||||
// we must wait before our next clip
|
||||
disable_channel();
|
||||
// now wait for next clip
|
||||
if (xQueueReceive(play_clip_queue, &next_clip, portMAX_DELAY) == pdTRUE) {
|
||||
push_clip(next_clip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// send 1 block
|
||||
std::memset(audio_buf, 0, audio_block_size * sizeof(int16_t));
|
||||
|
||||
for (int clip_idx = playing_clips.size()-1; clip_idx >= 0; clip_idx--) {
|
||||
playing_audio_clip_t& clip = playing_clips.at(clip_idx);
|
||||
|
||||
size_t samples_read = fread(file_buf, sizeof(uint16_t), audio_block_size, clip.file_handle);
|
||||
if (samples_read == 0) {
|
||||
if (clip.repeat) {
|
||||
ESP_LOGI(TAG, "repeating...");
|
||||
fseek(fh, 44, SEEK_SET);
|
||||
ESP_LOGV(TAG, "repeating %s", clip.file_name);
|
||||
fseek(clip.file_handle, 44, SEEK_SET);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "deleting...");
|
||||
ESP_LOGV(TAG, "finishing %s", clip.file_name);
|
||||
fclose(clip.file_handle);
|
||||
free(clip.file_name);
|
||||
playing_clips.erase(playing_clips.begin() + clip_idx);
|
||||
@ -78,166 +140,48 @@ static void speaker_task(void* arg) {
|
||||
}
|
||||
}
|
||||
|
||||
size_t bytes_to_write = audio_block_size * sizeof(int16_t);
|
||||
size_t bytes_written;
|
||||
i2s_channel_write(tx_chan, audio_buf, AUDIO_BLOCK_SIZE * sizeof(int16_t), &bytes_written, portMAX_DELAY);
|
||||
if (!channel_enabled) {
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(i2s_channel_preload_data(tx_chan, audio_buf, bytes_to_write, &bytes_written));
|
||||
enable_channel();
|
||||
} else {
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(i2s_channel_write(tx_chan, audio_buf, bytes_to_write, &bytes_written, portMAX_DELAY));
|
||||
}
|
||||
if (bytes_written != bytes_to_write) {
|
||||
ESP_LOGW(TAG, "only %d bytes written to the i2s channel! (expected %d)", bytes_written, bytes_to_write);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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) {
|
||||
FILE *fh = fopen(fp, "rb");
|
||||
if (fh == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to open file");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
bool play_clip_wav(const char* file_name, bool play_immediatly, bool repeat, uint8_t prescaler, TickType_t ticks_to_wait) {
|
||||
// clone the passed in string to the heap.
|
||||
size_t len = strlen(file_name);
|
||||
char* dynamic_file_name = (char*) malloc(len+1);
|
||||
strcpy(dynamic_file_name, file_name);
|
||||
|
||||
audio_clip_t clip = {
|
||||
.file_name = dynamic_file_name,
|
||||
.prescaler = prescaler,
|
||||
.repeat = repeat,
|
||||
.play_immediatly = play_immediatly,
|
||||
};
|
||||
|
||||
if (play_immediatly) {
|
||||
return xQueueSendToFront(play_clip_queue, &clip, ticks_to_wait) == pdTRUE;
|
||||
}
|
||||
return xQueueSend(play_clip_queue, &clip, ticks_to_wait) == pdTRUE;
|
||||
}
|
||||
|
||||
bool stop_clip(const char* file_name, TickType_t ticks_to_wait) {
|
||||
// clone the passed in string to the heap.
|
||||
size_t len = strlen(file_name);
|
||||
char* dynamic_file_name = (char*) malloc(len+1);
|
||||
strcpy(dynamic_file_name, file_name);
|
||||
|
||||
// create a writer buffer
|
||||
uint8_t *read_buf = (uint8_t*) calloc(AUDIO_BLOCK_SIZE, sizeof(uint8_t));
|
||||
uint16_t *write_buf = (uint16_t*) calloc(AUDIO_BLOCK_SIZE, sizeof(uint16_t));
|
||||
size_t bytes_read = 0;
|
||||
size_t bytes_written = 0;
|
||||
|
||||
esp_err_t channel_enable_result = i2s_channel_enable(tx_chan);
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(channel_enable_result);
|
||||
if (channel_enable_result != ESP_OK) {
|
||||
return channel_enable_result;
|
||||
}
|
||||
|
||||
bytes_read = fread(read_buf, sizeof(uint8_t), AUDIO_BLOCK_SIZE, fh);
|
||||
for (int i = 0; i < bytes_read; i++) {
|
||||
write_buf[i] = read_buf[i] << 4;
|
||||
}
|
||||
|
||||
// i2s_channel_enable(tx_handle);
|
||||
|
||||
while (bytes_read > 0) {
|
||||
// write the buffer to the i2s
|
||||
// ESP_LOGI(TAG, "Writing: ");
|
||||
// for (int i = 0; i < words_read; i++) {
|
||||
// int16_t val = buf[i];
|
||||
// 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);
|
||||
bytes_read = fread(read_buf, sizeof(uint8_t), AUDIO_BLOCK_SIZE, fh);
|
||||
for (int i = 0; i < bytes_read; i++) {
|
||||
write_buf[i] = read_buf[i] << 4;
|
||||
}
|
||||
uint8_t recv = 0;
|
||||
if (xQueueReceive(stop_handle, &recv, 0)) {
|
||||
break;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
|
||||
i2s_channel_disable(tx_chan);
|
||||
free(read_buf);
|
||||
free(write_buf);
|
||||
fclose(fh);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t play_wav(const char *fp) {
|
||||
FILE *fh = fopen(fp, "rb");
|
||||
if (fh == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to open file");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// skip the header...
|
||||
fseek(fh, 44, SEEK_SET);
|
||||
|
||||
int16_t *buf = (int16_t*) calloc(AUDIO_BLOCK_SIZE, sizeof(int16_t));
|
||||
size_t bytes_read = 0;
|
||||
size_t bytes_written = 0;
|
||||
|
||||
bytes_read = fread(buf, sizeof(int16_t), AUDIO_BLOCK_SIZE, fh);
|
||||
for (int i = 0; i < bytes_read; i++) {
|
||||
buf[i] = buf[i] >> 2;
|
||||
}
|
||||
|
||||
i2s_channel_preload_data(tx_chan, buf, bytes_read * sizeof(int16_t), &bytes_written);
|
||||
i2s_channel_enable(tx_chan);
|
||||
|
||||
while (bytes_read > 0)
|
||||
{
|
||||
bytes_read = fread(buf, sizeof(int16_t), AUDIO_BLOCK_SIZE, fh);
|
||||
for (int i = 0; i < bytes_read; i++) {
|
||||
buf[i] = buf[i] >> 2;
|
||||
}
|
||||
// write the buffer to the i2s
|
||||
i2s_channel_write(tx_chan, buf, bytes_read * sizeof(int16_t), &bytes_written, portMAX_DELAY);
|
||||
// ESP_LOGI(TAG, "Bytes read: %d", bytes_read);
|
||||
}
|
||||
|
||||
i2s_channel_disable(tx_chan);
|
||||
free(buf);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t play_raw(const char *fp) {
|
||||
FILE *fh = fopen(fp, "rb");
|
||||
if (fh == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to open file");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// create a writer buffer
|
||||
uint8_t *read_buf = (uint8_t*) calloc(AUDIO_BLOCK_SIZE, sizeof(uint8_t));
|
||||
uint16_t *write_buf = (uint16_t*) calloc(AUDIO_BLOCK_SIZE, sizeof(uint16_t));
|
||||
size_t bytes_read = 0;
|
||||
size_t bytes_written = 0;
|
||||
|
||||
bytes_read = fread(read_buf, sizeof(uint8_t), AUDIO_BLOCK_SIZE, fh);
|
||||
for (int i = 0; i < bytes_read; i++) {
|
||||
write_buf[i] = read_buf[i] << 4;
|
||||
}
|
||||
|
||||
i2s_channel_preload_data(tx_chan, write_buf, bytes_read * sizeof(int16_t), &bytes_written);
|
||||
esp_err_t channel_enable_result = i2s_channel_enable(tx_chan);
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(channel_enable_result);
|
||||
if (channel_enable_result != ESP_OK) {
|
||||
return channel_enable_result;
|
||||
}
|
||||
|
||||
while (bytes_read > 0) {
|
||||
// write the buffer to the i2s
|
||||
// ESP_LOGI(TAG, "Writing: ");
|
||||
// for (int i = 0; i < words_read; i++) {
|
||||
// int16_t val = buf[i];
|
||||
// printf("%s0x%04X ", (val < 0 ? "-" : "+"), (val < 0 ? -val : val));
|
||||
// }>
|
||||
bytes_read = fread(read_buf, sizeof(uint8_t), AUDIO_BLOCK_SIZE, fh);
|
||||
for (int i = 0; i < bytes_read; i++) {
|
||||
write_buf[i] = read_buf[i] << 4;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
i2s_channel_write(tx_chan, write_buf, bytes_read * sizeof(int16_t), &bytes_written, portMAX_DELAY);
|
||||
}
|
||||
|
||||
i2s_channel_disable(tx_chan);
|
||||
free(read_buf);
|
||||
free(write_buf);
|
||||
fclose(fh);
|
||||
|
||||
return ESP_OK;
|
||||
return xQueueSend(play_clip_queue, &dynamic_file_name, ticks_to_wait) == pdTRUE;
|
||||
}
|
||||
|
||||
void init_speaker(void) {
|
||||
@ -264,32 +208,20 @@ void init_speaker(void) {
|
||||
};
|
||||
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_chan, &tx_std_cfg));
|
||||
|
||||
// init queues and list
|
||||
sequential_clip_queue = xQueueCreate(8, sizeof(audio_clip_t));
|
||||
i2s_chan_info_t info = {};
|
||||
i2s_channel_get_info(tx_chan, &info);
|
||||
if (info.total_dma_buf_size != 0) {
|
||||
audio_block_size = info.total_dma_buf_size / sizeof(int16_t);
|
||||
}
|
||||
|
||||
// init queues
|
||||
play_clip_queue = xQueueCreate(CLIP_QUEUE_SIZE, sizeof(audio_clip_t));
|
||||
stop_clip_queue = xQueueCreate(CLIP_QUEUE_SIZE, sizeof(char*));
|
||||
|
||||
// start task
|
||||
// TODO: make stack 4096 again :(
|
||||
xTaskCreate(speaker_task, "play_audio", 16384, NULL, 5, NULL);
|
||||
xTaskCreate(speaker_task, "play_audio", 4096, 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));
|
||||
play_clip_wav(MOUNT_POINT "/startup.wav", true, false, 3, 0);
|
||||
|
||||
ESP_LOGI(TAG, "Speaker initialized!");
|
||||
}
|
||||
|
||||
void play_example() {
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(play_raw("/sdcard/o.pcm"));
|
||||
}
|
||||
|
||||
@ -19,11 +19,8 @@
|
||||
#define SPEAKER_PIN_WS GPIO_NUM_9
|
||||
#define SPEAKER_PIN_DOUT GPIO_NUM_3
|
||||
#define SAMPLE_RATE 44100
|
||||
#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
|
||||
// The maximum number of clips that can be queued at one time.
|
||||
#define CLIP_QUEUE_SIZE 8
|
||||
|
||||
extern i2s_chan_handle_t tx_chan;
|
||||
|
||||
@ -41,14 +38,26 @@ typedef struct {
|
||||
bool play_immediatly;
|
||||
} audio_clip_t;
|
||||
|
||||
/// Plays a audio file stopping when something is received on `stop_handle`
|
||||
///
|
||||
/// `stop_handle` should be of size `uint8_t`.
|
||||
esp_err_t play_raw_stop_queue(const char *fp, QueueHandle_t stop_handle);
|
||||
esp_err_t play_raw(const char *fp);
|
||||
|
||||
/// @brief Initalizes the speaker
|
||||
void init_speaker();
|
||||
void play_example();
|
||||
|
||||
/// @brief Plays a wav audio clip.
|
||||
/// @param file_name The name of the file to play. Fully qualified with the `.wav` extention.
|
||||
/// @param play_immediatly If `true`, the file will play immediatly even if there is already
|
||||
/// another clip being played. The two clips will play simultaniously. If `false` the clip
|
||||
/// will play once all the previous clips have finished.
|
||||
/// @param repeat If `true` the clip will repeat until stopped. If `false` the clip will
|
||||
/// stop when finished.
|
||||
/// @param prescaler A number to shift right all samples by. This makes the music half as
|
||||
/// loud. Useful for loud audio files.
|
||||
/// @param ticks_to_wait The number of ticks to wait if the queue is full.
|
||||
/// @return true if the clip was added to the queue.
|
||||
bool play_clip_wav(const char* file_name, bool play_immediatly, bool repeat, uint8_t prescaler, TickType_t ticks_to_wait);
|
||||
|
||||
/// @brief Stops an audio clip from playing.
|
||||
/// @param file_name The file name of the audio clip that was played.
|
||||
/// @param ticks_to_wait The number of ticks to wait if the queue is full.
|
||||
/// @return true if the clip was added to the queue.
|
||||
bool stop_clip(const char* file_name, TickType_t ticks_to_wait);
|
||||
|
||||
#endif /* SPEAKER_H */
|
||||
@ -49,7 +49,7 @@ extern "C" void app_main(void) {
|
||||
|
||||
stop_game_timer();
|
||||
ESP_LOGI(TAG, "Bomb has been diffused. Counter-Terrorists win.");
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(play_raw("/sdcard/diffused.pcm"));
|
||||
play_clip_wav(MOUNT_POINT "/diffused.wav", true, false, 3, 0);
|
||||
|
||||
display_game_results();
|
||||
}
|
||||
|
||||
@ -264,7 +264,7 @@ static bool play_part(uint32_t time) {
|
||||
xSemaphoreGive(xGuiSemaphore);
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(80));
|
||||
play_raw(MOUNT_POINT "/correct.pcm");
|
||||
play_clip_wav(MOUNT_POINT "/correct.wav", true, false, 3, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -100,7 +100,7 @@ void step2(void) {
|
||||
char c = char_of_keypad_key(key);
|
||||
// ESP_LOGI(TAG, "Pressed: %c", c);
|
||||
if (c == answer_char) {
|
||||
play_raw(MOUNT_POINT "/correct.pcm");
|
||||
play_clip_wav(MOUNT_POINT "/correct.wav", true, false, 3, 0);
|
||||
solved_times++;
|
||||
if (solved_times < NUM_SOLVES) {
|
||||
clean_bomb();
|
||||
|
||||
@ -13,12 +13,12 @@ static int tone = 0;
|
||||
static int times = 0;
|
||||
|
||||
static const char* TONE_FILES[] = {
|
||||
MOUNT_POINT "/low-1.pcm",
|
||||
MOUNT_POINT "/low-3.pcm",
|
||||
MOUNT_POINT "/low-6.pcm",
|
||||
MOUNT_POINT "/high-1.pcm",
|
||||
MOUNT_POINT "/high-3.pcm",
|
||||
MOUNT_POINT "/high-6.pcm",
|
||||
MOUNT_POINT "/low-1.wav",
|
||||
MOUNT_POINT "/low-3.wav",
|
||||
MOUNT_POINT "/low-6.wav",
|
||||
MOUNT_POINT "/high-1.wav",
|
||||
MOUNT_POINT "/high-3.wav",
|
||||
MOUNT_POINT "/high-6.wav",
|
||||
};
|
||||
|
||||
static const char* LCD_STRINGS[] = {
|
||||
@ -80,8 +80,8 @@ void step3(void) {
|
||||
// tone = 2;
|
||||
while (get_button_pressed(nullptr)) vTaskDelay(pdMS_TO_TICKS(10));
|
||||
|
||||
play_raw(MOUNT_POINT "/que.pcm");
|
||||
play_raw(TONE_FILES[tone]);
|
||||
play_clip_wav(MOUNT_POINT "/correct.wav", true, false, 3, 0);
|
||||
play_clip_wav(TONE_FILES[tone], false, false, 3, 0);
|
||||
|
||||
bool correct = false;
|
||||
switch (tone % 3) {
|
||||
@ -98,7 +98,7 @@ void step3(void) {
|
||||
if (correct) {
|
||||
times++;
|
||||
clean_bomb();
|
||||
play_raw(MOUNT_POINT "/correct.pcm");
|
||||
play_clip_wav(MOUNT_POINT "/correct.wav", true, false, 3, 0);
|
||||
} else {
|
||||
vTaskDelay(pdMS_TO_TICKS(1500));
|
||||
}
|
||||
|
||||
@ -18,8 +18,8 @@ static lv_obj_t* line_clear_img;
|
||||
static lv_style_t game_over_style;
|
||||
static lv_obj_t* game_over_label;
|
||||
|
||||
static const void* LINE_CLEAR_SRC = (void*)"A:/sdcard/clear.bin";
|
||||
static const void* BACKGROUND_SRC = (void*)"A:/sdcard/bg.bin";
|
||||
static const void* LINE_CLEAR_SRC = (void*)"A:" MOUNT_POINT "/clear.bin";
|
||||
static const void* BACKGROUND_SRC = (void*)"A:" MOUNT_POINT "/bg.bin";
|
||||
// LV_IMG_DECLARE(background);
|
||||
// static const void* BACKGROUND_SRC = (void*)&background;
|
||||
|
||||
@ -28,13 +28,13 @@ static bool playing_music = true;
|
||||
|
||||
static const char* PIECE_IMG_SRC[] = {
|
||||
NULL,
|
||||
"A:/sdcard/lb.bin",
|
||||
"A:/sdcard/db.bin",
|
||||
"A:/sdcard/orange.bin",
|
||||
"A:/sdcard/yellow.bin",
|
||||
"A:/sdcard/green.bin",
|
||||
"A:/sdcard/purple.bin",
|
||||
"A:/sdcard/red.bin",
|
||||
"A:" MOUNT_POINT "/lb.bin",
|
||||
"A:" MOUNT_POINT "/db.bin",
|
||||
"A:" MOUNT_POINT "/orange.bin",
|
||||
"A:" MOUNT_POINT "/yellow.bin",
|
||||
"A:" MOUNT_POINT "/green.bin",
|
||||
"A:" MOUNT_POINT "/purple.bin",
|
||||
"A:" MOUNT_POINT "/red.bin",
|
||||
};
|
||||
|
||||
static bool game = true;
|
||||
@ -124,21 +124,7 @@ static int bdca(int i) { // [0,1,2,3] -> [ 0,+2,+1,-1]
|
||||
return map[i];
|
||||
}
|
||||
|
||||
static void music_task(void* arg) {
|
||||
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);
|
||||
}
|
||||
|
||||
static void init_screen(void) {
|
||||
static void init_screen() {
|
||||
while (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdFALSE) vTaskDelay(pdMS_TO_TICKS(10));
|
||||
|
||||
img = lv_img_create(lv_scr_act());
|
||||
@ -176,19 +162,17 @@ static void init_screen(void) {
|
||||
|
||||
xSemaphoreGive(xGuiSemaphore);
|
||||
|
||||
xTaskCreate(music_task, "music", 4096, NULL, 5, NULL);
|
||||
play_clip_wav(MOUNT_POINT "/tetris.wav", true, false, 3, 0);
|
||||
}
|
||||
|
||||
static void deinit_screen(void) {
|
||||
static void deinit_screen() {
|
||||
while (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) == pdFALSE) vTaskDelay(pdMS_TO_TICKS(10));
|
||||
|
||||
lv_obj_clean(lv_scr_act());
|
||||
xSemaphoreGive(xGuiSemaphore);
|
||||
|
||||
playing_music = false;
|
||||
uint8_t value = 0;
|
||||
if (!xQueueSend(stop_music, &value, pdMS_TO_TICKS(1000))) {
|
||||
ESP_LOGE(TAG, "Faild to send stop queue");
|
||||
if (!stop_clip(MOUNT_POINT "/tetris.wav", pdMS_TO_TICKS(1000))) {
|
||||
ESP_LOGW(TAG, "Can't stop, addicted to the shindig.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -878,7 +878,7 @@ void step5(void) {
|
||||
stop_module_timer();
|
||||
if (solved_correctly) {
|
||||
solved_puzzles++;
|
||||
play_raw(MOUNT_POINT "/correct.pcm");
|
||||
play_clip_wav(MOUNT_POINT "/correct.wav", true, false, 3, 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
solved_correctly = false;
|
||||
} else {
|
||||
|
||||
@ -22,7 +22,7 @@ void step6(void) {
|
||||
for (int i = 0; i < NUM_WIRES; i++) {
|
||||
if (just_cut_wires & (1<<i)) {
|
||||
if (solution[i]) {
|
||||
play_raw(MOUNT_POINT "/correct.pcm");
|
||||
play_clip_wav(MOUNT_POINT "/correct.wav", true, false, 3, 0);
|
||||
} else {
|
||||
strike("Cut wrong wire");
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#include "wires_puzzle.h"
|
||||
|
||||
const static char* WIRES_FILE_PATH = "/sdcard/wires.txt";
|
||||
const static char* WIRES_FILE_PATH = MOUNT_POINT "/wires.txt";
|
||||
const static char* TAG = "wires_puzzle";
|
||||
|
||||
static int color_name_len[NUM_COLORS] = {
|
||||
|
||||
@ -3,8 +3,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <esp_random.h>
|
||||
#include <string.h>
|
||||
#include "esp_vfs_fat.h"
|
||||
#include "drivers/sd.h"
|
||||
|
||||
#define NUM_COLORS 6
|
||||
#define NUM_WIRES 8
|
||||
|
||||
Loading…
Reference in New Issue
Block a user