Skip to content

Commit a4421bd

Browse files
committed
Add basic WAV file reader for use in examples.
Signed-off-by: iabdalkader <[email protected]>
1 parent f7d081c commit a4421bd

File tree

3 files changed

+183
-0
lines changed

3 files changed

+183
-0
lines changed

src/Arduino_AdvancedAnalog.h

+1
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@
2626

2727
#include "AdvancedADC.h"
2828
#include "AdvancedDAC.h"
29+
#include "WavReader.h"
2930

3031
#endif /* ADVANCEDANALOGREDUX_ARDUINO_ADVANCEDANALOG_H */

src/WavReader.cpp

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
This file is part of the Arduino_AdvancedAnalog library.
3+
Copyright (c) 2024 Arduino SA. All rights reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#include "Arduino.h"
21+
#include "WavReader.h"
22+
23+
WavReader::~WavReader() {
24+
stop();
25+
}
26+
27+
int WavReader::begin(const char *path, size_t n_samples, size_t n_buffers, bool loop) {
28+
this->loop = loop;
29+
30+
if ((file = fopen(path, "rb")) == nullptr) {
31+
return 0;
32+
}
33+
34+
// Read file header
35+
fread(&header, sizeof(header), 1, file);
36+
37+
// Add more sanity checks if needed.
38+
if (memcmp(header.chunk_id, "RIFF", 4) != 0 ||
39+
memcmp(header.format, "WAVEfmt", 7) != 0 ||
40+
(n_samples * header.num_channels) > sample_count()) {
41+
stop();
42+
return 0;
43+
}
44+
45+
// Allocate the DMA buffer pool.
46+
pool = new DMABufferPool<Sample>(n_samples, header.num_channels, n_buffers);
47+
if (pool == nullptr) {
48+
stop();
49+
return 0;
50+
}
51+
return 1;
52+
}
53+
54+
void WavReader::stop() {
55+
if (file) {
56+
fclose(file);
57+
}
58+
if (pool) {
59+
delete pool;
60+
}
61+
pool = nullptr;
62+
file = nullptr;
63+
}
64+
65+
bool WavReader::available() {
66+
if (file != nullptr && pool != nullptr) {
67+
return pool->writable();
68+
}
69+
return false;
70+
}
71+
72+
DMABuffer<Sample> &WavReader::read() {
73+
while (!available()) {
74+
__WFI();
75+
}
76+
77+
DMABuffer<Sample> *buf = pool->allocate();
78+
size_t offset = 0;
79+
Sample *rawbuf = buf->data();
80+
size_t n_samples = buf->size();
81+
82+
while (offset < n_samples) {
83+
offset += fread(&rawbuf[offset], sizeof(Sample), n_samples - offset, file);
84+
if (offset < n_samples) {
85+
if (loop) {
86+
rewind();
87+
} else {
88+
for (size_t i=offset; i<n_samples; i++) {
89+
rawbuf[i] = 0;
90+
}
91+
fclose(file);
92+
file = nullptr;
93+
break;
94+
}
95+
}
96+
}
97+
return *buf;
98+
}
99+
100+
int WavReader::rewind() {
101+
if (file == nullptr) {
102+
return 0;
103+
}
104+
if (fseek(file, sizeof(WavHeader), SEEK_SET) == -1) {
105+
return 0;
106+
}
107+
return 1;
108+
}

src/WavReader.h

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
This file is part of the Arduino_AdvancedAnalog library.
3+
Copyright (c) 2024 Arduino SA. All rights reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#include "AdvancedAnalog.h"
21+
22+
#ifndef ARDUINO_WAV_READER_H_
23+
#define ARDUINO_WAV_READER_H_
24+
25+
class WavReader {
26+
typedef struct {
27+
char chunk_id[4];
28+
unsigned int chunk_size;
29+
char format[4];
30+
char subchunk1_id[4];
31+
unsigned int subchunk1_size;
32+
unsigned short audio_format;
33+
unsigned short num_channels;
34+
unsigned int sample_rate;
35+
unsigned int byte_rate;
36+
unsigned short block_align;
37+
unsigned short bits_per_sample;
38+
char subchunk2_id[4];
39+
unsigned int subchunk2_size;
40+
} WavHeader;
41+
42+
private:
43+
FILE *file;
44+
bool loop;
45+
WavHeader header;
46+
DMABufferPool<Sample> *pool;
47+
48+
public:
49+
WavReader(): file(nullptr), loop(false), pool(nullptr) {
50+
}
51+
~WavReader();
52+
size_t channels() {
53+
return header.num_channels;
54+
}
55+
56+
size_t resolution() {
57+
return header.bits_per_sample;
58+
}
59+
60+
size_t sample_rate() {
61+
return header.sample_rate;
62+
}
63+
64+
size_t sample_count() {
65+
return (header.subchunk2_size * 8) / header.bits_per_sample;
66+
}
67+
68+
int begin(const char *path, size_t n_samples, size_t n_buffers, bool loop=false);
69+
void stop();
70+
bool available();
71+
SampleBuffer read();
72+
int rewind();
73+
};
74+
#endif /* ARDUINO_WAV_READER_H_ */

0 commit comments

Comments
 (0)