GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
audioread.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2013-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <algorithm>
31 #include <map>
32 #include <string>
33 
34 #include "dMatrix.h"
35 #include "dRowVector.h"
36 #include "file-ops.h"
37 #include "file-stat.h"
38 #include "oct-locbuf.h"
39 #include "unwind-prot.h"
40 
41 #include "defun-dld.h"
42 #include "error.h"
43 #include "errwarn.h"
44 #include "ov.h"
45 #include "ovl.h"
46 #include "pager.h"
47 
48 #if defined (HAVE_SNDFILE)
49 # include <sndfile.h>
50 #endif
51 
52 #if defined (HAVE_SNDFILE)
53 static void
54 safe_close (SNDFILE *file)
55 {
56  sf_close (file);
57 }
58 #endif
59 
60 DEFUN_DLD (audioread, args, ,
61  doc: /* -*- texinfo -*-
62 @deftypefn {} {[@var{y}, @var{fs}] =} audioread (@var{filename})
63 @deftypefnx {} {[@var{y}, @var{fs}] =} audioread (@var{filename}, @var{samples})
64 
65 @deftypefnx {} {[@var{y}, @var{fs}] =} audioread (@var{filename}, @var{datatype})
66 @deftypefnx {} {[@var{y}, @var{fs}] =} audioread (@var{filename}, @var{samples}, @var{datatype})
67 Read the audio file @var{filename} and return the audio data @var{y} and
68 sampling rate @var{fs}.
69 
70 The audio data is stored as matrix with rows corresponding to audio frames
71 and columns corresponding to channels.
72 
73 The optional two-element vector argument @var{samples} specifies starting
74 and ending frames.
75 
76 The optional argument @var{datatype} specifies the datatype to return.
77 If it is @qcode{"native"}, then the type of data depends on how the data
78 is stored in the audio file.
79 @seealso{audiowrite, audioformats, audioinfo}
80 @end deftypefn */)
81 {
82 #if defined (HAVE_SNDFILE)
83 
84  int nargin = args.length ();
85 
86  if (nargin < 1 || nargin > 3)
87  print_usage ();
88 
89  std::string filename = args(0).xstring_value ("audioread: FILENAME must be a string");
90 
91  SF_INFO info;
92  info.format = 0;
93  SNDFILE *file = sf_open (filename.c_str (), SFM_READ, &info);
94 
95  if (! file)
96  error ("audioread: failed to open input file '%s': %s",
97  filename.c_str (), sf_strerror (file));
98 
100 
101  frame.add_fcn (safe_close, file);
102 
103  OCTAVE_LOCAL_BUFFER (double, data, info.frames * info.channels);
104 
105  sf_read_double (file, data, info.frames * info.channels);
106 
107  sf_count_t start = 0;
108  sf_count_t end = info.frames;
109 
110  if ((nargin == 2 && ! args(1).is_string ()) || nargin == 3)
111  {
112  RowVector range = args(1).row_vector_value ();
113 
114  if (range.numel () != 2)
115  error ("audioread: invalid specification for range of frames");
116 
117  double dstart = (octave::math::isinf (range(0)) ? info.frames : range(0));
118  double dend = (octave::math::isinf (range(1)) ? info.frames : range(1));
119 
120  if (dstart < 1 || dstart > dend || dend > info.frames
121  || octave::math::x_nint (dstart) != dstart
122  || octave::math::x_nint (dend) != dend)
123  error ("audioread: invalid specification for range of frames");
124 
125  start = dstart - 1;
126  end = dend;
127  }
128 
129  sf_count_t items = end - start;
130 
131  Matrix audio (items, info.channels);
132 
133  double *paudio = audio.fortran_vec ();
134 
135  data += start * info.channels;
136 
137  for (int i = 0; i < items; i++)
138  {
139  for (int channel = 0; channel < info.channels; channel++)
140  paudio[items*channel+i] = *data++;
141  }
142 
143  octave_value ret_audio;
144 
145  if ((nargin == 2 && args(1).is_string ()) || nargin == 3)
146  {
147  std::string type;
148  if (nargin == 3)
149  type = args(2).string_value ();
150  else
151  type = args(1).string_value ();
152 
153  if (type == "native")
154  {
155  switch (info.format & SF_FORMAT_SUBMASK)
156  {
157  case SF_FORMAT_PCM_S8:
158  ret_audio = int8NDArray (audio * 128);
159  break;
160  case SF_FORMAT_PCM_U8:
161  ret_audio = uint8NDArray (audio * 128 + 128);
162  break;
163  case SF_FORMAT_PCM_16:
164  ret_audio = int16NDArray (audio * 32768);
165  break;
166  case SF_FORMAT_PCM_24:
167  ret_audio = int32NDArray (audio * 8388608);
168  break;
169  case SF_FORMAT_PCM_32:
170  ret_audio = int32NDArray (audio * 2147483648);
171  break;
172  case SF_FORMAT_FLOAT:
173  ret_audio = FloatNDArray (audio);
174  break;
175  default:
176  ret_audio = audio;
177  break;
178  }
179  }
180  else
181  ret_audio = audio;
182  }
183  else
184  ret_audio = audio;
185 
186  return ovl (ret_audio, info.samplerate);
187 
188 #else
189 
190  octave_unused_parameter (args);
191 
192  err_disabled_feature ("audioread",
193  "reading and writing sound files through libsndfile");
194 
195 #endif
196 }
197 
198 #if defined (HAVE_SNDFILE)
199 
200 static int
201 extension_to_format (const std::string& ext)
202 {
203  static bool initialized = false;
204 
205  static std::map<std::string, int> table;
206 
207  if (! initialized)
208  {
209  table["wav"] = SF_FORMAT_WAV;
210  table["aiff"] = SF_FORMAT_AIFF;
211  table["au"] = SF_FORMAT_AU;
212  table["raw"] = SF_FORMAT_RAW;
213  table["paf"] = SF_FORMAT_PAF;
214  table["svx"] = SF_FORMAT_SVX;
215  table["nist"] = SF_FORMAT_NIST;
216  table["voc"] = SF_FORMAT_VOC;
217  table["ircam"] = SF_FORMAT_IRCAM;
218  table["w64"] = SF_FORMAT_W64;
219  table["mat4"] = SF_FORMAT_MAT4;
220  table["mat5"] = SF_FORMAT_MAT5;
221  table["pvf"] = SF_FORMAT_PVF;
222  table["xi"] = SF_FORMAT_XI;
223  table["htk"] = SF_FORMAT_HTK;
224  table["sds"] = SF_FORMAT_SDS;
225  table["avr"] = SF_FORMAT_AVR;
226  table["wavex"] = SF_FORMAT_WAVEX;
227  table["sd2"] = SF_FORMAT_SD2;
228  table["flac"] = SF_FORMAT_FLAC;
229  table["caf"] = SF_FORMAT_CAF;
230  table["wve"] = SF_FORMAT_WVE;
231  table["ogg"] = SF_FORMAT_OGG;
232  table["mpc2k"] = SF_FORMAT_MPC2K;
233  table["rf64"] = SF_FORMAT_RF64;
234 
235  initialized = true;
236  }
237 
238  std::map<std::string, int>::const_iterator it = table.find (ext);
239 
240  return (it != table.end ()) ? it->second : 0;
241 }
242 
243 #endif
244 
245 DEFUN_DLD (audiowrite, args, ,
246  doc: /* -*- texinfo -*-
247 @deftypefn {} {} audiowrite (@var{filename}, @var{y}, @var{fs})
248 @deftypefnx {} {} audiowrite (@var{filename}, @var{y}, @var{fs}, @var{name}, @var{value}, @dots{})
249 
250 Write audio data from the matrix @var{y} to @var{filename} at sampling rate
251 @var{fs} with the file format determined by the file extension.
252 
253 Additional name/value argument pairs may be used to specify the
254 following options:
255 
256 @table @samp
257 @item BitsPerSample
258 Number of bits per sample. Valid values are 8, 16, 24, and 32. Default is
259 16.
260 
261 @item BitRate
262 Valid argument name, but ignored. Left for compatibility with @sc{matlab}.
263 
264 @item Quality
265 Quality setting for the Ogg Vorbis compressor. Values can range between 0
266 and 100 with 100 being the highest quality setting. Default is 75.
267 
268 @item Title
269 Title for the audio file.
270 
271 @item Artist
272 Artist name.
273 
274 @item Comment
275 Comment.
276 @end table
277 @seealso{audioread, audioformats, audioinfo}
278 @end deftypefn */)
279 {
280 #if defined (HAVE_SNDFILE)
281 
282  int nargin = args.length ();
283 
284  if (nargin < 3)
285  print_usage ();
286 
287  std::string filename = args(0).xstring_value ("audiowrite: FILENAME must be a string");
288 
289  double bias = 0.0;
290  double scale = 1.0;
291 
292  if (args(1).is_uint8_type ())
293  bias = scale = 127.5;
294  else if (args(1).is_int16_type ())
295  scale = 32768; // 2^15
296  else if (args(1).is_int32_type ())
297  scale = 2147483648; // 2^31
298  else if (args(1).isinteger ())
299  err_wrong_type_arg ("audiowrite", args(1));
300 
301  Matrix audio = args(1).matrix_value ();
302 
303  if (! args(2).is_scalar_type () || ! args(2).isnumeric ())
304  error ("audiowrite: sample rate FS must be a positive scalar integer");
305  int samplerate = args(2).int_value ();
306  if (samplerate < 1)
307  error ("audiowrite: sample rate FS must be a positive scalar integer");
308 
309  std::string ext;
310  size_t dotpos = filename.find_last_of ('.');
311  if (dotpos != std::string::npos)
312  ext = filename.substr (dotpos + 1);
313  std::transform (ext.begin (), ext.end (), ext.begin (), ::tolower);
314 
315  sf_count_t items_to_write = audio.rows () * audio.columns ();
316 
317  if (audio.rows () == 1)
318  audio = audio.transpose ();
319 
320  OCTAVE_LOCAL_BUFFER (double, data, items_to_write);
321 
322  sf_count_t idx = 0;
323  for (int i = 0; i < audio.rows (); i++)
324  {
325  for (int j = 0; j < audio.columns (); j++)
326  {
327  double elem = (audio.xelem (i, j) - bias) / scale;
328  data[idx++] = std::min (std::max (elem, -1.0), 1.0);
329  }
330  }
331 
332  SF_INFO info;
333 
334  memset (&info, 0, sizeof (info));
335 
336  sf_count_t chunk_size = 0;
337 
338  if (ext == "ogg")
339  {
340  info.format = SF_FORMAT_VORBIS;
341 
342  // FIXME: There seems to be a bug writing ogg files in one shot that
343  // causes a segfault: https://bugs.debian.org/760898.
344  // Breaking it up into a series of smaller chunks appears to avoid the
345  // problem and produces valid files.
346  chunk_size = 0x100000;
347  }
348  else
349  info.format = SF_FORMAT_PCM_16;
350 
351  info.channels = audio.columns ();
352  info.samplerate = samplerate;
353  info.format |= extension_to_format (ext);
354 
355  std::string title = "";
356  std::string artist = "";
357  std::string comment = "";
358  double quality = 0.75;
359 
360  for (int i = 3; i < nargin; i += 2)
361  {
362  if (i >= nargin - 1)
363  error ("audiowrite: invalid number of arguments");
364 
365  std::string keyword_orig = args(i).string_value ();
366  std::string keyword = args(i).xtolower ().string_value ();
367  octave_value value_arg = args(i+1);
368 
369  if (keyword == "bitspersample")
370  {
371  info.format &= ~SF_FORMAT_SUBMASK;
372  int bits = value_arg.int_value ();
373  if (bits == 8)
374  {
375  if ((info.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV)
376  info.format |= SF_FORMAT_PCM_U8;
377  else
378  info.format |= SF_FORMAT_PCM_S8;
379  }
380  else if (bits == 16)
381  info.format |= SF_FORMAT_PCM_16;
382  else if (bits == 24)
383  {
384  if ((info.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV)
385  info.format |= SF_FORMAT_PCM_32;
386  else
387  info.format |= SF_FORMAT_PCM_24;
388  }
389  else if (bits == 32)
390  {
391  if ((info.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV
392  && args(1).isfloat ())
393  info.format |= SF_FORMAT_FLOAT;
394  else
395  info.format |= SF_FORMAT_PCM_32;
396  }
397  else if (bits == 64)
398  info.format |= SF_FORMAT_DOUBLE;
399  else
400  error ("audiowrite: wrong number of bits specified");
401  }
402  else if (keyword == "bitrate")
403  warning_with_id ("Octave:audiowrite:unused-parameter",
404  "audiowrite: 'BitRate' accepted for Matlab "
405  "compatibility, but is ignored");
406  else if (keyword == "quality")
407  {
408  if (! value_arg.is_scalar_type ())
409  error ("audiowrite: Quality value must be a scalar");
410 
411  double value = value_arg.xdouble_value ("audiowrite: Quality value must be a numeric scalar between 0 and 100");
412 
413  if (octave::math::isnan (value) || value < 0 || value > 100)
414  error ("audiowrite: Quality value must be a number between 0 and 100");
415 
416  quality = value / 100;
417  }
418  else if (keyword == "title")
419  title = value_arg.string_value ();
420  else if (keyword == "artist")
421  artist = value_arg.string_value ();
422  else if (keyword == "comment")
423  comment = value_arg.string_value ();
424  else
425  error ("audiowrite: unrecognized option: '%s'", keyword_orig.c_str ());
426  }
427 
428  SNDFILE *file = sf_open (filename.c_str (), SFM_WRITE, &info);
429 
430  if (! file)
431  error ("audiowrite: failed to open output file '%s': %s",
432  filename.c_str (), sf_strerror (file));
433 
435 
436  frame.add_fcn (safe_close, file);
437 
438  sf_command (file, SFC_SET_NORM_DOUBLE, nullptr, SF_TRUE);
439  sf_command (file, SFC_SET_CLIPPING, nullptr, SF_TRUE) ;
440  sf_command (file, SFC_SET_VBR_ENCODING_QUALITY, &quality, sizeof (quality));
441 
442  if (title != "")
443  sf_set_string (file, SF_STR_TITLE, title.c_str ());
444 
445  if (artist != "")
446  sf_set_string (file, SF_STR_ARTIST, artist.c_str ());
447 
448  if (comment != "")
449  sf_set_string (file, SF_STR_COMMENT, comment.c_str ());
450 
451  sf_count_t total_items_written = 0;
452  sf_count_t offset = 0;
453 
454  if (chunk_size == 0)
455  chunk_size = items_to_write;
456 
457  while (total_items_written < items_to_write)
458  {
459  if (items_to_write - offset < chunk_size)
460  chunk_size = items_to_write - offset;
461 
462  sf_count_t items_written = sf_write_double (file, data+offset, chunk_size);
463 
464  if (items_written != chunk_size)
465  error ("audiowrite: write failed, wrote %" PRId64 " of %" PRId64
466  " items\n", items_written, chunk_size);
467 
468  total_items_written += items_written;
469  offset += chunk_size;
470  }
471 
472  // FIXME: shouldn't we return something to indicate whether the file
473  // was written successfully?
474  return ovl ();
475 
476 #else
477 
478  octave_unused_parameter (args);
479 
480  err_disabled_feature ("audiowrite",
481  "reading and writing sound files through libsndfile");
482 
483 #endif
484 }
485 
486 /*
487 ## Joint audiowrite/audioread tests
488 ## 8-bit Unsigned PCM
489 %!testif HAVE_SNDFILE <*56889>
490 %! fname = [tempname() ".wav"];
491 %! unwind_protect
492 %! y1 = uint8 ([0, 1, 2, 253, 254, 255]);
493 %! audiowrite (fname, y1, 8000, "BitsPerSample", 8);
494 %! y2 = audioread (fname, "native");
495 %! unwind_protect_cleanup
496 %! unlink (fname);
497 %! end_unwind_protect
498 %! assert (y1(:), y2);
499 
500 ## 8-bit Signed PCM
501 %!testif HAVE_SNDFILE <*56889>
502 %! fname = [tempname() ".au"];
503 %! unwind_protect
504 %! y1 = uint8 ([0, 1, 2, 253, 254, 255]);
505 %! audiowrite (fname, y1, 8000, "BitsPerSample", 8);
506 %! y2 = audioread (fname, "native");
507 %! unwind_protect_cleanup
508 %! unlink (fname);
509 %! end_unwind_protect
510 %! assert (y2, int8 ([-128; -127; -126; 125; 126; 127]));
511 
512 ## 16-bit Signed PCM
513 %!testif HAVE_SNDFILE <*56889>
514 %! fname = [tempname() ".wav"];
515 %! unwind_protect
516 %! y1 = int16 ([-32768, -32767, -32766, 32765, 32766, 32767]);
517 %! audiowrite (fname, y1, 8000, "BitsPerSample", 16);
518 %! y2 = audioread (fname, "native");
519 %! unwind_protect_cleanup
520 %! unlink (fname);
521 %! end_unwind_protect
522 %! assert (y1(:), y2);
523 
524 ## 24-bit Signed PCM
525 %!testif HAVE_SNDFILE <*56889>
526 %! fname = [tempname() ".au"];
527 %! unwind_protect
528 %! y1 = [-8388608, -8388607, -8388606, 8388605, 8388606, 8388607] / 8388608;
529 %! audiowrite (fname, y1, 8000, "BitsPerSample", 24);
530 %! y2 = audioread (fname, "native");
531 %! unwind_protect_cleanup
532 %! unlink (fname);
533 %! end_unwind_protect
534 %! assert (int32 ([-8388608; -8388607; -8388606; 8388605; 8388606; 8388607]),
535 %! y2);
536 
537 ## 32-bit Signed PCM
538 %!testif HAVE_SNDFILE <*56889>
539 %! fname = [tempname() ".wav"];
540 %! unwind_protect
541 %! y1 = int32 ([-2147483648, -2147483647, -2147483646, 2147483645, 2147483646, 2147483647 ]);
542 %! audiowrite (fname, y1, 8000, "BitsPerSample", 32);
543 %! y2 = audioread (fname, "native");
544 %! unwind_protect_cleanup
545 %! unlink (fname);
546 %! end_unwind_protect
547 %! assert (y1(:), y2);
548 
549 ## Test input validation
550 %!testif HAVE_SNDFILE
551 %! fail ("audiowrite (1, 1, 8e3)", "FILENAME must be a string");
552 %! fail ("audiowrite ('foo', int64 (1), 8e3)", "wrong type argument 'int64 scalar'");
553 %! fail ("audiowrite ('foo', [0 1], [8e3, 8e3])", "FS must be a positive scalar");
554 %! fail ("audiowrite ('foo', 1, {8e3})", "FS must be a .* integer");
555 %! fail ("audiowrite ('foo', 1, -8e3)", "FS must be a positive");
556 %! fail ("audiowrite ('foo', 1, 8e3, 'bitspersample')", "invalid number of arguments");
557 %! fail ("audiowrite ('foo', 1, 8e3, 'bitspersample', 48)", "wrong number of bits specified");
558 %! fail ("audiowrite ('foo', 1, 8e3, 'quality', [2 3 4])", "Quality value must be a scalar");
559 %! fail ("audiowrite ('foo', 1, 8e3, 'quality', NaN)", "Quality value must be .* between 0 and 100");
560 %! fail ("audiowrite ('foo', 1, 8e3, 'quality', -1)", "Quality value must be .* between 0 and 100");
561 %! fail ("audiowrite ('foo', 1, 8e3, 'quality', 101)", "Quality value must be .* between 0 and 100");
562 %! fail ("audiowrite ('foo', 1, 8e3, 'foo', 'bar')", "unrecognized option: 'foo'");
563 */
564 
565 DEFUN_DLD (audioinfo, args, ,
566  doc: /* -*- texinfo -*-
567 @deftypefn {} {@var{info} =} audioinfo (@var{filename})
568 Return information about an audio file specified by @var{filename}.
569 
570 The output @var{info} is a structure containing the following fields:
571 
572 @table @samp
573 @item Filename
574 Name of the audio file.
575 
576 @item CompressionMethod
577 Audio compression method. Unused, only present for compatibility with
578 @sc{matlab}.
579 
580 @item NumChannels
581 Number of audio channels.
582 
583 @item SampleRate
584 Sample rate of the audio, in Hertz.
585 
586 @item TotalSamples
587 Number of samples in the file.
588 
589 @item Duration
590 Duration of the audio, in seconds.
591 
592 @item BitsPerSample
593 Number of bits per sample.
594 
595 @item BitRate
596 Audio bit rate. Unused, only present for compatibility with @sc{matlab}.
597 
598 @item Title
599 @qcode{"Title"} audio metadata value as a string, or empty if not present.
600 
601 @item Artist
602 @qcode{"Artist"} audio metadata value as a string, or empty if not present.
603 
604 @item Comment
605 @qcode{"Comment"} audio metadata value as a string, or empty if not present.
606 @end table
607 @seealso{audioread, audiowrite}
608 @end deftypefn */)
609 {
610 #if defined (HAVE_SNDFILE)
611 
612  if (args.length () != 1)
613  print_usage ();
614 
615  std::string filename = args(0).xstring_value ("audioinfo: FILENAME must be a string");
616 
617  octave::sys::file_stat fs (filename);
618  if (! fs.exists ())
619  error ("audioinfo: FILENAME '%s' not found", filename.c_str ());
620 
621  SF_INFO info;
622  info.format = 0;
623  SNDFILE *file = sf_open (filename.c_str (), SFM_READ, &info);
624 
625  if (! file)
626  error ("audioinfo: failed to open input file '%s': %s",
627  filename.c_str (), sf_strerror (file));
628 
630 
631  frame.add_fcn (safe_close, file);
632 
633  octave_scalar_map result;
634 
635  std::string full_name = octave::sys::canonicalize_file_name (filename);
636 
637  result.assign ("Filename", full_name);
638  result.assign ("CompressionMethod", "");
639  result.assign ("NumChannels", info.channels);
640  result.assign ("SampleRate", info.samplerate);
641  result.assign ("TotalSamples", info.frames);
642 
643  double dframes = info.frames;
644  double drate = info.samplerate;
645  result.assign ("Duration", dframes / drate);
646 
647  int bits;
648  switch (info.format & SF_FORMAT_SUBMASK)
649  {
650  case SF_FORMAT_PCM_S8:
651  bits = 8;
652  break;
653  case SF_FORMAT_PCM_U8:
654  bits = 8;
655  break;
656  case SF_FORMAT_PCM_16:
657  bits = 16;
658  break;
659  case SF_FORMAT_PCM_24:
660  bits = 24;
661  break;
662  case SF_FORMAT_PCM_32:
663  bits = 32;
664  break;
665  case SF_FORMAT_FLOAT:
666  bits = 32;
667  break;
668  case SF_FORMAT_DOUBLE:
669  bits = 64;
670  break;
671  default:
672  bits = -1;
673  break;
674  }
675 
676  result.assign ("BitsPerSample", bits);
677  result.assign ("BitRate", -1);
678  result.assign ("Title", sf_get_string (file, SF_STR_TITLE));
679  result.assign ("Artist", sf_get_string (file, SF_STR_ARTIST));
680  result.assign ("Comment", sf_get_string (file, SF_STR_COMMENT));
681 
682  return ovl (result);
683 
684 #else
685 
686  octave_unused_parameter (args);
687 
688  err_disabled_feature ("audioinfo",
689  "reading and writing sound files through libsndfile");
690 
691 #endif
692 }
693 
694 #if defined (HAVE_SNDFILE)
695 
696 static void
697 audio_sub_formats (int format)
698 {
699  int count;
700  sf_command (nullptr, SFC_GET_FORMAT_SUBTYPE_COUNT, &count, sizeof (int));
701 
702  for (int i = 0; i < count; i++)
703  {
704  SF_FORMAT_INFO info;
705  info.format = i;
706  sf_command (nullptr, SFC_GET_FORMAT_SUBTYPE, &info, sizeof (info));
707 
708  SF_INFO sfinfo;
709  memset (&sfinfo, 0, sizeof (sfinfo));
710  sfinfo.channels = 1;
711  sfinfo.format = (format & SF_FORMAT_TYPEMASK) | info.format;
712 
713  if (sf_format_check (&sfinfo))
714  octave_stdout << " " << info.name << std::endl;
715  }
716 }
717 
718 #endif
719 
720 DEFUN_DLD (audioformats, args, ,
721  doc: /* -*- texinfo -*-
722 @deftypefn {} {} audioformats ()
723 @deftypefnx {} {} audioformats (@var{format})
724 Display information about all supported audio formats.
725 
726 If the optional argument @var{format} is given, then display only formats
727 with names that start with @var{format}.
728 @seealso{audioread, audiowrite}
729 @end deftypefn */)
730 {
731 #if defined (HAVE_SNDFILE)
732 
733  if (args.length () > 1)
734  print_usage ();
735 
736  std::string search = "";
737  if (args.length () > 0)
738  {
739  search = args(0).string_value ();
740  std::transform (search.begin (), search.end (), search.begin (), tolower);
741  }
742 
743  int count;
744  sf_command (nullptr, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof (int));
745 
746  for (int i = 0; i < count; i++)
747  {
748  SF_FORMAT_INFO info;
749  info.format = i;
750  sf_command (nullptr, SFC_GET_FORMAT_MAJOR, &info, sizeof (info));
751  bool match = true;
752 
753  if (! search.empty ())
754  {
755  std::string nm = info.name;
756  std::transform (nm.begin (), nm.end (), nm.begin (), tolower);
757  match = nm.compare (0, search.length (), search) == 0;
758  }
759 
760  if (match)
761  {
762  octave_stdout << "name: " << info.name << std::endl;
763  octave_stdout << "extension: " << info.extension << std::endl;
764  octave_stdout << "id: " << info.format << std::endl;
765  octave_stdout << "subformats:" << std::endl;
766 
767  audio_sub_formats (info.format);
768  }
769  }
770 
771 #else
772 
773  octave_unused_parameter (args);
774 
775  err_disabled_feature ("audioformats",
776  "getting sound formats through libsndfile");
777 
778 #endif
779 
780  return octave_value_list ();
781 }
static int elem
Definition: __contourc__.cc:52
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
octave_idx_type columns(void) const
Definition: Array.h:424
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:469
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:377
octave_idx_type rows(void) const
Definition: Array.h:415
const T * fortran_vec(void) const
Size of the specified dimension.
Definition: Array.h:583
Definition: dMatrix.h:42
Matrix transpose(void) const
Definition: dMatrix.h:135
void add_fcn(void(*fcn)(Params...), Args &&... args)
bool exists(void) const
Definition: file-stat.h:147
void assign(const std::string &k, const octave_value &val)
Definition: oct-map.h:238
int int_value(bool req_int=false, bool frc_str_conv=false) const
Definition: ov.h:765
bool is_scalar_type(void) const
Definition: ov.h:697
double xdouble_value(const char *fmt,...) const
std::string string_value(bool force=false) const
Definition: ov.h:927
#define DEFUN_DLD(name, args_name, nargout_name, doc)
Macro to define an at run time dynamically loadable builtin function.
Definition: defun-dld.h:61
OCTINTERP_API void print_usage(void)
Definition: defun.cc:53
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:1065
void error(const char *fmt,...)
Definition: error.cc:968
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:53
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:166
void scale(Matrix &m, double x, double y, double z)
Definition: graphics.cc:5846
ColumnVector transform(const Matrix &m, double x, double y, double z)
Definition: graphics.cc:5814
intNDArray< octave_int16 > int16NDArray
Definition: int16NDArray.h:36
intNDArray< octave_int32 > int32NDArray
Definition: int32NDArray.h:36
intNDArray< octave_int8 > int8NDArray
Definition: int8NDArray.h:36
static std::list< std::string > search(const std::string &path, const std::string &original_name, bool all)
Definition: kpse.cc:486
T x_nint(T x)
Definition: lo-mappers.h:262
bool isnan(bool)
Definition: lo-mappers.h:178
bool isinf(double x)
Definition: lo-mappers.h:203
bool isinteger(double x)
Definition: lo-mappers.h:218
std::string canonicalize_file_name(const std::string &name)
Definition: file-ops.cc:693
size_t format(std::ostream &os, const char *fmt,...)
Definition: utils.cc:1329
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211
#define octave_stdout
Definition: pager.h:313
intNDArray< octave_uint8 > uint8NDArray
Definition: uint8NDArray.h:36