IT++ Logo
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
audiofile.cpp
Go to the documentation of this file.
1 
29 #include <itpp/srccode/audiofile.h>
30 #include <itpp/base/converters.h>
31 #include <iostream>
32 
34 
35 #define SND_MAGIC 0x2e736e64
36 
37 using std::istream;
38 using std::ostream;
39 using std::ifstream;
40 using std::ofstream;
41 using std::ios;
42 
43 namespace itpp
44 {
45 
46 inline static short double_to_short(double x)
47 {
48  if (x >= 32767.0)
49  return 32767;
50  else if (x <= -32768.0)
51  return -32768;
52  else
53  return static_cast<short>(round_i(x));
54 }
55 
56 inline static signed char double_to_char(double x)
57 {
58  if (x >= 127.0)
59  return 127;
60  else if (x <= -128.0)
61  return -128;
62  else
63  return static_cast<char>(round_i(x));
64 }
65 
66 bool raw16le_read(const char *fname, vec &v)
67 {
68  ifstream file(fname, ios::in | ios::binary);
69  if (!file)
70  return false;
71 
72  // Check size of a file
73  file.seekg(0, ios::end);
74  int size = int(file.tellg());
75  file.seekg(0, ios::beg);
76 
77  bool switch_endian = is_bigendian(); // if BIG_ENDIAN than switch
78  int n = size / 2; // short vs. byte
79  v.set_size(n, false);
80  for (int i = 0; i < n; i++)
81  v(i) = read_endian<short>(file, switch_endian) / 32768.0;
82 
83  return true;
84 }
85 
86 bool raw16le_read(const char *fname, vec &v, int beg, int len)
87 {
88  it_assert_debug(len >= 0, "raw16le_read()");
89  ifstream file(fname, ios::in | ios::binary);
90  if (!file)
91  return false;
92 
93  bool switch_endian = is_bigendian(); // if BIG_ENDIAN than switch
94  v.set_size(len, false);
95  file.seekg(2 * beg);
96  for (int i = 0; i < len; i++)
97  v(i) = read_endian<short>(file, switch_endian) / 32768.0;
98 
99  return true;
100 }
101 
102 bool raw16le_write(const char *fname, const vec &v, bool append)
103 {
104  ofstream file(fname, (append ? ios::app | ios::ate : ios::out | ios::trunc) | ios::binary);
105  if (!file)
106  return false;
107 
108  bool switch_endian = is_bigendian(); // if BIG_ENDIAN than switch
109  for (int i = 0; i < v.size(); i++)
110  write_endian<short>(file, double_to_short(v(i) * 32768.0), switch_endian);
111 
112  return true;
113 }
114 
115 bool raw16be_read(const char *fname, vec &v)
116 {
117  ifstream file(fname, ios::in | ios::binary);
118  if (!file)
119  return false;
120 
121  // Check size of a file
122  file.seekg(0, ios::end);
123  int size = int(file.tellg());
124  file.seekg(0, ios::beg);
125 
126  bool switch_endian = !is_bigendian(); // if LITTLE_ENDIAN than switch
127  int n = size / 2; // short vs. byte
128  v.set_size(n, false);
129  for (int i = 0; i < n; i++)
130  v(i) = read_endian<short>(file, switch_endian) / 32768.0;
131 
132  return true;
133 }
134 
135 bool raw16be_read(const char *fname, vec &v, int beg, int len)
136 {
137  it_assert_debug(len >= 0, "raw16le_read()");
138  ifstream file(fname, ios::in | ios::binary);
139  if (!file)
140  return false;
141 
142  bool switch_endian = !is_bigendian(); // if LITTLE_ENDIAN than switch
143  v.set_size(len, false);
144  file.seekg(2 * beg);
145  for (int i = 0; i < len; i++)
146  v(i) = read_endian<short>(file, switch_endian) / 32768.0;
147 
148  return true;
149 }
150 
151 bool raw16be_write(const char *fname, const vec &v, bool append)
152 {
153  ofstream file(fname, (append ? ios::app | ios::ate : ios::out | ios::trunc) | ios::binary);
154  if (!file)
155  return false;
156 
157  bool switch_endian = !is_bigendian(); // if LITTLE_ENDIAN than switch
158  for (int i = 0; i < v.size(); i++)
159  write_endian<short>(file, double_to_short(v(i) * 32768.0), switch_endian);
160 
161  return true;
162 }
163 
165 //
166 // Audio_File
167 //
170 {
171  is_valid = false;
172 }
173 
175 //
176 // SND_Format
177 //
179 int SND_Format::sample_size() const
180 {
181  switch (header.encoding) {
182  case enc_mulaw8 :
183  return 1;
184  case enc_alaw8 :
185  return 1;
186  case enc_linear8 :
187  return 1;
188  case enc_linear16 :
189  return 2;
190  case enc_linear24 :
191  return 3;
192  case enc_linear32 :
193  return 4;
194  case enc_float :
195  return 4;
196  case enc_double :
197  return 8;
198  }
199  return 0;
200 }
201 
202 bool SND_Format::read_header(std::istream &f)
203 {
204  bool switch_endian = !is_bigendian(); // if LITTLE_ENDIAN than switch
205  f.seekg(0);
206  header.magic = read_endian<unsigned int>(f, switch_endian);
207  header.hdr_size = read_endian<unsigned int>(f, switch_endian);
208  header.data_size = read_endian<unsigned int>(f, switch_endian);
209  header.encoding = read_endian<unsigned int>(f, switch_endian);
210  header.sample_rate = read_endian<unsigned int>(f, switch_endian);
211  header.channels = read_endian<unsigned int>(f, switch_endian);
212  f.read(header.info, SND_INFO_LEN);
213  if (!f || header.magic != SND_MAGIC) {
214  std::cerr << header.magic << " != " << SND_MAGIC << std::endl;
215  it_warning("SND_Format::read_header(): This is not a .snd file!");
216  return false;
217  }
218  f.seekg(header.hdr_size);
219 
220  return f.good();
221 }
222 
223 bool SND_Format::write_header(std::ostream &f)
224 {
225  f.seekp(0);
226  header.magic = SND_MAGIC;
227  header.hdr_size = sizeof(header);
228  memset(header.info, 0, SND_INFO_LEN);
229 
230  bool switch_endian = !is_bigendian(); // if LITTLE_ENDIAN than switch
231  write_endian<unsigned int>(f, header.magic, switch_endian);
232  write_endian<unsigned int>(f, header.hdr_size, switch_endian);
233  write_endian<unsigned int>(f, header.data_size, switch_endian);
234  write_endian<unsigned int>(f, header.encoding, switch_endian);
235  write_endian<unsigned int>(f, header.sample_rate, switch_endian);
236  write_endian<unsigned int>(f, header.channels, switch_endian);
237  f.write(reinterpret_cast<char *>(&header.info), SND_INFO_LEN);
238 
239  return f.good();
240 }
241 
243 //
244 // SND_In_File
245 //
247 
249 {
250 }
251 
252 SND_In_File::SND_In_File(const char *fname)
253 {
254  open(fname);
255 }
256 
257 bool SND_In_File::open(const char *fname)
258 {
259  if (file.is_open())
260  close();
261  file.clear();
262  is_valid = false;
263  file.open(fname, ios::in | ios::binary);
264  if (!file)
265  return false;
266  if (!read_header(file)) {
267  file.close();
268  return false;
269  }
270 
271  is_valid = true;
272  return true;
273 }
274 
275 void SND_In_File::close()
276 {
277  file.close();
278  is_valid = false;
279 }
280 
281 bool SND_In_File::seek_read(int pos)
282 {
283  if (pos < 0)
284  file.seekg(0, ios::end);
285  else
286  file.seekg(header.hdr_size + header.channels * sample_size() * pos);
287  return true;
288 }
289 
291 {
292  if (!good())
293  return -1;
294 
295  return ((static_cast<int>(file.tellg()) - sizeof(header))
296  / (header.channels * sample_size()));
297 }
298 
299 bool SND_In_File::read(vec &v)
300 {
301  if (!good())
302  return false;
303 
304  int i, n;
305 
306  n = samples();
307  v.set_size(n, false);
308  seek_read(0);
309 
310  bool switch_endian = !is_bigendian(); // if LITTLE_ENDIAN than switch
311  switch (header.encoding) {
312  case enc_linear8 :
313  for (i = 0; i < n; i++)
314  v(i) = read_endian<char>(file, switch_endian) / 128.0;
315  break;
316  case enc_linear16 :
317  for (i = 0; i < n; i++)
318  v(i) = read_endian<short>(file, switch_endian) / 32768.0;
319  break;
320  case enc_float :
321  for (i = 0; i < n; i++)
322  v(i) = read_endian<float>(file, switch_endian);
323  break;
324  case enc_double :
325  for (i = 0; i < n; i++)
326  v(i) = read_endian<double>(file, switch_endian);
327  break;
328  default :
329  it_warning("SND_In_File::read(): Unsupported encoding!");
330  return false;
331  }
332  return file.good();
333 }
334 
335 bool SND_In_File::read(vec &v, int n)
336 {
337  if (!good())
338  return false;
339 
340  int i;
341 
342  bool switch_endian = !is_bigendian(); // if LITTLE_ENDIAN than switch
343  v.set_size(n, false);
344  switch (header.encoding) {
345  case enc_linear8 :
346  for (i = 0; i < n; i++)
347  v(i) = read_endian<char>(file, switch_endian) / 128.0;
348  break;
349  case enc_linear16 :
350  for (i = 0; i < n; i++)
351  v(i) = read_endian<short>(file, switch_endian) / 32768.0;
352  break;
353  case enc_float :
354  for (i = 0; i < n; i++)
355  v(i) = read_endian<float>(file, switch_endian);
356  break;
357  case enc_double :
358  for (i = 0; i < n; i++)
359  v(i) = read_endian<double>(file, switch_endian);
360  break;
361  default :
362  it_warning("SND_In_File::read(): Unsupported encoding!");
363  return false;
364  }
365  return file.good();
366 }
367 
369 //
370 // SND_Out_File
371 //
374 {
375 }
376 
377 SND_Out_File::SND_Out_File(const char *fname, int rate, data_encoding e)
378 {
379  open(fname, rate, e);
380 }
381 
382 bool SND_Out_File::open(const char *fname, int rate, data_encoding e)
383 {
384  if (file.is_open())
385  close();
386  file.clear();
387  is_valid = false;
388  file.open(fname, ios::out | ios::trunc | ios::binary);
389  if (!file)
390  return false;
391 
392  header.data_size = 0;
393  header.encoding = static_cast<unsigned int>(e);
394  header.sample_rate = rate;
395  header.channels = 1;
396 
397  if (!write_header(file))
398  return false;
399 
400  is_valid = true;
401  return true;
402 }
403 
404 void SND_Out_File::close()
405 {
406  file.seekp(0, ios::end);
407  header.data_size = static_cast<int>(file.tellp()) - sizeof(header);
408  write_header(file);
409  file.close();
410  is_valid = false;
411 }
412 
413 bool SND_Out_File::seek_write(int pos)
414 {
415  if (!good())
416  return false;
417 
418  if (pos < 0)
419  file.seekp(0, ios::end);
420  else
421  file.seekp(sizeof(header) + header.channels * sample_size() * pos);
422  return true;
423 }
424 
426 {
427  if (!good())
428  return -1;
429 
430  return ((static_cast<int>(file.tellp()) - sizeof(header))
431  / (header.channels * sample_size()));
432 }
433 
434 bool SND_Out_File::write(const vec &v)
435 {
436  if (!good())
437  return false;
438 
439  int i;
440 
441  bool switch_endian = !is_bigendian(); // if LITTLE_ENDIAN than switch
442  switch (header.encoding) {
443  case enc_linear8 :
444  for (i = 0; i < v.size(); i++)
445  write_endian<char>(file, double_to_char(v(i) * 128.0), switch_endian);
446  break;
447  case enc_linear16 :
448  for (i = 0; i < v.size(); i++)
449  write_endian<short>(file, double_to_short(v(i) * 32768.0),
450  switch_endian);
451  break;
452  case enc_float :
453  for (i = 0; i < v.size(); i++)
454  write_endian<float>(file, static_cast<float>(v(i)), switch_endian);
455  break;
456  case enc_double :
457  for (i = 0; i < v.size(); i++)
458  write_endian<double>(file, static_cast<double>(v(i)), switch_endian);
459  break;
460  default :
461  it_warning("SND_Out_File::write(): Unsupported encoding!");
462  return false;
463  }
464 
465  return file.good();
466 }
467 
469 //
470 // SND_IO_File
471 //
473 bool SND_IO_File::open(const char *fname)
474 {
475  if (file.is_open())
476  close();
477  file.clear();
478  is_valid = false;
479  file.open(fname, ios::in | ios::out | ios::binary);
480  if (!file)
481  return false;
482 
483  if (!read_header(file)) {
484  file.close();
485  return false;
486  }
487 
488  if (!seek_read(0) || !seek_write(0)) {
489  file.close();
490  return false;
491  }
492 
493  is_valid = true;
494  return true;
495 }
496 
497 void SND_IO_File::close()
498 {
499  write_header(file);
500  file.close();
501  is_valid = false;
502 }
503 
504 bool snd_read(const char *fname, vec &v)
505 {
506  SND_In_File file;
507 
508  if (!file.open(fname))
509  return false;
510 
511  return file.read(v);
512 }
513 
514 bool snd_read(const char *fname, vec &v, int beg, int len)
515 {
516  SND_In_File file;
517 
518  if (!file.open(fname))
519  return false;
520 
521  file.seek_read(beg);
522  return file.read(v, len);
523 }
524 
525 bool snd_write(const char *fname, const vec &v, int rate, SND_Format::data_encoding e)
526 {
527  SND_Out_File file;
528 
529  if (!file.open(fname, rate, e))
530  return false;
531 
532  return file.write(v);
533 }
534 
535 } // namespace itpp
536 
SourceForge Logo

Generated on Fri Mar 21 2014 17:14:14 for IT++ by Doxygen 1.8.1.2