GNU Octave 7.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-2022 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
52OCTAVE_NAMESPACE_BEGIN
53
54DEFUN_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})
61Read the audio file @var{filename} and return the audio data @var{y} and
62sampling rate @var{fs}.
63
64The audio data is stored as matrix with rows corresponding to audio frames
65and columns corresponding to channels.
66
67The optional two-element vector argument @var{samples} specifies starting
68and ending frames.
69
70The optional argument @var{datatype} specifies the datatype to return.
71If it is @qcode{"native"}, then the type of data depends on how the data
72is 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
198static int
199extension_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
243DEFUN_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
248Write 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
251Additional name/value argument pairs may be used to specify the
252following options:
253
254@table @samp
255@item BitsPerSample
256Number of bits per sample. Valid values are 8, 16, 24, and 32. Default is
25716.
258
259@item BitRate
260Valid argument name, but ignored. Left for compatibility with @sc{matlab}.
261
262@item Quality
263Quality setting for the Ogg Vorbis compressor. Values can range between 0
264and 100 with 100 being the highest quality setting. Default is 75.
265
266@item Title
267Title for the audio file.
268
269@item Artist
270Artist name.
271
272@item Comment
273Comment.
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 = value_arg.xdouble_value ("audiowrite: Quality value must be a numeric scalar between 0 and 100");
410
411 if (math::isnan (value) || value < 0 || value > 100)
412 error ("audiowrite: Quality value must be a number between 0 and 100");
413
414 quality = value / 100;
415 }
416 else if (keyword == "title")
417 title = value_arg.string_value ();
418 else if (keyword == "artist")
419 artist = value_arg.string_value ();
420 else if (keyword == "comment")
421 comment = value_arg.string_value ();
422 else
423 error ("audiowrite: unrecognized option: '%s'", keyword_orig.c_str ());
424 }
425
426 SNDFILE *file = sf_open (filename.c_str (), SFM_WRITE, &info);
427
428 if (! file)
429 error ("audiowrite: failed to open output file '%s': %s",
430 filename.c_str (), sf_strerror (file));
431
432 unwind_action close_open_file ([=] () { sf_close (file); });
433
434 sf_command (file, SFC_SET_NORM_DOUBLE, nullptr, SF_TRUE);
435 sf_command (file, SFC_SET_CLIPPING, nullptr, SF_TRUE) ;
436 sf_command (file, SFC_SET_VBR_ENCODING_QUALITY, &quality, sizeof (quality));
437
438 if (title != "")
439 sf_set_string (file, SF_STR_TITLE, title.c_str ());
440
441 if (artist != "")
442 sf_set_string (file, SF_STR_ARTIST, artist.c_str ());
443
444 if (comment != "")
445 sf_set_string (file, SF_STR_COMMENT, comment.c_str ());
446
447 sf_count_t total_items_written = 0;
448 sf_count_t offset = 0;
449
450 if (chunk_size == 0)
451 chunk_size = items_to_write;
452
453 while (total_items_written < items_to_write)
454 {
455 if (items_to_write - offset < chunk_size)
456 chunk_size = items_to_write - offset;
457
458 sf_count_t items_written = sf_write_double (file, data+offset, chunk_size);
459
460 if (items_written != chunk_size)
461 error ("audiowrite: write failed, wrote %" PRId64 " of %" PRId64
462 " items\n", items_written, chunk_size);
463
464 total_items_written += items_written;
465 offset += chunk_size;
466 }
467
468 // FIXME: shouldn't we return something to indicate whether the file
469 // was written successfully?
470 return ovl ();
471
472#else
473
474 octave_unused_parameter (args);
475
476 err_disabled_feature ("audiowrite",
477 "reading and writing sound files through libsndfile");
478
479#endif
480}
481
482/*
483## Joint audiowrite/audioread tests
484## 8-bit Unsigned PCM
485%!testif HAVE_SNDFILE <*56889>
486%! fname = [tempname() ".wav"];
487%! unwind_protect
488%! y1 = uint8 ([0, 1, 2, 253, 254, 255]);
489%! audiowrite (fname, y1, 8000, "BitsPerSample", 8);
490%! y2 = audioread (fname, "native");
491%! unwind_protect_cleanup
492%! unlink (fname);
493%! end_unwind_protect
494%! assert (y1(:), y2);
495
496## 8-bit Signed PCM
497%!testif HAVE_SNDFILE <*56889>
498%! fname = [tempname() ".au"];
499%! unwind_protect
500%! y1 = uint8 ([0, 1, 2, 253, 254, 255]);
501%! audiowrite (fname, y1, 8000, "BitsPerSample", 8);
502%! y2 = audioread (fname, "native");
503%! unwind_protect_cleanup
504%! unlink (fname);
505%! end_unwind_protect
506%! assert (y2, int8 ([-128; -127; -126; 125; 126; 127]));
507
508## 16-bit Signed PCM
509%!testif HAVE_SNDFILE <*56889>
510%! fname = [tempname() ".wav"];
511%! unwind_protect
512%! y1 = int16 ([-32768, -32767, -32766, 32765, 32766, 32767]);
513%! audiowrite (fname, y1, 8000, "BitsPerSample", 16);
514%! y2 = audioread (fname, "native");
515%! unwind_protect_cleanup
516%! unlink (fname);
517%! end_unwind_protect
518%! assert (y1(:), y2);
519
520## 24-bit Signed PCM
521%!testif HAVE_SNDFILE <*56889>
522%! fname = [tempname() ".au"];
523%! unwind_protect
524%! y1 = [-8388608, -8388607, -8388606, 8388605, 8388606, 8388607] / 8388608;
525%! audiowrite (fname, y1, 8000, "BitsPerSample", 24);
526%! y2 = audioread (fname, "native");
527%! unwind_protect_cleanup
528%! unlink (fname);
529%! end_unwind_protect
530%! assert (int32 ([-8388608; -8388607; -8388606; 8388605; 8388606; 8388607]),
531%! y2);
532
533## 32-bit Signed PCM
534%!testif HAVE_SNDFILE <*56889>
535%! fname = [tempname() ".wav"];
536%! unwind_protect
537%! y1 = int32 ([-2147483648, -2147483647, -2147483646, 2147483645, 2147483646, 2147483647 ]);
538%! audiowrite (fname, y1, 8000, "BitsPerSample", 32);
539%! y2 = audioread (fname, "native");
540%! unwind_protect_cleanup
541%! unlink (fname);
542%! end_unwind_protect
543%! assert (y1(:), y2);
544
545## Test input validation
546%!testif HAVE_SNDFILE
547%! fail ("audiowrite (1, 1, 8e3)", "FILENAME must be a string");
548%! fail ("audiowrite ('foo', int64 (1), 8e3)", "wrong type argument 'int64 scalar'");
549%! fail ("audiowrite ('foo', [0 1], [8e3, 8e3])", "FS must be a positive scalar");
550%! fail ("audiowrite ('foo', 1, {8e3})", "FS must be a .* integer");
551%! fail ("audiowrite ('foo', 1, -8e3)", "FS must be a positive");
552%! fail ("audiowrite ('foo', 1, 8e3, 'bitspersample')", "invalid number of arguments");
553%! fail ("audiowrite ('foo', 1, 8e3, 'bitspersample', 48)", "wrong number of bits specified");
554%! fail ("audiowrite ('foo', 1, 8e3, 'quality', [2 3 4])", "Quality value must be a scalar");
555%! fail ("audiowrite ('foo', 1, 8e3, 'quality', NaN)", "Quality value must be .* between 0 and 100");
556%! fail ("audiowrite ('foo', 1, 8e3, 'quality', -1)", "Quality value must be .* between 0 and 100");
557%! fail ("audiowrite ('foo', 1, 8e3, 'quality', 101)", "Quality value must be .* between 0 and 100");
558%! fail ("audiowrite ('foo', 1, 8e3, 'foo', 'bar')", "unrecognized option: 'foo'");
559*/
560
561DEFUN_DLD (audioinfo, args, ,
562 doc: /* -*- texinfo -*-
563@deftypefn {} {@var{info} =} audioinfo (@var{filename})
564Return information about an audio file specified by @var{filename}.
565
566The output @var{info} is a structure containing the following fields:
567
568@table @samp
569@item Filename
570Name of the audio file.
571
572@item CompressionMethod
573Audio compression method. Unused, only present for compatibility with
574@sc{matlab}.
575
576@item NumChannels
577Number of audio channels.
578
579@item SampleRate
580Sample rate of the audio, in Hertz.
581
582@item TotalSamples
583Number of samples in the file.
584
585@item Duration
586Duration of the audio, in seconds.
587
588@item BitsPerSample
589Number of bits per sample.
590
591@item BitRate
592Audio bit rate. Unused, only present for compatibility with @sc{matlab}.
593
594@item Title
595@qcode{"Title"} audio metadata value as a string, or empty if not present.
596
597@item Artist
598@qcode{"Artist"} audio metadata value as a string, or empty if not present.
599
600@item Comment
601@qcode{"Comment"} audio metadata value as a string, or empty if not present.
602@end table
603@seealso{audioread, audiowrite}
604@end deftypefn */)
605{
606#if defined (HAVE_SNDFILE)
607
608 if (args.length () != 1)
609 print_usage ();
610
611 std::string filename = args(0).xstring_value ("audioinfo: FILENAME must be a string");
612
613 sys::file_stat fs (filename);
614 if (! fs.exists ())
615 error ("audioinfo: FILENAME '%s' not found", filename.c_str ());
616
617 SF_INFO info;
618 info.format = 0;
619 SNDFILE *file = sf_open (filename.c_str (), SFM_READ, &info);
620
621 if (! file)
622 error ("audioinfo: failed to open input file '%s': %s",
623 filename.c_str (), sf_strerror (file));
624
625 unwind_action close_open_file ([=] () { sf_close (file); });
626
627 octave_scalar_map result;
628
629 std::string full_name = sys::canonicalize_file_name (filename);
630
631 result.assign ("Filename", full_name);
632 result.assign ("CompressionMethod", "");
633 result.assign ("NumChannels", info.channels);
634 result.assign ("SampleRate", info.samplerate);
635 double dframes;
636 if (info.frames != SF_COUNT_MAX)
637 dframes = info.frames;
638 else
639 dframes = -1;
640 result.assign ("TotalSamples", dframes);
641
642 if (dframes != -1)
643 {
644 double drate = info.samplerate;
645 result.assign ("Duration", dframes / drate);
646 }
647 else
648 result.assign ("Duration", -1);
649
650 int bits;
651 switch (info.format & SF_FORMAT_SUBMASK)
652 {
653 case SF_FORMAT_PCM_S8:
654 bits = 8;
655 break;
656 case SF_FORMAT_PCM_U8:
657 bits = 8;
658 break;
659 case SF_FORMAT_PCM_16:
660 bits = 16;
661 break;
662 case SF_FORMAT_PCM_24:
663 bits = 24;
664 break;
665 case SF_FORMAT_PCM_32:
666 bits = 32;
667 break;
668 case SF_FORMAT_FLOAT:
669 bits = 32;
670 break;
671 case SF_FORMAT_DOUBLE:
672 bits = 64;
673 break;
674 default:
675 bits = -1;
676 break;
677 }
678
679 result.assign ("BitsPerSample", bits);
680 result.assign ("BitRate", -1);
681 result.assign ("Title", sf_get_string (file, SF_STR_TITLE));
682 result.assign ("Artist", sf_get_string (file, SF_STR_ARTIST));
683 result.assign ("Comment", sf_get_string (file, SF_STR_COMMENT));
684
685 return ovl (result);
686
687#else
688
689 octave_unused_parameter (args);
690
691 err_disabled_feature ("audioinfo",
692 "reading and writing sound files through libsndfile");
693
694#endif
695}
696
697#if defined (HAVE_SNDFILE)
698
699static void
700audio_sub_formats (int format)
701{
702 int count;
703 sf_command (nullptr, SFC_GET_FORMAT_SUBTYPE_COUNT, &count, sizeof (int));
704
705 for (int i = 0; i < count; i++)
706 {
707 SF_FORMAT_INFO info;
708 info.format = i;
709 sf_command (nullptr, SFC_GET_FORMAT_SUBTYPE, &info, sizeof (info));
710
711 SF_INFO sfinfo;
712 memset (&sfinfo, 0, sizeof (sfinfo));
713 sfinfo.channels = 1;
714 sfinfo.format = (format & SF_FORMAT_TYPEMASK) | info.format;
715
716 if (sf_format_check (&sfinfo))
717 octave_stdout << " " << info.name << std::endl;
718 }
719}
720
721#endif
722
723DEFUN_DLD (audioformats, args, ,
724 doc: /* -*- texinfo -*-
725@deftypefn {} {} audioformats ()
726@deftypefnx {} {} audioformats (@var{format})
727Display information about all supported audio formats.
728
729If the optional argument @var{format} is given, then display only formats
730with names that start with @var{format}.
731@seealso{audioread, audiowrite}
732@end deftypefn */)
733{
734#if defined (HAVE_SNDFILE)
735
736 if (args.length () > 1)
737 print_usage ();
738
739 std::string search = "";
740 if (args.length () > 0)
741 {
742 search = args(0).string_value ();
743 std::transform (search.begin (), search.end (), search.begin (), tolower);
744 }
745
746 int count;
747 sf_command (nullptr, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof (int));
748
749 for (int i = 0; i < count; i++)
750 {
751 SF_FORMAT_INFO info;
752 info.format = i;
753 sf_command (nullptr, SFC_GET_FORMAT_MAJOR, &info, sizeof (info));
754 bool match = true;
755
756 if (! search.empty ())
757 {
758 std::string nm = info.name;
759 std::transform (nm.begin (), nm.end (), nm.begin (), tolower);
760 match = nm.compare (0, search.length (), search) == 0;
761 }
762
763 if (match)
764 {
765 octave_stdout << "name: " << info.name << std::endl;
766 octave_stdout << "extension: " << info.extension << std::endl;
767 octave_stdout << "id: " << info.format << std::endl;
768 octave_stdout << "subformats:" << std::endl;
769
770 audio_sub_formats (info.format);
771 }
772 }
773
774#else
775
776 octave_unused_parameter (args);
777
778 err_disabled_feature ("audioformats",
779 "getting sound formats through libsndfile");
780
781#endif
782
783 return octave_value_list ();
784}
785
786OCTAVE_NAMESPACE_END
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
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:504
octave_idx_type rows(void) const
Definition: Array.h:449
octave_idx_type columns(void) const
Definition: Array.h:458
OCTARRAY_API T * fortran_vec(void)
Size of the specified dimension.
Definition: Array.cc:1744
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
#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:1070
void error(const char *fmt,...)
Definition: error.cc:980
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:5893
ColumnVector transform(const Matrix &m, double x, double y, double z)
Definition: graphics.cc:5861
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
class OCTAVE_API FloatNDArray
Definition: mx-fwd.h:40
T x_nint(T x)
Definition: lo-mappers.h:269
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:225
std::string canonicalize_file_name(const std::string &name)
Definition: file-ops.cc:688
class OCTAVE_API range
Definition: range-fwd.h:33
#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
intNDArray< octave_uint8 > uint8NDArray
Definition: uint8NDArray.h:36
std::size_t format(std::ostream &os, const char *fmt,...)
Definition: utils.cc:1471