-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPlayWavBetter.ino
175 lines (160 loc) · 6.37 KB
/
PlayWavBetter.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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include "driver/i2s.h"
#include "WavData.h"
#include "PlayWavBetter.h"
static const i2s_port_t i2s_num = I2S_NUM_0; // i2s port number
const unsigned char* TheData; //
uint32_t DataIdx=0;
// Function Prototypes
void setupSound();
bool ValidWavData(WavHeader_Struct* Wav);
void DumpWAVHeader(WavHeader_Struct* Wav);
void playTheSound();
static const i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = 44100,
.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, // 8 buffers
.dma_buf_len = 1024, // 1K per buffer, so 8K of buffer space
.use_apll=0,
.tx_desc_auto_clear= true,
.fixed_mclk=-1
};
static const i2s_pin_config_t pin_config = {
.bck_io_num = 27, // The bit clock connection, goes to pin 27 of ESP32
.ws_io_num = 26, // Word select, also known as word select or left right clock
.data_out_num = 25, // Data out from the ESP32, connect to DIN on 38357A
.data_in_num = I2S_PIN_NO_CHANGE // we are not interested in I2S data into the ESP32
};
void setupSound() {
const unsigned char *WavFile=WavData16BitMono;
Serial.begin(9600);
memcpy(&WavHeader,WavFile,44);
// Copy the header part of the wav data into our structure
DumpWAVHeader(&WavHeader);
// Dump the header data to serial
if(ValidWavData(&WavHeader))
{
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); // ESP32 will allocate resources to run I2S
i2s_set_pin(i2s_num, &pin_config); // Tell it the pins you will be using
i2s_set_sample_rates(i2s_num, WavHeader.SampleRate); // Set sample rate
TheData=WavFile+44; // Set to start of data
}
else // End code here
while(true);
}
bool ValidWavData(WavHeader_Struct* Wav)
{
if(memcmp(Wav->RIFFSectionID,"RIFF",4)!=0)
{
Serial.print("Invalid data - Not RIFF format");
return false;
}
if(memcmp(Wav->RiffFormat,"WAVE",4)!=0)
{
Serial.print("Invalid data - Not Wave file");
return false;
}
if(memcmp(Wav->FormatSectionID,"fmt",3)!=0)
{
Serial.print("Invalid data - No format section found");
return false;
}
if(memcmp(Wav->DataSectionID,"data",4)!=0)
{
Serial.print("Invalid data - data section not found");
return false;
}
if(Wav->FormatID!=1)
{
Serial.print("Invalid data - format Id must be 1");
return false;
}
if(Wav->FormatSize!=16)
{
Serial.print("Invalid data - format section size must be 16.");
return false;
}
if(Wav->NumChannels!=1)
{
Serial.print("Invalid data - only mono permitted.");
return false;
}
if(Wav->SampleRate>48000)
{
Serial.print("Invalid data - Sample rate cannot be greater than 48000");
return false;
}
if(Wav->BitsPerSample!=16)
{
Serial.print("Invalid data - Only 16 bits per sample permitted.");
return false;
}
return true;
}
void DumpWAVHeader(WavHeader_Struct* Wav)
{
if(memcmp(Wav->RIFFSectionID,"RIFF",4)!=0)
{
Serial.print("Not a RIFF format file - ");
PrintData(Wav->RIFFSectionID,4);
return;
}
if(memcmp(Wav->RiffFormat,"WAVE",4)!=0)
{
Serial.print("Not a WAVE file - ");
PrintData(Wav->RiffFormat,4);
return;
}
if(memcmp(Wav->FormatSectionID,"fmt",3)!=0)
{
Serial.print("fmt ID not present - ");
PrintData(Wav->FormatSectionID,3);
return;
}
if(memcmp(Wav->DataSectionID,"data",4)!=0)
{
Serial.print("data ID not present - ");
PrintData(Wav->DataSectionID,4);
return;
}
// All looks good, dump the data to Serial
Serial.print("Total size :");Serial.println(Wav->Size);
Serial.print("Format section size :");Serial.println(Wav->FormatSize);
Serial.print("Wave format :");Serial.println(Wav->FormatID);
Serial.print("Channels :");Serial.println(Wav->NumChannels);
Serial.print("Sample Rate :");Serial.println(Wav->SampleRate);
Serial.print("Byte Rate :");Serial.println(Wav->ByteRate);
Serial.print("Block Align :");Serial.println(Wav->BlockAlign);
Serial.print("Bits Per Sample :");Serial.println(Wav->BitsPerSample);
Serial.print("Data Size :");Serial.println(Wav->DataSize);
}
void PrintData(const char* Data,uint8_t NumBytes)
{
for(uint8_t i=0;i<NumBytes;i++)
Serial.print(Data[i]);
Serial.println();
}
void playTheSound()
{
for(int i = 0; i < WavHeader.DataSize; i++ ) {
uint8_t Mono[4]; // This holds the data we actually send to the I2S if mono sound
const unsigned char *Data; // Points to the data we are going to send
size_t BytesWritten; // Returned by the I2S write routine, we are not interested in it
if(WavHeader.NumChannels==1) // mono
{
Mono[0]=*(TheData+DataIdx); // copy the sample to both left and right samples, this is left
Mono[1]=*(TheData+DataIdx+1);
Mono[2]=*(TheData+DataIdx); // Same data to the right channel
Mono[3]=*(TheData+DataIdx+1);
Data=Mono;
}
else // stereo
Data=TheData+DataIdx;
i2s_write(i2s_num,Data,4,&BytesWritten,portMAX_DELAY);
DataIdx+=WavHeader.BlockAlign; // increase the data index to next next sample
}
DataIdx=0;
}