YARP
Yet Another Robot Platform
SoundFileWav.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-FileCopyrightText: 2006-2010 RobotCub Consortium
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
8
9#include <yarp/conf/system.h>
10
11#include <yarp/os/NetInt16.h>
12#include <yarp/os/NetInt32.h>
14#include <yarp/os/Vocab.h>
15
16#include <yarp/sig/Sound.h>
17#include <yarp/os/Log.h>
18#include <yarp/os/LogStream.h>
19
20#include <cstdio>
21#include <cstring>
22
23using namespace yarp::os;
24using namespace yarp::sig;
25using namespace yarp::sig::file;
26
27namespace
28{
29 YARP_LOG_COMPONENT(SOUNDFILE_WAV, "yarp.sig.SoundFileWav")
30}
31
34public:
40
41 struct {
48 } pcm;
50
54
57
58 void setup_to_write(const Sound& sound, FILE *fp);
59 bool parse_from_file(FILE *fp);
60};
62
64{
65 yCTrace(SOUNDFILE_WAV, "bool PcmWavHeader::parse_from_file(FILE *fp)\n");
66
67 size_t ret;
68
69 ret = fread(&wavHeader, sizeof(wavHeader), 1, fp);
70 if (ret != 1) {
71 yCError(SOUNDFILE_WAV, "failed to read .wav file");
72 return false;
73 }
74
75 ret = fread(&wavLength, sizeof(wavLength), 1, fp);
76 if (ret != 1) {
77 yCError(SOUNDFILE_WAV, "failed to read .wav file");
78 return false;
79 }
80
81 ret = fread(&formatHeader1, sizeof(formatHeader1), 1, fp);
82 if (ret != 1) {
83 yCError(SOUNDFILE_WAV, "failed to read .wav file");
84 return false;
85 }
86
87 ret = fread(&formatHeader2, sizeof(formatHeader2), 1, fp);
88 if (ret != 1) {
89 yCError(SOUNDFILE_WAV, "failed to read .wav file");
90 return false;
91 }
92
93 ret = fread(&formatLength, sizeof(formatLength), 1, fp);
94 if (ret != 1) {
95 yCError(SOUNDFILE_WAV, "failed to read .wav file");
96 return false;
97 }
98
99 ret = fread(&pcm.pcmFormatTag, sizeof(pcm.pcmFormatTag), 1, fp);
100 if (ret != 1) {
101 yCError(SOUNDFILE_WAV, "failed to read .wav file");
102 return false;
103 }
104
105 ret = fread(&pcm.pcmChannels, sizeof(pcm.pcmChannels), 1, fp);
106 if (ret != 1) {
107 yCError(SOUNDFILE_WAV, "failed to read .wav file");
108 return false;
109 }
110
111 ret = fread(&pcm.pcmSamplesPerSecond, sizeof(pcm.pcmSamplesPerSecond), 1, fp);
112 if (ret != 1) {
113 yCError(SOUNDFILE_WAV, "failed to read .wav file");
114 return false;
115 }
116
117 ret = fread(&pcm.pcmBytesPerSecond, sizeof(pcm.pcmBytesPerSecond), 1, fp);
118 if (ret != 1) {
119 yCError(SOUNDFILE_WAV, "failed to read .wav file");
120 return false;
121 }
122
123 ret = fread(&pcm.pcmBlockAlign, sizeof(pcm.pcmBlockAlign), 1, fp);
124 if (ret != 1) {
125 yCError(SOUNDFILE_WAV, "failed to read .wav file");
126 return false;
127 }
128
129 ret = fread(&pcm.pcmBitsPerSample, sizeof(pcm.pcmBitsPerSample), 1, fp);
130 if (ret != 1) {
131 yCError(SOUNDFILE_WAV, "failed to read .wav file");
132 return false;
133 }
134 if (pcm.pcmBitsPerSample != 16)
135 {
136 yCError(SOUNDFILE_WAV, "sorry, lousy .wav read code only does 16-bit ints\n");
137 return false;
138 }
139
140 //extra bytes in pcm chuck
141 int extra_size = formatLength - sizeof(pcm);
142 if (extra_size != 0)
143 {
144 yCError(SOUNDFILE_WAV, "extra_size = %d\n", extra_size);
145 pcmExtraData.allocate(extra_size);
146 ret = fread(&pcmExtraData, extra_size, 1, fp);
147 if (ret != 1) {
148 yCError(SOUNDFILE_WAV, "failed to read .wav file");
149 return false;
150 }
151 }
152
153 //extra chunks
154 ret = fread(&dummyHeader, sizeof(dummyHeader), 1, fp);
155 if (ret != 1) {
156 yCError(SOUNDFILE_WAV, "failed to read .wav file");
157 return false;
158 }
159
160 while (dummyHeader != yarp::os::createVocab32('d', 'a', 't', 'a'))
161 {
162 ret = fread(&dummyLength, sizeof(dummyLength), 1, fp);
163 if (ret != 1) {
164 yCError(SOUNDFILE_WAV, "failed to read .wav file");
165 return false;
166 }
169 ret = fread(&dummyData, dummyLength, 1, fp);
170 if (ret != 1) {
171 yCError(SOUNDFILE_WAV, "failed to read .wav file");
172 return false;
173 }
174 ret = fread(&dummyHeader, sizeof(dummyHeader), 1, fp);
175 if (ret != 1) {
176 yCError(SOUNDFILE_WAV, "failed to read .wav file");
177 return false;
178 }
179 }
180
182 ret = fread(&dataLength, sizeof(dataLength), 1, fp);
183 if (ret != 1) {
184 yCError(SOUNDFILE_WAV, "failed to read .wav file");
185 return false;
186 }
187
188 return true;
189}
190
191void PcmWavHeader::setup_to_write(const Sound& src, FILE *fp)
192{
193 int bitsPerSample = 16;
194 size_t channels = src.getChannels();
195 size_t bytes = channels*src.getSamples()*2;
196 int align = channels*((bitsPerSample+7)/8);
197
198 wavHeader = yarp::os::createVocab32('R','I','F','F');
199 wavLength = bytes + sizeof(PcmWavHeader) - 2*sizeof(NetInt32);
200 formatHeader1 = yarp::os::createVocab32('W','A','V','E');
201 formatHeader2 = yarp::os::createVocab32('f','m','t',' ');
202 formatLength = sizeof(pcm);
203
204 pcm.pcmFormatTag = 1; /* PCM! */
205 pcm.pcmChannels = channels;
206 pcm.pcmSamplesPerSecond = (int)src.getFrequency();
207 pcm.pcmBytesPerSecond = align*pcm.pcmSamplesPerSecond;
208 pcm.pcmBlockAlign = align;
209 pcm.pcmBitsPerSample = bitsPerSample;
210
211 dataHeader = yarp::os::createVocab32('d','a','t','a');
212 dataLength = bytes;
213
214
215 fwrite(&wavHeader,sizeof(wavHeader),1,fp);
216 fwrite(&wavLength,sizeof(wavLength),1,fp);
217 fwrite(&formatHeader1,sizeof(formatHeader1),1,fp);
218
219 fwrite(&formatHeader2,sizeof(formatHeader2),1,fp);
220 fwrite(&formatLength,sizeof(formatLength),1,fp);
221
222 fwrite(&pcm.pcmFormatTag,sizeof(pcm.pcmFormatTag),1,fp);
223 fwrite(&pcm.pcmChannels,sizeof(pcm.pcmChannels),1,fp);
224 fwrite(&pcm.pcmSamplesPerSecond,sizeof(pcm.pcmSamplesPerSecond),1,fp);
225 fwrite(&pcm.pcmBytesPerSecond,sizeof(pcm.pcmBytesPerSecond),1,fp);
226 fwrite(&pcm.pcmBlockAlign,sizeof(pcm.pcmBlockAlign),1,fp);
227 fwrite(&pcm.pcmBitsPerSample,sizeof(pcm.pcmBitsPerSample),1,fp);
228
229 fwrite(&dataHeader,sizeof(dataHeader),1,fp);
230 fwrite(&dataLength,sizeof(dataLength),1,fp);
231
232}
233
234//#######################################################################################################
235
236bool yarp::sig::file::read_wav_file(Sound& sound_data, const char * filename)
237{
238 FILE *fp = fopen(filename, "rb");
239 if (!fp) {
240 yCError(SOUNDFILE_WAV, "cannot open file %s for reading\n", filename);
241 return false;
242 }
243
244 PcmWavHeader header;
245 if (!header.parse_from_file(fp))
246 {
247 yCError(SOUNDFILE_WAV, "error parsing header of file %s\n", filename);
248 fclose(fp);
249 return false;
250 };
251
252
253 int freq = header.pcm.pcmSamplesPerSecond;
254 int channels = header.pcm.pcmChannels;
255 int bits = header.pcm.pcmBitsPerSample;
256 int samples = header.dataLength/(bits/8)/channels;
257 sound_data.resize(samples,channels);
258 sound_data.setFrequency(freq);
259 ManagedBytes bytes(header.dataLength);
260 yCDebug(SOUNDFILE_WAV, "%d channels %d samples %d frequency\n", channels, samples, freq);
261
262 size_t result;
263 result = fread(bytes.get(),bytes.length(),1,fp);
264 YARP_UNUSED(result);
265
266 auto* data = reinterpret_cast<NetInt16*>(bytes.get());
267 int ct = 0;
268 for (int i=0; i<samples; i++) {
269 for (int j=0; j<channels; j++) {
270 sound_data.set(data[ct],i,j);
271 ct++;
272 }
273 }
274
275 fclose(fp);
276 return true;
277}
278
279bool yarp::sig::file::read_wav_bytestream(Sound& data, const char* bytestream)
280{
281 yCError(SOUNDFILE_WAV, "read_wav_bytestream() Not yet implemented");
282 return true;
283}
284
285bool yarp::sig::file::write_wav_file(const Sound& sound_data, const char * filename)
286{
287 FILE *fp = fopen(filename, "wb");
288 if (!fp) {
289 yCError(SOUNDFILE_WAV, "cannot open file %s for writing\n", filename);
290 return false;
291 }
292
293 PcmWavHeader header;
294 header.setup_to_write(sound_data, fp);
295
296 ManagedBytes bytes(header.dataLength);
297 auto* data = reinterpret_cast<NetInt16*>(bytes.get());
298 int ct = 0;
299 size_t samples = sound_data.getSamples();
300 size_t channels = sound_data.getChannels();
301 for (size_t i=0; i<samples; i++) {
302 for (size_t j=0; j<channels; j++) {
303 int v = sound_data.get(i,j);
304 data[ct] = v;
305 ct++;
306 }
307 }
308 fwrite(bytes.get(),bytes.length(),1,fp);
309
310 fclose(fp);
311 return true;
312}
int16_t * samples
bool ret
NetInt32 formatLength
NetInt32 pcmSamplesPerSecond
NetInt32 dummyHeader
NetInt32 dummyLength
ManagedBytes pcmExtraData
NetInt32 wavLength
void setup_to_write(const Sound &sound, FILE *fp)
NetInt16 pcmFormatTag
NetInt32 dataHeader
NetInt32 pcmBytesPerSecond
NetInt16 pcmChannels
NetInt32 dataLength
NetInt16 pcmBlockAlign
struct PcmWavHeader::@86 pcm
ManagedBytes dummyData
NetInt32 formatHeader2
NetInt32 formatHeader1
NetInt16 pcmBitsPerSample
bool parse_from_file(FILE *fp)
NetInt32 wavHeader
An abstraction for a block of bytes, with optional responsibility for allocating/destroying that bloc...
Definition: ManagedBytes.h:21
void clear()
Disassociate object with any data block (deleting block if appropriate).
void allocate(size_t len)
Makes a data block of the specified length that will be deleted if this object is destroyed.
const char * get() const
Class for storing sounds See Audio in YARP for additional documentation on YARP audio.
Definition: Sound.h:25
void setFrequency(int freq)
Set the frequency of the sound (i.e.
Definition: Sound.cpp:229
size_t getChannels() const
Get the number of channels of the sound.
Definition: Sound.cpp:424
void resize(size_t samples, size_t channels=1)
Set the sound size.
Definition: Sound.cpp:168
int getFrequency() const
Get the frequency of the sound (i.e.
Definition: Sound.cpp:224
audio_sample get(size_t sample, size_t channel=0) const
Definition: Sound.cpp:175
void set(audio_sample value, size_t sample, size_t channel=0)
Definition: Sound.cpp:209
size_t getSamples() const
Get the number of samples contained in the sound.
Definition: Sound.cpp:419
#define yCError(component,...)
Definition: LogComponent.h:213
#define yCTrace(component,...)
Definition: LogComponent.h:84
#define yCDebug(component,...)
Definition: LogComponent.h:128
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:76
An interface to the operating system, including Port based communication.
std::int16_t NetInt16
Definition of the NetInt16 type.
Definition: NetInt16.h:29
std::int32_t NetInt32
Definition of the NetInt32 type.
Definition: NetInt32.h:29
constexpr yarp::conf::vocab32_t createVocab32(char a, char b=0, char c=0, char d=0)
Create a vocab from chars.
Definition: Vocab.h:27
bool read_wav_file(Sound &data, const char *filename)
Read a sound from a .wav audio file.
bool write_wav_file(const Sound &data, const char *filename)
Write a sound to a .wav file.
bool read_wav_bytestream(Sound &data, const char *bytestream)
Read a sound from a byte array.
#define YARP_END_PACK
Ends 1 byte packing for structs/classes.
Definition: system.h:193
#define YARP_BEGIN_PACK
Starts 1 byte packing for structs/classes.
Definition: system.h:192
#define YARP_UNUSED(var)
Definition: api.h:162