Mercurial > octave
view libinterp/dldfcn/audioread.cc @ 20939:b17fda023ca6
maint: Use new C++ archetype in more files.
Place input validation first in files.
Move declaration of retval down in function to be closer to point of usage.
Eliminate else clause after if () error.
Use "return ovl()" where it makes sense.
* find.cc, gammainc.cc, gcd.cc, getgrent.cc, getpwent.cc, givens.cc,
graphics.cc, help.cc, hess.cc, hex2num.cc, input.cc, kron.cc, load-path.cc,
load-save.cc, lookup.cc, mappers.cc, matrix_type.cc, mgorth.cc, nproc.cc,
ordschur.cc, pager.cc, pinv.cc, pr-output.cc, profiler.cc, psi.cc, quad.cc,
rcond.cc, regexp.cc, schur.cc, sighandlers.cc, sparse.cc, str2double.cc,
strfind.cc, strfns.cc, sub2ind.cc, svd.cc, sylvester.cc, symtab.cc,
syscalls.cc, sysdep.cc, time.cc, toplev.cc, tril.cc, tsearch.cc, typecast.cc,
urlwrite.cc, utils.cc, variables.cc, __delaunayn__.cc, __eigs__.cc,
__glpk__.cc, __magick_read__.cc, __osmesa_print__.cc, __voronoi__.cc, amd.cc,
audiodevinfo.cc, audioread.cc, chol.cc, colamd.cc, dmperm.cc, fftw.cc, qr.cc,
symbfact.cc, symrcm.cc, ov-bool-mat.cc, ov-cell.cc, ov-class.cc,
ov-classdef.cc, ov-fcn-handle.cc, ov-fcn-inline.cc, ov-flt-re-mat.cc,
ov-java.cc, ov-null-mat.cc, ov-oncleanup.cc, ov-re-mat.cc, ov-struct.cc,
ov-typeinfo.cc, ov-usr-fcn.cc, ov.cc, octave.cc:
Use new C++ archetype in more files.
author | Rik <rik@octave.org> |
---|---|
date | Fri, 18 Dec 2015 15:37:22 -0800 |
parents | 4a6d4375a0ca |
children | 48b2ad5ee801 |
line wrap: on
line source
/* Copyright (C) 2013-2015 Vytautas JanĨauskas This file is part of Octave. Octave is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. Octave is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Octave; see the file COPYING. If not, see <http://www.gnu.org/licenses/>. */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <string> #include <map> #include "oct-locbuf.h" #include "unwind-prot.h" #include "defun-dld.h" #include "error.h" #include "gripes.h" #include "oct-obj.h" #include "ov.h" #include "ov-struct.h" #ifdef HAVE_SNDFILE #include <sndfile.h> #endif #ifdef HAVE_SNDFILE static void safe_close (SNDFILE *file) { sf_close (file); } #endif DEFUN_DLD (audioread, args, , "-*- texinfo -*-\n\ @deftypefn {} {[@var{y}, @var{fs}] =} audioread (@var{filename})\n\ @deftypefnx {} {[@var{y}, @var{fs}] =} audioread (@var{filename}, @var{samples})\n\ \n\ @deftypefnx {} {[@var{y}, @var{fs}] =} audioread (@var{filename}, @var{datatype})\n\ @deftypefnx {} {[@var{y}, @var{fs}] =} audioread (@var{filename}, @var{samples}, @var{datatype})\n\ Read the audio file @var{filename} and return the audio data @var{y} and\n\ sampling rate @var{fs}.\n\ \n\ The audio data is stored as matrix with rows corresponding to audio frames\n\ and columns corresponding to channels.\n\ \n\ The optional two-element vector argument @var{samples} specifies starting\n\ and ending frames.\n\ \n\ The optional argument @var{datatype} specifies the datatype to return.\n\ If it is @qcode{\"native\"}, then the type of data depends on how the data\n\ is stored in the audio file.\n\ @end deftypefn") { #ifdef HAVE_SNDFILE int nargin = args.length (); if (nargin < 1 || nargin > 3) print_usage (); std::string filename = args(0).xstring_value ("audioread: FILENAME must be a string"); SF_INFO info; info.format = 0; SNDFILE *file = sf_open (filename.c_str (), SFM_READ, &info); if (! file) error ("audioread: failed to open input file %s", filename.c_str ()); unwind_protect frame; frame.add_fcn (safe_close, file); OCTAVE_LOCAL_BUFFER (float, data, info.frames * info.channels); sf_read_float (file, data, info.frames * info.channels); sf_count_t start = 0; sf_count_t end = info.frames; if ((nargin == 2 && ! args(1).is_string ()) || nargin == 3) { RowVector range = args(1).row_vector_value (); if (range.numel () != 2) error ("audioread: invalid specification for range of frames"); double dstart = xisinf (range(0)) ? info.frames : range(0); double dend = xisinf (range(1)) ? info.frames : range(1); if (dstart < 1 || dstart > dend || dend > info.frames || D_NINT (dstart) != dstart || D_NINT (dend) != dend) error ("audioread: invalid specification for range of frames"); start = dstart - 1; end = dend; } sf_count_t items = end - start; Matrix audio (items, info.channels); double *paudio = audio.fortran_vec (); data += start * info.channels; for (int i = 0; i < items; i++) { for (int channel = 0; channel < info.channels; channel++) paudio[items*channel+i] = *data++; } octave_value ret_audio; if ((nargin == 2 && args(1).is_string ()) || nargin == 3) { std::string type; if (nargin == 3) type = args(2).string_value (); else type = args(1).string_value (); if (type == "native") { switch (info.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8: ret_audio = int8NDArray (audio * 127); break; case SF_FORMAT_PCM_U8: ret_audio = uint8NDArray (audio * 127 + 127); break; case SF_FORMAT_PCM_16: ret_audio = int16NDArray (audio * 32767); break; case SF_FORMAT_PCM_24: ret_audio = int32NDArray (audio * 8388608); break; case SF_FORMAT_PCM_32: ret_audio = int32NDArray (audio * 2147483648); break; default: ret_audio = audio; break; } } else ret_audio = audio; } else ret_audio = audio; return ovl (ret_audio, info.samplerate); #else error ("sndfile not found on your system and thus audioread is not functional"); #endif } #ifdef HAVE_SNDFILE static int extension_to_format (const std::string& ext) { static bool initialized = false; static std::map<std::string, int> table; if (! initialized) { table["wav"] = SF_FORMAT_WAV; table["aiff"] = SF_FORMAT_AIFF; table["au"] = SF_FORMAT_AU; table["raw"] = SF_FORMAT_RAW; table["paf"] = SF_FORMAT_PAF; table["svx"] = SF_FORMAT_SVX; table["nist"] = SF_FORMAT_NIST; table["voc"] = SF_FORMAT_VOC; table["ircam"] = SF_FORMAT_IRCAM; table["w64"] = SF_FORMAT_W64; table["mat4"] = SF_FORMAT_MAT4; table["mat5"] = SF_FORMAT_MAT5; table["pvf"] = SF_FORMAT_PVF; table["xi"] = SF_FORMAT_XI; table["htk"] = SF_FORMAT_HTK; table["sds"] = SF_FORMAT_SDS; table["avr"] = SF_FORMAT_AVR; table["wavex"] = SF_FORMAT_WAVEX; table["sd2"] = SF_FORMAT_SD2; table["flac"] = SF_FORMAT_FLAC; table["caf"] = SF_FORMAT_CAF; table["wve"] = SF_FORMAT_WVE; table["ogg"] = SF_FORMAT_OGG; table["mpc2k"] = SF_FORMAT_MPC2K; table["rf64"] = SF_FORMAT_RF64; initialized = true; } std::map<std::string, int>::const_iterator it = table.find (ext); return (it != table.end ()) ? it->second : 0; } #endif DEFUN_DLD (audiowrite, args, , "-*- texinfo -*-\n\ @deftypefn {} {} audiowrite (@var{filename}, @var{y}, @var{fs})\n\ @deftypefnx {} {} audiowrite (@var{filename}, @var{y}, @var{fs}, @var{name}, @var{value}, @dots{})\n\ \n\ Write audio data from the matrix @var{y} to @var{filename} at sampling rate\n\ @var{fs} with the file format determined by the file extension.\n\ \n\ Additional name/value argument pairs may be used to specify the\n\ following options:\n\ \n\ @table @samp\n\ @item BitsPerSample\n\ Number of bits per sample, valid values are 8, 16, 24 and 32. Default is 16.\n\ \n\ @item BitRate\n\ Valid argument name, but ignored. Left for compatibility with @sc{matlab}.\n\ \n\ @item Quality\n\ Quality setting for the Ogg Vorbis compressor. Values can range between 0\n\ and 100 with 100 being the highest quality setting. Default is 75.\n\ \n\ @item Title\n\ Title for the audio file.\n\ \n\ @item Artist\n\ Artist name.\n\ \n\ @item Comment\n\ Comment.\n\ @end table\n\ @end deftypefn") { #ifdef HAVE_SNDFILE int nargin = args.length (); if (nargin < 3) print_usage (); std::string filename = args(0).xstring_value ("audiowrite: FILENAME must be a string"); double bias = 0.0; double scale = 1.0; if (args(1).is_uint8_type ()) bias = scale = std::pow (2.0, 7); else if (args(1).is_int16_type ()) scale = std::pow (2.0, 15); else if (args(1).is_int32_type ()) scale = std::pow (2.0, 31); else if (args(1).is_integer_type ()) { gripe_wrong_type_arg ("audiowrite", args(1)); return octave_value_list (); } Matrix audio = args(1).matrix_value (); int samplerate = args(2).int_value (); std::string ext; size_t dotpos = filename.find_last_of ("."); if (dotpos != std::string::npos) ext = filename.substr (dotpos + 1); std::transform (ext.begin (), ext.end (), ext.begin (), ::tolower); sf_count_t items_to_write = audio.rows () * audio.columns (); if (audio.rows () == 1) audio = audio.transpose (); OCTAVE_LOCAL_BUFFER (float, data, items_to_write); sf_count_t idx = 0; for (int i = 0; i < audio.rows (); i++) { for (int j = 0; j < audio.columns (); j++) { double elem = (audio.xelem (i, j) - bias) / scale; data[idx++] = std::min (std::max (elem, -1.0), 1.0); } } SF_INFO info; memset (&info, 0, sizeof (info)) ; sf_count_t chunk_size = 0; if (ext == "ogg") { info.format = SF_FORMAT_VORBIS; // FIXME: there seems to be a bug writing ogg files in one shot // that causes a segfault. Breaking it up into a series of // smaller chunks seems to avoid the problem and produce valid // files. chunk_size = 0x1FFFFE; } else info.format = SF_FORMAT_PCM_16; info.channels = audio.columns (); info.samplerate = samplerate; info.channels = audio.cols (); info.format |= extension_to_format (ext); std::string title = ""; std::string artist = ""; std::string comment = ""; // Quality is currently unused? // // float quality = 0.75; for (int i = 3; i < nargin; i += 2) { if (args(i).string_value () == "BitsPerSample") { info.format &= ~SF_FORMAT_SUBMASK; int bits = args(i + 1).int_value (); if (bits == 8) { if ((info.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV) info.format |= SF_FORMAT_PCM_U8; else info.format |= SF_FORMAT_PCM_S8; } else if (bits == 16) info.format |= SF_FORMAT_PCM_16; else if (bits == 24) info.format |= SF_FORMAT_PCM_24; else if (bits == 32) info.format |= SF_FORMAT_PCM_32; else error ("audiowrite: wrong number of bits specified"); } else if (args(i).string_value () == "BitRate") ; // Quality is currently unused? // // else if (args(i).string_value () == "Quality") // quality = args(i + 1).int_value () * 0.01; else if (args(i).string_value () == "Title") title = args(i + 1).string_value (); else if (args(i).string_value () == "Artist") artist = args(i + 1).string_value (); else if (args(i).string_value () == "Comment") comment = args(i + 1).string_value (); else error ("audiowrite: wrong argument name"); } SNDFILE *file = sf_open (filename.c_str (), SFM_WRITE, &info); if (! file) error ("audiowrite: failed to open output file %s", filename.c_str ()); unwind_protect frame; frame.add_fcn (safe_close, file); if (title != "") sf_set_string (file, SF_STR_TITLE, title.c_str ()); if (artist != "") sf_set_string (file, SF_STR_ARTIST, artist.c_str ()); if (comment != "") sf_set_string (file, SF_STR_COMMENT, comment.c_str ()); sf_count_t total_items_written = 0; sf_count_t offset = 0; if (chunk_size == 0) chunk_size = items_to_write; while (total_items_written < items_to_write) { if (items_to_write - offset < chunk_size) chunk_size = items_to_write - offset; sf_count_t items_written = sf_write_float (file, data+offset, chunk_size); if (items_written != chunk_size) error ("audiowrite: write failed, wrote %ld of %ld items\n", items_written, chunk_size); total_items_written += items_written; offset += chunk_size; } // FIXME: shouldn't we return something to indicate whether the file // was written successfully? return octave_value_list (); #else error ("sndfile not found on your system and thus audiowrite is not functional"); #endif } DEFUN_DLD (audioinfo, args, , "-*- texinfo -*-\n\ @deftypefn {} {@var{info} =} audioinfo (@var{filename})\n\ Return information about an audio file specified by @var{filename}.\n\ @end deftypefn") { #ifdef HAVE_SNDFILE if (args.length () != 1) print_usage (); std::string filename = args(0).xstring_value ("audioinfo: FILENAME must be a string"); SF_INFO info; info.format = 0; SNDFILE *file = sf_open (filename.c_str (), SFM_READ, &info); if (! file) error ("audioinfo: failed to open file %s", filename.c_str ()); unwind_protect frame; frame.add_fcn (safe_close, file); octave_scalar_map result; result.assign ("Filename", filename); result.assign ("CompressionMethod", ""); result.assign ("NumChannels", info.channels); result.assign ("SampleRate", info.samplerate); result.assign ("TotalSamples", info.frames); double dframes = info.frames; double drate = info.samplerate; result.assign ("Duration", dframes / drate); int bits; switch (info.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8: bits = 8; break; case SF_FORMAT_PCM_U8: bits = 8; break; case SF_FORMAT_PCM_16: bits = 16; break; case SF_FORMAT_PCM_24: bits = 24; break; case SF_FORMAT_PCM_32: bits = 32; break; default: bits = -1; break; } result.assign ("BitsPerSample", bits); result.assign ("BitRate", -1); result.assign ("Title", sf_get_string (file, SF_STR_TITLE)); result.assign ("Artist", sf_get_string (file, SF_STR_ARTIST)); result.assign ("Comment", sf_get_string (file, SF_STR_COMMENT)); return ovl (result); #else error ("sndfile not found on your system and thus audioinfo is not functional"); #endif }