Part 6: Audio
This commit is contained in:
parent
e525a823dc
commit
8f17172aa3
|
@ -1,6 +1,7 @@
|
||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRCS
|
SRCS
|
||||||
"main.c"
|
"main.c"
|
||||||
|
"odroid/audio.c"
|
||||||
"odroid/battery.c"
|
"odroid/battery.c"
|
||||||
"odroid/display.c"
|
"odroid/display.c"
|
||||||
"odroid/input.c"
|
"odroid/input.c"
|
||||||
|
|
38
src/main.c
38
src/main.c
|
@ -1,3 +1,4 @@
|
||||||
|
#include "odroid/audio.h"
|
||||||
#include "odroid/battery.h"
|
#include "odroid/battery.h"
|
||||||
#include "odroid/display.h"
|
#include "odroid/display.h"
|
||||||
#include "odroid/input.h"
|
#include "odroid/input.h"
|
||||||
|
@ -12,12 +13,14 @@
|
||||||
static const char* LOG_TAG = "Main";
|
static const char* LOG_TAG = "Main";
|
||||||
static uint16_t gFramebuffer[LCD_WIDTH * LCD_HEIGHT];
|
static uint16_t gFramebuffer[LCD_WIDTH * LCD_HEIGHT];
|
||||||
|
|
||||||
|
|
||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
Odroid_InitializeInput();
|
Odroid_InitializeInput();
|
||||||
Odroid_InitializeDisplay();
|
Odroid_InitializeDisplay();
|
||||||
Odroid_InitializeSdcard();
|
Odroid_InitializeSdcard();
|
||||||
Odroid_InitializeBatteryReader();
|
Odroid_InitializeBatteryReader();
|
||||||
|
Odroid_InitializeAudio();
|
||||||
|
|
||||||
// Load sprite
|
// Load sprite
|
||||||
uint16_t* sprite = (uint16_t*)malloc(64 * 64 * sizeof(uint16_t));
|
uint16_t* sprite = (uint16_t*)malloc(64 * 64 * sizeof(uint16_t));
|
||||||
|
@ -36,6 +39,28 @@ void app_main(void)
|
||||||
fclose(spriteFile);
|
fclose(spriteFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load sound effect
|
||||||
|
uint16_t* soundBuffer;
|
||||||
|
int soundEffectLength = 1441;
|
||||||
|
{
|
||||||
|
FILE* soundFile = fopen("/sdcard/jump", "r");
|
||||||
|
assert(soundFile);
|
||||||
|
|
||||||
|
uint8_t* soundEffect = malloc(soundEffectLength);
|
||||||
|
assert(soundEffect);
|
||||||
|
|
||||||
|
soundBuffer = malloc(soundEffectLength*2);
|
||||||
|
assert(soundBuffer);
|
||||||
|
|
||||||
|
fread(soundEffect, soundEffectLength, 1, soundFile);
|
||||||
|
|
||||||
|
for (int i = 0; i < soundEffectLength; ++i)
|
||||||
|
{
|
||||||
|
// 16 bits required but only MSB is actually sent to the DAC
|
||||||
|
soundBuffer[i] = (soundEffect[i] << 8u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ESP_LOGI(LOG_TAG, "Odroid initialization complete - entering main loop");
|
ESP_LOGI(LOG_TAG, "Odroid initialization complete - entering main loop");
|
||||||
|
|
||||||
|
@ -44,6 +69,8 @@ void app_main(void)
|
||||||
|
|
||||||
uint16_t color = 0xffff;
|
uint16_t color = 0xffff;
|
||||||
|
|
||||||
|
int lastState = 0;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
memset(gFramebuffer, 0, 320 * 240 * 2);
|
memset(gFramebuffer, 0, 320 * 240 * 2);
|
||||||
|
@ -61,6 +88,17 @@ void app_main(void)
|
||||||
else if (input.start) { color = SWAP_ENDIAN_16(RGB565(0, 0, 0xff)); }
|
else if (input.start) { color = SWAP_ENDIAN_16(RGB565(0, 0, 0xff)); }
|
||||||
else if (input.select) { color = SWAP_ENDIAN_16(RGB565(0xff, 0xff, 0xff)); }
|
else if (input.select) { color = SWAP_ENDIAN_16(RGB565(0xff, 0xff, 0xff)); }
|
||||||
|
|
||||||
|
|
||||||
|
int thisState = input.volume;
|
||||||
|
|
||||||
|
if ((thisState == 1) && (thisState != lastState))
|
||||||
|
{
|
||||||
|
Odroid_PlayAudio(soundBuffer, soundEffectLength*2);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastState = thisState;
|
||||||
|
|
||||||
|
|
||||||
int spriteRow = 0;
|
int spriteRow = 0;
|
||||||
int spriteCol = 0;
|
int spriteCol = 0;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
#include "audio.h"
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
|
#include <driver/i2s.h>
|
||||||
|
|
||||||
|
|
||||||
|
static const gpio_num_t AUDIO_AMP_SD_PIN = GPIO_NUM_25;
|
||||||
|
|
||||||
|
static QueueHandle_t gQueue;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t* buffer;
|
||||||
|
int length;
|
||||||
|
} QueueData;
|
||||||
|
|
||||||
|
|
||||||
|
static void PlayTask(void *arg)
|
||||||
|
{
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
QueueData data;
|
||||||
|
|
||||||
|
if (xQueueReceive(gQueue, &data, 10))
|
||||||
|
{
|
||||||
|
size_t bytesWritten;
|
||||||
|
i2s_write(I2S_NUM_0, data.buffer, data.length, &bytesWritten, portMAX_DELAY);
|
||||||
|
i2s_zero_dma_buffer(I2S_NUM_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Odroid_InitializeAudio(void)
|
||||||
|
{
|
||||||
|
// Configure the amplifier shutdown signal
|
||||||
|
{
|
||||||
|
gpio_config_t gpioConfig = {};
|
||||||
|
|
||||||
|
gpioConfig.mode = GPIO_MODE_OUTPUT;
|
||||||
|
gpioConfig.pin_bit_mask = 1ULL << AUDIO_AMP_SD_PIN;
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(gpio_config(&gpioConfig));
|
||||||
|
|
||||||
|
gpio_set_level(AUDIO_AMP_SD_PIN, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the I2S driver
|
||||||
|
{
|
||||||
|
i2s_config_t i2sConfig= {};
|
||||||
|
|
||||||
|
i2sConfig.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN;
|
||||||
|
i2sConfig.sample_rate = 5512;
|
||||||
|
i2sConfig.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
|
||||||
|
i2sConfig.communication_format = I2S_COMM_FORMAT_I2S_MSB;
|
||||||
|
i2sConfig.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
|
||||||
|
i2sConfig.dma_buf_count = 8;
|
||||||
|
i2sConfig.dma_buf_len = 64;
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(i2s_driver_install(I2S_NUM_0, &i2sConfig, 0, NULL));
|
||||||
|
ESP_ERROR_CHECK(i2s_set_dac_mode(I2S_DAC_CHANNEL_LEFT_EN));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create task for playing sounds so that our main task isn't blocked
|
||||||
|
{
|
||||||
|
gQueue = xQueueCreate(1, sizeof(QueueData));
|
||||||
|
assert(gQueue);
|
||||||
|
|
||||||
|
BaseType_t result = xTaskCreatePinnedToCore(&PlayTask, "I2S Task", 1024, NULL, 5, NULL, 1);
|
||||||
|
assert(result == pdPASS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Odroid_PlayAudio(uint16_t* buffer, int length)
|
||||||
|
{
|
||||||
|
QueueData data = {};
|
||||||
|
|
||||||
|
data.buffer = buffer;
|
||||||
|
data.length = length;
|
||||||
|
|
||||||
|
xQueueSendToBack(gQueue, &data, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
void Odroid_InitializeAudio(void);
|
||||||
|
void Odroid_PlayAudio(uint16_t* buffer, int length);
|
||||||
|
|
Loading…
Reference in New Issue