Skip to content

Commit 8bedbc5

Browse files
committed
WAF file support
1 parent 40c2971 commit 8bedbc5

File tree

9 files changed

+321
-111
lines changed

9 files changed

+321
-111
lines changed

.DS_Store

0 Bytes
Binary file not shown.

sandbox/a2dp-file_aac/a2dp-file_aac.ino

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,17 @@ void read_data_stream(const uint8_t *data, uint32_t length) {
4141
// Handle meta data changes
4242
void avrc_metadata_callback(uint8_t data1, const uint8_t *data2) {
4343
Serial.printf("AVRC metadata rsp: attribute id 0x%x, %s\n", data1, data2);
44-
openFile()
44+
if (data1==01 && strncmp(last, (char*)data2, 100)!=0){
45+
openFile();
46+
}
47+
if (data2) strncpy(last,(char*)data2,100);
4548
}
4649

4750
void setup() {
4851
Serial.begin(115200);
4952

5053
// setup A2DP
51-
a2dp_sink.set_stream_reader(read_data_stream);
54+
a2dp_sink.set_stream_reader(read_data_stream, false);
5255
a2dp_sink.set_avrc_metadata_callback(avrc_metadata_callback);
5356
a2dp_sink.start("AAC-Recorder");
5457

sandbox/wav_decode/wav_decode.ino

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
1-
#include "AudioWAV.h"
1+
#include "WiFi.h"
22
#include "AudioTools.h"
3+
#include "AudioWAV.h"
4+
5+
using namespace audio_tools;
6+
7+
I2S<int16_t> i2s; // I2S output destination
8+
I2SStream i2s_stream(i2s); // WAVDecoder neads I2S Output as stream
9+
WAVDecoder decoder(i2s_stream); // Decoder writing to I2S Stream
10+
UrlStream music; // Music Stream
11+
const size_t buffer_size = 512;
12+
uint8_t buffer[buffer_size];
13+
bool is_valid = true;
314

4-
I2S i2s; // I2S output destination
5-
WAVDecoder decoder(i2s);
6-
UrlStream music;
715

816
void setup(){
917
Serial.begin(115200);
@@ -14,15 +22,18 @@ void setup(){
1422
Serial.print(".");
1523
}
1624

25+
// start I2S with the default configuration
26+
I2SConfig<int16_t> config = i2s.defaultConfig(TX_MODE);
27+
i2s.begin(config);
28+
29+
// open music stream
1730
music.begin("https://www2.cs.uic.edu/~i101/SoundFiles/BabyElephantWalk60.wav");
18-
i2s.begin();
1931
decoder.begin();
2032
}
2133

2234
void loop(){
23-
static uint8_t buffer[512];
2435
if (music.available()>0){
25-
int len = music.readBytes(buffer, 512);
36+
int len = music.readBytes(buffer, buffer_size);
2637
decoder.write(buffer, len);
27-
}
28-
}
38+
}
39+
}

src/AudioTools.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@
1616
#include "AudioTools/ADC.h"
1717
#include "AudioTools/AudioLogger.h"
1818
#include "AudioTools/Buffers.h"
19+
#include "AudioTools/Streams.h"

src/AudioTools/Buffers.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ class BaseBuffer {
5454

5555
// checks if the buffer is full
5656
virtual bool isFull() = 0;
57+
58+
bool isEmpty() {
59+
return available() == 0;
60+
}
5761

5862
// write add an entry to the buffer
5963
virtual bool write(T data) = 0;
@@ -83,8 +87,8 @@ template<typename T>
8387
class SingleBuffer : public BaseBuffer<T> {
8488
public:
8589
SingleBuffer(int size){
86-
this->size = size;
87-
buffer = new T[size];
90+
this->max_size = size;
91+
buffer = new T[max_size];
8892
reset();
8993
}
9094

@@ -94,7 +98,7 @@ class SingleBuffer : public BaseBuffer<T> {
9498

9599
bool write(T sample){
96100
bool result = false;
97-
if (current_write_pos<size){
101+
if (current_write_pos<max_size){
98102
buffer[current_write_pos++] = sample;
99103
result = true;
100104
}
@@ -123,7 +127,7 @@ class SingleBuffer : public BaseBuffer<T> {
123127
}
124128

125129
int availableToWrite() {
126-
return size - current_write_pos;
130+
return max_size - current_write_pos;
127131
}
128132

129133
bool isFull(){
@@ -138,9 +142,19 @@ class SingleBuffer : public BaseBuffer<T> {
138142
current_read_pos = 0;
139143
current_write_pos = 0;
140144
}
145+
146+
/// If we load values directly into the address we need to set the avialeble size
147+
void setAvailable(size_t available_size){
148+
current_read_pos = 0;
149+
current_write_pos = available_size;
150+
}
151+
152+
size_t size() {
153+
return max_size;
154+
}
141155

142156
protected:
143-
int size;
157+
int max_size;
144158
int current_read_pos;
145159
int current_write_pos;
146160
T *buffer;

src/AudioTools/I2S.h

Lines changed: 79 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "esp_a2dp_api.h"
66
#include "driver/i2s.h"
77
#include "freertos/queue.h"
8+
#include "SoundTypes.h"
89

910
namespace audio_tools {
1011

@@ -21,6 +22,12 @@ class I2SConfig {
2122
i2s_port_t port_no = I2S_NUM_0;
2223
i2s_config_t i2s;
2324
i2s_pin_config_t pin;
25+
int channels = 2;
26+
27+
I2SConfig() {
28+
i2s = defaultConfig(TX_MODE);
29+
pin = defaultPinConfig(TX_MODE);
30+
}
2431

2532
/// Default Constructor
2633
I2SConfig(I2SMode mode) {
@@ -39,7 +46,7 @@ class I2SConfig {
3946
protected:
4047
i2s_config_t defaultConfig(I2SMode mode) {
4148
ESP_LOGD(I2S_TAG, "%s", __func__);
42-
i2s_config_t i2s_config = {
49+
i2s_config_t config = {
4350
.mode = (i2s_mode_t) ((mode == TX_MODE) ? (I2S_MODE_MASTER | I2S_MODE_TX) : (I2S_MODE_MASTER | I2S_MODE_RX)) ,
4451
.sample_rate = 44100,
4552
.bits_per_sample = (i2s_bits_per_sample_t) (sizeof(T) * 8),
@@ -50,18 +57,18 @@ class I2SConfig {
5057
.dma_buf_len = 1024,
5158
.use_apll = false,
5259
};
53-
return i2s_config;
60+
return config;
5461
}
5562

5663
i2s_pin_config_t defaultPinConfig(I2SMode mode = TX_MODE) {
5764
ESP_LOGD(I2S_TAG, "%s - mode: %s", __func__, mode==TX_MODE ? "TX" : "RX");
58-
i2s_pin_config_t pin_config_const = {
65+
i2s_pin_config_t config = {
5966
.bck_io_num = 14,
6067
.ws_io_num = 15,
6168
.data_out_num = mode == TX_MODE ? 22 : I2S_PIN_NO_CHANGE,
6269
.data_in_num = mode == RX_MODE ? 32 : I2S_PIN_NO_CHANGE
6370
};
64-
return pin_config_const;
71+
return config;
6572
}
6673
};
6774

@@ -72,8 +79,11 @@ class I2SConfig {
7279
* @copyright GPLv3
7380
*/
7481
template<typename T>
75-
class I2S {
82+
class I2S : public AudioBaseInfoDependent {
83+
friend class I2SStream;
84+
7685
public:
86+
7787
/// Default Constructor
7888
I2S() {
7989
}
@@ -86,43 +96,57 @@ class I2S {
8696
/// Provides the default configuration
8797
I2SConfig<T> defaultConfig(I2SMode mode) {
8898
ESP_LOGD(I2S_TAG, "%s", __func__);
89-
I2SConfig<T> config(mode);
90-
return config;
99+
I2SConfig<T> c(mode);
100+
return c;
91101
}
92102

93103
/// starts the DAC
94104
void begin(I2SConfig<T> cfg) {
95105
ESP_LOGD(I2S_TAG, "%s", __func__);
106+
this->cfg = cfg;
96107
this->i2s_num = cfg.port_no;
97-
this->i2s_config = cfg.i2s;
98-
this->pin_config = cfg.pin;
99108

100-
ESP_LOGD(I2S_TAG, "sample rate: %d", i2s_config.sample_rate);
101-
ESP_LOGD(I2S_TAG, "bits per sample: %d", i2s_config.bits_per_sample);
102-
ESP_LOGD(I2S_TAG, "pin bck_io_num: %d", pin_config.bck_io_num);
103-
ESP_LOGD(I2S_TAG, "pin ws_io_num: %d", pin_config.ws_io_num);
104-
ESP_LOGD(I2S_TAG, "pin data_out_num: %d", pin_config.data_out_num);
105-
ESP_LOGD(I2S_TAG, "pin data_in_num: %d", pin_config.data_in_num);
109+
// We make sure that we can reconfigure
110+
if (is_started) {
111+
stop();
112+
ESP_LOGD(I2S_TAG, "%s", "I2S restarting");
113+
}
114+
115+
ESP_LOGD(I2S_TAG, "sample rate: %d", cfg.i2s.sample_rate);
116+
ESP_LOGD(I2S_TAG, "bits per sample: %d", cfg.i2s.bits_per_sample);
117+
ESP_LOGD(I2S_TAG, "number of channels: %d", cfg.channels);
106118

107119
// setup config
108-
if (i2s_driver_install(i2s_num, &i2s_config, 0, NULL)!=ESP_OK){
120+
if (i2s_driver_install(i2s_num, &cfg.i2s, 0, NULL)!=ESP_OK){
109121
ESP_LOGE(I2S_TAG, "%s - %s", __func__, "i2s_driver_install");
110122
}
111123

112124
// setup pin config
113-
if (i2s_set_pin(i2s_num, &pin_config)!= ESP_OK){
114-
ESP_LOGE(I2S_TAG, "%s - %s", __func__, "i2s_set_pin");
125+
if (this->cfg.i2s.mode & I2S_MODE_DAC_BUILT_IN ) {
126+
ESP_LOGD(I2S_TAG, "Using built in DAC");
127+
//for internal DAC, this will enable both of the internal channels
128+
i2s_set_pin(i2s_num, NULL);
129+
} else {
130+
if (i2s_set_pin(i2s_num, &cfg.pin)!= ESP_OK){
131+
ESP_LOGD(I2S_TAG, "pin bck_io_num: %d", cfg.pin.bck_io_num);
132+
ESP_LOGD(I2S_TAG, "pin ws_io_num: %d", cfg.pin.ws_io_num);
133+
ESP_LOGD(I2S_TAG, "pin data_out_num: %d", cfg.pin.data_out_num);
134+
ESP_LOGD(I2S_TAG, "pin data_in_num: %d", cfg.pin.data_in_num);
135+
ESP_LOGE(I2S_TAG, "%s - %s", __func__, "i2s_set_pin");
136+
}
115137
}
116138

117139
// clear initial buffer
118140
i2s_zero_dma_buffer(i2s_num);
119141

142+
is_started = true;
120143
}
121144

122145
/// stops the I2C and unistalls the driver
123146
void stop(){
124147
ESP_LOGD(I2S_TAG, "%s", __func__);
125-
i2s_driver_uninstall(i2s_num);
148+
i2s_driver_uninstall(i2s_num);
149+
is_started = false;
126150
}
127151

128152
/// writes the data to the I2S interface
@@ -139,12 +163,44 @@ class I2S {
139163
return result;
140164
}
141165

166+
/// provides the actual configuration
167+
I2SConfig<T> config() {
168+
return cfg;
169+
}
170+
171+
/// updates the sample rate dynamically
172+
virtual void setAudioBaseInfo(AudioBaseInfo info) {
173+
bool is_update = false;
174+
175+
if (cfg.i2s.sample_rate != info.sample_rate
176+
|| cfg.i2s.bits_per_sample != info.bits_per_sample) {
177+
cfg.i2s.sample_rate = info.sample_rate;
178+
cfg.i2s.bits_per_sample = static_cast<i2s_bits_per_sample_t>(info.bits_per_sample);
179+
is_update = true;
180+
}
181+
182+
if (cfg.channels != info.channels){
183+
if (info.channels==2){
184+
cfg.i2s.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT;
185+
} else if (info.channels==1){
186+
cfg.i2s.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT;
187+
}
188+
cfg.channels = info.channels;
189+
is_update = true;
190+
}
191+
192+
if (is_update){
193+
// restart
194+
begin(config());
195+
}
196+
197+
}
198+
142199
protected:
200+
I2SConfig<T> cfg;
143201
i2s_port_t i2s_num;
144-
i2s_pin_config_t pin_config;
145-
i2s_config_t i2s_config;
202+
bool is_started = false;
146203

147-
148204
/// writes the data to the I2S interface
149205
size_t writeBytes(const void *src, size_t size_bytes, TickType_t ticks_to_wait=portMAX_DELAY){
150206
size_t result = 0;
@@ -154,17 +210,16 @@ class I2S {
154210
return result;
155211
}
156212

157-
158213
size_t readBytes(void *dest, size_t size_bytes, TickType_t ticks_to_wait=portMAX_DELAY){
159214
size_t result = 0;
160215
if (i2s_read(i2s_num, dest, size_bytes, &result, ticks_to_wait)!=ESP_OK){
161216
ESP_LOGE(I2S_TAG, "%s", __func__);
162217
}
163218
return result;
164219
}
165-
166220
};
167221

222+
168223
}
169224

170225
#endif

src/AudioTools/SoundTypes.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,26 @@ class int24_t {
7171
uint8_t value[3];
7272
};
7373

74+
75+
/**
76+
* @brief Basic Audio information which drives e.g. I2S
77+
*
78+
*/
79+
struct AudioBaseInfo {
80+
//AudioBaseInfo(AudioBaseInfo& c) = default;
81+
int sample_rate;
82+
int bits_per_sample;
83+
int channels;
84+
};
85+
86+
/**
87+
* @brief Supports changes to the sampling rate, bits and channels
88+
*/
89+
class AudioBaseInfoDependent {
90+
public:
91+
virtual ~AudioBaseInfoDependent(){}
92+
virtual void setAudioBaseInfo(AudioBaseInfo info) {};
93+
};
94+
95+
7496
}

0 commit comments

Comments
 (0)