last updated: 23/12/19
Sometimes we only want to play a short sound sample on our microcontroller. With an ESP32 we can use the internal DAC. With other controller the analogWrite() method gives us a PWM (PCM). In the following example I use a little speaker (one of those contained in birthday cards) connected do pin D7 (GPIO13) of an ESP8266 (Wemos D1 mini pro).
File > Export > Export as WAV. In the new window we chose `Other uncompressed files` as file format and `Unsigned 8-bit PWM` in Encoding (no header).
#### Python
The WAV file has a header of 44 byte. This has to be removed. The remaining bytes contain the 8 bit (0-255) values of our PWM. As we use Arduino (C, C++) we need an array variable to contain the data. As these variables are quite big, we will write them in a separate header file. For such tasks python is a cool programming language. The following script does the work:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# gpio_blink.py
import sys
from functools import partial
if len(sys.argv) < 2:
sys.exit('Usage: %s file' % sys.argv[0])
old_file = sys.argv[1]
variable_name = sys.argv[1].split('.')
variable_name = variable_name[0]
new_file = variable_name + ".h"
print (new_file)
with open(new_file, 'w') as outfile:
outfile.write("const byte ")
outfile.write(variable_name)
outfile.write("[] PROGMEM = {")
n = 0
with open(old_file, "rb") as in_file:
for c in iter(partial(in_file.read, 1), b''):
if n > 44:
outfile.write("0x%02X," % ord(c))
n += 1
if (n % 16 == 0) and (n > 44):
outfile.write("\n")
outfile.write("};")
python3 wav2c.py xmas_22050.wav
const byte xmas_22050[] PROGMEM = {0x7C,0x7F,0x83,0x83,0x7F,0x78,
...
...
0x84,0x83,0x83,0x80,0x83,0x82,0x7F,0x79,0x7C,0x7E,0x7D,0x7A,0x7C};
// play_wav.ino
// play wav files (8 bit, sr 22050Hz) on ESP8266
// weigu.lu
#include "xmas_22050.h"
#define wav xmas_22050
unsigned long now_micros, prev_micros, count;
void setup() {
analogWriteFreq(22050); // 22kHz PWM
analogWriteRange(255); // reduce to 8 bit
}
void loop() {
count = 0;
prev_micros = micros();
while (count != sizeof(wav)) {
now_micros = micros();
if ((now_micros - prev_micros) > 45) {
prev_micros = now_micros;
byte a_value = pgm_read_byte(wav+count);
analogWrite(D7,a_value);
count++;
yield(); // to avoid watchdog reset
}
}
delay(2000);
}