1
0
Fork 0

pwm audio poc

sd2
radex 2024-05-16 13:47:49 +02:00
parent e32f90d4af
commit cb718266d6
Signed by: radex
SSH Key Fingerprint: SHA256:hvqRXAGG1h89yqnS+cyFTLKQbzjWD4uXIqw7Y+0ws30
6 changed files with 137 additions and 0 deletions

2
firmware/.gitignore vendored
View File

@ -4,4 +4,6 @@
.vscode/launch.json
.vscode/ipch
src/gfx_png.h
src/audio_sample.h
gfx/
audio/

View File

@ -11,3 +11,15 @@ move to `gfx` folder, then:
```
python3 scripts/gfx_convert.py
```
convert audio
```
ffmpeg -i badapple.webm -t 30 -ar 11000 output.wav
```
move to `audio` folder, then:
```
python3 scripts/audio_convert.py
```

View File

@ -0,0 +1,57 @@
import os
import sys
import soundfile as sf
import samplerate
# Adapted from https://github.com/rgrosset/pico-pwm-audio
print("loading file...")
soundfile = 'audio/output.wav'
data_in, datasamplerate = sf.read(soundfile)
# This means stereo so extract one channel 0
if len(data_in.shape)>1:
data_in = data_in[:,0]
print("resampling...")
converter = 'sinc_best' # or 'sinc_fastest', ...
desired_sample_rate = 11000.0
ratio = desired_sample_rate/datasamplerate
data_out = samplerate.resample(data_in, ratio, converter)
print("analyzing...")
maxValue = max(data_out)
minValue = min(data_out)
print("length", len(data_out))
print("max value", max(data_out))
print("min value", min(data_out))
vrange = (maxValue - minValue)
print("value range", vrange)
print("normalizing...")
# normalize to 0-1
normalized = [int((v-minValue)/vrange*255) for v in data_out]
print("generating header...")
m68code = "/* File "+soundfile+ "\r\n * Sample rate "+str(int(desired_sample_rate)) +" Hz\r\n */\r\n"
m68code += "#define WAV_DATA_LENGTH "+str(len(data_out))+" \r\n\r\n"
m68code += "static const uint8_t WAV_DATA[] = {\r\n "
m68code += ','.join(str(v) for v in normalized)
# keep track of first and last values to avoid
# blip when the loop restarts.. make the end value
# the average of the first and last.
end_value = int( (normalized[0] + normalized[len(normalized) - 1]) / 2)
m68code+=","+str(end_value)+'\n};\n'
print("writing output...")
with open("src/audio_sample.h", "w") as f:
f.write(m68code)
print("done!")

62
firmware/src/audio.cpp Normal file
View File

@ -0,0 +1,62 @@
#include <Arduino.h>
#include "hardware/irq.h" // interrupts
#include "hardware/pwm.h" // pwm
#include "hardware/sync.h" // wait for interrupt
#include "hardware/gpio.h"
#include "audio_sample.h"
// Adapted from https://github.com/rgrosset/pico-pwm-audio
#define AUDIO_PIN 23
int wav_position = 0;
/*
* PWM Interrupt Handler which outputs PWM level and advances the
* current sample.
*
* We repeat the same value for 8 cycles this means sample rate etc
* adjust by factor of 8 (this is what bitshifting <<3 is doing)
*
*/
void pwm_interrupt_handler() {
pwm_clear_irq(pwm_gpio_to_slice_num(AUDIO_PIN));
if (wav_position < (WAV_DATA_LENGTH<<3) - 1) {
// set pwm level
// allow the pwm value to repeat for 8 cycles this is >>3
pwm_set_gpio_level(AUDIO_PIN, WAV_DATA[wav_position>>3]);
wav_position++;
} else {
// reset to start
wav_position = 0;
}
}
// 11 KHz is fine for speech. Phone lines generally sample at 8 KHz
#define SYS_CLOCK 125000000.0f
#define AUDIO_WRAP 250.0f
#define AUDIO_RATE 11000.0f
#define AUDIO_CLK_DIV (SYS_CLOCK / AUDIO_WRAP / 8 / AUDIO_RATE)
void init_audio() {
gpio_set_function(AUDIO_PIN, GPIO_FUNC_PWM);
int audio_pin_slice = pwm_gpio_to_slice_num(AUDIO_PIN);
// Setup PWM interrupt to fire when PWM cycle is complete
pwm_clear_irq(audio_pin_slice);
pwm_set_irq_enabled(audio_pin_slice, true);
// set the handle function above
irq_set_exclusive_handler(PWM_IRQ_WRAP, pwm_interrupt_handler);
irq_set_enabled(PWM_IRQ_WRAP, true);
// Setup PWM for audio output
pwm_config config = pwm_get_default_config();
pwm_config_set_clkdiv(&config, AUDIO_CLK_DIV);
pwm_config_set_wrap(&config, 250);
pwm_init(audio_pin_slice, 0, &config, true);
pwm_set_gpio_level(AUDIO_PIN, 0);
}

1
firmware/src/audio.h Normal file
View File

@ -0,0 +1 @@
void init_audio();

View File

@ -4,6 +4,7 @@
#include "pico/multicore.h"
#include "hardware/gpio.h"
#include "mbed_wait_api.h"
#include "audio.h"
#define Serial Serial1
@ -60,6 +61,8 @@ void setup() {
Serial.begin(115200);
Serial.println("Hello worldd!");
init_audio();
memset(framebuffer, 0, sizeof(framebuffer));
// disable output