Skip to content

Commit

Permalink
Merge pull request #712 from Gadgetoid/picosystem-audio
Browse files Browse the repository at this point in the history
PicoSystem bleepy audio
  • Loading branch information
Gadgetoid committed Sep 13, 2021
2 parents c2c1207 + a337750 commit 3789c78
Show file tree
Hide file tree
Showing 15 changed files with 380 additions and 62 deletions.
118 changes: 65 additions & 53 deletions 32blit-pico/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,64 +7,76 @@ set(32BLIT_PICO 1 PARENT_SCOPE)

add_library(BlitHalPico INTERFACE)
target_sources(BlitHalPico INTERFACE

${CMAKE_CURRENT_LIST_DIR}/../3rd-party/fatfs/ff.c
${CMAKE_CURRENT_LIST_DIR}/../3rd-party/fatfs/ffunicode.c

${CMAKE_CURRENT_LIST_DIR}/audio.cpp
${CMAKE_CURRENT_LIST_DIR}/file.cpp
${CMAKE_CURRENT_LIST_DIR}/input.cpp
${CMAKE_CURRENT_LIST_DIR}/led.cpp
${CMAKE_CURRENT_LIST_DIR}/main.cpp
${CMAKE_CURRENT_LIST_DIR}/storage.cpp
${CMAKE_CURRENT_LIST_DIR}/st7789.cpp
${CMAKE_CURRENT_LIST_DIR}/usb.cpp
${CMAKE_CURRENT_LIST_DIR}/usb_descriptors.c
${CMAKE_CURRENT_LIST_DIR}/../3rd-party/fatfs/ff.c
${CMAKE_CURRENT_LIST_DIR}/../3rd-party/fatfs/ffunicode.c

${CMAKE_CURRENT_LIST_DIR}/audio.cpp
${CMAKE_CURRENT_LIST_DIR}/file.cpp
${CMAKE_CURRENT_LIST_DIR}/input.cpp
${CMAKE_CURRENT_LIST_DIR}/led.cpp
${CMAKE_CURRENT_LIST_DIR}/main.cpp
${CMAKE_CURRENT_LIST_DIR}/storage.cpp
${CMAKE_CURRENT_LIST_DIR}/st7789.cpp
${CMAKE_CURRENT_LIST_DIR}/usb.cpp
${CMAKE_CURRENT_LIST_DIR}/usb_descriptors.c
)

pico_generate_pio_header(BlitHalPico ${CMAKE_CURRENT_LIST_DIR}/st7789.pio)

target_link_libraries(BlitHalPico INTERFACE hardware_dma hardware_pio hardware_pwm hardware_spi pico_stdlib pico_unique_id tinyusb_device)
target_include_directories(BlitHalPico INTERFACE
${CMAKE_CURRENT_LIST_DIR} # for tusb_config
${CMAKE_CURRENT_LIST_DIR}/../3rd-party/fatfs
${CMAKE_CURRENT_LIST_DIR} # for tusb_config
${CMAKE_CURRENT_LIST_DIR}/../3rd-party/fatfs
)

target_compile_definitions(BlitHalPico INTERFACE
PICO_AUDIO_I2S_MONO_INPUT=1
PICO_AUDIO_DMA_IRQ=1
PICO_AUDIO_I2S_MONO_INPUT=1
PICO_AUDIO_DMA_IRQ=1
)

if(${PICO_BOARD} STREQUAL "vgaboard")
message("Using VGA board...")
target_link_libraries(BlitHalPico INTERFACE pico_scanvideo_dpi pico_audio_i2s)
target_compile_definitions(BlitHalPico INTERFACE
PICO_SCANVIDEO_PLANE1_VARIABLE_FRAGMENT_DMA=1
AUDIO_I2S
DISPLAY_SCANVIDEO
)
message("Using VGA board...")
target_link_libraries(BlitHalPico INTERFACE pico_scanvideo_dpi pico_audio_i2s)
target_compile_definitions(BlitHalPico INTERFACE
PICO_SCANVIDEO_PLANE1_VARIABLE_FRAGMENT_DMA=1
AUDIO_I2S
DISPLAY_SCANVIDEO
)
elseif(${PICO_BOARD} STREQUAL "pimoroni_picosystem")
message("Using picosystem...")
target_compile_definitions(BlitHalPico INTERFACE
DISPLAY_ST7789
INPUT_GPIO
)
message("Using picosystem...")
target_compile_definitions(BlitHalPico INTERFACE
DISPLAY_ST7789
INPUT_GPIO
)
if(AUDIO_PWM)
target_link_libraries(BlitHalPico INTERFACE pico_audio_pwm)
target_compile_definitions(BlitHalPico INTERFACE
PICO_AUDIO_PWM_MONO_PIN=11
PICO_AUDIO_PWM_PIO=1
AUDIO_PWM
)
else()
target_compile_definitions(BlitHalPico INTERFACE
AUDIO_BEEP_PIN=11
AUDIO_BEEP
)
endif()
else()
message(WARNING "Using default config for \"${PICO_BOARD}\"...")
target_link_libraries(BlitHalPico INTERFACE pico_audio_i2s)
# messy explorer-based setup
target_compile_definitions(BlitHalPico INTERFACE
PICO_AUDIO_I2S_DATA_PIN=6
PICO_AUDIO_I2S_CLOCK_PIN_BASE=20
AUDIO_I2S
DISPLAY_ST7789
INPUT_GPIO
)
message(WARNING "Using default config for \"${PICO_BOARD}\"...")
target_link_libraries(BlitHalPico INTERFACE pico_audio_i2s)
# messy explorer-based setup
target_compile_definitions(BlitHalPico INTERFACE
PICO_AUDIO_I2S_DATA_PIN=6
PICO_AUDIO_I2S_CLOCK_PIN_BASE=20
AUDIO_I2S
DISPLAY_ST7789
INPUT_GPIO
)
endif()


function(blit_executable_common NAME)
target_link_libraries(${NAME} BlitEngine)
target_link_libraries(${NAME} BlitEngine)

endfunction()

Expand All @@ -77,25 +89,25 @@ function(blit_executable_int_flash NAME SOURCES)

pico_add_extra_outputs(${NAME})

install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.uf2
DESTINATION bin
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.uf2
DESTINATION bin
)
endfunction()

function(blit_executable NAME SOURCES)
blit_executable_int_flash(${NAME} ${SOURCES} ${ARGN})
blit_executable_int_flash(${NAME} ${SOURCES} ${ARGN})
endfunction()

function(blit_metadata TARGET FILE)
# cause cmake to reconfigure whenever the asset list changes
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${FILE})
# cause cmake to reconfigure whenever the asset list changes
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${FILE})

# get the inputs/outputs for the asset tool (at configure time)
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m ttblit cmake --config ${CMAKE_CURRENT_SOURCE_DIR}/${FILE} --cmake ${CMAKE_CURRENT_BINARY_DIR}/metadata.cmake)
include(${CMAKE_CURRENT_BINARY_DIR}/metadata.cmake)
# get the inputs/outputs for the asset tool (at configure time)
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m ttblit cmake --config ${CMAKE_CURRENT_SOURCE_DIR}/${FILE} --cmake ${CMAKE_CURRENT_BINARY_DIR}/metadata.cmake)
include(${CMAKE_CURRENT_BINARY_DIR}/metadata.cmake)

pico_set_program_name(${TARGET} "${METADATA_TITLE}")
pico_set_program_description(${TARGET} "${METADATA_DESCRIPTION}")
pico_set_program_version(${TARGET} "${METADATA_VERSION}")
pico_set_program_url(${TARGET} "${METADATA_URL}")
pico_set_program_name(${TARGET} "${METADATA_TITLE}")
pico_set_program_description(${TARGET} "${METADATA_DESCRIPTION}")
pico_set_program_version(${TARGET} "${METADATA_VERSION}")
pico_set_program_url(${TARGET} "${METADATA_URL}")
endfunction()
100 changes: 95 additions & 5 deletions 32blit-pico/audio.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
#include "audio.hpp"
#include "config.h"

#ifdef AUDIO_I2S
#include "pico/audio_i2s.h"
#define HAVE_AUDIO
#define AUDIO_SAMPLE_FREQ 44100
#endif

#ifdef AUDIO_PWM
#include "pico/audio_pwm.h"
#include "hardware/pio.h"
#define HAVE_AUDIO
#define AUDIO_SAMPLE_FREQ 22050
#endif

#ifdef AUDIO_BEEP
#include "hardware/pwm.h"
#include "hardware/clocks.h"
#include "hardware/gpio.h"

static const uint32_t PWM_WRAP = 65535;
static uint32_t slice_num = 0;
static float clock_hz = 0.0;
static uint32_t beep_time = 0;
#endif

#include "audio/audio.hpp"
Expand All @@ -12,9 +32,18 @@ static audio_buffer_pool *audio_pool = nullptr;
#endif

void init_audio() {
#ifdef AUDIO_I2S
#ifdef AUDIO_BEEP
clock_hz = clock_get_hz(clk_sys);

gpio_set_function(AUDIO_BEEP_PIN, GPIO_FUNC_PWM);
slice_num = pwm_gpio_to_slice_num(AUDIO_BEEP_PIN);

pwm_set_wrap(slice_num, PWM_WRAP);
#endif

#ifdef HAVE_AUDIO
static audio_format_t audio_format = {
.sample_freq = 44100,
.sample_freq = AUDIO_SAMPLE_FREQ,
.format = AUDIO_BUFFER_FORMAT_PCM_S16,
.channel_count = 1
};
Expand All @@ -27,6 +56,7 @@ void init_audio() {
struct audio_buffer_pool *producer_pool = audio_new_producer_pool(&producer_format, 4, 441);
const struct audio_format *output_format;

#ifdef AUDIO_I2S
struct audio_i2s_config config = {
.data_pin = PICO_AUDIO_I2S_DATA_PIN,
.clock_pin_base = PICO_AUDIO_I2S_CLOCK_PIN_BASE,
Expand All @@ -42,24 +72,84 @@ void init_audio() {
bool ok = audio_i2s_connect(producer_pool);
assert(ok);
audio_i2s_set_enabled(true);
#endif

#ifdef AUDIO_PWM
struct audio_pwm_channel_config audio_pwm_config = {
.core = {
.base_pin = PICO_AUDIO_PWM_MONO_PIN,
.dma_channel = 1,
.pio_sm = 1,
},
.pattern = 3,
};
output_format = audio_pwm_setup(&audio_format, -1, &audio_pwm_config);
if (!output_format) {
panic("PicoAudio: Unable to open audio device.\n");
}
#if OVERCLOCK_250
pio_sm_set_clkdiv(pio1, 1, 2.0f);
#endif
bool ok = audio_pwm_default_connect(producer_pool, false);
assert(ok);
audio_pwm_set_enabled(true);
gpio_set_drive_strength(PICO_AUDIO_PWM_MONO_PIN, GPIO_DRIVE_STRENGTH_4MA);
gpio_set_slew_rate(PICO_AUDIO_PWM_MONO_PIN, GPIO_SLEW_RATE_FAST);
#endif

audio_pool = producer_pool;
#endif
}

void update_audio() {
void update_audio(uint32_t time) {
#ifdef AUDIO_BEEP
bool on = false;
uint32_t elapsed = time - beep_time;
beep_time = time;

for(auto f = 0u; f < elapsed * blit::sample_rate / 1000; f++) {
blit::get_audio_frame();
}

// Find the first square wave enabled channel and use freq/pulse width to drive the beeper
for(int c = 0; c < CHANNEL_COUNT; c++) {
auto &channel = blit::channels[c];

if(channel.waveforms & blit::Waveform::SQUARE) {
on = channel.volume
&& channel.adsr_phase != blit::ADSRPhase::RELEASE
&& channel.adsr_phase != blit::ADSRPhase::OFF;

if(on) {
pwm_set_clkdiv(slice_num, (clock_hz / PWM_WRAP) / channel.frequency);
pwm_set_gpio_level(AUDIO_BEEP_PIN, channel.pulse_width);
break;
}
}
}

pwm_set_enabled(slice_num, on);
#endif
#ifdef HAVE_AUDIO
// audio
struct audio_buffer *buffer = take_audio_buffer(audio_pool, false);
if(buffer) {
auto samples = (int16_t *) buffer->buffer->bytes;
#ifdef AUDIO_I2S
for(uint32_t i = 0; i < buffer->max_sample_count; i += 2) {
int val = (int)blit::get_audio_frame() - 0x8000;
*samples++ = val;
*samples++ = val;
}

#endif
#ifdef AUDIO_PWM
for(uint32_t i = 0; i < buffer->max_sample_count; i++) {
int val = (int)blit::get_audio_frame() - 0x8000;
*samples++ = val;
}
#endif
buffer->sample_count = buffer->max_sample_count;
give_audio_buffer(audio_pool, buffer);
}
#endif
}
}
3 changes: 2 additions & 1 deletion 32blit-pico/audio.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include <cstdint>

void init_audio();
void update_audio();
void update_audio(uint32_t time);
2 changes: 1 addition & 1 deletion 32blit-pico/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ int main() {
#endif
update_input();
int ms_to_next_update = tick(::now());
update_audio();
update_audio(now);
update_led();
update_usb();

Expand Down
5 changes: 5 additions & 0 deletions 32blit/audio/audio.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,15 @@ namespace blit {
adsr_step = (int32_t(sustain << 8) - int32_t(adsr)) / int32_t(adsr_end_frame);
}
void trigger_sustain() {
if(sustain == 0) {
off();
return;
}
adsr_frame = 0;
adsr_phase = ADSRPhase::SUSTAIN;
adsr_end_frame = 0;
adsr_step = 0;
adsr = int32_t(sustain << 8);
}
void trigger_release() {
adsr_frame = 0;
Expand Down
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ add_subdirectory(fizzlefade)
add_subdirectory(flight)
add_subdirectory(geometry)
add_subdirectory(hardware-test)
add_subdirectory(picosystem-hardware-test)
add_subdirectory(jpeg)
add_subdirectory(logo)
add_subdirectory(matrix-test)
Expand Down
2 changes: 1 addition & 1 deletion examples/geometry/geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ void init() {
channels[0].release_ms = 10;
channels[0].volume = 4000;

channels[1].waveforms = Waveform::SINE;
channels[1].waveforms = Waveform::SQUARE | Waveform::SINE;
channels[1].frequency = 0;
channels[1].attack_ms = 10;
channels[1].decay_ms = 500;
Expand Down
6 changes: 6 additions & 0 deletions examples/hardware-test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
cmake_minimum_required(VERSION 3.9)
project (hardware-test)
find_package (32BLIT CONFIG REQUIRED PATHS ../..)

if(32BLIT_PICO)
# PicoSystem has its own picosystem-hardware-test
return()
endif()

blit_executable (hardware-test hardware-test.cpp)
blit_metadata (hardware-test metadata.yml)
11 changes: 11 additions & 0 deletions examples/picosystem-hardware-test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.9)
project (picosystem-hardware-test)
find_package (32BLIT CONFIG REQUIRED PATHS ../..)

if(NOT 32BLIT_PICO)
# Hooks into the Pico SDK to get battery charge and VBUS status
return()
endif()

blit_executable (picosystem-hardware-test hardware-test.cpp)
blit_metadata (picosystem-hardware-test metadata.yml)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 3789c78

Please sign in to comment.