GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
audioread.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2013-2024 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 #if defined (HAVE_LIB_SNDFILE_FORMAT_MP3)
233  table["m1a"] = SF_FORMAT_MPEG;
234 #endif
235 
236  initialized = true;
237  }
238 
239  std::map<std::string, int>::const_iterator it = table.find (ext);
240 
241  return (it != table.end ()) ? it->second : 0;
242 }
243 
244 #endif
245 
246 DEFUN_DLD (audiowrite, args, ,
247  doc: /* -*- texinfo -*-
248 @deftypefn {} {} audiowrite (@var{filename}, @var{y}, @var{fs})
249 @deftypefnx {} {} audiowrite (@var{filename}, @var{y}, @var{fs}, @var{name}, @var{value}, @dots{})
250 
251 Write audio data from the matrix @var{y} to @var{filename} at sampling rate
252 @var{fs} with the file format determined by the file extension.
253 
254 Additional name/value argument pairs may be used to specify the
255 following options:
256 
257 @table @samp
258 @item BitsPerSample
259 Number of bits per sample. Valid values are 8, 16, 24, and 32. Default is
260 16.
261 
262 @item BitRate
263 Valid argument name, but ignored. Left for compatibility with @sc{matlab}.
264 
265 @item Quality
266 Quality setting for the Ogg Vorbis compressor. Values can range between 0
267 and 100 with 100 being the highest quality setting. Default is 75.
268 
269 @item Title
270 Title for the audio file.
271 
272 @item Artist
273 Artist name.
274 
275 @item Comment
276 Comment.
277 @end table
278 @seealso{audioread, audioformats, audioinfo}
279 @end deftypefn */)
280 {
281 #if defined (HAVE_SNDFILE)
282 
283  int nargin = args.length ();
284 
285  if (nargin < 3)
286  print_usage ();
287 
288  std::string filename = args(0).xstring_value ("audiowrite: FILENAME must be a string");
289 
290  double bias = 0.0;
291  double scale = 1.0;
292 
293  if (args(1).is_uint8_type ())
294  bias = scale = 127.5;
295  else if (args(1).is_int16_type ())
296  scale = 32768; // 2^15
297  else if (args(1).is_int32_type ())
298  scale = 2147483648; // 2^31
299  else if (args(1).isinteger ())
300  err_wrong_type_arg ("audiowrite", args(1));
301 
302  Matrix audio = args(1).matrix_value ();
303 
304  if (! args(2).is_scalar_type () || ! args(2).isnumeric ())
305  error ("audiowrite: sample rate FS must be a positive scalar integer");
306  int samplerate = args(2).int_value ();
307  if (samplerate < 1)
308  error ("audiowrite: sample rate FS must be a positive scalar integer");
309 
310  std::string ext;
311  std::size_t dotpos = filename.find_last_of ('.');
312  if (dotpos != std::string::npos)
313  ext = filename.substr (dotpos + 1);
314  std::transform (ext.begin (), ext.end (), ext.begin (), ::tolower);
315 
316  sf_count_t items_to_write = audio.rows () * audio.columns ();
317 
318  if (audio.rows () == 1)
319  audio = audio.transpose ();
320 
321  OCTAVE_LOCAL_BUFFER (double, data, items_to_write);
322 
323  sf_count_t idx = 0;
324  for (int i = 0; i < audio.rows (); i++)
325  {
326  for (int j = 0; j < audio.columns (); j++)
327  {
328  double elem = (audio.xelem (i, j) - bias) / scale;
329  data[idx++] = std::min (std::max (elem, -1.0), 1.0);
330  }
331  }
332 
333  SF_INFO info;
334 
335  memset (&info, 0, sizeof (info));
336 
337  sf_count_t chunk_size = 0;
338 
339  if (ext == "ogg")
340  {
341  info.format = SF_FORMAT_VORBIS;
342 
343  // FIXME: There seems to be a bug writing ogg files in one shot that
344  // causes a segfault: https://bugs.debian.org/760898.
345  // Breaking it up into a series of smaller chunks appears to avoid the
346  // problem and produces valid files.
347  chunk_size = 0x100000;
348  }
349 #if defined (HAVE_LIB_SNDFILE_FORMAT_MP3)
350  else if (ext == "mp1")
351  info.format = SF_FORMAT_MPEG|SF_FORMAT_MPEG_LAYER_I;
352  else if (ext == "mp2")
353  info.format = SF_FORMAT_MPEG|SF_FORMAT_MPEG_LAYER_II;
354  else if (ext == "mp3")
355  info.format = SF_FORMAT_MPEG|SF_FORMAT_MPEG_LAYER_III;
356 #endif
357  else
358  info.format = SF_FORMAT_PCM_16;
359 
360  info.channels = audio.columns ();
361  info.samplerate = samplerate;
362  info.format |= extension_to_format (ext);
363 
364  std::string title = "";
365  std::string artist = "";
366  std::string comment = "";
367  double quality = 0.75;
368 
369  for (int i = 3; i < nargin; i += 2)
370  {
371  if (i >= nargin - 1)
372  error ("audiowrite: invalid number of arguments");
373 
374  std::string keyword_orig = args(i).string_value ();
375  std::string keyword = args(i).xtolower ().string_value ();
376  octave_value value_arg = args(i+1);
377 
378  if (keyword == "bitspersample")
379  {
380  info.format &= ~SF_FORMAT_SUBMASK;
381  int bits = value_arg.int_value ();
382  if (bits == 8)
383  {
384  if ((info.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV)
385  info.format |= SF_FORMAT_PCM_U8;
386  else
387  info.format |= SF_FORMAT_PCM_S8;
388  }
389  else if (bits == 16)
390  info.format |= SF_FORMAT_PCM_16;
391  else if (bits == 24)
392  {
393  if ((info.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV)
394  info.format |= SF_FORMAT_PCM_32;
395  else
396  info.format |= SF_FORMAT_PCM_24;
397  }
398  else if (bits == 32)
399  {
400  if ((info.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV
401  && args(1).isfloat ())
402  info.format |= SF_FORMAT_FLOAT;
403  else
404  info.format |= SF_FORMAT_PCM_32;
405  }
406  else if (bits == 64)
407  info.format |= SF_FORMAT_DOUBLE;
408  else
409  error ("audiowrite: wrong number of bits specified");
410  }
411  else if (keyword == "bitrate")
412  warning_with_id ("Octave:audiowrite:unused-parameter",
413  "audiowrite: 'BitRate' accepted for Matlab "
414  "compatibility, but is ignored");
415  else if (keyword == "quality")
416  {
417  if (! value_arg.is_scalar_type ())
418  error ("audiowrite: Quality value must be a scalar");
419 
420  double value =
421  value_arg.xdouble_value ("audiowrite: Quality value must be a numeric scalar between 0 and 100");
422 
423  if (math::isnan (value) || value < 0 || value > 100)
424  error ("audiowrite: Quality value must be a number between 0 and 100");
425 
426  quality = value / 100;
427  }
428  else if (keyword == "title")
429  title = value_arg.string_value ();
430  else if (keyword == "artist")
431  artist = value_arg.string_value ();
432  else if (keyword == "comment")
433  comment = value_arg.string_value ();
434  else
435  error ("audiowrite: unrecognized option: '%s'", keyword_orig.c_str ());
436  }
437 
438  SNDFILE *file = sf_open (filename.c_str (), SFM_WRITE, &info);
439 
440  if (! file)
441  error ("audiowrite: failed to open output file '%s': %s",
442  filename.c_str (), sf_strerror (file));
443 
444  unwind_action close_open_file ([=] () { sf_close (file); });
445 
446  sf_command (file, SFC_SET_NORM_DOUBLE, nullptr, SF_TRUE);
447  sf_command (file, SFC_SET_CLIPPING, nullptr, SF_TRUE) ;
448  sf_command (file, SFC_SET_VBR_ENCODING_QUALITY, &quality, sizeof (quality));
449 
450  if (title != "")
451  sf_set_string (file, SF_STR_TITLE, title.c_str ());
452 
453  if (artist != "")
454  sf_set_string (file, SF_STR_ARTIST, artist.c_str ());
455 
456  if (comment != "")
457  sf_set_string (file, SF_STR_COMMENT, comment.c_str ());
458 
459  sf_count_t total_items_written = 0;
460  sf_count_t offset = 0;
461 
462  if (chunk_size == 0)
463  chunk_size = items_to_write;
464 
465  while (total_items_written < items_to_write)
466  {
467  if (items_to_write - offset < chunk_size)
468  chunk_size = items_to_write - offset;
469 
470  sf_count_t items_written = sf_write_double (file, data+offset, chunk_size);
471 
472  if (items_written != chunk_size)
473  error ("audiowrite: write failed, wrote %" PRId64 " of %" PRId64
474  " items\n", items_written, chunk_size);
475 
476  total_items_written += items_written;
477  offset += chunk_size;
478  }
479 
480  // FIXME: Shouldn't we return something to indicate whether the file
481  // was written successfully? On the other hand, Matlab doesn't
482  // return anything.
483  return ovl ();
484 
485 #else
486 
487  octave_unused_parameter (args);
488 
489  err_disabled_feature ("audiowrite",
490  "reading and writing sound files through libsndfile");
491 
492 #endif
493 }
494 
495 /*
496 ## Joint audiowrite/audioread tests
497 ## 8-bit Unsigned PCM
498 %!testif HAVE_SNDFILE <*56889>
499 %! fname = [tempname() ".wav"];
500 %! unwind_protect
501 %! y1 = uint8 ([0, 1, 2, 253, 254, 255]);
502 %! audiowrite (fname, y1, 8000, "BitsPerSample", 8);
503 %! y2 = audioread (fname, "native");
504 %! unwind_protect_cleanup
505 %! unlink (fname);
506 %! end_unwind_protect
507 %! assert (y1(:), y2);
508 
509 ## 8-bit Signed PCM
510 %!testif HAVE_SNDFILE <*56889>
511 %! fname = [tempname() ".au"];
512 %! unwind_protect
513 %! y1 = uint8 ([0, 1, 2, 253, 254, 255]);
514 %! audiowrite (fname, y1, 8000, "BitsPerSample", 8);
515 %! y2 = audioread (fname, "native");
516 %! unwind_protect_cleanup
517 %! unlink (fname);
518 %! end_unwind_protect
519 %! assert (y2, int8 ([-128; -127; -126; 125; 126; 127]));
520 
521 ## 16-bit Signed PCM
522 %!testif HAVE_SNDFILE <*56889>
523 %! fname = [tempname() ".wav"];
524 %! unwind_protect
525 %! y1 = int16 ([-32768, -32767, -32766, 32765, 32766, 32767]);
526 %! audiowrite (fname, y1, 8000, "BitsPerSample", 16);
527 %! y2 = audioread (fname, "native");
528 %! unwind_protect_cleanup
529 %! unlink (fname);
530 %! end_unwind_protect
531 %! assert (y1(:), y2);
532 
533 ## 24-bit Signed PCM
534 %!testif HAVE_SNDFILE <*56889>
535 %! fname = [tempname() ".au"];
536 %! unwind_protect
537 %! y1 = [-8388608, -8388607, -8388606, 8388605, 8388606, 8388607] / 8388608;
538 %! audiowrite (fname, y1, 8000, "BitsPerSample", 24);
539 %! y2 = audioread (fname, "native");
540 %! unwind_protect_cleanup
541 %! unlink (fname);
542 %! end_unwind_protect
543 %! assert (int32 ([-8388608; -8388607; -8388606; 8388605; 8388606; 8388607]),
544 %! y2);
545 
546 ## 32-bit Signed PCM
547 %!testif HAVE_SNDFILE <*56889>
548 %! fname = [tempname() ".wav"];
549 %! unwind_protect
550 %! y1 = int32 ([-2147483648, -2147483647, -2147483646, 2147483645, 2147483646, 2147483647 ]);
551 %! audiowrite (fname, y1, 8000, "BitsPerSample", 32);
552 %! y2 = audioread (fname, "native");
553 %! unwind_protect_cleanup
554 %! unlink (fname);
555 %! end_unwind_protect
556 %! assert (y1(:), y2);
557 
558 ## Test input validation
559 %!testif HAVE_SNDFILE
560 %! fail ("audiowrite (1, 1, 8e3)", "FILENAME must be a string");
561 %! fail ("audiowrite ('foo', int64 (1), 8e3)",
562 %! "wrong type argument 'int64 scalar'");
563 %! fail ("audiowrite ('foo', [0 1], [8e3, 8e3])",
564 %! "FS must be a positive scalar");
565 %! fail ("audiowrite ('foo', 1, {8e3})", "FS must be a .* integer");
566 %! fail ("audiowrite ('foo', 1, -8e3)", "FS must be a positive");
567 %! fail ("audiowrite ('foo', 1, 8e3, 'bitspersample')",
568 %! "invalid number of arguments");
569 %! fail ("audiowrite ('foo', 1, 8e3, 'bitspersample', 48)",
570 %! "wrong number of bits specified");
571 %! fail ("audiowrite ('foo', 1, 8e3, 'quality', [2 3 4])",
572 %! "Quality value must be a scalar");
573 %! fail ("audiowrite ('foo', 1, 8e3, 'quality', NaN)",
574 %! "Quality value must be .* between 0 and 100");
575 %! fail ("audiowrite ('foo', 1, 8e3, 'quality', -1)",
576 %! "Quality value must be .* between 0 and 100");
577 %! fail ("audiowrite ('foo', 1, 8e3, 'quality', 101)",
578 %! "Quality value must be .* between 0 and 100");
579 %! fail ("audiowrite ('foo', 1, 8e3, 'foo', 'bar')",
580 %! "unrecognized option: 'foo'");
581 */
582 
583 DEFUN_DLD (audioinfo, args, ,
584  doc: /* -*- texinfo -*-
585 @deftypefn {} {@var{info} =} audioinfo (@var{filename})
586 Return information about an audio file specified by @var{filename}.
587 
588 The output @var{info} is a structure containing the following fields:
589 
590 @table @samp
591 @item Filename
592 Name of the audio file.
593 
594 @item CompressionMethod
595 Audio compression method. Unused, only present for compatibility with
596 @sc{matlab}.
597 
598 @item NumChannels
599 Number of audio channels.
600 
601 @item SampleRate
602 Sample rate of the audio, in Hertz.
603 
604 @item TotalSamples
605 Number of samples in the file.
606 
607 @item Duration
608 Duration of the audio, in seconds.
609 
610 @item BitsPerSample
611 Number of bits per sample.
612 
613 @item BitRate
614 Audio bit rate. Unused, only present for compatibility with @sc{matlab}.
615 
616 @item Title
617 @qcode{"Title"} audio metadata value as a string, or empty if not present.
618 
619 @item Artist
620 @qcode{"Artist"} audio metadata value as a string, or empty if not present.
621 
622 @item Comment
623 @qcode{"Comment"} audio metadata value as a string, or empty if not present.
624 @end table
625 @seealso{audioread, audiowrite}
626 @end deftypefn */)
627 {
628 #if defined (HAVE_SNDFILE)
629 
630  if (args.length () != 1)
631  print_usage ();
632 
633  std::string filename = args(0).xstring_value ("audioinfo: FILENAME must be a string");
634 
635  sys::file_stat fs (filename);
636  if (! fs.exists ())
637  error ("audioinfo: FILENAME '%s' not found", filename.c_str ());
638 
639  SF_INFO info;
640  info.format = 0;
641  SNDFILE *file = sf_open (filename.c_str (), SFM_READ, &info);
642 
643  if (! file)
644  error ("audioinfo: failed to open input file '%s': %s",
645  filename.c_str (), sf_strerror (file));
646 
647  unwind_action close_open_file ([=] () { sf_close (file); });
648 
649  octave_scalar_map result;
650 
651  std::string full_name = sys::canonicalize_file_name (filename);
652 
653  result.assign ("Filename", full_name);
654  result.assign ("CompressionMethod", "");
655  result.assign ("NumChannels", info.channels);
656  result.assign ("SampleRate", info.samplerate);
657  double dframes;
658  if (info.frames != SF_COUNT_MAX)
659  dframes = info.frames;
660  else
661  dframes = -1;
662  result.assign ("TotalSamples", dframes);
663 
664  if (dframes != -1)
665  {
666  double drate = info.samplerate;
667  result.assign ("Duration", dframes / drate);
668  }
669  else
670  result.assign ("Duration", -1);
671 
672  int bits;
673  switch (info.format & SF_FORMAT_SUBMASK)
674  {
675  case SF_FORMAT_PCM_S8:
676  bits = 8;
677  break;
678  case SF_FORMAT_PCM_U8:
679  bits = 8;
680  break;
681  case SF_FORMAT_PCM_16:
682  bits = 16;
683  break;
684  case SF_FORMAT_PCM_24:
685  bits = 24;
686  break;
687  case SF_FORMAT_PCM_32:
688  bits = 32;
689  break;
690  case SF_FORMAT_FLOAT:
691  bits = 32;
692  break;
693  case SF_FORMAT_DOUBLE:
694  bits = 64;
695  break;
696  default:
697  bits = -1;
698  break;
699  }
700 
701  result.assign ("BitsPerSample", bits);
702  result.assign ("BitRate", -1);
703  result.assign ("Title", sf_get_string (file, SF_STR_TITLE));
704  result.assign ("Artist", sf_get_string (file, SF_STR_ARTIST));
705  result.assign ("Comment", sf_get_string (file, SF_STR_COMMENT));
706 
707  return ovl (result);
708 
709 #else
710 
711  octave_unused_parameter (args);
712 
713  err_disabled_feature ("audioinfo",
714  "reading and writing sound files through libsndfile");
715 
716 #endif
717 }
718 
719 #if defined (HAVE_SNDFILE)
720 
721 static void
722 audio_sub_formats (int format)
723 {
724  int count;
725  sf_command (nullptr, SFC_GET_FORMAT_SUBTYPE_COUNT, &count, sizeof (int));
726 
727  for (int i = 0; i < count; i++)
728  {
729  SF_FORMAT_INFO info;
730  info.format = i;
731  sf_command (nullptr, SFC_GET_FORMAT_SUBTYPE, &info, sizeof (info));
732 
733  SF_INFO sfinfo;
734  memset (&sfinfo, 0, sizeof (sfinfo));
735  sfinfo.channels = 1;
736  sfinfo.format = (format & SF_FORMAT_TYPEMASK) | info.format;
737 
738  if (sf_format_check (&sfinfo))
739  octave_stdout << " " << info.name << std::endl;
740  }
741 }
742 
743 #endif
744 
745 DEFUN_DLD (audioformats, args, ,
746  doc: /* -*- texinfo -*-
747 @deftypefn {} {} audioformats ()
748 @deftypefnx {} {} audioformats (@var{format})
749 Display information about all supported audio formats.
750 
751 If the optional argument @var{format} is given, then display only formats
752 with names that start with @var{format}.
753 @seealso{audioread, audiowrite}
754 @end deftypefn */)
755 {
756 #if defined (HAVE_SNDFILE)
757 
758  if (args.length () > 1)
759  print_usage ();
760 
761  std::string search = "";
762  if (args.length () > 0)
763  {
764  search = args(0).string_value ();
765  std::transform (search.begin (), search.end (), search.begin (), tolower);
766  }
767 
768  int count;
769  sf_command (nullptr, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof (int));
770 
771  for (int i = 0; i < count; i++)
772  {
773  SF_FORMAT_INFO info;
774  info.format = i;
775  sf_command (nullptr, SFC_GET_FORMAT_MAJOR, &info, sizeof (info));
776  bool match = true;
777 
778  if (! search.empty ())
779  {
780  std::string nm = info.name;
781  std::transform (nm.begin (), nm.end (), nm.begin (), tolower);
782  match = nm.compare (0, search.length (), search) == 0;
783  }
784 
785  if (match)
786  {
787  octave_stdout << "name: " << info.name << std::endl;
788  octave_stdout << "extension: " << info.extension << std::endl;
789  octave_stdout << "id: " << info.format << std::endl;
790  octave_stdout << "subformats:" << std::endl;
791 
792  audio_sub_formats (info.format);
793  }
794  }
795 
796  return octave_value_list ();
797 
798 #else
799 
800  octave_unused_parameter (args);
801 
802  err_disabled_feature ("audioformats",
803  "getting sound formats through libsndfile");
804 
805 #endif
806 }
807 
808 OCTAVE_END_NAMESPACE(octave)
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
T * fortran_vec()
Size of the specified dimension.
Definition: Array-base.cc:1764
octave_idx_type rows() const
Definition: Array.h:459
octave_idx_type columns() const
Definition: Array.h:471
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:524
Definition: dMatrix.h:42
Matrix transpose() const
Definition: dMatrix.h:140
int int_value(bool req_int=false, bool frc_str_conv=false) const
Definition: ov.h:812
bool is_scalar_type() const
Definition: ov.h:744
double xdouble_value(const char *fmt,...) const
std::string string_value(bool force=false) const
Definition: ov.h:974
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
void print_usage(void)
Definition: defun-int.h:72
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:1078
void() error(const char *fmt,...)
Definition: error.cc:988
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:5500
ColumnVector transform(const Matrix &m, double x, double y, double z)
Definition: graphics.cc:5468
intNDArray< octave_int16 > int16NDArray
Definition: int16NDArray.h:36
intNDArray< octave_int32 > int32NDArray
Definition: int32NDArray.h:36
intNDArray< octave_int8 > int8NDArray
Definition: int8NDArray.h:36
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
std::string canonicalize_file_name(const std::string &name)
Definition: file-ops.cc:798
#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:219
#define octave_stdout
Definition: pager.h:309
intNDArray< octave_uint8 > uint8NDArray
Definition: uint8NDArray.h:36
std::size_t format(std::ostream &os, const char *fmt,...)