YARP
Yet Another Robot Platform
SoundFile.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  * Copyright (C) 2006-2010 RobotCub Consortium
4  * All rights reserved.
5  *
6  * This software may be modified and distributed under the terms of the
7  * BSD-3-Clause license. See the accompanying LICENSE file for details.
8  */
9 
10 #include <yarp/sig/SoundFile.h>
11 
12 #include <yarp/conf/system.h>
13 
14 #include <yarp/os/NetInt16.h>
15 #include <yarp/os/NetInt32.h>
16 #include <yarp/os/ManagedBytes.h>
17 #include <yarp/os/Vocab.h>
18 
19 #include <yarp/sig/Sound.h>
20 
21 #include <cstdio>
22 #include <cstring>
23 
24 using namespace yarp::os;
25 using namespace yarp::sig;
26 using namespace yarp::sig::file;
27 
29 class PcmWavHeader {
30 public:
36 
37  struct {
44  } pcm;
46 
50 
53 
54  void setup_to_write(const Sound& sound, FILE *fp);
55  bool parse_from_file(FILE *fp);
56 };
58 
60 {
61  printf("bool PcmWavHeader::parse_from_file(FILE *fp)\n");
62 
63  size_t ret;
64 
65  ret = fread(&wavHeader, sizeof(wavHeader), 1, fp);
66  if (ret != 1) {
67  printf("failed to read wav file");
68  return false;
69  }
70 
71  ret = fread(&wavLength, sizeof(wavLength), 1, fp);
72  if (ret != 1) {
73  printf("failed to read wav file");
74  return false;
75  }
76 
77  ret = fread(&formatHeader1, sizeof(formatHeader1), 1, fp);
78  if (ret != 1) {
79  printf("failed to read wav file");
80  return false;
81  }
82 
83  ret = fread(&formatHeader2, sizeof(formatHeader2), 1, fp);
84  if (ret != 1) {
85  printf("failed to read wav file");
86  return false;
87  }
88 
89  ret = fread(&formatLength, sizeof(formatLength), 1, fp);
90  if (ret != 1) {
91  printf("failed to read wav file");
92  return false;
93  }
94 
95  ret = fread(&pcm.pcmFormatTag, sizeof(pcm.pcmFormatTag), 1, fp);
96  if (ret != 1) {
97  printf("failed to read wav file");
98  return false;
99  }
100 
101  ret = fread(&pcm.pcmChannels, sizeof(pcm.pcmChannels), 1, fp);
102  if (ret != 1) {
103  printf("failed to read wav file");
104  return false;
105  }
106 
107  ret = fread(&pcm.pcmSamplesPerSecond, sizeof(pcm.pcmSamplesPerSecond), 1, fp);
108  if (ret != 1) {
109  printf("failed to read wav file");
110  return false;
111  }
112 
113  ret = fread(&pcm.pcmBytesPerSecond, sizeof(pcm.pcmBytesPerSecond), 1, fp);
114  if (ret != 1) {
115  printf("failed to read wav file");
116  return false;
117  }
118 
119  ret = fread(&pcm.pcmBlockAlign, sizeof(pcm.pcmBlockAlign), 1, fp);
120  if (ret != 1) {
121  printf("failed to read wav file");
122  return false;
123  }
124 
125  ret = fread(&pcm.pcmBitsPerSample, sizeof(pcm.pcmBitsPerSample), 1, fp);
126  if (ret != 1) {
127  printf("failed to read wav file");
128  return false;
129  }
130  if (pcm.pcmBitsPerSample != 16)
131  {
132  printf("sorry, lousy wav read code only does 16-bit ints\n");
133  return false;
134  }
135 
136  //extra bytes in pcm chuck
137  int extra_size = formatLength - sizeof(pcm);
138  if (extra_size != 0) {
139  printf("extra_size = %d\n", extra_size);
140  pcmExtraData.allocate(extra_size);
141  ret = fread(&pcmExtraData, extra_size, 1, fp);
142  if (ret != 1) {
143  printf("failed to read wav file");
144  return false;
145  }
146  }
147 
148  //extra chunks
149  ret = fread(&dummyHeader, sizeof(dummyHeader), 1, fp);
150  if (ret != 1) {
151  printf("failed to read wav file");
152  return false;
153  }
154 
155  while (dummyHeader != yarp::os::createVocab('d', 'a', 't', 'a'))
156  {
157  fread(&dummyLength, sizeof(dummyLength), 1, fp);
158  if (ret != 1) {
159  printf("failed to read wav file");
160  return false;
161  }
162  dummyData.clear();
163  dummyData.allocate(dummyLength);
164  fread(&dummyData, dummyLength, 1, fp);
165  if (ret != 1) {
166  printf("failed to read wav file");
167  return false;
168  }
169  fread(&dummyHeader, sizeof(dummyHeader), 1, fp);
170  if (ret != 1) {
171  printf("failed to read wav file");
172  return false;
173  }
174  }
175 
176  dataHeader = dummyHeader;
177  fread(&dataLength, sizeof(dataLength), 1, fp);
178  if (ret != 1) {
179  printf("failed to read wav file");
180  return false;
181  }
182 
183  return true;
184 }
185 
186 void PcmWavHeader::setup_to_write(const Sound& src, FILE *fp)
187 {
188  int bitsPerSample = 16;
189  int channels = src.getChannels();
190  int bytes = channels*src.getSamples()*2;
191  int align = channels*((bitsPerSample+7)/8);
192 
193  wavHeader = yarp::os::createVocab('R','I','F','F');
194  wavLength = bytes + sizeof(PcmWavHeader) - 2*sizeof(NetInt32);
195  formatHeader1 = yarp::os::createVocab('W','A','V','E');
196  formatHeader2 = yarp::os::createVocab('f','m','t',' ');
197  formatLength = sizeof(pcm);
198 
199  pcm.pcmFormatTag = 1; /* PCM! */
200  pcm.pcmChannels = channels;
201  pcm.pcmSamplesPerSecond = (int)src.getFrequency();
202  pcm.pcmBytesPerSecond = align*pcm.pcmSamplesPerSecond;
203  pcm.pcmBlockAlign = align;
204  pcm.pcmBitsPerSample = bitsPerSample;
205 
206  dataHeader = yarp::os::createVocab('d','a','t','a');
207  dataLength = bytes;
208 
209 
210  fwrite(&wavHeader,sizeof(wavHeader),1,fp);
211  fwrite(&wavLength,sizeof(wavLength),1,fp);
212  fwrite(&formatHeader1,sizeof(formatHeader1),1,fp);
213 
214  fwrite(&formatHeader2,sizeof(formatHeader2),1,fp);
215  fwrite(&formatLength,sizeof(formatLength),1,fp);
216 
217  fwrite(&pcm.pcmFormatTag,sizeof(pcm.pcmFormatTag),1,fp);
218  fwrite(&pcm.pcmChannels,sizeof(pcm.pcmChannels),1,fp);
219  fwrite(&pcm.pcmSamplesPerSecond,sizeof(pcm.pcmSamplesPerSecond),1,fp);
220  fwrite(&pcm.pcmBytesPerSecond,sizeof(pcm.pcmBytesPerSecond),1,fp);
221  fwrite(&pcm.pcmBlockAlign,sizeof(pcm.pcmBlockAlign),1,fp);
222  fwrite(&pcm.pcmBitsPerSample,sizeof(pcm.pcmBitsPerSample),1,fp);
223 
224  fwrite(&dataHeader,sizeof(dataHeader),1,fp);
225  fwrite(&dataLength,sizeof(dataLength),1,fp);
226 
227 }
228 
229 bool yarp::sig::file::read(Sound& dest, const char *src)
230 {
231  FILE *fp = fopen(src, "rb");
232  if (!fp) {
233  printf("cannot open file %s for reading\n", src);
234  return false;
235  }
236 
237  PcmWavHeader header;
238  if (!header.parse_from_file(fp))
239  {
240  printf("error parsing header of file %s\n", src);
241  fclose(fp);
242  return false;
243  };
244 
245 
246  int freq = header.pcm.pcmSamplesPerSecond;
247  int channels = header.pcm.pcmChannels;
248  int bits = header.pcm.pcmBitsPerSample;
249  int samples = header.dataLength/(bits/8)/channels;
250  dest.resize(samples,channels);
251  dest.setFrequency(freq);
252  ManagedBytes bytes(header.dataLength);
253  printf("%d channels %d samples %d frequency\n", channels, samples, freq);
254 
255  size_t result;
256  result = fread(bytes.get(),bytes.length(),1,fp);
257  YARP_UNUSED(result);
258 
259  auto* data = reinterpret_cast<NetInt16*>(bytes.get());
260  int ct = 0;
261  for (int i=0; i<samples; i++) {
262  for (int j=0; j<channels; j++) {
263  dest.set(data[ct],i,j);
264  ct++;
265  }
266  }
267 
268  fclose(fp);
269  return true;
270 }
271 
272 
273 bool yarp::sig::file::write(const Sound& src, const char *dest)
274 {
275  FILE *fp = fopen(dest, "wb");
276  if (!fp) {
277  printf("cannot open file %s for writing\n", dest);
278  return false;
279  }
280 
281  PcmWavHeader header;
282  header.setup_to_write(src, fp);
283 
284  ManagedBytes bytes(header.dataLength);
285  auto* data = reinterpret_cast<NetInt16*>(bytes.get());
286  int ct = 0;
287  size_t samples = src.getSamples();
288  size_t channels = src.getChannels();
289  for (size_t i=0; i<samples; i++) {
290  for (size_t j=0; j<channels; j++) {
291  int v = src.get(i,j);
292  data[ct] = v;
293  ct++;
294  }
295  }
296  fwrite(bytes.get(),bytes.length(),1,fp);
297 
298  fclose(fp);
299  return true;
300 }
301 
303 {
304  if (fp)
305  {
306  printf("file %s is already open\n", fname);
307  return false;
308  }
309 
310  fp = fopen(filename, "rb");
311  if (!fp)
312  {
313  printf("cannot open file %s for reading\n", filename);
314  return false;
315  }
316  strcpy(fname,filename);
317  PcmWavHeader header;
318  if (!header.parse_from_file(fp))
319  {
320  printf("error parsing header of file %s\n", fname);
321  fclose(fp);
322  return false;
323  }
324  this->soundInfo.freq = header.pcm.pcmSamplesPerSecond;
325  this->soundInfo.channels = header.pcm.pcmChannels;
326  this->soundInfo.bits = header.pcm.pcmBitsPerSample;
327  this->soundInfo.samples = header.dataLength/(this->soundInfo.bits/8)/this->soundInfo.channels;
328  this->soundInfo.data_start_offset = ftell(fp);
329 
330  return true;
331 }
332 
334 {
335  if (!fp)
336  {
337  printf("no files open\n");
338  return false;
339  }
340 
341  fclose(fp);
342  fname[0]=0;
343  index=0;
344  return true;
345 }
346 
347 size_t yarp::sig::file::soundStreamReader::readBlock(Sound& dest, size_t block_size)
348 {
349  int expected_bytes = (int)(block_size*(soundInfo.bits/8)*soundInfo.channels);
350 
351  //this probably works only if soundInfo.bits=16
352  int expected_words=expected_bytes/(soundInfo.bits/8);
353  auto* data = new NetInt16 [expected_words];
354 
355  size_t bytes_read = fread(data,1,expected_bytes,fp);
356  size_t samples_read = bytes_read/(soundInfo.bits/8)/soundInfo.channels;
357 
358  dest.resize((int)samples_read,soundInfo.channels);
359  dest.setFrequency(soundInfo.freq);
360 
361  int ct = 0;
362  for (size_t i=0; i<samples_read; i++) {
363  for (size_t j=0; j< (size_t) soundInfo.channels; j++) {
364  dest.set(data[ct],i,j);
365  ct++;
366  }
367  }
368  index+=samples_read;
369 
370  delete [] data;
371  return samples_read;
372 }
373 
375 {
376  if (!fp)
377  {
378  printf("no files open\n");
379  return false;
380  }
381 
382  if ((int)sample_offset>this->soundInfo.samples)
383  {
384  printf("invalid sample_offset\n");
385  return false;
386  }
387 
388  fseek(fp,(long int)(this->soundInfo.data_start_offset+(sample_offset*this->soundInfo.channels*this->soundInfo.bits/2)),SEEK_SET);
389  index=sample_offset;
390 
391  return true;
392 }
393 
395 {
396  return index;
397 }
yarp::sig::file::soundStreamReader::getIndex
size_t getIndex()
Definition: SoundFile.cpp:394
yarp::sig::Sound::setFrequency
void setFrequency(int freq)
Set the frequency of the sound (i.e.
Definition: Sound.cpp:226
PcmWavHeader::formatHeader2
NetInt32 formatHeader2
Definition: SoundFile.cpp:34
yarp::os::createVocab
constexpr yarp::conf::vocab32_t createVocab(char a, char b=0, char c=0, char d=0)
Definition: Vocab.h:22
yarp::sig::Sound::getFrequency
int getFrequency() const
Get the frequency of the sound (i.e.
Definition: Sound.cpp:221
PcmWavHeader::wavHeader
NetInt32 wavHeader
Definition: SoundFile.cpp:31
yarp::sig::file::read
bool read(ImageOf< PixelRgb > &dest, const std::string &src, image_fileformat format=FORMAT_ANY)
Definition: ImageFile.cpp:827
PcmWavHeader::dataLength
NetInt32 dataLength
Definition: SoundFile.cpp:52
yarp::sig
Signal processing.
Definition: Image.h:25
YARP_END_PACK
#define YARP_END_PACK
Ends 1 byte packing for structs/classes.
Definition: system.h:194
yarp::sig::Sound::getSamples
size_t getSamples() const
Get the number of samples contained in the sound.
Definition: Sound.cpp:404
NetInt32.h
YARP_BEGIN_PACK
#define YARP_BEGIN_PACK
Starts 1 byte packing for structs/classes.
Definition: system.h:193
yarp::sig::file::soundStreamReader::close
bool close()
Definition: SoundFile.cpp:333
PcmWavHeader::formatLength
NetInt32 formatLength
Definition: SoundFile.cpp:35
yarp::sig::file::soundStreamReader::rewind
bool rewind(size_t sample_offset=0)
Definition: SoundFile.cpp:374
PcmWavHeader::dummyHeader
NetInt32 dummyHeader
Definition: SoundFile.cpp:47
samples
int16_t * samples
Definition: FfmpegWriter.cpp:76
YARP_UNUSED
#define YARP_UNUSED(var)
Definition: api.h:159
yarp::sig::Sound::getChannels
size_t getChannels() const
Get the number of channels of the sound.
Definition: Sound.cpp:409
ret
bool ret
Definition: ImplementAxisInfo.cpp:72
yarp::sig::file::soundStreamReader::open
bool open(const char *filename)
Definition: SoundFile.cpp:302
PcmWavHeader::pcmFormatTag
NetInt16 pcmFormatTag
Definition: SoundFile.cpp:38
PcmWavHeader::dummyData
ManagedBytes dummyData
Definition: SoundFile.cpp:49
ManagedBytes.h
yarp::os::ManagedBytes
An abstraction for a block of bytes, with optional responsibility for allocating/destroying that bloc...
Definition: ManagedBytes.h:25
PcmWavHeader::setup_to_write
void setup_to_write(const Sound &sound, FILE *fp)
Definition: SoundFile.cpp:186
PcmWavHeader::wavLength
NetInt32 wavLength
Definition: SoundFile.cpp:32
PcmWavHeader::pcmSamplesPerSecond
NetInt32 pcmSamplesPerSecond
Definition: SoundFile.cpp:40
yarp::sig::Sound::set
void set(audio_sample value, size_t sample, size_t channel=0)
Definition: Sound.cpp:206
yarp::sig::file::soundStreamReader::readBlock
size_t readBlock(Sound &dest, size_t block_size)
Definition: SoundFile.cpp:347
yarp::sig::Sound::get
audio_sample get(size_t sample, size_t channel=0) const
Definition: Sound.cpp:174
PcmWavHeader::pcmExtraData
ManagedBytes pcmExtraData
Definition: SoundFile.cpp:45
PcmWavHeader::pcmBlockAlign
NetInt16 pcmBlockAlign
Definition: SoundFile.cpp:42
system.h
yarp::sig::file
Image file operations.
Definition: ImageFile.h:24
PcmWavHeader
Definition: SoundFile.cpp:29
yarp::os
An interface to the operating system, including Port based communication.
Definition: AbstractCarrier.h:17
yarp::sig::Sound
Class for storing sounds.
Definition: Sound.h:28
PcmWavHeader::pcmBitsPerSample
NetInt16 pcmBitsPerSample
Definition: SoundFile.cpp:43
PcmWavHeader::formatHeader1
NetInt32 formatHeader1
Definition: SoundFile.cpp:33
yarp::os::NetInt16
std::int16_t NetInt16
Definition of the NetInt16 type.
Definition: NetInt16.h:33
SoundFile.h
Vocab.h
PcmWavHeader::dataHeader
NetInt32 dataHeader
Definition: SoundFile.cpp:51
yarp::sig::Sound::resize
void resize(size_t samples, size_t channels=1)
Set the sound size.
Definition: Sound.cpp:167
yarp::os::ManagedBytes::get
const char * get() const
Definition: ManagedBytes.cpp:154
PcmWavHeader::pcmBytesPerSecond
NetInt32 pcmBytesPerSecond
Definition: SoundFile.cpp:41
NetInt16.h
PcmWavHeader::pcmChannels
NetInt16 pcmChannels
Definition: SoundFile.cpp:39
yarp::os::ManagedBytes::length
size_t length() const
Definition: ManagedBytes.cpp:144
yarp::sig::file::write
bool write(const ImageOf< PixelRgb > &src, const std::string &dest, image_fileformat format=FORMAT_PPM)
Definition: ImageFile.cpp:971
Sound.h
PcmWavHeader::dummyLength
NetInt32 dummyLength
Definition: SoundFile.cpp:48
PcmWavHeader::parse_from_file
bool parse_from_file(FILE *fp)
Definition: SoundFile.cpp:59
PcmWavHeader::pcm
struct PcmWavHeader::@0 pcm
yarp::os::NetInt32
std::int32_t NetInt32
Definition of the NetInt32 type.
Definition: NetInt32.h:33