Skip to content

Commit 01a75f6

Browse files
committed
Automatic format conversion for ESP32 I2S
1 parent 82051ae commit 01a75f6

File tree

10 files changed

+665
-335
lines changed

10 files changed

+665
-335
lines changed

src/AudioHttp/HttpHeader.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ class HttpHeader {
239239
}
240240
put(line);
241241
}
242+
242243
}
243244
}
244245

src/AudioHttp/HttpRequest.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ class HttpRequest {
205205
chunk_reader.open(*client_ptr);
206206
};
207207

208+
// wait for data
208209
return reply_header.statusCode();
209210
}
210211

src/AudioHttp/URLStreamArduino.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ class URLStream : public Stream {
4545
result = request.process(action, url, reqMime, reqData);
4646
size = request.getReceivedContentLength();
4747
LOGI("size: %d", size);
48+
if (size>0){
49+
waitForData();
50+
}
4851
return result == 200;
4952
}
5053

@@ -121,6 +124,16 @@ class URLStream : public Stream {
121124
delay(500);
122125
}
123126

127+
virtual void waitForData() {
128+
if(request.available()==0){
129+
LOGI("Request written ... waiting for reply")
130+
while(request.available()==0){
131+
delay(500);
132+
}
133+
}
134+
}
135+
136+
124137
};
125138

126139
}

src/AudioPWM/PWMforAVR.h

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
2+
#pragma once
3+
#include "Stream.h"
4+
#include "AudioConfig.h"
5+
#include "AudioTools/AudioLogger.h"
6+
#include "AudioTools/Vector.h"
7+
8+
#ifdef __AVR__
9+
#include <limits> // std::numeric_limits
10+
11+
namespace audio_tools {
12+
13+
// forwrd declaratioin of callback
14+
bool defaultAudioOutputCallback(repeating_timer* ptr);
15+
16+
/**
17+
* @brief Configuration for PWM output
18+
*
19+
*/
20+
struct PWMConfig {
21+
int sample_rate = 10000; // sample rate in Hz
22+
int channels = 2;
23+
int pwm_freq = 60000; // audable range is from 20 to 20,000Hz
24+
int amplitude_out = 127; // amplitude of square wave (pwm values -amplitude to amplitude) for one byte
25+
int amplitude_in = 0;
26+
int start_pin = 2; // channel 0 will be on gpio 2, channel 1 on 3 etc
27+
} default_config;
28+
29+
/**
30+
* @brief Audio output to PWM pins
31+
*
32+
*/
33+
34+
template <class T>
35+
class AudioPWM : public Stream {
36+
friend bool defaultAudioOutputCallback(repeating_timer* ptr);
37+
38+
public:
39+
40+
AudioPWM(){
41+
T amplitude_in = getDefaultAmplitude();
42+
audio_config.amplitude_in = amplitude_in;
43+
default_config.amplitude_in = amplitude_in;
44+
}
45+
46+
PWMConfig defaultConfig() {
47+
return default_config;
48+
}
49+
50+
PWMConfig config() {
51+
return audio_config;
52+
}
53+
54+
// starts the processing
55+
void begin(PWMConfig config){
56+
LOGD(__FUNCTION__);
57+
this->audio_config = config;
58+
LOGI("sample_rate: %d", audio_config.sample_rate);
59+
LOGI("channels: %d", audio_config.channels);
60+
LOGI("pwm_freq: %d", audio_config.pwm_freq);
61+
LOGI("start_pin: %d", audio_config.start_pin);
62+
LOGI("amplitude_out: %d", audio_config.amplitude_out);
63+
LOGI("amplitude_in: %d", audio_config.amplitude_in);
64+
65+
setupPins();
66+
setupPWM();
67+
setupTimer();
68+
}
69+
70+
// Ends the output
71+
void end(){
72+
LOGD(__FUNCTION__);
73+
cancel_repeating_timer(&timer);
74+
for(auto pin : pins) {
75+
if (pin.gpio!=-1){
76+
pwm_set_enabled(pin.slice, false);
77+
}
78+
}
79+
}
80+
81+
// not supported
82+
virtual int available() {
83+
LOGE("not supported");
84+
return 0;
85+
}
86+
87+
// not supported
88+
virtual int read(){
89+
LOGE("not supported");
90+
return -1;
91+
}
92+
93+
// not supported
94+
virtual int peek() {
95+
LOGE("not supported");
96+
return -1;
97+
}
98+
99+
// not supported
100+
virtual size_t readBytes(char *buffer, size_t length){
101+
LOGE("not supported");
102+
return 0;
103+
}
104+
105+
virtual int availableForWrite() {
106+
return buffer.availableToWrite();
107+
}
108+
109+
virtual void flush() {
110+
}
111+
112+
// blocking write for a single byte
113+
virtual size_t write(uint8_t value) {
114+
LOGE("not supported");
115+
return -1;
116+
}
117+
118+
// blocking write for an array: we expect a singed value and convert it into a unsigned
119+
virtual size_t write(const uint8_t *wrt_buffer, size_t size){
120+
int len = size/sizeof(T);
121+
T* ptr = (T*) wrt_buffer;
122+
for (int j=0;j<len;j++){
123+
int32_t value = static_cast<float>(ptr[j] / (audio_config.amplitude_in / audio_config.amplitude_out)) + audio_config.amplitude_out;
124+
// try to write value into buffer
125+
while(buffer.write(value)==0)
126+
delay(5);
127+
}
128+
data_write_started = true;
129+
return size;
130+
}
131+
132+
// number of times we did not have enough data for output
133+
uint64_t underflowCount(){
134+
return underflow_count;
135+
}
136+
137+
138+
protected:
139+
PWMConfig audio_config;
140+
Vector<int> pins;
141+
NBuffer<T> buffer = NBuffer<T>(DEFAULT_BUFFER_SIZE,4);
142+
repeating_timer_t timer;
143+
uint64_t underflow_count = 0;
144+
bool data_write_started = false;
145+
146+
// setup pwm config and all pins
147+
void setupPins(){
148+
LOGD(__FUNCTION__);
149+
// initialize empty pins
150+
pins.resize(audio_config.channels, empty);
151+
// setup pin values
152+
for (int j;j< audio_config.channels;j++) {
153+
int gpio = audio_config.start_pin + j;
154+
pins[j]=gpio;
155+
pinMode(gpio, OUTPUT);
156+
}
157+
}
158+
159+
void setupPWM(){
160+
161+
}
162+
163+
void setupTimer(){
164+
165+
}
166+
167+
168+
169+
170+
// Output of the next frame - called by the timer callback
171+
void playNextFrame(){
172+
if (data_write_started){
173+
for (int j=0;j<audio_config.channels;j++){
174+
if (buffer.available()>0){
175+
pwm_set_chan_level(pins[j].slice, pins[j].channel, buffer.read());
176+
} else {
177+
underflow_count++;
178+
}
179+
}
180+
}
181+
}
182+
183+
// determines the max amplitude for the selected data type
184+
T getDefaultAmplitude() {
185+
std::numeric_limits<T> limits;
186+
return limits.max();
187+
}
188+
189+
};
190+
191+
192+
// timed output executed at the sampleRate
193+
bool defaultAudioOutputCallback(repeating_timer* ptr) {
194+
AudioPWM<int16_t> *self = (AudioPWM<int16_t> *) ptr->user_data;
195+
self->playNextFrame();
196+
return true;
197+
}
198+
199+
} // Namespace
200+
201+
202+
#endif
203+

0 commit comments

Comments
 (0)