annotate src/libsndfile-1.0.27/Octave/sndfile.cc @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents 1df64224f5ac
children
rev   line source
Chris@40 1 /*
Chris@40 2 ** Copyright (C) 2007-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
Chris@40 3 **
Chris@40 4 ** This program is free software; you can redistribute it and/or modify
Chris@40 5 ** it under the terms of the GNU Lesser General Public License as published by
Chris@40 6 ** the Free Software Foundation; either version 2.1 of the License, or
Chris@40 7 ** (at your option) any later version.
Chris@40 8 **
Chris@40 9 ** This program is distributed in the hope that it will be useful,
Chris@40 10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@40 11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@40 12 ** GNU Lesser General Public License for more details.
Chris@40 13 **
Chris@40 14 ** You should have received a copy of the GNU Lesser General Public License
Chris@40 15 ** along with this program; if not, write to the Free Software
Chris@40 16 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Chris@40 17 */
Chris@40 18
Chris@40 19 #include <octave/oct.h>
Chris@40 20
Chris@40 21 #include "sndfile.h"
Chris@40 22
Chris@40 23 #define FOUR_GIG (0x100000000LL)
Chris@40 24 #define BUFFER_FRAMES 8192
Chris@40 25
Chris@40 26
Chris@40 27 static int format_of_str (const std::string & fmt) ;
Chris@40 28 static void string_of_format (std::string & fmt, int format) ;
Chris@40 29
Chris@40 30
Chris@40 31 DEFUN_DLD (sfversion, args, nargout ,
Chris@40 32 "-*- texinfo -*-\n\
Chris@40 33 @deftypefn {Loadable Function} {@var{version} =} sfversion ()\n\
Chris@40 34 @cindex Reading sound files\n\
Chris@40 35 Return a string containing the libsndfile version.\n\
Chris@40 36 @seealso{sfread, sfwrite}\n\
Chris@40 37 @end deftypefn")
Chris@40 38 { char buffer [256] ;
Chris@40 39 octave_value_list retval ;
Chris@40 40
Chris@40 41 /* Bail out if the input parameters are bad. */
Chris@40 42 if (args.length () != 0 || nargout > 1)
Chris@40 43 { print_usage () ;
Chris@40 44 return retval ;
Chris@40 45 } ;
Chris@40 46
Chris@40 47 sf_command (NULL, SFC_GET_LIB_VERSION, buffer, sizeof (buffer)) ;
Chris@40 48
Chris@40 49 std::string version (buffer) ;
Chris@40 50
Chris@40 51 retval.append (version) ;
Chris@40 52 return retval ;
Chris@40 53 } /* sfversion */
Chris@40 54
Chris@40 55
Chris@40 56 DEFUN_DLD (sfread, args, nargout ,
Chris@40 57 "-*- texinfo -*-\n\
Chris@40 58 @deftypefn {Loadable Function} {@var{data},@var{srate},@var{format} =} sfread (@var{filename})\n\
Chris@40 59 @cindex Reading sound files\n\
Chris@40 60 Read a sound file from disk using libsndfile.\n\
Chris@40 61 @seealso{sfversion, sfwrite}\n\
Chris@40 62 @end deftypefn")
Chris@40 63 { SNDFILE * file ;
Chris@40 64 SF_INFO sfinfo ;
Chris@40 65
Chris@40 66 octave_value_list retval ;
Chris@40 67
Chris@40 68 int nargin = args.length () ;
Chris@40 69
Chris@40 70 /* Bail out if the input parameters are bad. */
Chris@40 71 if ((nargin != 1) || !args (0) .is_string () || nargout < 1 || nargout > 3)
Chris@40 72 { print_usage () ;
Chris@40 73 return retval ;
Chris@40 74 } ;
Chris@40 75
Chris@40 76 memset (&sfinfo, 0, sizeof (sfinfo)) ;
Chris@40 77
Chris@40 78 std::string filename = args (0).string_value () ;
Chris@40 79
Chris@40 80 if ((file = sf_open (filename.c_str (), SFM_READ, &sfinfo)) == NULL)
Chris@40 81 { error ("sfread: couldn't open file %s : %s", filename.c_str (), sf_strerror (NULL)) ;
Chris@40 82 return retval ;
Chris@40 83 } ;
Chris@40 84
Chris@40 85 if (sfinfo.frames > FOUR_GIG)
Chris@40 86 printf ("This is a really huge file (%lld frames).\nYou may run out of memory trying to load it.\n", (long long) sfinfo.frames) ;
Chris@40 87
Chris@40 88 dim_vector dim = dim_vector () ;
Chris@40 89 dim.resize (2) ;
Chris@40 90 dim (0) = sfinfo.frames ;
Chris@40 91 dim (1) = sfinfo.channels ;
Chris@40 92
Chris@40 93 /* Should I be using Matrix instead? */
Chris@40 94 NDArray out (dim, 0.0) ;
Chris@40 95
Chris@40 96 float buffer [BUFFER_FRAMES * sfinfo.channels] ;
Chris@40 97 int readcount ;
Chris@40 98 sf_count_t total = 0 ;
Chris@40 99
Chris@40 100 do
Chris@40 101 { readcount = sf_readf_float (file, buffer, BUFFER_FRAMES) ;
Chris@40 102
Chris@40 103 /* Make sure we don't read more frames than we allocated. */
Chris@40 104 if (total + readcount > sfinfo.frames)
Chris@40 105 readcount = sfinfo.frames - total ;
Chris@40 106
Chris@40 107 for (int ch = 0 ; ch < sfinfo.channels ; ch++)
Chris@40 108 { for (int k = 0 ; k < readcount ; k++)
Chris@40 109 out (total + k, ch) = buffer [k * sfinfo.channels + ch] ;
Chris@40 110 } ;
Chris@40 111
Chris@40 112 total += readcount ;
Chris@40 113 } while (readcount > 0 && total < sfinfo.frames) ;
Chris@40 114
Chris@40 115 retval.append (out.squeeze ()) ;
Chris@40 116
Chris@40 117 if (nargout >= 2)
Chris@40 118 retval.append ((octave_uint32) sfinfo.samplerate) ;
Chris@40 119
Chris@40 120 if (nargout >= 3)
Chris@40 121 { std::string fmt ("") ;
Chris@40 122 string_of_format (fmt, sfinfo.format) ;
Chris@40 123 retval.append (fmt) ;
Chris@40 124 } ;
Chris@40 125
Chris@40 126 /* Clean up. */
Chris@40 127 sf_close (file) ;
Chris@40 128
Chris@40 129 return retval ;
Chris@40 130 } /* sfread */
Chris@40 131
Chris@40 132 DEFUN_DLD (sfwrite, args, nargout ,
Chris@40 133 "-*- texinfo -*-\n\
Chris@40 134 @deftypefn {Function File} sfwrite (@var{filename},@var{data},@var{srate},@var{format})\n\
Chris@40 135 Write a sound file to disk using libsndfile.\n\
Chris@40 136 @seealso{sfread, sfversion}\n\
Chris@40 137 @end deftypefn\n\
Chris@40 138 ")
Chris@40 139 { SNDFILE * file ;
Chris@40 140 SF_INFO sfinfo ;
Chris@40 141
Chris@40 142 octave_value_list retval ;
Chris@40 143
Chris@40 144 int nargin = args.length () ;
Chris@40 145
Chris@40 146 /* Bail out if the input parameters are bad. */
Chris@40 147 if (nargin != 4 || !args (0).is_string () || !args (1).is_real_matrix ()
Chris@40 148 || !args (2).is_real_scalar () || !args (3).is_string ()
Chris@40 149 || nargout != 0)
Chris@40 150 { print_usage () ;
Chris@40 151 return retval ;
Chris@40 152 } ;
Chris@40 153
Chris@40 154 std::string filename = args (0).string_value () ;
Chris@40 155 std::string format = args (3).string_value () ;
Chris@40 156
Chris@40 157 memset (&sfinfo, 0, sizeof (sfinfo)) ;
Chris@40 158
Chris@40 159 sfinfo.format = format_of_str (format) ;
Chris@40 160 if (sfinfo.format == 0)
Chris@40 161 { error ("Bad format '%s'", format.c_str ()) ;
Chris@40 162 return retval ;
Chris@40 163 } ;
Chris@40 164
Chris@40 165 sfinfo.samplerate = lrint (args (2).scalar_value ()) ;
Chris@40 166 if (sfinfo.samplerate < 1)
Chris@40 167 { error ("Bad sample rate : %d.\n", sfinfo.samplerate) ;
Chris@40 168 return retval ;
Chris@40 169 } ;
Chris@40 170
Chris@40 171 Matrix data = args (1).matrix_value () ;
Chris@40 172 long rows = args (1).rows () ;
Chris@40 173 long cols = args (1).columns () ;
Chris@40 174
Chris@40 175 if (cols > rows)
Chris@40 176 { error ("Audio data should have one column per channel, but supplied data "
Chris@40 177 "has %ld rows and %ld columns.\n", rows, cols) ;
Chris@40 178 return retval ;
Chris@40 179 } ;
Chris@40 180
Chris@40 181 sfinfo.channels = cols ;
Chris@40 182
Chris@40 183 if ((file = sf_open (filename.c_str (), SFM_WRITE, &sfinfo)) == NULL)
Chris@40 184 { error ("Couldn't open file %s : %s", filename.c_str (), sf_strerror (NULL)) ;
Chris@40 185 return retval ;
Chris@40 186 } ;
Chris@40 187
Chris@40 188 float buffer [BUFFER_FRAMES * sfinfo.channels] ;
Chris@40 189 int writecount ;
Chris@40 190 long total = 0 ;
Chris@40 191
Chris@40 192 do
Chris@40 193 {
Chris@40 194 writecount = BUFFER_FRAMES ;
Chris@40 195
Chris@40 196 /* Make sure we don't read more frames than we allocated. */
Chris@40 197 if (total + writecount > rows)
Chris@40 198 writecount = rows - total ;
Chris@40 199
Chris@40 200 for (int ch = 0 ; ch < sfinfo.channels ; ch++)
Chris@40 201 { for (int k = 0 ; k < writecount ; k++)
Chris@40 202 buffer [k * sfinfo.channels + ch] = data (total + k, ch) ;
Chris@40 203 } ;
Chris@40 204
Chris@40 205 if (writecount > 0)
Chris@40 206 sf_writef_float (file, buffer, writecount) ;
Chris@40 207
Chris@40 208 total += writecount ;
Chris@40 209 } while (writecount > 0 && total < rows) ;
Chris@40 210
Chris@40 211 /* Clean up. */
Chris@40 212 sf_close (file) ;
Chris@40 213
Chris@40 214 return retval ;
Chris@40 215 } /* sfwrite */
Chris@40 216
Chris@40 217
Chris@40 218 static void
Chris@40 219 str_split (const std::string & str, const std::string & delim, std::vector <std::string> & output)
Chris@40 220 {
Chris@40 221 unsigned int offset = 0 ;
Chris@40 222 size_t delim_index = 0 ;
Chris@40 223
Chris@40 224 delim_index = str.find (delim, offset) ;
Chris@40 225
Chris@40 226 while (delim_index != std::string::npos)
Chris@40 227 {
Chris@40 228 output.push_back (str.substr(offset, delim_index - offset)) ;
Chris@40 229 offset += delim_index - offset + delim.length () ;
Chris@40 230 delim_index = str.find (delim, offset) ;
Chris@40 231 }
Chris@40 232
Chris@40 233 output.push_back (str.substr (offset)) ;
Chris@40 234 } /* str_split */
Chris@40 235
Chris@40 236 static int
Chris@40 237 hash_of_str (const std::string & str)
Chris@40 238 {
Chris@40 239 int hash = 0 ;
Chris@40 240
Chris@40 241 for (unsigned k = 0 ; k < str.length () ; k++)
Chris@40 242 hash = (hash * 3) + tolower (str [k]) ;
Chris@40 243
Chris@40 244 return hash ;
Chris@40 245 } /* hash_of_str */
Chris@40 246
Chris@40 247 static int
Chris@40 248 major_format_of_hash (const std::string & str)
Chris@40 249 { int hash ;
Chris@40 250
Chris@40 251 hash = hash_of_str (str) ;
Chris@40 252
Chris@40 253 switch (hash)
Chris@40 254 {
Chris@40 255 case 0x5c8 : /* 'wav' */ return SF_FORMAT_WAV ;
Chris@40 256 case 0xf84 : /* 'aiff' */ return SF_FORMAT_AIFF ;
Chris@40 257 case 0x198 : /* 'au' */ return SF_FORMAT_AU ;
Chris@40 258 case 0x579 : /* 'paf' */ return SF_FORMAT_PAF ;
Chris@40 259 case 0x5e5 : /* 'svx' */ return SF_FORMAT_SVX ;
Chris@40 260 case 0x1118 : /* 'nist' */ return SF_FORMAT_NIST ;
Chris@40 261 case 0x5d6 : /* 'voc' */ return SF_FORMAT_VOC ;
Chris@40 262 case 0x324a : /* 'ircam' */ return SF_FORMAT_IRCAM ;
Chris@40 263 case 0x505 : /* 'w64' */ return SF_FORMAT_W64 ;
Chris@40 264 case 0x1078 : /* 'mat4' */ return SF_FORMAT_MAT4 ;
Chris@40 265 case 0x1079 : /* 'mat5' */ return SF_FORMAT_MAT5 ;
Chris@40 266 case 0x5b8 : /* 'pvf' */ return SF_FORMAT_PVF ;
Chris@40 267 case 0x1d1 : /* 'xi' */ return SF_FORMAT_XI ;
Chris@40 268 case 0x56f : /* 'htk' */ return SF_FORMAT_HTK ;
Chris@40 269 case 0x5aa : /* 'sds' */ return SF_FORMAT_SDS ;
Chris@40 270 case 0x53d : /* 'avr' */ return SF_FORMAT_AVR ;
Chris@40 271 case 0x11d0 : /* 'wavx' */ return SF_FORMAT_WAVEX ;
Chris@40 272 case 0x569 : /* 'sd2' */ return SF_FORMAT_SD2 ;
Chris@40 273 case 0x1014 : /* 'flac' */ return SF_FORMAT_FLAC ;
Chris@40 274 case 0x504 : /* 'caf' */ return SF_FORMAT_CAF ;
Chris@40 275 case 0x5f6 : /* 'wve' */ return SF_FORMAT_WVE ;
Chris@40 276 default : break ;
Chris@40 277 } ;
Chris@40 278
Chris@40 279 printf ("%s : hash '%s' -> 0x%x\n", __func__, str.c_str (), hash) ;
Chris@40 280
Chris@40 281 return 0 ;
Chris@40 282 } /* major_format_of_hash */
Chris@40 283
Chris@40 284 static int
Chris@40 285 minor_format_of_hash (const std::string & str)
Chris@40 286 { int hash ;
Chris@40 287
Chris@40 288 hash = hash_of_str (str) ;
Chris@40 289
Chris@40 290 switch (hash)
Chris@40 291 {
Chris@40 292 case 0x1085 : /* 'int8' */ return SF_FORMAT_PCM_S8 ;
Chris@40 293 case 0x358a : /* 'uint8' */ return SF_FORMAT_PCM_U8 ;
Chris@40 294 case 0x31b0 : /* 'int16' */ return SF_FORMAT_PCM_16 ;
Chris@40 295 case 0x31b1 : /* 'int24' */ return SF_FORMAT_PCM_24 ;
Chris@40 296 case 0x31b2 : /* 'int32' */ return SF_FORMAT_PCM_32 ;
Chris@40 297 case 0x3128 : /* 'float' */ return SF_FORMAT_FLOAT ;
Chris@40 298 case 0x937d : /* 'double' */ return SF_FORMAT_DOUBLE ;
Chris@40 299 case 0x11bd : /* 'ulaw' */ return SF_FORMAT_ULAW ;
Chris@40 300 case 0xfa1 : /* 'alaw' */ return SF_FORMAT_ALAW ;
Chris@40 301 case 0xfc361 : /* 'ima_adpcm' */ return SF_FORMAT_IMA_ADPCM ;
Chris@40 302 case 0x5739a : /* 'ms_adpcm' */ return SF_FORMAT_MS_ADPCM ;
Chris@40 303 case 0x9450 : /* 'gsm610' */ return SF_FORMAT_GSM610 ;
Chris@40 304 case 0x172a3 : /* 'g721_32' */ return SF_FORMAT_G721_32 ;
Chris@40 305 case 0x172d8 : /* 'g723_24' */ return SF_FORMAT_G723_24 ;
Chris@40 306 case 0x172da : /* 'g723_40' */ return SF_FORMAT_G723_40 ;
Chris@40 307 default : break ;
Chris@40 308 } ;
Chris@40 309
Chris@40 310 printf ("%s : hash '%s' -> 0x%x\n", __func__, str.c_str (), hash) ;
Chris@40 311
Chris@40 312 return 0 ;
Chris@40 313 } /* minor_format_of_hash */
Chris@40 314
Chris@40 315
Chris@40 316 static const char *
Chris@40 317 string_of_major_format (int format)
Chris@40 318 {
Chris@40 319 switch (format & SF_FORMAT_TYPEMASK)
Chris@40 320 {
Chris@40 321 case SF_FORMAT_WAV : return "wav" ;
Chris@40 322 case SF_FORMAT_AIFF : return "aiff" ;
Chris@40 323 case SF_FORMAT_AU : return "au" ;
Chris@40 324 case SF_FORMAT_PAF : return "paf" ;
Chris@40 325 case SF_FORMAT_SVX : return "svx" ;
Chris@40 326 case SF_FORMAT_NIST : return "nist" ;
Chris@40 327 case SF_FORMAT_VOC : return "voc" ;
Chris@40 328 case SF_FORMAT_IRCAM : return "ircam" ;
Chris@40 329 case SF_FORMAT_W64 : return "w64" ;
Chris@40 330 case SF_FORMAT_MAT4 : return "mat4" ;
Chris@40 331 case SF_FORMAT_MAT5 : return "mat5" ;
Chris@40 332 case SF_FORMAT_PVF : return "pvf" ;
Chris@40 333 case SF_FORMAT_XI : return "xi" ;
Chris@40 334 case SF_FORMAT_HTK : return "htk" ;
Chris@40 335 case SF_FORMAT_SDS : return "sds" ;
Chris@40 336 case SF_FORMAT_AVR : return "avr" ;
Chris@40 337 case SF_FORMAT_WAVEX : return "wavx" ;
Chris@40 338 case SF_FORMAT_SD2 : return "sd2" ;
Chris@40 339 case SF_FORMAT_FLAC : return "flac" ;
Chris@40 340 case SF_FORMAT_CAF : return "caf" ;
Chris@40 341 case SF_FORMAT_WVE : return "wfe" ;
Chris@40 342 default : break ;
Chris@40 343 } ;
Chris@40 344
Chris@40 345 return "unknown" ;
Chris@40 346 } /* string_of_major_format */
Chris@40 347
Chris@40 348 static const char *
Chris@40 349 string_of_minor_format (int format)
Chris@40 350 {
Chris@40 351 switch (format & SF_FORMAT_SUBMASK)
Chris@40 352 {
Chris@40 353 case SF_FORMAT_PCM_S8 : return "int8" ;
Chris@40 354 case SF_FORMAT_PCM_U8 : return "uint8" ;
Chris@40 355 case SF_FORMAT_PCM_16 : return "int16" ;
Chris@40 356 case SF_FORMAT_PCM_24 : return "int24" ;
Chris@40 357 case SF_FORMAT_PCM_32 : return "int32" ;
Chris@40 358 case SF_FORMAT_FLOAT : return "float" ;
Chris@40 359 case SF_FORMAT_DOUBLE : return "double" ;
Chris@40 360 case SF_FORMAT_ULAW : return "ulaw" ;
Chris@40 361 case SF_FORMAT_ALAW : return "alaw" ;
Chris@40 362 case SF_FORMAT_IMA_ADPCM : return "ima_adpcm" ;
Chris@40 363 case SF_FORMAT_MS_ADPCM : return "ms_adpcm" ;
Chris@40 364 case SF_FORMAT_GSM610 : return "gsm610" ;
Chris@40 365 case SF_FORMAT_G721_32 : return "g721_32" ;
Chris@40 366 case SF_FORMAT_G723_24 : return "g723_24" ;
Chris@40 367 case SF_FORMAT_G723_40 : return "g723_40" ;
Chris@40 368 default : break ;
Chris@40 369 } ;
Chris@40 370
Chris@40 371 return "unknown" ;
Chris@40 372 } /* string_of_minor_format */
Chris@40 373
Chris@40 374 static int
Chris@40 375 format_of_str (const std::string & fmt)
Chris@40 376 {
Chris@40 377 std::vector <std::string> split ;
Chris@40 378
Chris@40 379 str_split (fmt, "-", split) ;
Chris@40 380
Chris@40 381 if (split.size () != 2)
Chris@40 382 return 0 ;
Chris@40 383
Chris@40 384 int major_fmt = major_format_of_hash (split.at (0)) ;
Chris@40 385 if (major_fmt == 0)
Chris@40 386 return 0 ;
Chris@40 387
Chris@40 388 int minor_fmt = minor_format_of_hash (split.at (1)) ;
Chris@40 389 if (minor_fmt == 0)
Chris@40 390 return 0 ;
Chris@40 391
Chris@40 392 return major_fmt | minor_fmt ;
Chris@40 393 } /* format_of_str */
Chris@40 394
Chris@40 395 static void
Chris@40 396 string_of_format (std::string & fmt, int format)
Chris@40 397 {
Chris@40 398 char buffer [64] ;
Chris@40 399
Chris@40 400 snprintf (buffer, sizeof (buffer), "%s-%s", string_of_major_format (format), string_of_minor_format (format)) ;
Chris@40 401
Chris@40 402 fmt = buffer ;
Chris@40 403
Chris@40 404 return ;
Chris@40 405 } /* string_of_format */