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