wip: audiocore: integrate mp3 decoding
This commit is contained in:
@@ -7,15 +7,19 @@ make_unity_test(NAME test_audiocore
|
||||
INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/../test/include" "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
)
|
||||
|
||||
find_package(SDL2 REQUIRED)
|
||||
find_package(SDL2)
|
||||
|
||||
add_executable(mp3test
|
||||
if (SDL2_FOUND)
|
||||
add_executable(mp3test
|
||||
"dr_mp3.c"
|
||||
"mp3test.c"
|
||||
)
|
||||
)
|
||||
|
||||
target_include_directories(mp3test PRIVATE
|
||||
target_include_directories(mp3test PRIVATE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../../lib/dr_mp3"
|
||||
)
|
||||
)
|
||||
|
||||
target_link_libraries(mp3test SDL2::SDL2)
|
||||
target_link_libraries(mp3test SDL2::SDL2)
|
||||
else()
|
||||
message(STATIC "Didn't find SDL2, not building mp3test")
|
||||
endif()
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
#include "audiocore.h"
|
||||
#include "i2s.h"
|
||||
|
||||
#include "mp3.h"
|
||||
#include "py/mperrno.h"
|
||||
|
||||
struct audiocore_context core1_context = {{}, 0, 0};
|
||||
|
||||
void core1_main(void)
|
||||
{
|
||||
if (!i2s_init(shared_context.out_pin, shared_context.sideset_base, shared_context.samplerate)) {
|
||||
@@ -14,14 +17,23 @@ void core1_main(void)
|
||||
}
|
||||
|
||||
multicore_fifo_push_blocking(0);
|
||||
uint32_t cmd;
|
||||
while ((cmd = multicore_fifo_pop_blocking()) != AUDIOCORE_CMD_SHUTDOWN) {
|
||||
switch (cmd) {
|
||||
default:
|
||||
break;
|
||||
while (true) {
|
||||
if (multicore_fifo_rvalid()) {
|
||||
const uint32_t cmd = multicore_fifo_pop_blocking();
|
||||
switch (cmd) {
|
||||
default:
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
while (audiocore_get_pcm_buffer_space() >= MP3_MAX_PCM_FRAMES_PER_MP3_FRAME &&
|
||||
audiocore_get_mp3_buffer_avail() > 0) {
|
||||
mp3_decode();
|
||||
}
|
||||
|
||||
__wfe();
|
||||
}
|
||||
|
||||
shutdown:
|
||||
i2s_deinit();
|
||||
multicore_fifo_push_blocking(0);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Copyright (c) 2024 Matthias Blankertz <matthias@blankertz.org>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <hardware/sync.h>
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -17,7 +16,9 @@
|
||||
* communication between the cores.
|
||||
*/
|
||||
|
||||
#define AUDIO_BUFFER_SIZE 2048
|
||||
#define PCM_BUFFER_SIZE 2048
|
||||
|
||||
#define MP3_BUFFER_SIZE 2048
|
||||
|
||||
// Context shared between the micropython runtime on core0 and the audio task on
|
||||
// core1 All access must hold "lock" unless otherwise noted
|
||||
@@ -28,55 +29,127 @@ struct audiocore_shared_context {
|
||||
int out_pin, sideset_base, samplerate;
|
||||
|
||||
// Must hold lock
|
||||
uint32_t audio_buffer[AUDIO_BUFFER_SIZE];
|
||||
int audio_buffer_write, audio_buffer_read;
|
||||
int underruns;
|
||||
uint8_t mp3_buffer[MP3_BUFFER_SIZE];
|
||||
int mp3_buffer_write, mp3_buffer_read;
|
||||
int i2s_underruns;
|
||||
};
|
||||
|
||||
extern struct audiocore_shared_context shared_context;
|
||||
|
||||
static inline unsigned audiocore_get_audio_buffer_space(void)
|
||||
// Context exclusive to core1
|
||||
struct audiocore_context {
|
||||
// Must disable interrupts on core1
|
||||
uint32_t pcm_buffer[PCM_BUFFER_SIZE];
|
||||
int pcm_buffer_write, pcm_buffer_read;
|
||||
};
|
||||
|
||||
extern struct audiocore_context core1_context;
|
||||
|
||||
static inline unsigned audiocore_get_pcm_buffer_space(void)
|
||||
{
|
||||
if (shared_context.audio_buffer_write >= shared_context.audio_buffer_read)
|
||||
return AUDIO_BUFFER_SIZE - 1 - (shared_context.audio_buffer_write - shared_context.audio_buffer_read);
|
||||
if (core1_context.pcm_buffer_write >= core1_context.pcm_buffer_read)
|
||||
return PCM_BUFFER_SIZE - 1 - (core1_context.pcm_buffer_write - core1_context.pcm_buffer_read);
|
||||
else
|
||||
return shared_context.audio_buffer_read - shared_context.audio_buffer_write - 1;
|
||||
return core1_context.pcm_buffer_read - core1_context.pcm_buffer_write - 1;
|
||||
}
|
||||
|
||||
static inline unsigned audiocore_get_audio_buffer_avail(void)
|
||||
static inline unsigned audiocore_get_pcm_buffer_avail(void)
|
||||
{
|
||||
if (shared_context.audio_buffer_write >= shared_context.audio_buffer_read)
|
||||
return shared_context.audio_buffer_write - shared_context.audio_buffer_read;
|
||||
if (core1_context.pcm_buffer_write >= core1_context.pcm_buffer_read)
|
||||
return core1_context.pcm_buffer_write - core1_context.pcm_buffer_read;
|
||||
else
|
||||
return AUDIO_BUFFER_SIZE - (shared_context.audio_buffer_read - shared_context.audio_buffer_write);
|
||||
return PCM_BUFFER_SIZE - (core1_context.pcm_buffer_read - core1_context.pcm_buffer_write);
|
||||
}
|
||||
|
||||
static inline void audiocore_audio_buffer_put(const uint32_t *restrict src, const size_t len)
|
||||
static inline void audiocore_pcm_buffer_put(const uint32_t *restrict src, const size_t len)
|
||||
{
|
||||
const unsigned end_samples = AUDIO_BUFFER_SIZE - shared_context.audio_buffer_write;
|
||||
memcpy(shared_context.audio_buffer + shared_context.audio_buffer_write, src,
|
||||
const unsigned end_samples = PCM_BUFFER_SIZE - core1_context.pcm_buffer_write;
|
||||
memcpy(core1_context.pcm_buffer + core1_context.pcm_buffer_write, src,
|
||||
4 * ((end_samples >= len) ? len : end_samples));
|
||||
if (end_samples < len) {
|
||||
memcpy(shared_context.audio_buffer, src + end_samples, 4 * (len - end_samples));
|
||||
shared_context.audio_buffer_write = len - end_samples;
|
||||
memcpy(core1_context.pcm_buffer, src + end_samples, 4 * (len - end_samples));
|
||||
core1_context.pcm_buffer_write = len - end_samples;
|
||||
} else {
|
||||
shared_context.audio_buffer_write += len;
|
||||
core1_context.pcm_buffer_write += len;
|
||||
}
|
||||
shared_context.audio_buffer_write %= AUDIO_BUFFER_SIZE;
|
||||
core1_context.pcm_buffer_write %= PCM_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
static inline void audiocore_audio_buffer_get(uint32_t *restrict dst, const size_t len)
|
||||
static inline void audiocore_pcm_buffer_get(uint32_t *restrict dst, const size_t len)
|
||||
{
|
||||
const unsigned end_samples = AUDIO_BUFFER_SIZE - shared_context.audio_buffer_read;
|
||||
memcpy(dst, shared_context.audio_buffer + shared_context.audio_buffer_read,
|
||||
const unsigned end_samples = PCM_BUFFER_SIZE - core1_context.pcm_buffer_read;
|
||||
memcpy(dst, core1_context.pcm_buffer + core1_context.pcm_buffer_read,
|
||||
4 * ((end_samples >= len) ? len : end_samples));
|
||||
if (end_samples < len) {
|
||||
memcpy(dst + end_samples, shared_context.audio_buffer, 4 * (len - end_samples));
|
||||
shared_context.audio_buffer_read = len - end_samples;
|
||||
memcpy(dst + end_samples, core1_context.pcm_buffer, 4 * (len - end_samples));
|
||||
core1_context.pcm_buffer_read = len - end_samples;
|
||||
} else {
|
||||
shared_context.audio_buffer_read += len;
|
||||
core1_context.pcm_buffer_read += len;
|
||||
}
|
||||
shared_context.audio_buffer_read %= AUDIO_BUFFER_SIZE;
|
||||
core1_context.pcm_buffer_read %= PCM_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
static inline unsigned audiocore_get_mp3_buffer_space(void)
|
||||
{
|
||||
if (shared_context.mp3_buffer_write >= shared_context.mp3_buffer_read)
|
||||
return MP3_BUFFER_SIZE - 1 - (shared_context.mp3_buffer_write - shared_context.mp3_buffer_read);
|
||||
else
|
||||
return shared_context.mp3_buffer_read - shared_context.mp3_buffer_write - 1;
|
||||
}
|
||||
|
||||
static inline unsigned audiocore_get_mp3_buffer_avail(void)
|
||||
{
|
||||
if (shared_context.mp3_buffer_write >= shared_context.mp3_buffer_read)
|
||||
return shared_context.mp3_buffer_write - shared_context.mp3_buffer_read;
|
||||
else
|
||||
return MP3_BUFFER_SIZE - (shared_context.mp3_buffer_read - shared_context.mp3_buffer_write);
|
||||
}
|
||||
|
||||
static inline void audiocore_mp3_buffer_put(const uint8_t *restrict src, const size_t len)
|
||||
{
|
||||
const unsigned end_bytes = MP3_BUFFER_SIZE - shared_context.mp3_buffer_write;
|
||||
memcpy(shared_context.mp3_buffer + shared_context.mp3_buffer_write, src, (end_bytes >= len) ? len : end_bytes);
|
||||
if (end_bytes < len) {
|
||||
memcpy(shared_context.mp3_buffer, src + end_bytes, len - end_bytes);
|
||||
shared_context.mp3_buffer_write = len - end_bytes;
|
||||
} else {
|
||||
shared_context.mp3_buffer_write += len;
|
||||
}
|
||||
shared_context.mp3_buffer_write %= MP3_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
/* static inline void audiocore_mp3_buffer_get(uint8_t *restrict dst, const size_t len) */
|
||||
/* { */
|
||||
/* const unsigned end_bytes = MP3_BUFFER_SIZE - shared_context.mp3_buffer_read; */
|
||||
/* memcpy(dst, shared_context.mp3_buffer + shared_context.mp3_buffer_read, */
|
||||
/* (end_bytes >= len) ? len : end_bytes); */
|
||||
/* if (end_bytes < len) { */
|
||||
/* memcpy(dst + end_bytes, shared_context.mp3_buffer, len - end_bytes); */
|
||||
/* shared_context.mp3_buffer_read = len - end_bytes; */
|
||||
/* } else { */
|
||||
/* shared_context.mp3_buffer_read += len; */
|
||||
/* } */
|
||||
/* shared_context.mp3_buffer_read %= MP3_BUFFER_SIZE; */
|
||||
/* } */
|
||||
|
||||
static inline size_t audiocore_mp3_buffer_get_ptr(uint8_t **data)
|
||||
{
|
||||
const unsigned avail = audiocore_get_mp3_buffer_avail();
|
||||
const unsigned end_bytes = MP3_BUFFER_SIZE - shared_context.mp3_buffer_read;
|
||||
*data = shared_context.mp3_buffer + shared_context.mp3_buffer_read;
|
||||
return end_bytes >= avail ? avail : end_bytes;
|
||||
}
|
||||
|
||||
static inline void audiocore_mp3_buffer_consume(const size_t len)
|
||||
{
|
||||
const unsigned end_bytes = MP3_BUFFER_SIZE - shared_context.mp3_buffer_read;
|
||||
if (end_bytes < len) {
|
||||
shared_context.mp3_buffer_read = len - end_bytes;
|
||||
} else {
|
||||
shared_context.mp3_buffer_read += len;
|
||||
}
|
||||
shared_context.mp3_buffer_read %= MP3_BUFFER_SIZE;
|
||||
;
|
||||
}
|
||||
|
||||
void core1_main(void);
|
||||
|
||||
@@ -29,11 +29,11 @@ static void dma_isr(void)
|
||||
return;
|
||||
dma_channel_acknowledge_irq1(i2s_context.dma_ch);
|
||||
const uint32_t flags = spin_lock_blocking(shared_context.lock);
|
||||
if (audiocore_get_audio_buffer_avail() >= I2S_DMA_BUF_SIZE) {
|
||||
audiocore_audio_buffer_get(i2s_context.dma_buf, I2S_DMA_BUF_SIZE);
|
||||
if (audiocore_get_pcm_buffer_avail() >= I2S_DMA_BUF_SIZE) {
|
||||
audiocore_pcm_buffer_get(i2s_context.dma_buf, I2S_DMA_BUF_SIZE);
|
||||
spin_unlock(shared_context.lock, flags);
|
||||
} else {
|
||||
++shared_context.underruns;
|
||||
++shared_context.i2s_underruns;
|
||||
spin_unlock(shared_context.lock, flags);
|
||||
memset(i2s_context.dma_buf, 0, sizeof(uint32_t) * I2S_DMA_BUF_SIZE);
|
||||
}
|
||||
|
||||
@@ -7,13 +7,16 @@ pico_generate_pio_header(usermod_audiocore ${CMAKE_CURRENT_LIST_DIR}/i2s_max9835
|
||||
|
||||
target_sources(usermod_audiocore INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/audiocore.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/dr_mp3.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/module.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mp3.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/i2s.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/i2s_max98357.pio.h
|
||||
)
|
||||
|
||||
target_include_directories(usermod_audiocore INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../lib/dr_mp3
|
||||
)
|
||||
|
||||
target_link_libraries(usermod INTERFACE usermod_audiocore)
|
||||
|
||||
@@ -38,10 +38,10 @@ static MP_DEFINE_CONST_FUN_OBJ_1(audiocore_Context_deinit_obj, audiocore_Context
|
||||
/*
|
||||
* (copied, buf_space, undderuns) = audiocore.Context.put(self, buffer)
|
||||
*
|
||||
* Copies as many integers as possible from the buffer to the audiocore ring buffer for playback.
|
||||
* 'buffer' must be any object supporting the buffer protocol with data in unsigned int (array typecode 'I')
|
||||
* Copies as many bytes as possible from the buffer to the audiocore ring buffer for decoding and playback.
|
||||
* 'buffer' must be any object supporting the buffer protocol with data in bytes (array typecode 'b' or 'B')
|
||||
* format. The actual number of elements copied is returned in 'copied', the remaining free ring buffer space
|
||||
* is in 'buf_space', and the total number of buffer underruns since initialization of the audiocore Context
|
||||
* is in 'buf_space', and the total number of audio underruns since initialization of the audiocore Context
|
||||
* is in 'underruns'.
|
||||
*/
|
||||
static mp_obj_t audiocore_Context_put(mp_obj_t self_in, mp_obj_t buffer)
|
||||
@@ -51,18 +51,18 @@ static mp_obj_t audiocore_Context_put(mp_obj_t self_in, mp_obj_t buffer)
|
||||
mp_buffer_info_t bufinfo;
|
||||
if (!mp_get_buffer(buffer, &bufinfo, MP_BUFFER_READ))
|
||||
mp_raise_ValueError("not a read buffer");
|
||||
if (bufinfo.typecode != 'I')
|
||||
if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B')
|
||||
mp_raise_ValueError("unsupported buffer type");
|
||||
unsigned to_copy = bufinfo.len / 4;
|
||||
unsigned to_copy = bufinfo.len;
|
||||
|
||||
const uint32_t flags = spin_lock_blocking(shared_context.lock);
|
||||
const unsigned buf_space = audiocore_get_audio_buffer_space();
|
||||
const unsigned buf_space = audiocore_get_mp3_buffer_space();
|
||||
if (to_copy > buf_space)
|
||||
to_copy = buf_space;
|
||||
if (to_copy > 0) {
|
||||
audiocore_audio_buffer_put(bufinfo.buf, to_copy);
|
||||
audiocore_mp3_buffer_put(bufinfo.buf, to_copy);
|
||||
}
|
||||
const unsigned underruns = shared_context.underruns;
|
||||
const unsigned underruns = shared_context.i2s_underruns;
|
||||
spin_unlock(shared_context.lock, flags);
|
||||
|
||||
mp_obj_t items[] = {
|
||||
@@ -107,8 +107,8 @@ static mp_obj_t audiocore_init(mp_obj_t pin_obj, mp_obj_t sideset_obj, mp_obj_t
|
||||
mp_raise_OSError(MP_ENOMEM);
|
||||
shared_context.lock = spin_lock_init(lock);
|
||||
}
|
||||
shared_context.audio_buffer_write = shared_context.audio_buffer_read = shared_context.underruns = 0;
|
||||
memset(shared_context.audio_buffer, 0, AUDIO_BUFFER_SIZE * 4);
|
||||
shared_context.mp3_buffer_write = shared_context.mp3_buffer_read = shared_context.i2s_underruns = 0;
|
||||
memset(shared_context.mp3_buffer, 0, MP3_BUFFER_SIZE);
|
||||
multicore_reset_core1();
|
||||
struct audiocore_Context_obj *context = m_malloc_with_finaliser(sizeof(struct audiocore_Context_obj));
|
||||
context->base.type = &audiocore_Context_type;
|
||||
|
||||
38
software/src/audiocore/mp3.c
Normal file
38
software/src/audiocore/mp3.c
Normal file
@@ -0,0 +1,38 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2024 Matthias Blankertz <matthias@blankertz.org>
|
||||
|
||||
#include "mp3.h"
|
||||
|
||||
#include "audiocore.h"
|
||||
#include "dr_mp3.h"
|
||||
#include "platform.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static drmp3dec mp3dec;
|
||||
static int16_t pcm_buffer[DRMP3_MAX_SAMPLES_PER_FRAME];
|
||||
|
||||
void mp3_init(void) { drmp3dec_init(&mp3dec); }
|
||||
|
||||
void mp3_decode(void)
|
||||
{
|
||||
drmp3dec_frame_info info = {};
|
||||
uint8_t *data = NULL;
|
||||
uint32_t flags = spin_lock_blocking(shared_context.lock);
|
||||
const size_t avail = audiocore_mp3_buffer_get_ptr(&data);
|
||||
spin_unlock(shared_context.lock, flags);
|
||||
// This unlocked access to the shared buffer is safe as the writer will never overwrite the data
|
||||
// that has not been consumed by the reader.
|
||||
const int decoded_pcm = drmp3dec_decode_frame(&mp3dec, data, avail, &pcm_buffer, &info);
|
||||
assert(info.frame_bytes <= avail);
|
||||
flags = spin_lock_blocking(shared_context.lock);
|
||||
audiocore_mp3_buffer_consume(info.frame_bytes);
|
||||
spin_unlock(shared_context.lock, flags);
|
||||
if (!decoded_pcm)
|
||||
return;
|
||||
assert(decoded_pcm <= MP3_MAX_PCM_FRAMES_PER_MP3_FRAME);
|
||||
flags = ENTER_CRITICAL_SECTION();
|
||||
audiocore_pcm_buffer_put((uint32_t *)pcm_buffer, decoded_pcm);
|
||||
EXIT_CRITICAL_SECTION(flags);
|
||||
}
|
||||
9
software/src/audiocore/mp3.h
Normal file
9
software/src/audiocore/mp3.h
Normal file
@@ -0,0 +1,9 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2024 Matthias Blankertz <matthias@blankertz.org>
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152
|
||||
|
||||
void mp3_init(void);
|
||||
void mp3_decode(void);
|
||||
@@ -31,6 +31,8 @@ void i2s_deinit(void)
|
||||
|
||||
void multicore_fifo_push_blocking(unsigned val) { multicore_fifo_push_last = val; }
|
||||
|
||||
bool multicore_fifo_rvalid(void) { return multicore_fifo_pop_blocking_cb; }
|
||||
|
||||
unsigned multicore_fifo_pop_blocking(void)
|
||||
{
|
||||
if (multicore_fifo_pop_blocking_cb)
|
||||
@@ -38,6 +40,8 @@ unsigned multicore_fifo_pop_blocking(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mp3_decode(void) {}
|
||||
|
||||
void test_audiocore_handles_i2sinit_failure(void)
|
||||
{
|
||||
i2s_init_return = false;
|
||||
@@ -65,65 +69,65 @@ void test_audiocore_init_deinit(void)
|
||||
void test_audiocore_buffer_space(void)
|
||||
{
|
||||
// empty ring buffer
|
||||
shared_context.audio_buffer_read = shared_context.audio_buffer_write = 0;
|
||||
TEST_ASSERT_EQUAL(AUDIO_BUFFER_SIZE - 1, audiocore_get_audio_buffer_space());
|
||||
core1_context.pcm_buffer_read = core1_context.pcm_buffer_write = 0;
|
||||
TEST_ASSERT_EQUAL(PCM_BUFFER_SIZE - 1, audiocore_get_pcm_buffer_space());
|
||||
|
||||
shared_context.audio_buffer_read = shared_context.audio_buffer_write = 23;
|
||||
TEST_ASSERT_EQUAL(AUDIO_BUFFER_SIZE - 1, audiocore_get_audio_buffer_space());
|
||||
core1_context.pcm_buffer_read = core1_context.pcm_buffer_write = 23;
|
||||
TEST_ASSERT_EQUAL(PCM_BUFFER_SIZE - 1, audiocore_get_pcm_buffer_space());
|
||||
|
||||
shared_context.audio_buffer_read = shared_context.audio_buffer_write = AUDIO_BUFFER_SIZE - 1;
|
||||
TEST_ASSERT_EQUAL(AUDIO_BUFFER_SIZE - 1, audiocore_get_audio_buffer_space());
|
||||
core1_context.pcm_buffer_read = core1_context.pcm_buffer_write = PCM_BUFFER_SIZE - 1;
|
||||
TEST_ASSERT_EQUAL(PCM_BUFFER_SIZE - 1, audiocore_get_pcm_buffer_space());
|
||||
|
||||
// full ring buffer
|
||||
shared_context.audio_buffer_write = 0;
|
||||
shared_context.audio_buffer_read = 1;
|
||||
TEST_ASSERT_EQUAL(0, audiocore_get_audio_buffer_space());
|
||||
core1_context.pcm_buffer_write = 0;
|
||||
core1_context.pcm_buffer_read = 1;
|
||||
TEST_ASSERT_EQUAL(0, audiocore_get_pcm_buffer_space());
|
||||
|
||||
shared_context.audio_buffer_write = AUDIO_BUFFER_SIZE - 1;
|
||||
shared_context.audio_buffer_read = 0;
|
||||
TEST_ASSERT_EQUAL(0, audiocore_get_audio_buffer_space());
|
||||
core1_context.pcm_buffer_write = PCM_BUFFER_SIZE - 1;
|
||||
core1_context.pcm_buffer_read = 0;
|
||||
TEST_ASSERT_EQUAL(0, audiocore_get_pcm_buffer_space());
|
||||
|
||||
// write > read
|
||||
shared_context.audio_buffer_write = 10;
|
||||
shared_context.audio_buffer_read = 0;
|
||||
TEST_ASSERT_EQUAL(AUDIO_BUFFER_SIZE - 1 - 10, audiocore_get_audio_buffer_space());
|
||||
core1_context.pcm_buffer_write = 10;
|
||||
core1_context.pcm_buffer_read = 0;
|
||||
TEST_ASSERT_EQUAL(PCM_BUFFER_SIZE - 1 - 10, audiocore_get_pcm_buffer_space());
|
||||
|
||||
// write < read
|
||||
shared_context.audio_buffer_write = 0;
|
||||
shared_context.audio_buffer_read = 10;
|
||||
TEST_ASSERT_EQUAL(9, audiocore_get_audio_buffer_space());
|
||||
core1_context.pcm_buffer_write = 0;
|
||||
core1_context.pcm_buffer_read = 10;
|
||||
TEST_ASSERT_EQUAL(9, audiocore_get_pcm_buffer_space());
|
||||
}
|
||||
|
||||
void test_audiocore_buffer_avail(void)
|
||||
{
|
||||
// empty ring buffer
|
||||
shared_context.audio_buffer_read = shared_context.audio_buffer_write = 0;
|
||||
TEST_ASSERT_EQUAL(0, audiocore_get_audio_buffer_avail());
|
||||
core1_context.pcm_buffer_read = core1_context.pcm_buffer_write = 0;
|
||||
TEST_ASSERT_EQUAL(0, audiocore_get_pcm_buffer_avail());
|
||||
|
||||
shared_context.audio_buffer_read = shared_context.audio_buffer_write = 23;
|
||||
TEST_ASSERT_EQUAL(0, audiocore_get_audio_buffer_avail());
|
||||
core1_context.pcm_buffer_read = core1_context.pcm_buffer_write = 23;
|
||||
TEST_ASSERT_EQUAL(0, audiocore_get_pcm_buffer_avail());
|
||||
|
||||
shared_context.audio_buffer_read = shared_context.audio_buffer_write = AUDIO_BUFFER_SIZE - 1;
|
||||
TEST_ASSERT_EQUAL(0, audiocore_get_audio_buffer_avail());
|
||||
core1_context.pcm_buffer_read = core1_context.pcm_buffer_write = PCM_BUFFER_SIZE - 1;
|
||||
TEST_ASSERT_EQUAL(0, audiocore_get_pcm_buffer_avail());
|
||||
|
||||
// full ring buffer
|
||||
shared_context.audio_buffer_write = 0;
|
||||
shared_context.audio_buffer_read = 1;
|
||||
TEST_ASSERT_EQUAL(AUDIO_BUFFER_SIZE - 1, audiocore_get_audio_buffer_avail());
|
||||
core1_context.pcm_buffer_write = 0;
|
||||
core1_context.pcm_buffer_read = 1;
|
||||
TEST_ASSERT_EQUAL(PCM_BUFFER_SIZE - 1, audiocore_get_pcm_buffer_avail());
|
||||
|
||||
shared_context.audio_buffer_write = AUDIO_BUFFER_SIZE - 1;
|
||||
shared_context.audio_buffer_read = 0;
|
||||
TEST_ASSERT_EQUAL(AUDIO_BUFFER_SIZE - 1, audiocore_get_audio_buffer_avail());
|
||||
core1_context.pcm_buffer_write = PCM_BUFFER_SIZE - 1;
|
||||
core1_context.pcm_buffer_read = 0;
|
||||
TEST_ASSERT_EQUAL(PCM_BUFFER_SIZE - 1, audiocore_get_pcm_buffer_avail());
|
||||
|
||||
// write > read
|
||||
shared_context.audio_buffer_write = 10;
|
||||
shared_context.audio_buffer_read = 0;
|
||||
TEST_ASSERT_EQUAL(10, audiocore_get_audio_buffer_avail());
|
||||
core1_context.pcm_buffer_write = 10;
|
||||
core1_context.pcm_buffer_read = 0;
|
||||
TEST_ASSERT_EQUAL(10, audiocore_get_pcm_buffer_avail());
|
||||
|
||||
// write < read
|
||||
shared_context.audio_buffer_write = 0;
|
||||
shared_context.audio_buffer_read = 10;
|
||||
TEST_ASSERT_EQUAL(AUDIO_BUFFER_SIZE - 10, audiocore_get_audio_buffer_avail());
|
||||
core1_context.pcm_buffer_write = 0;
|
||||
core1_context.pcm_buffer_read = 10;
|
||||
TEST_ASSERT_EQUAL(PCM_BUFFER_SIZE - 10, audiocore_get_pcm_buffer_avail());
|
||||
}
|
||||
|
||||
static unsigned fill_buffer_helper(void)
|
||||
@@ -132,11 +136,11 @@ static unsigned fill_buffer_helper(void)
|
||||
uint32_t ctr = 0;
|
||||
|
||||
unsigned avail, filled = 0;
|
||||
while ((avail = audiocore_get_audio_buffer_space()) > 0) {
|
||||
while ((avail = audiocore_get_pcm_buffer_space()) > 0) {
|
||||
const unsigned todo = avail > 100 ? 100 : avail;
|
||||
for (unsigned i = 0; i < todo; ++i)
|
||||
test_data[i] = ctr++;
|
||||
audiocore_audio_buffer_put(test_data, todo);
|
||||
audiocore_pcm_buffer_put(test_data, todo);
|
||||
filled += todo;
|
||||
}
|
||||
return filled;
|
||||
@@ -144,18 +148,18 @@ static unsigned fill_buffer_helper(void)
|
||||
|
||||
void test_audiocore_buffer_put(void)
|
||||
{
|
||||
shared_context.audio_buffer_read = shared_context.audio_buffer_write = 0;
|
||||
core1_context.pcm_buffer_read = core1_context.pcm_buffer_write = 0;
|
||||
|
||||
TEST_ASSERT_EQUAL(AUDIO_BUFFER_SIZE - 1, fill_buffer_helper());
|
||||
for (unsigned i = 0; i < AUDIO_BUFFER_SIZE - 1; ++i) {
|
||||
TEST_ASSERT_EQUAL(i, shared_context.audio_buffer[i]);
|
||||
TEST_ASSERT_EQUAL(PCM_BUFFER_SIZE - 1, fill_buffer_helper());
|
||||
for (unsigned i = 0; i < PCM_BUFFER_SIZE - 1; ++i) {
|
||||
TEST_ASSERT_EQUAL(i, core1_context.pcm_buffer[i]);
|
||||
}
|
||||
|
||||
// test wraparound fill
|
||||
shared_context.audio_buffer_read = shared_context.audio_buffer_write = AUDIO_BUFFER_SIZE - 10;
|
||||
TEST_ASSERT_EQUAL(AUDIO_BUFFER_SIZE - 1, fill_buffer_helper());
|
||||
for (unsigned i = 0; i < AUDIO_BUFFER_SIZE - 1; ++i) {
|
||||
TEST_ASSERT_EQUAL(i, shared_context.audio_buffer[(i + AUDIO_BUFFER_SIZE - 10) % AUDIO_BUFFER_SIZE]);
|
||||
core1_context.pcm_buffer_read = core1_context.pcm_buffer_write = PCM_BUFFER_SIZE - 10;
|
||||
TEST_ASSERT_EQUAL(PCM_BUFFER_SIZE - 1, fill_buffer_helper());
|
||||
for (unsigned i = 0; i < PCM_BUFFER_SIZE - 1; ++i) {
|
||||
TEST_ASSERT_EQUAL(i, core1_context.pcm_buffer[(i + PCM_BUFFER_SIZE - 10) % PCM_BUFFER_SIZE]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,9 +169,9 @@ static unsigned get_buffer_helper(void)
|
||||
uint32_t ctr = 0;
|
||||
|
||||
unsigned avail, gotten = 0;
|
||||
while ((avail = audiocore_get_audio_buffer_avail()) > 0) {
|
||||
while ((avail = audiocore_get_pcm_buffer_avail()) > 0) {
|
||||
const unsigned todo = avail > 100 ? 100 : avail;
|
||||
audiocore_audio_buffer_get(test_data, todo);
|
||||
audiocore_pcm_buffer_get(test_data, todo);
|
||||
for (unsigned i = 0; i < todo; ++i)
|
||||
TEST_ASSERT_EQUAL(ctr++, test_data[i]);
|
||||
gotten += todo;
|
||||
@@ -177,16 +181,16 @@ static unsigned get_buffer_helper(void)
|
||||
|
||||
void test_audiocore_buffer_get(void)
|
||||
{
|
||||
shared_context.audio_buffer_read = 0;
|
||||
shared_context.audio_buffer_write = AUDIO_BUFFER_SIZE - 1;
|
||||
for (unsigned i = 0; i < AUDIO_BUFFER_SIZE - 1; ++i)
|
||||
shared_context.audio_buffer[i] = i;
|
||||
TEST_ASSERT_EQUAL(AUDIO_BUFFER_SIZE - 1, get_buffer_helper());
|
||||
core1_context.pcm_buffer_read = 0;
|
||||
core1_context.pcm_buffer_write = PCM_BUFFER_SIZE - 1;
|
||||
for (unsigned i = 0; i < PCM_BUFFER_SIZE - 1; ++i)
|
||||
core1_context.pcm_buffer[i] = i;
|
||||
TEST_ASSERT_EQUAL(PCM_BUFFER_SIZE - 1, get_buffer_helper());
|
||||
|
||||
// test wraparound read
|
||||
shared_context.audio_buffer_read = 10;
|
||||
shared_context.audio_buffer_write = 9;
|
||||
for (unsigned i = 0; i < AUDIO_BUFFER_SIZE - 1; ++i)
|
||||
shared_context.audio_buffer[(i + 10) % AUDIO_BUFFER_SIZE] = i;
|
||||
TEST_ASSERT_EQUAL(AUDIO_BUFFER_SIZE - 1, get_buffer_helper());
|
||||
core1_context.pcm_buffer_read = 10;
|
||||
core1_context.pcm_buffer_write = 9;
|
||||
for (unsigned i = 0; i < PCM_BUFFER_SIZE - 1; ++i)
|
||||
core1_context.pcm_buffer[(i + 10) % PCM_BUFFER_SIZE] = i;
|
||||
TEST_ASSERT_EQUAL(PCM_BUFFER_SIZE - 1, get_buffer_helper());
|
||||
}
|
||||
|
||||
@@ -3,8 +3,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct spin_lock;
|
||||
typedef struct spin_lock spin_lock_t;
|
||||
|
||||
bool multicore_fifo_rvalid(void);
|
||||
void multicore_fifo_push_blocking(unsigned val);
|
||||
unsigned multicore_fifo_pop_blocking(void);
|
||||
#define __wfe()
|
||||
|
||||
Reference in New Issue
Block a user