GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
audioread.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2013-2017 Vytautas JanĨauskas
4 Copyright (C) 2016 Damjan Angelovski
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #if defined (HAVE_CONFIG_H)
25 # include "config.h"
26 #endif
27 
28 #include <string>
29 #include <map>
30 
31 #include "oct-locbuf.h"
32 #include "unwind-prot.h"
33 
34 #include "defun-dld.h"
35 #include "error.h"
36 #include "errwarn.h"
37 #include "ovl.h"
38 #include "ov.h"
39 #include "ov-struct.h"
40 #include "pager.h"
41 
42 #if defined (HAVE_SNDFILE)
43 # include <sndfile.h>
44 #endif
45 
46 #if defined (HAVE_SNDFILE)
47 static void
48 safe_close (SNDFILE *file)
49 {
50  sf_close (file);
51 }
52 #endif
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 @end deftypefn */)
74 {
75 #if defined (HAVE_SNDFILE)
76 
77  int nargin = args.length ();
78 
79  if (nargin < 1 || nargin > 3)
80  print_usage ();
81 
82  std::string filename = args(0).xstring_value ("audioread: FILENAME must be a string");
83 
84  SF_INFO info;
85  info.format = 0;
86  SNDFILE *file = sf_open (filename.c_str (), SFM_READ, &info);
87 
88  if (! file)
89  error ("audioread: failed to open input file %s", filename.c_str ());
90 
92 
93  frame.add_fcn (safe_close, file);
94 
95  OCTAVE_LOCAL_BUFFER (float, data, info.frames * info.channels);
96 
97  sf_read_float (file, data, info.frames * info.channels);
98 
99  sf_count_t start = 0;
100  sf_count_t end = info.frames;
101 
102  if ((nargin == 2 && ! args(1).is_string ()) || nargin == 3)
103  {
104  RowVector range = args(1).row_vector_value ();
105 
106  if (range.numel () != 2)
107  error ("audioread: invalid specification for range of frames");
108 
109  double dstart = octave::math::isinf (range(0)) ? info.frames : range(0);
110  double dend = octave::math::isinf (range(1)) ? info.frames : range(1);
111 
112  if (dstart < 1 || dstart > dend || dend > info.frames
113  || octave::math::x_nint (dstart) != dstart
114  || octave::math::x_nint (dend) != dend)
115  error ("audioread: invalid specification for range of frames");
116 
117  start = dstart - 1;
118  end = dend;
119  }
120 
121  sf_count_t items = end - start;
122 
123  Matrix audio (items, info.channels);
124 
125  double *paudio = audio.fortran_vec ();
126 
127  data += start * info.channels;
128 
129  for (int i = 0; i < items; i++)
130  {
131  for (int channel = 0; channel < info.channels; channel++)
132  paudio[items*channel+i] = *data++;
133  }
134 
135  octave_value ret_audio;
136 
137  if ((nargin == 2 && args(1).is_string ()) || nargin == 3)
138  {
140  if (nargin == 3)
141  type = args(2).string_value ();
142  else
143  type = args(1).string_value ();
144 
145  if (type == "native")
146  {
147  switch (info.format & SF_FORMAT_SUBMASK)
148  {
149  case SF_FORMAT_PCM_S8:
150  ret_audio = int8NDArray (audio * 127);
151  break;
152  case SF_FORMAT_PCM_U8:
153  ret_audio = uint8NDArray (audio * 127 + 127);
154  break;
155  case SF_FORMAT_PCM_16:
156  ret_audio = int16NDArray (audio * 32767);
157  break;
158  case SF_FORMAT_PCM_24:
159  ret_audio = int32NDArray (audio * 8388608);
160  break;
161  case SF_FORMAT_PCM_32:
162  ret_audio = int32NDArray (audio * 2147483648);
163  break;
164  default:
165  ret_audio = audio;
166  break;
167  }
168  }
169  else
170  ret_audio = audio;
171  }
172  else
173  ret_audio = audio;
174 
175  return ovl (ret_audio, info.samplerate);
176 
177 #else
178 
179  octave_unused_parameter (args);
180 
181  err_disabled_feature ("audioread",
182  "reading and writing sound files through libsndfile");
183 
184 #endif
185 }
186 
187 #if defined (HAVE_SNDFILE)
188 
189 static int
190 extension_to_format (const std::string& ext)
191 {
192  static bool initialized = false;
193 
194  static std::map<std::string, int> table;
195 
196  if (! initialized)
197  {
198  table["wav"] = SF_FORMAT_WAV;
199  table["aiff"] = SF_FORMAT_AIFF;
200  table["au"] = SF_FORMAT_AU;
201  table["raw"] = SF_FORMAT_RAW;
202  table["paf"] = SF_FORMAT_PAF;
203  table["svx"] = SF_FORMAT_SVX;
204  table["nist"] = SF_FORMAT_NIST;
205  table["voc"] = SF_FORMAT_VOC;
206  table["ircam"] = SF_FORMAT_IRCAM;
207  table["w64"] = SF_FORMAT_W64;
208  table["mat4"] = SF_FORMAT_MAT4;
209  table["mat5"] = SF_FORMAT_MAT5;
210  table["pvf"] = SF_FORMAT_PVF;
211  table["xi"] = SF_FORMAT_XI;
212  table["htk"] = SF_FORMAT_HTK;
213  table["sds"] = SF_FORMAT_SDS;
214  table["avr"] = SF_FORMAT_AVR;
215  table["wavex"] = SF_FORMAT_WAVEX;
216  table["sd2"] = SF_FORMAT_SD2;
217  table["flac"] = SF_FORMAT_FLAC;
218  table["caf"] = SF_FORMAT_CAF;
219  table["wve"] = SF_FORMAT_WVE;
220  table["ogg"] = SF_FORMAT_OGG;
221  table["mpc2k"] = SF_FORMAT_MPC2K;
222  table["rf64"] = SF_FORMAT_RF64;
223 
224  initialized = true;
225  }
226 
227  std::map<std::string, int>::const_iterator it = table.find (ext);
228 
229  return (it != table.end ()) ? it->second : 0;
230 }
231 
232 #endif
233 
234 DEFUN_DLD (audiowrite, args, ,
235  doc: /* -*- texinfo -*-
236 @deftypefn {} {} audiowrite (@var{filename}, @var{y}, @var{fs})
237 @deftypefnx {} {} audiowrite (@var{filename}, @var{y}, @var{fs}, @var{name}, @var{value}, @dots{})
238 
239 Write audio data from the matrix @var{y} to @var{filename} at sampling rate
240 @var{fs} with the file format determined by the file extension.
241 
242 Additional name/value argument pairs may be used to specify the
243 following options:
244 
245 @table @samp
246 @item BitsPerSample
247 Number of bits per sample. Valid values are 8, 16, 24, and 32. Default is
248 16.
249 
250 @item BitRate
251 Valid argument name, but ignored. Left for compatibility with @sc{matlab}.
252 
253 @item Quality
254 Quality setting for the Ogg Vorbis compressor. Values can range between 0
255 and 100 with 100 being the highest quality setting. Default is 75.
256 
257 @item Title
258 Title for the audio file.
259 
260 @item Artist
261 Artist name.
262 
263 @item Comment
264 Comment.
265 @end table
266 @end deftypefn */)
267 {
268 #if defined (HAVE_SNDFILE)
269 
270  int nargin = args.length ();
271 
272  if (nargin < 3)
273  print_usage ();
274 
275  std::string filename = args(0).xstring_value ("audiowrite: FILENAME must be a string");
276 
277  double bias = 0.0;
278  double scale = 1.0;
279 
280  if (args(1).is_uint8_type ())
281  bias = scale = std::pow (2.0, 7);
282  else if (args(1).is_int16_type ())
283  scale = std::pow (2.0, 15);
284  else if (args(1).is_int32_type ())
285  scale = std::pow (2.0, 31);
286  else if (args(1).is_integer_type ())
287  err_wrong_type_arg ("audiowrite", args(1));
288 
289  Matrix audio = args(1).matrix_value ();
290 
291  int samplerate = args(2).int_value ();
292 
293  std::string ext;
294  size_t dotpos = filename.find_last_of (".");
295  if (dotpos != std::string::npos)
296  ext = filename.substr (dotpos + 1);
297  std::transform (ext.begin (), ext.end (), ext.begin (), ::tolower);
298 
299  sf_count_t items_to_write = audio.rows () * audio.columns ();
300 
301  if (audio.rows () == 1)
302  audio = audio.transpose ();
303 
304  OCTAVE_LOCAL_BUFFER (float, data, items_to_write);
305 
306  sf_count_t idx = 0;
307  for (int i = 0; i < audio.rows (); i++)
308  {
309  for (int j = 0; j < audio.columns (); j++)
310  {
311  double elem = (audio.xelem (i, j) - bias) / scale;
312  data[idx++] = std::min (std::max (elem, -1.0), 1.0);
313  }
314  }
315 
316  SF_INFO info;
317 
318  memset (&info, 0, sizeof (info));
319 
320  sf_count_t chunk_size = 0;
321 
322  if (ext == "ogg")
323  {
324  info.format = SF_FORMAT_VORBIS;
325 
326  // FIXME: there seems to be a bug writing ogg files in one shot
327  // that causes a segfault. Breaking it up into a series of
328  // smaller chunks seems to avoid the problem and produce valid
329  // files.
330  chunk_size = 0x1FFFFE;
331  }
332  else
333  info.format = SF_FORMAT_PCM_16;
334 
335  info.channels = audio.columns ();
336  info.samplerate = samplerate;
337  info.channels = audio.cols ();
338  info.format |= extension_to_format (ext);
339 
340  std::string title = "";
341  std::string artist = "";
342  std::string comment = "";
343  // Quality is currently unused?
344  //
345  // float quality = 0.75;
346  for (int i = 3; i < nargin; i += 2)
347  {
348  if (i >= nargin - 1)
349  error ("audiowrite: invalid number of arguments");
350 
351  std::string keyword = args(i).string_value ();
352  octave_value value_arg = args(i+1);
353 
354  if (keyword == "BitsPerSample")
355  {
356  info.format &= ~SF_FORMAT_SUBMASK;
357  int bits = value_arg.int_value ();
358  if (bits == 8)
359  {
360  if ((info.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV)
361  info.format |= SF_FORMAT_PCM_U8;
362  else
363  info.format |= SF_FORMAT_PCM_S8;
364  }
365  else if (bits == 16)
366  info.format |= SF_FORMAT_PCM_16;
367  else if (bits == 24)
368  info.format |= SF_FORMAT_PCM_24;
369  else if (bits == 32)
370  info.format |= SF_FORMAT_PCM_32;
371  else
372  error ("audiowrite: wrong number of bits specified");
373  }
374  else if (keyword == "BitRate")
375  ;
376  // Quality is currently unused?
377  //
378  // else if (keyword == "Quality")
379  // quality = value_arg.int_value () * 0.01;
380  else if (keyword == "Title")
381  title = value_arg.string_value ();
382  else if (keyword == "Artist")
383  artist = value_arg.string_value ();
384  else if (keyword == "Comment")
385  comment = value_arg.string_value ();
386  else
387  error ("audiowrite: wrong argument name");
388  }
389 
390  SNDFILE *file = sf_open (filename.c_str (), SFM_WRITE, &info);
391 
392  if (! file)
393  error ("audiowrite: failed to open output file %s", filename.c_str ());
394 
396 
397  frame.add_fcn (safe_close, file);
398 
399  if (title != "")
400  sf_set_string (file, SF_STR_TITLE, title.c_str ());
401 
402  if (artist != "")
403  sf_set_string (file, SF_STR_ARTIST, artist.c_str ());
404 
405  if (comment != "")
406  sf_set_string (file, SF_STR_COMMENT, comment.c_str ());
407 
408  sf_count_t total_items_written = 0;
409  sf_count_t offset = 0;
410 
411  if (chunk_size == 0)
412  chunk_size = items_to_write;
413 
414  while (total_items_written < items_to_write)
415  {
416  if (items_to_write - offset < chunk_size)
417  chunk_size = items_to_write - offset;
418 
419  sf_count_t items_written = sf_write_float (file, data+offset, chunk_size);
420 
421  if (items_written != chunk_size)
422  error ("audiowrite: write failed, wrote %ld of %ld items\n",
423  items_written, chunk_size);
424 
425  total_items_written += items_written;
426  offset += chunk_size;
427  }
428 
429  // FIXME: shouldn't we return something to indicate whether the file
430  // was written successfully?
431  return ovl ();
432 
433 #else
434 
435  octave_unused_parameter (args);
436 
437  err_disabled_feature ("audiowrite",
438  "reading and writing sound files through libsndfile");
439 
440 #endif
441 }
442 
443 DEFUN_DLD (audioinfo, args, ,
444  doc: /* -*- texinfo -*-
445 @deftypefn {} {@var{info} =} audioinfo (@var{filename})
446 Return information about an audio file specified by @var{filename}.
447 @end deftypefn */)
448 {
449 #if defined (HAVE_SNDFILE)
450 
451  if (args.length () != 1)
452  print_usage ();
453 
454  std::string filename = args(0).xstring_value ("audioinfo: FILENAME must be a string");
455 
456  SF_INFO info;
457  info.format = 0;
458  SNDFILE *file = sf_open (filename.c_str (), SFM_READ, &info);
459 
460  if (! file)
461  error ("audioinfo: failed to open file %s", filename.c_str ());
462 
464 
465  frame.add_fcn (safe_close, file);
466 
468 
469  result.assign ("Filename", filename);
470  result.assign ("CompressionMethod", "");
471  result.assign ("NumChannels", info.channels);
472  result.assign ("SampleRate", info.samplerate);
473  result.assign ("TotalSamples", info.frames);
474 
475  double dframes = info.frames;
476  double drate = info.samplerate;
477  result.assign ("Duration", dframes / drate);
478 
479  int bits;
480  switch (info.format & SF_FORMAT_SUBMASK)
481  {
482  case SF_FORMAT_PCM_S8:
483  bits = 8;
484  break;
485  case SF_FORMAT_PCM_U8:
486  bits = 8;
487  break;
488  case SF_FORMAT_PCM_16:
489  bits = 16;
490  break;
491  case SF_FORMAT_PCM_24:
492  bits = 24;
493  break;
494  case SF_FORMAT_PCM_32:
495  bits = 32;
496  break;
497  default:
498  bits = -1;
499  break;
500  }
501 
502  result.assign ("BitsPerSample", bits);
503  result.assign ("BitRate", -1);
504  result.assign ("Title", sf_get_string (file, SF_STR_TITLE));
505  result.assign ("Artist", sf_get_string (file, SF_STR_ARTIST));
506  result.assign ("Comment", sf_get_string (file, SF_STR_COMMENT));
507 
508  return ovl (result);
509 
510 #else
511 
512  octave_unused_parameter (args);
513 
514  err_disabled_feature ("audioinfo",
515  "reading and writing sound files through libsndfile");
516 
517 #endif
518 }
519 
520 #if defined (HAVE_SNDFILE)
521 
522 static void
523 audio_sub_formats (int format)
524 {
525  int count;
526  sf_command (NULL, SFC_GET_FORMAT_SUBTYPE_COUNT, &count, sizeof (int));
527 
528  for (int i = 0; i < count; i++)
529  {
530  SF_FORMAT_INFO info;
531  info.format = i;
532  sf_command (NULL, SFC_GET_FORMAT_SUBTYPE, &info, sizeof (info));
533 
534  SF_INFO sfinfo;
535  memset (&sfinfo, 0, sizeof (sfinfo));
536  sfinfo.channels = 1;
537  sfinfo.format = (format & SF_FORMAT_TYPEMASK) | info.format;
538 
539  if (sf_format_check (&sfinfo))
540  octave_stdout << " " << info.name << std::endl;
541  }
542 }
543 
544 #endif
545 
546 DEFUN_DLD (audioformats, args, ,
547  doc: /* -*- texinfo -*-
548 @deftypefn {} {} audioformats ()
549 @deftypefnx {} {} audioformats (@var{format})
550 Display information about all supported audio formats.
551 
552 If the optional argument @var{format} is given, then display only formats
553 with names that start with @var{format}.
554 @end deftypefn */)
555 {
556 #if defined (HAVE_SNDFILE)
557 
558  if (args.length () > 1)
559  print_usage ();
560 
561  std::string search = "";
562  if (args.length () > 0)
563  {
564  search = args(0).string_value ();
565  std::transform (search.begin (), search.end (), search.begin (), tolower);
566  }
567 
568  int count;
569  sf_command (NULL, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof (int));
570 
571  for (int i = 0; i < count; i++)
572  {
573  SF_FORMAT_INFO info;
574  info.format = i;
575  sf_command (NULL, SFC_GET_FORMAT_MAJOR, &info, sizeof (info));
576  bool match = true;
577 
578  if (! search.empty ())
579  {
580  std::string nm = info.name;
581  std::transform (nm.begin (), nm.end (), nm.begin (), tolower);
582  match = nm.compare (0, search.length (), search) == 0;
583  }
584 
585  if (match)
586  {
587  octave_stdout << "name: " << info.name << std::endl;
588  octave_stdout << "extension: " << info.extension << std::endl;
589  octave_stdout << "id: " << info.format << std::endl;
590  octave_stdout << "subformats:" << std::endl;
591 
592  audio_sub_formats (info.format);
593  }
594  }
595 
596 #else
597 
598  octave_unused_parameter (args);
599 
600  err_disabled_feature ("audioformats",
601  "getting sound formats through libsndfile");
602 
603 #endif
604 
605  return octave_value ();
606 }
For example cd octave end example noindent changes the current working directory to file
Definition: dirfns.cc:120
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).is_integer_type())
OCTINTERP_API void print_usage(void)
Definition: defun.cc:52
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:363
intNDArray< octave_uint8 > uint8NDArray
Definition: uint8NDArray.h:33
int int_value(bool req_int=false, bool frc_str_conv=false) const
Definition: ov.h:746
void error(const char *fmt,...)
Definition: error.cc:570
std::string filename
Definition: urlwrite.cc:340
intNDArray< octave_int16 > int16NDArray
Definition: int16NDArray.h:33
octave_idx_type rows(void) const
Definition: Array.h:401
JNIEnv void * args
Definition: ov-java.cc:67
OCTAVE_EXPORT octave_value_list isdir nd deftypefn *std::string nm
Definition: utils.cc:941
void add_fcn(void(*fcn)(void))
intNDArray< octave_int8 > int8NDArray
Definition: int8NDArray.h:33
std::string string_value(bool force=false) const
Definition: ov.h:908
if(nargin< 2) print_usage()
Definition: cellfun.cc:405
int nargin
Definition: graphics.cc:10115
static int elem
Definition: __contourc__.cc:50
octave_int< T > pow(const octave_int< T > &a, const octave_int< T > &b)
Matrix transpose(void) const
Definition: dMatrix.h:129
idx type
Definition: ov.cc:3129
static std::list< std::string > search(const std::string &path, const std::string &original_name, bool all)
Definition: kpse.cc:395
Definition: dMatrix.h:37
LS_TEXT format
Definition: load-save.cc:1580
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:156
With real return the complex result
Definition: data.cc:3375
bool isinf(double x)
Definition: lo-mappers.cc:387
T & xelem(octave_idx_type n)
Definition: Array.h:455
octave::unwind_protect frame
Definition: graphics.cc:11584
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:228
intNDArray< octave_int32 > int32NDArray
Definition: int32NDArray.h:33
#define octave_stdout
Definition: pager.h:146
octave::sys::time start
Definition: graphics.cc:11731
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
void assign(const std::string &k, const octave_value &val)
Definition: oct-map.h:223
void scale(Matrix &m, double x, double y, double z)
Definition: graphics.cc:5150
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:200
ColumnVector transform(const Matrix &m, double x, double y, double z)
Definition: graphics.cc:5118
#define DEFUN_DLD(name, args_name, nargout_name, doc)
Definition: defun-dld.h:45
const T * fortran_vec(void) const
Definition: Array.h:584
octave_idx_type cols(void) const
Definition: Array.h:409
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:50
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
octave_idx_type columns(void) const
Definition: Array.h:410
OCTAVE_EXPORT octave_value_list or cell arrays Arguments are concatenated vertically The returned values are padded with blanks as needed to make each row of the string array have the same length Empty input strings are significant and will concatenated in the output For numerical each element is converted to the corresponding ASCII character A range error results if an input is outside the ASCII range(0-255).For cell arrays
T x_nint(T x)
Definition: lo-mappers.h:299
return octave_value(v1.char_array_value().concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string())? '\'': '"'))
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:205