YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
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
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 if (pcm.pcmChannels <= 0)
111 {
112 yCError(SOUNDFILE_WAV, "pcmChannels <=0, invalid wav file\n");
113 return false;
114 }
115
116 ret = fread(&pcm.pcmSamplesPerSecond, sizeof(pcm.pcmSamplesPerSecond), 1, fp);
117 if (ret != 1) {
118 yCError(SOUNDFILE_WAV, "failed to read .wav file");
119 return false;
120 }
121 if (pcm.pcmSamplesPerSecond <= 0)
122 {
123 yCError(SOUNDFILE_WAV, "pcmSamplesPerSecond <=0, invalid wav file\n");
124 return false;
125 }
126
127 ret = fread(&pcm.pcmBytesPerSecond, sizeof(pcm.pcmBytesPerSecond), 1, fp);
128 if (ret != 1) {
129 yCError(SOUNDFILE_WAV, "failed to read .wav file");
130 return false;
131 }
132 if (pcm.pcmBytesPerSecond <= 0)
133 {
134 yCError(SOUNDFILE_WAV, "pcmBytesPerSecond <=0, invalid wav file\n");
135 return false;
136 }
137
138 ret = fread(&pcm.pcmBlockAlign, sizeof(pcm.pcmBlockAlign), 1, fp);
139 if (ret != 1) {
140 yCError(SOUNDFILE_WAV, "failed to read .wav file");
141 return false;
142 }
143
144 ret = fread(&pcm.pcmBitsPerSample, sizeof(pcm.pcmBitsPerSample), 1, fp);
145 if (ret != 1) {
146 yCError(SOUNDFILE_WAV, "failed to read .wav file");
147 return false;
148 }
149 if (pcm.pcmBitsPerSample != 16)
150 {
151 yCError(SOUNDFILE_WAV, "sorry, lousy .wav read code only does 16-bit ints\n");
152 return false;
153 }
154
155 //extra bytes in pcm chuck
156 int extra_size = formatLength - sizeof(pcm);
157 if (extra_size != 0)
158 {
159 yCError(SOUNDFILE_WAV, "extra_size = %d\n", extra_size);
162 if (ret != 1) {
163 yCError(SOUNDFILE_WAV, "failed to read .wav file");
164 return false;
165 }
166 }
167
168 //extra chunks
169 ret = fread(&dummyHeader, sizeof(dummyHeader), 1, fp);
170 if (ret != 1) {
171 yCError(SOUNDFILE_WAV, "failed to read .wav file");
172 return false;
173 }
174
175 while (dummyHeader != yarp::os::createVocab32('d', 'a', 't', 'a'))
176 {
177 ret = fread(&dummyLength, sizeof(dummyLength), 1, fp);
178 if (ret != 1) {
179 yCError(SOUNDFILE_WAV, "failed to read .wav file");
180 return false;
181 }
185 if (ret != 1) {
186 yCError(SOUNDFILE_WAV, "failed to read .wav file");
187 return false;
188 }
189 ret = fread(&dummyHeader, sizeof(dummyHeader), 1, fp);
190 if (ret != 1) {
191 yCError(SOUNDFILE_WAV, "failed to read .wav file");
192 return false;
193 }
194 }
195
197 ret = fread(&dataLength, sizeof(dataLength), 1, fp);
198 if (ret != 1) {
199 yCError(SOUNDFILE_WAV, "failed to read .wav file");
200 return false;
201 }
202
203 return true;
204}
205
207{
208 int bitsPerSample = 16;
209 size_t channels = src.getChannels();
210 size_t bytes = channels*src.getSamples()*2;
211 int align = channels*((bitsPerSample+7)/8);
212
213 wavHeader = yarp::os::createVocab32('R','I','F','F');
214 wavLength = bytes + sizeof(PcmWavHeader) - 2*sizeof(NetInt32);
215 formatHeader1 = yarp::os::createVocab32('W','A','V','E');
216 formatHeader2 = yarp::os::createVocab32('f','m','t',' ');
217 formatLength = sizeof(pcm);
218
219 pcm.pcmFormatTag = 1; /* PCM! */
220 pcm.pcmChannels = channels;
221 pcm.pcmSamplesPerSecond = (int)src.getFrequency();
222 pcm.pcmBytesPerSecond = align*pcm.pcmSamplesPerSecond;
223 pcm.pcmBlockAlign = align;
224 pcm.pcmBitsPerSample = bitsPerSample;
225
226 dataHeader = yarp::os::createVocab32('d','a','t','a');
227 dataLength = bytes;
228
229
230 fwrite(&wavHeader,sizeof(wavHeader),1,fp);
231 fwrite(&wavLength,sizeof(wavLength),1,fp);
233
236
237 fwrite(&pcm.pcmFormatTag,sizeof(pcm.pcmFormatTag),1,fp);
238 fwrite(&pcm.pcmChannels,sizeof(pcm.pcmChannels),1,fp);
239 fwrite(&pcm.pcmSamplesPerSecond,sizeof(pcm.pcmSamplesPerSecond),1,fp);
240 fwrite(&pcm.pcmBytesPerSecond,sizeof(pcm.pcmBytesPerSecond),1,fp);
241 fwrite(&pcm.pcmBlockAlign,sizeof(pcm.pcmBlockAlign),1,fp);
242 fwrite(&pcm.pcmBitsPerSample,sizeof(pcm.pcmBitsPerSample),1,fp);
243
244 fwrite(&dataHeader,sizeof(dataHeader),1,fp);
245 fwrite(&dataLength,sizeof(dataLength),1,fp);
246
247}
248
249//#######################################################################################################
250
251bool yarp::sig::file::read_wav_file(Sound& sound_data, const char * filename)
252{
253 FILE *fp = fopen(filename, "rb");
254 if (!fp) {
255 yCError(SOUNDFILE_WAV, "cannot open file %s for reading\n", filename);
256 return false;
257 }
258
259 PcmWavHeader header;
260 if (!header.parse_from_file(fp))
261 {
262 yCError(SOUNDFILE_WAV, "error parsing header of file %s\n", filename);
263 fclose(fp);
264 return false;
265 };
266
267
268 int freq = header.pcm.pcmSamplesPerSecond;
269 int channels = header.pcm.pcmChannels;
270 int bits = header.pcm.pcmBitsPerSample;
271 int samples = header.dataLength/(bits/8)/channels;
272 sound_data.resize(samples,channels);
273 sound_data.setFrequency(freq);
274 ManagedBytes bytes(header.dataLength);
275 yCDebug(SOUNDFILE_WAV, "%d channels %d samples %d frequency\n", channels, samples, freq);
276
277 size_t result;
278 result = fread(bytes.get(),bytes.length(),1,fp);
279 YARP_UNUSED(result);
280
281 auto* data = reinterpret_cast<NetInt16*>(bytes.get());
282 int ct = 0;
283 for (int i=0; i<samples; i++) {
284 for (int j=0; j<channels; j++) {
285 sound_data.set(data[ct],i,j);
286 ct++;
287 }
288 }
289
290 fclose(fp);
291 return true;
292}
293
295{
296 yCError(SOUNDFILE_WAV, "read_wav_bytestream() Not yet implemented");
297 return true;
298}
299
300bool yarp::sig::file::write_wav_file(const Sound& sound_data, const char * filename)
301{
302 FILE *fp = fopen(filename, "wb");
303 if (!fp) {
304 yCError(SOUNDFILE_WAV, "cannot open file %s for writing\n", filename);
305 return false;
306 }
307
308 PcmWavHeader header;
309 header.setup_to_write(sound_data, fp);
310
311 ManagedBytes bytes(header.dataLength);
312 auto* data = reinterpret_cast<NetInt16*>(bytes.get());
313 int ct = 0;
314 size_t samples = sound_data.getSamples();
315 size_t channels = sound_data.getChannels();
316 for (size_t i=0; i<samples; i++) {
317 for (size_t j=0; j<channels; j++) {
318 int v = sound_data.get(i,j);
319 data[ct] = v;
320 ct++;
321 }
322 }
323 fwrite(bytes.get(),bytes.length(),1,fp);
324
325 fclose(fp);
326 return true;
327}
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
A mini-server for performing network communication in the background.
An abstraction for a block of bytes, with optional responsibility for allocating/destroying that bloc...
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:361
size_t getChannels() const
Get the number of channels of the sound.
Definition Sound.cpp:603
void resize(size_t samples, size_t channels=1)
Set the sound size.
Definition Sound.cpp:270
int getFrequency() const
Get the frequency of the sound (i.e.
Definition Sound.cpp:356
audio_sample get(size_t sample, size_t channel=0) const
Definition Sound.cpp:294
void set(audio_sample value, size_t sample, size_t channel=0)
Definition Sound.cpp:334
size_t getSamples() const
Get the number of samples contained in the sound.
Definition Sound.cpp:598
#define yCError(component,...)
#define yCTrace(component,...)
#define yCDebug(component,...)
#define YARP_LOG_COMPONENT(name,...)
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