YARP
Yet Another Robot Platform
SoundFile.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2018 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  fread(&wavHeader,sizeof(wavHeader),1,fp);
62  fread(&wavLength,sizeof(wavLength),1,fp);
63  fread(&formatHeader1,sizeof(formatHeader1),1,fp);
64 
65  fread(&formatHeader2,sizeof(formatHeader2),1,fp);
66  fread(&formatLength,sizeof(formatLength),1,fp);
67 
68  fread(&pcm.pcmFormatTag,sizeof(pcm.pcmFormatTag),1,fp);
69  fread(&pcm.pcmChannels,sizeof(pcm.pcmChannels),1,fp);
70  fread(&pcm.pcmSamplesPerSecond,sizeof(pcm.pcmSamplesPerSecond),1,fp);
71  fread(&pcm.pcmBytesPerSecond,sizeof(pcm.pcmBytesPerSecond),1,fp);
72  fread(&pcm.pcmBlockAlign,sizeof(pcm.pcmBlockAlign),1,fp);
73  fread(&pcm.pcmBitsPerSample,sizeof(pcm.pcmBitsPerSample),1,fp);
74  if (pcm.pcmBitsPerSample!=16)
75  {
76  printf("sorry, lousy wav read code only does 16-bit ints\n");
77  return false;
78  }
79 
80  //extra bytes in pcm chuck
81  int extra_size = formatLength-sizeof(pcm);
82  pcmExtraData.allocate(extra_size);
83  fread(&pcmExtraData,extra_size,1,fp);
84 
85  //extra chunks
86  fread(&dummyHeader,sizeof(dummyHeader),1,fp);
87 
88  while (dummyHeader!=yarp::os::createVocab('d','a','t','a'))
89  {
90  fread(&dummyLength,sizeof(dummyLength),1,fp);
91  dummyData.clear();
92  dummyData.allocate(dummyLength);
93  fread(&dummyData,dummyLength,1,fp);
94  fread(&dummyHeader,sizeof(dummyHeader),1,fp);
95  }
96 
97  dataHeader=dummyHeader;
98  fread(&dataLength,sizeof(dataLength),1,fp);
99 
100  return true;
101 }
102 
103 void PcmWavHeader::setup_to_write(const Sound& src, FILE *fp)
104 {
105  int bitsPerSample = 16;
106  int channels = src.getChannels();
107  int bytes = channels*src.getSamples()*2;
108  int align = channels*((bitsPerSample+7)/8);
109 
110  wavHeader = yarp::os::createVocab('R','I','F','F');
111  wavLength = bytes + sizeof(PcmWavHeader) - 2*sizeof(NetInt32);
112  formatHeader1 = yarp::os::createVocab('W','A','V','E');
113  formatHeader2 = yarp::os::createVocab('f','m','t',' ');
114  formatLength = sizeof(pcm);
115 
116  pcm.pcmFormatTag = 1; /* PCM! */
117  pcm.pcmChannels = channels;
118  pcm.pcmSamplesPerSecond = (int)src.getFrequency();
119  pcm.pcmBytesPerSecond = align*pcm.pcmSamplesPerSecond;
120  pcm.pcmBlockAlign = align;
121  pcm.pcmBitsPerSample = bitsPerSample;
122 
123  dataHeader = yarp::os::createVocab('d','a','t','a');
124  dataLength = bytes;
125 
126 
127  fwrite(&wavHeader,sizeof(wavHeader),1,fp);
128  fwrite(&wavLength,sizeof(wavLength),1,fp);
129  fwrite(&formatHeader1,sizeof(formatHeader1),1,fp);
130 
131  fwrite(&formatHeader2,sizeof(formatHeader2),1,fp);
132  fwrite(&formatLength,sizeof(formatLength),1,fp);
133 
134  fwrite(&pcm.pcmFormatTag,sizeof(pcm.pcmFormatTag),1,fp);
135  fwrite(&pcm.pcmChannels,sizeof(pcm.pcmChannels),1,fp);
136  fwrite(&pcm.pcmSamplesPerSecond,sizeof(pcm.pcmSamplesPerSecond),1,fp);
137  fwrite(&pcm.pcmBytesPerSecond,sizeof(pcm.pcmBytesPerSecond),1,fp);
138  fwrite(&pcm.pcmBlockAlign,sizeof(pcm.pcmBlockAlign),1,fp);
139  fwrite(&pcm.pcmBitsPerSample,sizeof(pcm.pcmBitsPerSample),1,fp);
140 
141  fwrite(&dataHeader,sizeof(dataHeader),1,fp);
142  fwrite(&dataLength,sizeof(dataLength),1,fp);
143 
144 }
145 
146 bool yarp::sig::file::read(Sound& dest, const char *src)
147 {
148  FILE *fp = fopen(src, "rb");
149  if (!fp) {
150  printf("cannot open file %s for reading\n", src);
151  return false;
152  }
153 
154  PcmWavHeader header;
155  if (!header.parse_from_file(fp))
156  {
157  printf("error parsing header of file %s\n", src);
158  fclose(fp);
159  return false;
160  };
161 
162 
163  int freq = header.pcm.pcmSamplesPerSecond;
164  int channels = header.pcm.pcmChannels;
165  int bits = header.pcm.pcmBitsPerSample;
166  int samples = header.dataLength/(bits/8)/channels;
167  dest.resize(samples,channels);
168  dest.setFrequency(freq);
169  ManagedBytes bytes(header.dataLength);
170  printf("%d channels %d samples %d frequency\n", channels, samples, freq);
171 
172  size_t result;
173  result = fread(bytes.get(),bytes.length(),1,fp);
174  YARP_UNUSED(result);
175 
176  NetInt16 *data = reinterpret_cast<NetInt16*>(bytes.get());
177  int ct = 0;
178  for (int i=0; i<samples; i++) {
179  for (int j=0; j<channels; j++) {
180  dest.set(data[ct],i,j);
181  ct++;
182  }
183  }
184 
185  fclose(fp);
186  return true;
187 }
188 
189 
190 bool yarp::sig::file::write(const Sound& src, const char *dest)
191 {
192  FILE *fp = fopen(dest, "wb");
193  if (!fp) {
194  printf("cannot open file %s for writing\n", dest);
195  return false;
196  }
197 
198  PcmWavHeader header;
199  header.setup_to_write(src, fp);
200 
201  ManagedBytes bytes(header.dataLength);
202  NetInt16 *data = reinterpret_cast<NetInt16*>(bytes.get());
203  int ct = 0;
204  int samples = src.getSamples();
205  int channels = src.getChannels();
206  for (int i=0; i<samples; i++) {
207  for (int j=0; j<channels; j++) {
208  int v = src.get(i,j);
209  data[ct] = v;
210  ct++;
211  }
212  }
213  fwrite(bytes.get(),bytes.length(),1,fp);
214 
215  fclose(fp);
216  return true;
217 }
218 
220 {
221  if (fp)
222  {
223  printf("file %s is already open\n", fname);
224  return false;
225  }
226 
227  fp = fopen(filename, "rb");
228  if (!fp)
229  {
230  printf("cannot open file %s for reading\n", filename);
231  return false;
232  }
233  strcpy(fname,filename);
234  PcmWavHeader header;
235  if (!header.parse_from_file(fp))
236  {
237  printf("error parsing header of file %s\n", fname);
238  fclose(fp);
239  return false;
240  }
241  this->soundInfo.freq = header.pcm.pcmSamplesPerSecond;
242  this->soundInfo.channels = header.pcm.pcmChannels;
243  this->soundInfo.bits = header.pcm.pcmBitsPerSample;
244  this->soundInfo.samples = header.dataLength/(this->soundInfo.bits/8)/this->soundInfo.channels;
245  this->soundInfo.data_start_offset = ftell(fp);
246 
247  return true;
248 }
249 
251 {
252  if (!fp)
253  {
254  printf("no files open\n");
255  return false;
256  }
257 
258  fclose(fp);
259  fname[0]=0;
260  index=0;
261  return true;
262 }
263 
264 size_t yarp::sig::file::soundStreamReader::readBlock(Sound& dest, size_t block_size)
265 {
266  int expected_bytes = (int)(block_size*(soundInfo.bits/8)*soundInfo.channels);
267 
268  //this probably works only if soundInfo.bits=16
269  int expected_words=expected_bytes/(soundInfo.bits/8);
270  NetInt16 *data = new NetInt16 [expected_words];
271 
272  size_t bytes_read = fread(data,1,expected_bytes,fp);
273  size_t samples_read = bytes_read/(soundInfo.bits/8)/soundInfo.channels;
274 
275  dest.resize((int)samples_read,soundInfo.channels);
276  dest.setFrequency(soundInfo.freq);
277 
278  int ct = 0;
279  for (size_t i=0; i<samples_read; i++) {
280  for (size_t j=0; j< (size_t) soundInfo.channels; j++) {
281  dest.set(data[ct],i,j);
282  ct++;
283  }
284  }
285  index+=samples_read;
286 
287  delete [] data;
288  return samples_read;
289 }
290 
292 {
293  if (!fp)
294  {
295  printf("no files open\n");
296  return false;
297  }
298 
299  if ((int)sample_offset>this->soundInfo.samples)
300  {
301  printf("invalid sample_offset\n");
302  return false;
303  }
304 
305  fseek(fp,(long int)(this->soundInfo.data_start_offset+(sample_offset*this->soundInfo.channels*this->soundInfo.bits/2)),SEEK_SET);
306  index=sample_offset;
307 
308  return true;
309 }
310 
312 {
313  return index;
314 }
bool write(const ImageOf< PixelRgb > &src, const std::string &dest, image_fileformat format=FORMAT_PPM)
Definition: ImageFile.cpp:430
NetInt32 formatLength
Definition: SoundFile.cpp:35
size_t getFrequency() const
Definition: Sound.cpp:186
bool read(ImageOf< PixelRgb > &dest, const std::string &src, image_fileformat format=FORMAT_ANY)
Definition: ImageFile.cpp:393
#define YARP_END_PACK
Ends 1 byte packing for structs/classes.
Definition: system.h:201
int get(size_t sample, size_t channel=0) const
Definition: Sound.cpp:159
bool parse_from_file(FILE *fp)
Definition: SoundFile.cpp:59
ManagedBytes dummyData
Definition: SoundFile.cpp:49
NetInt32 formatHeader2
Definition: SoundFile.cpp:34
void setup_to_write(const Sound &sound, FILE *fp)
Definition: SoundFile.cpp:103
bool rewind(size_t sample_offset=0)
Definition: SoundFile.cpp:291
NetInt16 pcmFormatTag
Definition: SoundFile.cpp:38
#define YARP_BEGIN_PACK
Starts 1 byte packing for structs/classes.
Definition: system.h:200
size_t getSamples() const
Definition: Sound.h:101
NetInt32 pcmSamplesPerSecond
Definition: SoundFile.cpp:40
Class for storing sounds.
Definition: Sound.h:28
NetInt32 wavLength
Definition: SoundFile.cpp:32
bool open(const char *filename)
Definition: SoundFile.cpp:219
struct PcmWavHeader::@87 pcm
ManagedBytes pcmExtraData
Definition: SoundFile.cpp:45
NetInt32 dummyHeader
Definition: SoundFile.cpp:47
size_t getChannels() const
Definition: Sound.h:103
std::int32_t NetInt32
Definition of the NetInt32 type.
Definition: NetInt32.h:32
size_t readBlock(Sound &dest, size_t block_size)
Definition: SoundFile.cpp:264
constexpr yarp::conf::vocab32_t createVocab(char a, char b=0, char c=0, char d=0)
Definition: Vocab.h:43
NetInt32 pcmBytesPerSecond
Definition: SoundFile.cpp:41
NetInt16 pcmChannels
Definition: SoundFile.cpp:39
#define YARP_UNUSED(var)
Definition: api.h:159
std::int16_t NetInt16
Definition of the NetInt16 type.
Definition: NetInt16.h:32
NetInt16 pcmBlockAlign
Definition: SoundFile.cpp:42
const char * get() const
NetInt32 dummyLength
Definition: SoundFile.cpp:48
void set(int value, size_t sample, size_t channel=0)
Definition: Sound.cpp:176
NetInt32 wavHeader
Definition: SoundFile.cpp:31
void resize(size_t samples, size_t channels=1)
Definition: Sound.cpp:153
An interface to the operating system, including Port based communication.
NetInt32 dataLength
Definition: SoundFile.cpp:52
An abstraction for a block of bytes, with optional responsibility for allocating/destroying that bloc...
Definition: ManagedBytes.h:27
int16_t * samples
Signal processing.
Definition: Image.h:25
void setFrequency(size_t freq)
Definition: Sound.cpp:190
NetInt32 dataHeader
Definition: SoundFile.cpp:51
NetInt16 pcmBitsPerSample
Definition: SoundFile.cpp:43
NetInt32 formatHeader1
Definition: SoundFile.cpp:33
Image file operations.
Definition: ImageFile.h:23