mirror of https://github.com/radex/radmatrix.git
pwm audio poc
parent
e32f90d4af
commit
cb718266d6
|
@ -4,4 +4,6 @@
|
|||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
src/gfx_png.h
|
||||
src/audio_sample.h
|
||||
gfx/
|
||||
audio/
|
||||
|
|
|
@ -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
|
||||
```
|
||||
|
|
|
@ -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!")
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
void init_audio();
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue