-
Notifications
You must be signed in to change notification settings - Fork 9
/
esp32_i2s_play_sdcard_wav_.ino
151 lines (141 loc) · 4.23 KB
/
esp32_i2s_play_sdcard_wav_.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include <mySD.h>
#include "driver/i2s.h"
#include "freertos/queue.h"
#define CCCC(c1, c2, c3, c4) ((c4 << 24) | (c3 << 16) | (c2 << 8) | c1)
/* these are data structures to process wav file */
typedef enum headerState_e {
HEADER_RIFF, HEADER_FMT, HEADER_DATA, DATA
} headerState_t;
typedef struct wavRiff_s {
uint32_t chunkID;
uint32_t chunkSize;
uint32_t format;
} wavRiff_t;
typedef struct wavProperties_s {
uint32_t chunkID;
uint32_t chunkSize;
uint16_t audioFormat;
uint16_t numChannels;
uint32_t sampleRate;
uint32_t byteRate;
uint16_t blockAlign;
uint16_t bitsPerSample;
} wavProperties_t;
/* variables hold file, state of process wav file and wav file properties */
File root;
headerState_t state = HEADER_RIFF;
wavProperties_t wavProps;
//i2s configuration
int i2s_num = 0; // i2s port number
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = 36000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 64 //Interrupt level 1
};
i2s_pin_config_t pin_config = {
.bck_io_num = 26, //this is BCK pin
.ws_io_num = 25, // this is LRCK pin
.data_out_num = 22, // this is DATA output pin
.data_in_num = -1 //Not used
};
//
void debug(uint8_t *buf, int len){
for(int i=0;i<len;i++){
Serial.print(buf[i], HEX);
Serial.print("\t");
}
Serial.println();
}
/* write sample data to I2S */
int i2s_write_sample_nb(uint32_t sample){
return i2s_write_bytes((i2s_port_t)i2s_num, (const char *)&sample, sizeof(uint32_t), 100);
}
/* read 4 bytes of data from wav file */
int read4bytes(File &file, uint32_t *chunkId){
int n = file.read((uint8_t *)chunkId, sizeof(uint32_t));
return n;
}
/* these are function to process wav file */
int readRiff(File &file, wavRiff_t *wavRiff){
int n = file.read((uint8_t *)wavRiff, sizeof(wavRiff_t));
return n;
}
int readProps(File &file, wavProperties_t *wavProps){
int n = file.read((uint8_t *)wavProps, sizeof(wavProperties_t));
return n;
}
void setup()
{
Serial.begin(115200);
Serial.print("Initializing SD card...");
if (!SD.begin(32, 14, 12, 27)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
delay(1000);
/* open wav file and process it */
root = SD.open("T.WAV");
if (root) {
int c = 0;
int n;
while (root.available()) {
switch(state){
case HEADER_RIFF:
wavRiff_t wavRiff;
n = readRiff(root, &wavRiff);
if(n == sizeof(wavRiff_t)){
if(wavRiff.chunkID == CCCC('R', 'I', 'F', 'F') && wavRiff.format == CCCC('W', 'A', 'V', 'E')){
state = HEADER_FMT;
Serial.println("HEADER_RIFF");
}
}
break;
case HEADER_FMT:
n = readProps(root, &wavProps);
if(n == sizeof(wavProperties_t)){
state = HEADER_DATA;
}
break;
case HEADER_DATA:
uint32_t chunkId, chunkSize;
n = read4bytes(root, &chunkId);
if(n == 4){
if(chunkId == CCCC('d', 'a', 't', 'a')){
Serial.println("HEADER_DATA");
}
}
n = read4bytes(root, &chunkSize);
if(n == 4){
Serial.println("prepare data");
state = DATA;
}
//initialize i2s with configurations above
i2s_driver_install((i2s_port_t)i2s_num, &i2s_config, 0, NULL);
i2s_set_pin((i2s_port_t)i2s_num, &pin_config);
//set sample rates of i2s to sample rate of wav file
i2s_set_sample_rates((i2s_port_t)i2s_num, wavProps.sampleRate);
break;
/* after processing wav file, it is time to process music data */
case DATA:
uint32_t data;
n = read4bytes(root, &data);
i2s_write_sample_nb(data);
break;
}
}
root.close();
} else {
Serial.println("error opening test.txt");
}
i2s_driver_uninstall((i2s_port_t)i2s_num); //stop & destroy i2s driver
Serial.println("done!");
}
void loop()
{
}