1# 2# Copyright (C) 2014 IRCAM 3# 4# author: Axel Roebel 5# date : 6.5.2014 6# 7# All rights reserved. 8# 9# This file is part of pysndfile. 10# 11# pysndfile is free software: you can redistribute it and/or modify 12# it under the terms of the GNU Lesser General Public License as published by 13# the Free Software Foundation, either version 3 of the License, or 14# (at your option) any later version. 15# 16# pysndfile is distributed in the hope that it will be useful, 17# but WITHOUT ANY WARRANTY; without even the implied warranty of 18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19# GNU Lesser General Public License for more details. 20# 21# You should have received a copy of the GNU Lesser General Public License 22# along with pysndfile. If not, see <http://www.gnu.org/licenses/>. 23# 24 25# cython: embedsignature=True 26# cython: language_level=2 27 28import numpy as np 29import warnings 30import os 31 32cimport numpy as cnp 33from libcpp.string cimport string 34 35cdef extern from "Python.h": 36 ctypedef int Py_intptr_t 37 38_pysndfile_version=(1, 4, 3) 39def get_pysndfile_version(): 40 """ 41 return tuple describing the version of pysndfile 42 """ 43 return _pysndfile_version 44 45 46_max_supported_string_length_tuple = ( 47 ("wav", 2040), 48 ("wavex", 2040), 49 ("aiff", 8190), 50 ("caf", 16370), 51 ) 52 53 54max_supported_string_length = dict(_max_supported_string_length_tuple) 55"""dict: the maximum length of each of the string types that can be read 56 from the various sound file formats in libsndfile is limited. 57 we ensure these limits during writing to be able to read the strings back 58""" 59 60cdef extern from "numpy/arrayobject.h": 61 void PyArray_ENABLEFLAGS(cnp.ndarray arr, int flags) 62 63 64cdef extern from "numpy/arrayobject.h": 65 ctypedef Py_intptr_t npy_intp 66 void *PyArray_DATA(cnp.ndarray arr) 67 int PyArray_NDIM(cnp.ndarray arr) 68 npy_intp* PyArray_DIMS(cnp.ndarray arr) 69 70IF UNAME_SYSNAME == "Windows": 71 cdef extern from *: 72 """ 73 #define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1 74 """ 75 76 from libc.stddef cimport wchar_t 77 78 cdef extern from "Windows.h": 79 ctypedef const wchar_t *LPCWSTR 80 81 cdef extern from "Python.h": 82 wchar_t* PyUnicode_AsWideCharString(object, Py_ssize_t *) 83 void PyMem_Free(void *p) 84 85cdef extern from "pysndfile.hh": 86 ctypedef struct SF_FORMAT_INFO: 87 int format 88 char *name 89 char *extension 90 91 ctypedef cnp.int64_t sf_count_t 92 93 struct SF_INFO: 94 sf_count_t frames 95 int channels 96 int samplerate 97 int format 98 int sections 99 int seekable 100 101 cdef struct SNDFILE : 102 pass 103 104 ctypedef struct SF_CUE_POINT: 105 int indx 106 unsigned int position 107 int fcc_chunk 108 int chunk_start 109 int block_start 110 unsigned int sample_offset 111 char name[256] 112 113 ctypedef struct SF_CUES: 114 unsigned int cue_count 115 SF_CUE_POINT cue_points[100] 116 117 cdef int sf_command(SNDFILE *sndfile, int command, void *data, int datasize) 118 cdef int sf_format_check (const SF_INFO *info) 119 cdef char *sf_error_number(int errnum) 120 121 cdef int C_SF_FORMAT_WAV "SF_FORMAT_WAV" # /* Microsoft WAV format (little endian default). */ 122 cdef int C_SF_FORMAT_AIFF "SF_FORMAT_AIFF" # /* Apple/SGI AIFF format (big endian). */ 123 cdef int C_SF_FORMAT_AU "SF_FORMAT_AU" # /* Sun/NeXT AU format (big endian). */ 124 cdef int C_SF_FORMAT_RAW "SF_FORMAT_RAW" # /* RAW PCM data. */ 125 cdef int C_SF_FORMAT_PAF "SF_FORMAT_PAF" # /* Ensoniq PARIS file format. */ 126 cdef int C_SF_FORMAT_SVX "SF_FORMAT_SVX" # /* Amiga IFF / SVX8 / SV16 format. */ 127 cdef int C_SF_FORMAT_NIST "SF_FORMAT_NIST" # /* Sphere NIST format. */ 128 cdef int C_SF_FORMAT_VOC "SF_FORMAT_VOC" # /* VOC files. */ 129 cdef int C_SF_FORMAT_IRCAM "SF_FORMAT_IRCAM" # /* Berkeley/IRCAM/CARL */ 130 cdef int C_SF_FORMAT_W64 "SF_FORMAT_W64" # /* Sonic Foundry's 64 bit RIFF/WAV */ 131 cdef int C_SF_FORMAT_MAT4 "SF_FORMAT_MAT4" # /* Matlab (tm) V4.2 / GNU Octave 2.0 */ 132 cdef int C_SF_FORMAT_MAT5 "SF_FORMAT_MAT5" # /* Matlab (tm) V5.0 / GNU Octave 2.1 */ 133 cdef int C_SF_FORMAT_PVF "SF_FORMAT_PVF" # /* Portable Voice Format */ 134 cdef int C_SF_FORMAT_XI "SF_FORMAT_XI" # /* Fasttracker 2 Extended Instrument */ 135 cdef int C_SF_FORMAT_HTK "SF_FORMAT_HTK" # /* HMM Tool Kit format */ 136 cdef int C_SF_FORMAT_SDS "SF_FORMAT_SDS" # /* Midi Sample Dump Standard */ 137 cdef int C_SF_FORMAT_AVR "SF_FORMAT_AVR" # /* Audio Visual Research */ 138 cdef int C_SF_FORMAT_WAVEX "SF_FORMAT_WAVEX" # /* MS WAVE with WAVEFORMATEX */ 139 cdef int C_SF_FORMAT_SD2 "SF_FORMAT_SD2" # /* Sound Designer 2 */ 140 cdef int C_SF_FORMAT_FLAC "SF_FORMAT_FLAC" # /* FLAC lossless file format */ 141 cdef int C_SF_FORMAT_CAF "SF_FORMAT_CAF" # /* Core Audio File format */ 142 cdef int C_SF_FORMAT_WVE "SF_FORMAT_WVE" # /* Psion WVE format */ 143 cdef int C_SF_FORMAT_OGG "SF_FORMAT_OGG" # /* Xiph OGG container */ 144 cdef int C_SF_FORMAT_MPCK "SF_FORMAT_MPC2K" # /* Akai MPC 2000 sampler */ 145 cdef int C_SF_FORMAT_RF64 "SF_FORMAT_RF64" # /* RF64 WAV file */ 146 147 #/* Subtypes from here on. */ 148 cdef int C_SF_FORMAT_PCM_S8 "SF_FORMAT_PCM_S8" # /* Signed 8 bit data */ 149 cdef int C_SF_FORMAT_PCM_16 "SF_FORMAT_PCM_16" # /* Signed 16 bit data */ 150 cdef int C_SF_FORMAT_PCM_24 "SF_FORMAT_PCM_24" # /* Signed 24 bit data */ 151 cdef int C_SF_FORMAT_PCM_32 "SF_FORMAT_PCM_32" # /* Signed 32 bit data */ 152 153 cdef int C_SF_FORMAT_PCM_U8 "SF_FORMAT_PCM_U8" # /* Unsigned 8 bit data (WAV and RAW only) */ 154 155 cdef int C_SF_FORMAT_FLOAT "SF_FORMAT_FLOAT" # /* 32 bit float data */ 156 cdef int C_SF_FORMAT_DOUBLE "SF_FORMAT_DOUBLE" # /* 64 bit float data */ 157 158 cdef int C_SF_FORMAT_ULAW "SF_FORMAT_ULAW" # /* U-Law encoded. */ 159 cdef int C_SF_FORMAT_ALAW "SF_FORMAT_ALAW" # /* A-Law encoded. */ 160 cdef int C_SF_FORMAT_IMA_ADPCM "SF_FORMAT_IMA_ADPCM" # /* IMA ADPCM. */ 161 cdef int C_SF_FORMAT_MS_ADPCM "SF_FORMAT_MS_ADPCM" # /* Microsoft ADPCM. */ 162 163 cdef int C_SF_FORMAT_GSM610 "SF_FORMAT_GSM610" # /* GSM 6.10 encoding. */ 164 cdef int C_SF_FORMAT_VOX_ADPCM "SF_FORMAT_VOX_ADPCM" # /* OKI / Dialogix ADPCM */ 165 cdef int C_SF_FORMAT_G721_32 "SF_FORMAT_G721_32" # /* 32kbs G721 ADPCM encoding. */ 166 cdef int C_SF_FORMAT_G723_24 "SF_FORMAT_G723_24" # /* 24kbs G723 ADPCM encoding. */ 167 cdef int C_SF_FORMAT_G723_40 "SF_FORMAT_G723_40" # /* 40kbs G723 ADPCM encoding. */ 168 169 cdef int C_SF_FORMAT_DWVW_12 "SF_FORMAT_DWVW_12" # /* 12 bit Delta Width Variable Word encoding. */ 170 cdef int C_SF_FORMAT_DWVW_16 "SF_FORMAT_DWVW_16" # /* 16 bit Delta Width Variable Word encoding. */ 171 cdef int C_SF_FORMAT_DWVW_24 "SF_FORMAT_DWVW_24" # /* 24 bit Delta Width Variable Word encoding. */ 172 cdef int C_SF_FORMAT_DWVW_N "SF_FORMAT_DWVW_N" # /* N bit Delta Width Variable Word encoding. */ 173 174 cdef int C_SF_FORMAT_DPCM_8 "SF_FORMAT_DPCM_8" # /* 8 bit differential PCM (XI only) */ 175 cdef int C_SF_FORMAT_DPCM_16 "SF_FORMAT_DPCM_16" # /* 16 bit differential PCM (XI only) */ 176 177 # /* Endian-ness options. */ 178 cdef int C_SF_ENDIAN_FILE "SF_ENDIAN_FILE" # /* Default file endian-ness. */ 179 cdef int C_SF_ENDIAN_LITTLE "SF_ENDIAN_LITTLE" # /* Force little endian-ness. */ 180 cdef int C_SF_ENDIAN_BIG "SF_ENDIAN_BIG" # /* Force big endian-ness. */ 181 cdef int C_SF_ENDIAN_CPU "SF_ENDIAN_CPU" # /* Force CPU endian-ness. */ 182 183 cdef int C_SF_FORMAT_SUBMASK "SF_FORMAT_SUBMASK" 184 cdef int C_SF_FORMAT_TYPEMASK "SF_FORMAT_TYPEMASK" 185 cdef int C_SF_FORMAT_ENDMASK "SF_FORMAT_ENDMASK" 186 187 # commands 188 cdef int C_SFC_GET_LIB_VERSION "SFC_GET_LIB_VERSION" 189 cdef int C_SFC_GET_LOG_INFO "SFC_GET_LOG_INFO" 190 191 cdef int C_SFC_GET_NORM_DOUBLE "SFC_GET_NORM_DOUBLE" 192 cdef int C_SFC_GET_NORM_FLOAT "SFC_GET_NORM_FLOAT" 193 cdef int C_SFC_SET_NORM_DOUBLE "SFC_SET_NORM_DOUBLE" 194 cdef int C_SFC_SET_NORM_FLOAT "SFC_SET_NORM_FLOAT" 195 cdef int C_SFC_SET_SCALE_FLOAT_INT_READ "SFC_SET_SCALE_FLOAT_INT_READ" 196 cdef int C_SFC_SET_SCALE_INT_FLOAT_WRITE "SFC_SET_SCALE_INT_FLOAT_WRITE" 197 198 cdef int C_SFC_GET_SIMPLE_FORMAT_COUNT "SFC_GET_SIMPLE_FORMAT_COUNT" 199 cdef int C_SFC_GET_SIMPLE_FORMAT "SFC_GET_SIMPLE_FORMAT" 200 201 cdef int C_SFC_GET_FORMAT_INFO "SFC_GET_FORMAT_INFO" 202 203 cdef int C_SFC_GET_FORMAT_MAJOR_COUNT "SFC_GET_FORMAT_MAJOR_COUNT" 204 cdef int C_SFC_GET_FORMAT_MAJOR "SFC_GET_FORMAT_MAJOR" 205 cdef int C_SFC_GET_FORMAT_SUBTYPE_COUNT "SFC_GET_FORMAT_SUBTYPE_COUNT" 206 cdef int C_SFC_GET_FORMAT_SUBTYPE "SFC_GET_FORMAT_SUBTYPE" 207 208 cdef int C_SFC_CALC_SIGNAL_MAX "SFC_CALC_SIGNAL_MAX" 209 cdef int C_SFC_CALC_NORM_SIGNAL_MAX "SFC_CALC_NORM_SIGNAL_MAX" 210 cdef int C_SFC_CALC_MAX_ALL_CHANNELS "SFC_CALC_MAX_ALL_CHANNELS" 211 cdef int C_SFC_CALC_NORM_MAX_ALL_CHANNELS "SFC_CALC_NORM_MAX_ALL_CHANNELS" 212 cdef int C_SFC_GET_SIGNAL_MAX "SFC_GET_SIGNAL_MAX" 213 cdef int C_SFC_GET_MAX_ALL_CHANNELS "SFC_GET_MAX_ALL_CHANNELS" 214 215 cdef int C_SFC_SET_ADD_PEAK_CHUNK "SFC_SET_ADD_PEAK_CHUNK" 216 217 cdef int C_SFC_UPDATE_HEADER_NOW "SFC_UPDATE_HEADER_NOW" 218 cdef int C_SFC_SET_UPDATE_HEADER_AUTO "SFC_SET_UPDATE_HEADER_AUTO" 219 220 cdef int C_SFC_FILE_TRUNCATE "SFC_FILE_TRUNCATE" 221 222 cdef int C_SFC_SET_RAW_START_OFFSET "SFC_SET_RAW_START_OFFSET" 223 224 cdef int C_SFC_SET_DITHER_ON_WRITE "SFC_SET_DITHER_ON_WRITE" 225 cdef int C_SFC_SET_DITHER_ON_READ "SFC_SET_DITHER_ON_READ" 226 227 cdef int C_SFC_GET_DITHER_INFO_COUNT "SFC_GET_DITHER_INFO_COUNT" 228 cdef int C_SFC_GET_DITHER_INFO "SFC_GET_DITHER_INFO" 229 230 cdef int C_SFC_GET_EMBED_FILE_INFO "SFC_GET_EMBED_FILE_INFO" 231 232 cdef int C_SFC_SET_CLIPPING "SFC_SET_CLIPPING" 233 cdef int C_SFC_GET_CLIPPING "SFC_GET_CLIPPING" 234 235 cdef int C_SFC_GET_CUE_COUNT "SFC_GET_CUE_COUNT" 236 cdef int C_SFC_GET_CUE "SFC_GET_CUE" 237 238 cdef int C_SFC_GET_INSTRUMENT "SFC_GET_INSTRUMENT" 239 cdef int C_SFC_SET_INSTRUMENT "SFC_SET_INSTRUMENT" 240 241 cdef int C_SFC_GET_LOOP_INFO "SFC_GET_LOOP_INFO" 242 243 cdef int C_SFC_GET_BROADCAST_INFO "SFC_GET_BROADCAST_INFO" 244 cdef int C_SFC_SET_BROADCAST_INFO "SFC_SET_BROADCAST_INFO" 245 246 cdef int C_SFC_WAVEX_SET_AMBISONIC "SFC_WAVEX_SET_AMBISONIC" 247 cdef int C_SFC_WAVEX_GET_AMBISONIC "SFC_WAVEX_GET_AMBISONIC" 248 249 cdef int C_SFC_RF64_AUTO_DOWNGRADE "SFC_RF64_AUTO_DOWNGRADE" 250 251 cdef int C_SFC_SET_VBR_ENCODING_QUALITY "SFC_SET_VBR_ENCODING_QUALITY" 252 cdef int C_SFC_SET_COMPRESSION_LEVEL "SFC_SET_COMPRESSION_LEVEL" 253 254 cdef int C_SF_STR_TITLE "SF_STR_TITLE" 255 cdef int C_SF_STR_COPYRIGHT "SF_STR_COPYRIGHT" 256 cdef int C_SF_STR_SOFTWARE "SF_STR_SOFTWARE" 257 cdef int C_SF_STR_ARTIST "SF_STR_ARTIST" 258 cdef int C_SF_STR_COMMENT "SF_STR_COMMENT" 259 cdef int C_SF_STR_DATE "SF_STR_DATE" 260 261 # these are the only values retrieved from the header file. So we cannot 262 # try to write/get strings that are not supported by the library we use. 263 cdef int C_SF_STR_FIRST "SF_STR_FIRST" 264 cdef int C_SF_STR_LAST "SF_STR_LAST" 265 266 cdef int C_SF_FALSE "SF_FALSE" 267 cdef int C_SF_TRUE "SF_TRUE" 268 269 # /* Modes for opening files. */ 270 cdef int C_SFM_READ "SFM_READ" 271 cdef int C_SFM_WRITE "SFM_WRITE" 272 cdef int C_SFM_RDWR "SFM_RDWR" 273 274 cdef int C_SEEK_SET "SEEK_SET" 275 cdef int C_SEEK_CUR "SEEK_CUR" 276 cdef int C_SEEK_END "SEEK_END" 277 278 cdef int C_SF_ERR_NO_ERROR "SF_ERR_NO_ERROR" 279 cdef int C_SF_ERR_UNRECOGNISED_FORMAT "SF_ERR_UNRECOGNISED_FORMAT" 280 cdef int C_SF_ERR_SYSTEM "SF_ERR_SYSTEM" 281 cdef int C_SF_ERR_MALFORMED_FILE "SF_ERR_MALFORMED_FILE" 282 cdef int C_SF_ERR_UNSUPPORTED_ENCODING "SF_ERR_UNSUPPORTED_ENCODING" 283 284 cdef int C_SF_COUNT_MAX "SF_COUNT_MAX" 285 286IF UNAME_SYSNAME == "Windows": 287 include "sndfile_win32.pxi" 288ELSE: 289 include "sndfile_linux.pxi" 290 291# these two come with more recent versions of libsndfile 292# to not break compilation they are defined outside sndfile.h 293cdef int C_SF_STR_ALBUM = 0x07 294cdef int C_SF_STR_LICENSE = 0x08 295cdef int C_SF_STR_TRACKNUMBER = 0x09 296cdef int C_SF_STR_GENRE = 0x10 297 298 299SF_MAX_CHANNELS = 1024 300"""int: maximum number if channels supported by libsndfile 1.0.28. 301""" 302 303SF_FORMAT_SUBMASK = C_SF_FORMAT_SUBMASK 304"""int: format submask to retrieve encoding from format integer. 305""" 306 307SF_FORMAT_TYPEMASK = C_SF_FORMAT_TYPEMASK 308"""int: format typemask to retrieve major file format from format integer. 309""" 310 311SF_FORMAT_ENDMASK = C_SF_FORMAT_ENDMASK 312"""int: endienness mask to retrieve endienness from format integer. 313""" 314 315_encoding_id_tuple = ( 316 ('pcms8' , C_SF_FORMAT_PCM_S8), 317 ('pcm16' , C_SF_FORMAT_PCM_16), 318 ('pcm24' , C_SF_FORMAT_PCM_24), 319 ('pcm32' , C_SF_FORMAT_PCM_32), 320 ('pcmu8' , C_SF_FORMAT_PCM_U8), 321 322 ('float32' , C_SF_FORMAT_FLOAT), 323 ('float64' , C_SF_FORMAT_DOUBLE), 324 325 ('ulaw' , C_SF_FORMAT_ULAW), 326 ('alaw' , C_SF_FORMAT_ALAW), 327 ('ima_adpcm' , C_SF_FORMAT_IMA_ADPCM), 328 ('ms_adpcm' , C_SF_FORMAT_MS_ADPCM), 329 330 ('gsm610' , C_SF_FORMAT_GSM610), 331 ('vox_adpcm' , C_SF_FORMAT_VOX_ADPCM), 332 333 ('g721_32' , C_SF_FORMAT_G721_32), 334 ('g723_24' , C_SF_FORMAT_G723_24), 335 ('g723_40' , C_SF_FORMAT_G723_40), 336 337 ('dww12' , C_SF_FORMAT_DWVW_12), 338 ('dww16' , C_SF_FORMAT_DWVW_16), 339 ('dww24' , C_SF_FORMAT_DWVW_24), 340 ('dwwN' , C_SF_FORMAT_DWVW_N), 341 342 ('dpcm8' , C_SF_FORMAT_DPCM_8), 343 ('dpcm16', C_SF_FORMAT_DPCM_16) 344 ) 345 346encoding_name_to_id = dict(_encoding_id_tuple) 347"""dict: mapping of pysndfile's encoding names to libsndfile's encoding ids. 348""" 349encoding_id_to_name = dict([(id, enc) for enc, id in _encoding_id_tuple]) 350"""dict: mapping of libsndfile's encoding ids to pysndfile's encoding names. 351""" 352 353_fileformat_id_tuple = ( 354 ('wav' , C_SF_FORMAT_WAV), 355 ('aiff' , C_SF_FORMAT_AIFF), 356 ('au' , C_SF_FORMAT_AU), 357 ('raw' , C_SF_FORMAT_RAW), 358 ('paf' , C_SF_FORMAT_PAF), 359 ('svx' , C_SF_FORMAT_SVX), 360 ('nist' , C_SF_FORMAT_NIST), 361 ('voc' , C_SF_FORMAT_VOC), 362 ('ircam', C_SF_FORMAT_IRCAM), 363 ('wav64', C_SF_FORMAT_W64), 364 ('mat4' , C_SF_FORMAT_MAT4), 365 ('mat5' , C_SF_FORMAT_MAT5), 366 ('pvf' , C_SF_FORMAT_PVF), 367 ('xi' , C_SF_FORMAT_XI), 368 ('htk' , C_SF_FORMAT_HTK), 369 ('sds' , C_SF_FORMAT_SDS), 370 ('avr' , C_SF_FORMAT_AVR), 371 ('wavex', C_SF_FORMAT_WAVEX), 372 ('sd2' , C_SF_FORMAT_SD2), 373 ('flac' , C_SF_FORMAT_FLAC), 374 ('caf' , C_SF_FORMAT_CAF), 375 ('wve' , C_SF_FORMAT_WVE), 376 ('ogg' , C_SF_FORMAT_OGG), 377 ('mpck' , C_SF_FORMAT_MPCK), 378 ('rf64' , C_SF_FORMAT_RF64), 379 ) 380 381 382#: mapping of pysndfile's major fileformat names to libsndfile's major fileformat ids. 383fileformat_name_to_id = dict (_fileformat_id_tuple) 384 385#: mapping of libsndfile's major fileformat ids to pysndfile's major fileformat names. 386fileformat_id_to_name = dict ([(id, format) for format, id in _fileformat_id_tuple]) 387 388 389_endian_to_id_tuple = ( 390 ('file' , C_SF_ENDIAN_FILE), 391 ('little' , C_SF_ENDIAN_LITTLE), 392 ('big' , C_SF_ENDIAN_BIG), 393 ('cpu' , C_SF_ENDIAN_CPU) 394 ) 395 396#: dict mapping of pysndfile's endian names to libsndfile's endian ids. 397endian_name_to_id = dict(_endian_to_id_tuple) 398#: dict mapping of libsndfile's endian ids to pysndfile's endian names. 399endian_id_to_name = dict([(id, endname) for endname, id in _endian_to_id_tuple]) 400 401_commands_to_id_tuple = ( 402 ("SFC_GET_LIB_VERSION" , C_SFC_GET_LIB_VERSION), 403 ("SFC_GET_LOG_INFO" , C_SFC_GET_LOG_INFO), 404 405 ("SFC_GET_NORM_DOUBLE" , C_SFC_GET_NORM_DOUBLE), 406 ("SFC_GET_NORM_FLOAT" , C_SFC_GET_NORM_FLOAT), 407 ("SFC_SET_NORM_DOUBLE" , C_SFC_SET_NORM_DOUBLE), 408 ("SFC_SET_NORM_FLOAT" , C_SFC_SET_NORM_FLOAT), 409 ("SFC_SET_SCALE_FLOAT_INT_READ" , C_SFC_SET_SCALE_FLOAT_INT_READ), 410 ("SFC_SET_SCALE_INT_FLOAT_WRITE" , C_SFC_SET_SCALE_INT_FLOAT_WRITE), 411 412 ("SFC_GET_SIMPLE_FORMAT_COUNT" , C_SFC_GET_SIMPLE_FORMAT_COUNT), 413 ("SFC_GET_SIMPLE_FORMAT" , C_SFC_GET_SIMPLE_FORMAT), 414 415 ("SFC_GET_FORMAT_INFO" , C_SFC_GET_FORMAT_INFO), 416 417 ("SFC_GET_FORMAT_MAJOR_COUNT" , C_SFC_GET_FORMAT_MAJOR_COUNT), 418 ("SFC_GET_FORMAT_MAJOR" , C_SFC_GET_FORMAT_MAJOR), 419 ("SFC_GET_FORMAT_SUBTYPE_COUNT" , C_SFC_GET_FORMAT_SUBTYPE_COUNT), 420 ("SFC_GET_FORMAT_SUBTYPE" , C_SFC_GET_FORMAT_SUBTYPE), 421 422 ("SFC_CALC_SIGNAL_MAX" , C_SFC_CALC_SIGNAL_MAX), 423 ("SFC_CALC_NORM_SIGNAL_MAX" , C_SFC_CALC_NORM_SIGNAL_MAX), 424 ("SFC_CALC_MAX_ALL_CHANNELS" , C_SFC_CALC_MAX_ALL_CHANNELS), 425 ("SFC_CALC_NORM_MAX_ALL_CHANNELS" , C_SFC_CALC_NORM_MAX_ALL_CHANNELS), 426 ("SFC_GET_SIGNAL_MAX" , C_SFC_GET_SIGNAL_MAX), 427 ("SFC_GET_MAX_ALL_CHANNELS" , C_SFC_GET_MAX_ALL_CHANNELS), 428 429 ("SFC_SET_ADD_PEAK_CHUNK" , C_SFC_SET_ADD_PEAK_CHUNK), 430 431 ("SFC_UPDATE_HEADER_NOW" , C_SFC_UPDATE_HEADER_NOW), 432 ("SFC_SET_UPDATE_HEADER_AUTO" , C_SFC_SET_UPDATE_HEADER_AUTO), 433 434 ("SFC_FILE_TRUNCATE" , C_SFC_FILE_TRUNCATE), 435 436 ("SFC_SET_RAW_START_OFFSET" , C_SFC_SET_RAW_START_OFFSET), 437 438 ("SFC_SET_DITHER_ON_WRITE" , C_SFC_SET_DITHER_ON_WRITE), 439 ("SFC_SET_DITHER_ON_READ" , C_SFC_SET_DITHER_ON_READ), 440 441 ("SFC_GET_DITHER_INFO_COUNT" , C_SFC_GET_DITHER_INFO_COUNT), 442 ("SFC_GET_DITHER_INFO" , C_SFC_GET_DITHER_INFO), 443 444 ("SFC_GET_EMBED_FILE_INFO" , C_SFC_GET_EMBED_FILE_INFO), 445 446 ("SFC_SET_CLIPPING" , C_SFC_SET_CLIPPING), 447 ("SFC_GET_CLIPPING" , C_SFC_GET_CLIPPING), 448 449 ("SFC_GET_INSTRUMENT" , C_SFC_GET_INSTRUMENT), 450 ("SFC_SET_INSTRUMENT" , C_SFC_SET_INSTRUMENT), 451 452 ("SFC_GET_LOOP_INFO", C_SFC_GET_LOOP_INFO), 453 454 ("SFC_GET_BROADCAST_INFO", C_SFC_GET_BROADCAST_INFO), 455 ("SFC_SET_BROADCAST_INFO", C_SFC_SET_BROADCAST_INFO), 456 457 ("SFC_WAVEX_SET_AMBISONIC", C_SFC_WAVEX_SET_AMBISONIC), 458 ("SFC_WAVEX_GET_AMBISONIC", C_SFC_WAVEX_GET_AMBISONIC), 459 ("SFC_RF64_AUTO_DOWNGRADE", C_SFC_RF64_AUTO_DOWNGRADE), 460 461 ("SFC_SET_VBR_ENCODING_QUALITY", C_SFC_SET_VBR_ENCODING_QUALITY), 462 ("SFC_SET_COMPRESSION_LEVEL", C_SFC_SET_COMPRESSION_LEVEL), 463 ) 464 465 466#:dict mapping of pysndfile's commandtype names to libsndfile's commandtype ids. 467commands_name_to_id = dict(_commands_to_id_tuple) 468#: dict mapping of libsndfile's commandtype ids to pysndfile's commandtype names. 469commands_id_to_name = dict([(id, com) for com, id in _commands_to_id_tuple]) 470 471# define these by hand so we can use here all string types known for the 472# most recent libsndfile version. STrings will be filtered according to SF_STR_LAST 473 474_stringtype_to_id_tuple = ( 475 ("SF_STR_TITLE", C_SF_STR_TITLE), 476 ("SF_STR_COPYRIGHT", C_SF_STR_COPYRIGHT), 477 ("SF_STR_SOFTWARE", C_SF_STR_SOFTWARE), 478 ("SF_STR_ARTIST", C_SF_STR_ARTIST), 479 ("SF_STR_COMMENT", C_SF_STR_COMMENT), 480 ("SF_STR_DATE", C_SF_STR_DATE), 481 ("SF_STR_ALBUM", C_SF_STR_ALBUM), 482 ("SF_STR_LICENSE", C_SF_STR_LICENSE), 483 ("SF_STR_TRACKNUMBER", C_SF_STR_TRACKNUMBER), 484 ("SF_STR_GENRE", C_SF_STR_GENRE), 485 ) 486 487#: dict mapping of pysndfile's stringtype nams to libsndfile's stringtype ids. 488stringtype_name_to_id = dict(_stringtype_to_id_tuple[:C_SF_STR_LAST+1]) 489 490#: dict mapping of libsndfile's stringtype ids to pysndfile's stringtype names. 491stringtype_id_to_name = dict([(id, com) for com, id in _stringtype_to_id_tuple[:C_SF_STR_LAST+1]]) 492 493 494def get_sndfile_version(): 495 """ 496 return a tuple of ints representing the version of libsndfile that is used 497 """ 498 cdef int status 499 cdef char buffer[256] 500 501 st = sf_command(NULL, C_SFC_GET_LIB_VERSION, buffer, 256) 502 version = buffer.decode("UTF-8") 503 504 # Get major, minor and micro from version 505 # Template: libsndfile-X.X.XpreX with preX being optional 506 version = version.split('-')[1] 507 prerelease = 0 508 major, minor, micro = [i for i in version.split('.')] 509 try: 510 micro = int(micro) 511 except ValueError,e: 512 #print "micro is " + str(micro) 513 micro, prerelease = micro.split('pre') 514 515 return int(major), int(minor), int(micro), prerelease 516 517 518def get_sndfile_encodings(major): 519 """ 520 Return lists of available encoding for the given sndfile format. 521 522 *Parameters* 523 524 :param major: (str) sndfile format for that the list of available encodings should 525 be returned. format should be specified as a string, using 526 one of the strings returned by :py:func:`get_sndfile_formats` 527 """ 528 529 # make major an id 530 if major in fileformat_id_to_name: 531 pass 532 elif major in fileformat_name_to_id: 533 major = fileformat_name_to_id[major] 534 else: 535 raise ValueError("PySndfile::File format {0} not known by PySndfile".format(str(major))) 536 537 if major not in get_sndfile_formats_from_libsndfile(): 538 raise ValueError("PySndfile::File format {0}:{1:x} not supported by libsndfile".format(fileformat_id_to_name[major], major)) 539 540 enc = [] 541 for i in _get_sub_formats_for_major(major): 542 # Handle the case where libsndfile supports an encoding we don't 543 if i not in encoding_id_to_name: 544 warnings.warn("Encoding {0:x} supported by libsndfile but not by PySndfile" 545 .format(i & C_SF_FORMAT_SUBMASK)) 546 else: 547 enc.append(encoding_id_to_name[i & C_SF_FORMAT_SUBMASK]) 548 return enc 549 550cdef _get_sub_formats_for_major(int major): 551 """ 552 Retrieve list of subtype formats or encodings given the major format specified as int. 553 554 internal function 555 556 :param major: (int) major format specified as integer, the mapping from format strings to integers 557 can be retrieved from :py:data:`fileformat_name_to_id` 558 559 :return: list of sub formats or encodings in form of integers, these integers can be converted to strings 560 by means of :py:data:`encoding_id_to_name` 561 """ 562 cdef int nsub 563 cdef int i 564 cdef SF_FORMAT_INFO info 565 cdef SF_INFO sfinfo 566 567 sf_command (NULL, C_SFC_GET_FORMAT_SUBTYPE_COUNT, &nsub, sizeof(int)) 568 569 subs = [] 570 # create a valid sfinfo struct 571 sfinfo.channels = 1 572 sfinfo.samplerate = 44100 573 for i in range(nsub): 574 info.format = i 575 sf_command (NULL, C_SFC_GET_FORMAT_SUBTYPE, &info, sizeof (info)) 576 sfinfo.format = (major & C_SF_FORMAT_TYPEMASK) | info.format 577 if sf_format_check(&sfinfo): 578 subs.append(info.format) 579 580 return subs 581 582cdef get_sndfile_formats_from_libsndfile(): 583 """ 584 retrieve list of major format ids 585 586 :return: list of strings representing all major sound formats that can be handled by the libsndfile 587 library that is used by pysndfile. 588 """ 589 cdef int nmajor 590 cdef int i 591 cdef SF_FORMAT_INFO info 592 593 sf_command (NULL, C_SFC_GET_FORMAT_MAJOR_COUNT, &nmajor, sizeof(int)) 594 595 majors = [] 596 for i in xrange(nmajor): 597 info.format = i 598 sf_command (NULL, C_SFC_GET_FORMAT_MAJOR, &info, sizeof (info)) 599 majors.append(info.format) 600 601 return majors 602 603def get_sf_log(): 604 """ 605 retrieve internal log from libsndfile, notably useful in case of errors. 606 607 :return: string representing the internal error log managed by libsndfile 608 """ 609 cdef char buf[2048] 610 sf_command (NULL, C_SFC_GET_LOG_INFO, &buf, sizeof (buf)) 611 return str(buf) 612 613def get_sndfile_formats(): 614 """ 615 Return lists of available file formats supported by libsndfile and pysndfile. 616 617 :return: list of strings representing all major sound formats that can be handled by the libsndfile 618 library and the pysndfile interface. 619 """ 620 fmt = [] 621 for i in get_sndfile_formats_from_libsndfile(): 622 # Handle the case where libsndfile supports a format we don't 623 if not i in fileformat_id_to_name: 624 warnings.warn("Format {0:x} supported by libsndfile but not " 625 "yet supported by PySndfile".format(i & C_SF_FORMAT_TYPEMASK)) 626 else: 627 fmt.append(fileformat_id_to_name[i & C_SF_FORMAT_TYPEMASK]) 628 return fmt 629 630cdef class PySndfile: 631 """\ 632 PySndfile is a python class for reading/writing audio files. 633 634 PySndfile is proxy for the SndfileHandle class in sndfile.hh 635 Once an instance is created, it can be used to read and/or write 636 data from/to numpy arrays, query the audio file meta-data, etc... 637 638 :param filename: <string or int> name of the file to open (string), or file descriptor (integer) 639 :param mode: <string> 'r' for read, 'w' for write, or 'rw' for read and write. 640 :param format: <int> Required when opening a new file for writing, or to read raw audio files (without header). 641 See function :py:meth:`construct_format`. 642 :param channels: <int> number of channels. 643 :param samplerate: <int> sampling rate. 644 645 :return: valid PySndfile instance. An IOError exception is thrown if any error is 646 encountered in libsndfile. A ValueError exception is raised if the arguments are invalid. 647 648 *Notes* 649 650 * the files will be opened with auto clipping set to True 651 see the member set_autoclipping for more information. 652 * the soundfile will be closed when the class is destroyed 653 * format, channels and samplerate need to be given only 654 in the write modes and for raw files. 655 """ 656 657 cdef SndfileHandle *thisPtr 658 cdef int fd 659 cdef string filename 660 def __cinit__(self, filename, mode='r', int format=0, 661 int channels=0, int samplerate=0, *args, **kwrds): 662 cdef int sfmode 663 cdef const char*cfilename 664 cdef int fh 665 666 IF UNAME_SYSNAME == "Windows": 667 cdef Py_ssize_t length 668 cdef wchar_t *my_wchars 669 670 # -1 will indicate that the file has been open from filename, not from 671 # file descriptor 672 self.fd = -1 673 self.thisPtr = NULL 674 675 if channels > SF_MAX_CHANNELS: 676 raise ValueError( "PySndfile:: max number of channels exceeded {} > {}!".format(channels, SF_MAX_CHANNELS)) 677 678 # Check the mode is one of the expected values 679 if mode == 'r': 680 sfmode = C_SFM_READ 681 elif mode == 'w': 682 sfmode = C_SFM_WRITE 683 if format is 0: 684 raise ValueError( "PySndfile::opening for writing requires a format argument !") 685 elif mode == 'rw': 686 sfmode = C_SFM_RDWR 687 if format is 0: 688 raise ValueError( "PySndfile::opening for writing requires a format argument !") 689 else: 690 raise ValueError("PySndfile::mode {0} not recognized".format(str(mode))) 691 692 self.fd = -1 693 if isinstance(filename, int): 694 fh = filename 695 self.thisPtr = new SndfileHandle(fh, 0, sfmode, format, channels, samplerate) 696 self.filename = b"" 697 self.fd = filename 698 else: 699 filename = os.path.expanduser(filename) 700 701 IF UNAME_SYSNAME == "Windows": 702 # Need to get the wchars before filename is converted to utf-8 703 my_wchars = PyUnicode_AsWideCharString(filename, &length) 704 705 if isinstance(filename, unicode): 706 filename = bytes(filename, "UTF-8") 707 self.filename = filename 708 709 IF UNAME_SYSNAME == "Windows": 710 if length > 0: 711 self.thisPtr = new SndfileHandle(my_wchars, sfmode, format, channels, samplerate) 712 PyMem_Free(my_wchars) 713 else: 714 raise RuntimeError("PySndfile::error while converting {0} into wchars".format(filename)) 715 ELSE: 716 self.thisPtr = new SndfileHandle(self.filename.c_str(), sfmode, format, channels, samplerate) 717 718 719 if self.thisPtr == NULL or self.thisPtr.rawHandle() == NULL: 720 raise IOError("PySndfile::error while opening {0}\n\t->{1}".format(self.filename, 721 self.thisPtr.strError())) 722 723 self.set_auto_clipping(True) 724 725 # supoort use as context manager 726 def __enter__(self): 727 return self 728 729 def __exit__(self, *args): 730 self.close() 731 732 def get_name(self): 733 """ 734 :return: <str> filename that was used to open the underlying sndfile 735 """ 736 return self.filename 737 738 def __dealloc__(self): 739 self.close() 740 741 def close(self): 742 """ 743 Closes file and deallocates internal structures 744 """ 745 if self.thisPtr != NULL and self.thisPtr: 746 del self.thisPtr 747 self.thisPtr = NULL 748 749 def command(self, command, arg=0) : 750 """ 751 interface for passing commands via sf_command to underlying soundfile 752 using sf_command(this_sndfile, command_id, NULL, arg) 753 754 :param command: <string or int> 755 libsndfile command macro to be used. They can be specified either as string using the command macros name, or the command id. 756 757 Supported commands are: 758 759| SFC_SET_NORM_FLOAT 760| SFC_SET_NORM_DOUBLE 761| SFC_GET_NORM_FLOAT 762| SFC_GET_NORM_DOUBLE 763| SFC_SET_SCALE_FLOAT_INT_READ 764| SFC_SET_SCALE_INT_FLOAT_WRITE 765| SFC_SET_ADD_PEAK_CHUNK 766| SFC_UPDATE_HEADER_NOW 767| SFC_SET_UPDATE_HEADER_AUTO 768| SFC_SET_CLIPPING (see :py:func:`pysndfile.PySndfile.set_auto_clipping`) 769| SFC_GET_CLIPPING (see :py:func:`pysndfile.PySndfile.set_auto_clipping`) 770| SFC_WAVEX_GET_AMBISONIC 771| SFC_WAVEX_SET_AMBISONIC 772| SFC_RAW_NEEDS_ENDSWAP 773 774 :param arg: <int> additional argument of the command 775 776 :return: <int> 1 for success or True, 0 for failure or False 777 """ 778 if isinstance(command, str) : 779 return self.thisPtr.command(commands_name_to_id[command], NULL, arg) 780 # so we suppose it is an int 781 return self.thisPtr.command(command, NULL, arg) 782 783 784 def set_auto_clipping( self, arg = True) : 785 """ 786 enable auto clipping when reading/writing samples from/to sndfile. 787 788 auto clipping is enabled by default. 789 auto clipping is required by libsndfile to properly handle scaling between sndfiles with pcm encoding and float representation of the samples in numpy. 790 When auto clipping is set to on reading pcm data into a float vector and writing it back with libsndfile will reproduce 791 the original samples. If auto clipping is off, samples will be changed slightly as soon as the amplitude is close to the 792 sample range because libsndfile applies slightly different scaling factors during read and write. 793 794 :param arg: <bool> indicator of the desired clipping state 795 796 :return: <int> 1 for success, 0 for failure 797 """ 798 if self.thisPtr == NULL or not self.thisPtr: 799 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 800 return self.thisPtr.command(C_SFC_SET_CLIPPING, NULL, arg); 801 802 def writeSync(self): 803 """ 804 call the operating system's function to force the writing of all 805 file cache buffers to disk the file. 806 807 No effect if file is open as read 808 """ 809 if self.thisPtr == NULL or not self.thisPtr: 810 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 811 self.thisPtr.writeSync() 812 813 814 def __str__( self): 815 if self.thisPtr == NULL or not self.thisPtr: 816 return "invalid sndfile" 817 repstr = ["----------------------------------------"] 818 if not self.fd == -1: 819 repstr += ["File : %d (opened by file descriptor)" % self.fd] 820 else: 821 repstr += ["File : %s" % self.filename.decode("UTF-8")] 822 repstr += ["Channels : %d" % self.thisPtr.channels()] 823 repstr += ["Sample rate : %d" % self.thisPtr.samplerate()] 824 repstr += ["Frames : %d" % self.thisPtr.frames()] 825 repstr += ["Raw Format : %#010x" % self.thisPtr.format()] 826 repstr += ["File format : %s" % fileformat_id_to_name[self.thisPtr.format()& C_SF_FORMAT_TYPEMASK]] 827 repstr += ["Encoding : %s" % encoding_id_to_name[self.thisPtr.format()& C_SF_FORMAT_SUBMASK]] 828 #repstr += ["Endianness : %s" % ] 829 #repstr += "Sections : %d\n" % self._sfinfo.sections 830 repstr += ["Seekable : %s\n" % self.thisPtr.seekable()] 831 #repstr += "Duration : %s\n" % self._generate_duration_str() 832 return "\n".join(repstr) 833 834 835 def read_frames(self, sf_count_t nframes=-1, dtype=np.float64, force_2d = False, fill_value=None, min_read=0): 836 """ 837 Read the given number of frames and put the data into a numpy array of 838 the requested dtype. 839 840 :param nframes: number of frames to read (default = -1 -> read all). 841 :type nframes: int 842 :param dtype: data type of the returned array containing read data (see note). 843 :type dtype: numpy.dtype 844 :param force_2d: always return 2D arrays even if file is mono 845 :type force_2d: bool 846 :param fill_value: value to use for filling frames in case nframes is larger than the file 847 :type fill_value: any tye that can be assigned to an array containing dtype 848 :param min_read: when fill_value is not None and EOFError will be thrown when the number 849 of read sample frames is equal to or lower than this value 850 :return: np.array<dtype> with sound data 851 852 *Notes* 853 854 * One column per channel. 855 856 """ 857 if self.thisPtr == NULL or not self.thisPtr: 858 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 859 860 if nframes < 0 : 861 whence = C_SEEK_CUR | C_SFM_READ 862 pos = self.thisPtr.seek(0, whence) 863 nframes = self.thisPtr.frames() - pos 864 if dtype == np.float64: 865 y = self.read_frames_double(nframes, fill_value=fill_value, min_read=min_read) 866 elif dtype == np.float32: 867 y = self.read_frames_float(nframes, fill_value=fill_value, min_read=min_read) 868 elif dtype == np.int32: 869 y = self.read_frames_int(nframes, fill_value=fill_value, min_read=min_read) 870 elif dtype == np.int16: 871 y = self.read_frames_short(nframes, fill_value=fill_value, min_read=min_read) 872 else: 873 raise RuntimeError("Sorry, dtype %s not supported" % str(dtype)) 874 875 if y.shape[1] == 1 and not force_2d: 876 y.shape = (y.shape[0],) 877 return y 878 879 cdef read_frames_double(self, sf_count_t nframes, fill_value=None, min_read=0): 880 cdef sf_count_t res 881 cdef cnp.ndarray[cnp.float64_t, ndim=2] ty = np.empty((nframes, self.thisPtr.channels()), 882 dtype=np.float64, order='C') 883 884 res = self.thisPtr.readf(<double*> PyArray_DATA(ty), nframes) 885 if not res == nframes: 886 if fill_value is None: 887 raise RuntimeError("Asked %d frames, read %d" % (nframes, res)) 888 elif res <= min_read: 889 raise EOFError() 890 else: 891 ty[res:,:] = fill_value 892 return ty 893 894 cdef read_frames_float(self, sf_count_t nframes, fill_value=None, min_read=0): 895 cdef sf_count_t res 896 # Use C order to cope with interleaving 897 cdef cnp.ndarray[cnp.float32_t, ndim=2] ty = np.empty((nframes, self.thisPtr.channels()), 898 dtype=np.float32, order='C') 899 900 res = self.thisPtr.readf(<float*>PyArray_DATA(ty), nframes) 901 if not res == nframes: 902 if fill_value is None: 903 raise RuntimeError("Asked %d frames, read %d" % (nframes, res)) 904 elif res <= min_read: 905 raise EOFError() 906 else: 907 ty[res:,:] = fill_value 908 return ty 909 910 cdef read_frames_int(self, sf_count_t nframes, fill_value=None, min_read=0): 911 cdef sf_count_t res 912 # Use C order to cope with interleaving 913 cdef cnp.ndarray[cnp.int32_t, ndim=2] ty = np.empty((nframes, self.thisPtr.channels()), 914 dtype=np.int32, order='C') 915 916 res = self.thisPtr.readf(<int*>PyArray_DATA(ty), nframes) 917 if not res == nframes: 918 if fill_value is None: 919 raise RuntimeError("Asked %d frames, read %d" % (nframes, res)) 920 elif res <= min_read: 921 raise EOFError() 922 else: 923 ty[res:,:] = fill_value 924 return ty 925 926 cdef read_frames_short(self, sf_count_t nframes, fill_value=None, min_read=0): 927 cdef sf_count_t res 928 # Use C order to cope with interleaving 929 cdef cnp.ndarray[cnp.int16_t, ndim=2] ty = np.empty((nframes, self.thisPtr.channels()), 930 dtype=np.short, order='C') 931 932 res = self.thisPtr.readf(<short*>PyArray_DATA(ty), nframes) 933 if res < nframes: 934 if fill_value is None: 935 raise RuntimeError("Asked %d frames, read %d" % (nframes, res)) 936 elif res <= min_read: 937 raise EOFError() 938 else: 939 ty[res:,:] = fill_value 940 return ty 941 942 def write_frames(self, cnp.ndarray input): 943 """ 944 write 1 or 2 dimensional array into sndfile. 945 946 :param input: <numpy array> 947 containing data to write. 948 949 :return: int representing the number of frames that have been written 950 951 *Notes* 952 * One column per channel. 953 * updates the write pointer. 954 * if the input type is float, and the file encoding is an integer type, 955 you should make sure the input data are normalized normalized data 956 (that is in the range [-1..1] - which will corresponds to the maximum 957 range allowed by the integer bitwidth). 958 """ 959 cdef int nc 960 cdef sf_count_t nframes 961 962 if self.thisPtr == NULL or not self.thisPtr: 963 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 964 965 # First, get the number of channels and frames from input 966 if PyArray_NDIM(input) == 2: 967 nc = PyArray_DIMS(input)[1] 968 nframes = input.size / nc 969 elif PyArray_NDIM(input) == 1: 970 nc = 1 971 input = input[:, None] 972 nframes = input.size 973 else: 974 raise ValueError("PySndfile::write_frames::error cannot handle arrays of {0:d} dimensions, please restrict to 2 dimensions".format(PyArray_NDIM(input))) 975 976 # Number of channels should be the one expected 977 if not nc == self.thisPtr.channels(): 978 raise ValueError("Expected %d channels, got %d" % 979 (self.thisPtr.channels(), nc)) 980 981 input = np.require(input, requirements = 'C') 982 983 if input.dtype == np.float64: 984 if (self.thisPtr.format() & C_SF_FORMAT_SUBMASK) not in [C_SF_FORMAT_FLOAT, C_SF_FORMAT_DOUBLE]: 985 if (np.max(np.abs(input.flat)) > 1.) : 986 warnings.warn("write_frames::warning::audio data has been clipped while writing to file {0}.".format(self.filename.decode("UTF-8"))) 987 res = self.thisPtr.writef(<double*>PyArray_DATA(input), nframes) 988 elif input.dtype == np.float32: 989 if (self.thisPtr.format() & C_SF_FORMAT_SUBMASK) not in [C_SF_FORMAT_FLOAT, C_SF_FORMAT_DOUBLE]: 990 if (np.max(np.abs(input.flat)) > 1.) : 991 warnings.warn("write_frames::warning::audio data has been clipped while writing to file {0}.".format(self.filename.decode("UTF-8"))) 992 res = self.thisPtr.writef(<float*>PyArray_DATA(input), nframes) 993 elif input.dtype == np.int32: 994 res = self.thisPtr.writef(<int*>PyArray_DATA(input), nframes) 995 elif input.dtype == np.short: 996 res = self.thisPtr.writef(<short*>PyArray_DATA(input), nframes) 997 else: 998 raise RuntimeError("type of input {0} not understood".format(str(input.dtype))) 999 1000 if not(res == nframes): 1001 raise IOError("write_frames::error::wrote {0:d} frames, expected to write {1:d}".format(res, nframes)) 1002 1003 return res 1004 1005 def format(self) : 1006 """ 1007 :return: <int> raw format specification that was used to create the present PySndfile instance. 1008 """ 1009 if self.thisPtr == NULL or not self.thisPtr: 1010 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 1011 return self.thisPtr.format() 1012 1013 def major_format_str(self) : 1014 """ 1015 1016 :return: short string representation of major format (e.g. aiff) 1017 1018 see :py:func:`pysndfile.get_sndfile_formats` for a complete lst of fileformats 1019 1020 """ 1021 if self.thisPtr == NULL or not self.thisPtr: 1022 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 1023 return fileformat_id_to_name[self.thisPtr.format() & C_SF_FORMAT_TYPEMASK] 1024 1025 def encoding_str(self) : 1026 """ 1027 :return: string representation of encoding (e.g. pcm16) 1028 1029 see :py:func:`pysndfile.get_sndfile_encodings` for a list of 1030 available encoding strings that are supported by a given sndfile format 1031 """ 1032 if self.thisPtr == NULL or not self.thisPtr: 1033 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 1034 return encoding_id_to_name[self.thisPtr.format() & C_SF_FORMAT_SUBMASK] 1035 1036 def channels(self) : 1037 """ 1038 :return: <int> number of channels of sndfile 1039 """ 1040 if self.thisPtr == NULL or not self.thisPtr: 1041 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 1042 return self.thisPtr.channels() 1043 1044 def frames(self) : 1045 """ 1046 :return: <int> number for frames (number of samples per channel) 1047 """ 1048 if self.thisPtr == NULL or not self.thisPtr: 1049 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 1050 return self.thisPtr.frames() 1051 1052 def samplerate(self) : 1053 """ 1054 :return: <int> samplerate 1055 """ 1056 if self.thisPtr == NULL or not self.thisPtr: 1057 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 1058 return self.thisPtr.samplerate() 1059 1060 def seekable(self) : 1061 """ 1062 :return: <bool> true for soundfiles that support seeking 1063 """ 1064 if self.thisPtr == NULL or not self.thisPtr: 1065 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 1066 return self.thisPtr.seekable() 1067 1068 def get_strings(self) : 1069 """ 1070 get all stringtypes from the sound file. 1071 1072 see :py:data:`stringtype_name_to_id` for the list of strings that are supported 1073 by the libsndfile version you use. 1074 1075 """ 1076 cdef const char* string_value 1077 if self.thisPtr == NULL or not self.thisPtr: 1078 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 1079 1080 str_dict = {} 1081 for ii in xrange(C_SF_STR_FIRST, C_SF_STR_LAST): 1082 string_value = self.thisPtr.getString(ii) 1083 if string_value != NULL: 1084 str_dict[stringtype_id_to_name[ii]] = string_value 1085 1086 return str_dict 1087 1088 def set_string(self, stringtype_name, string) : 1089 """ 1090 set one of the stringtype to the string given as argument. 1091 If you try to write a stringtype that is not supported by the library 1092 a RuntimeError will be raised 1093 If you try to write a string with length exceeding the length that 1094 can be read by libsndfile version 1.0.28 a RuntimeError will be raised as well 1095 these limits are stored in the dict max_supported_string_length. 1096 """ 1097 cdef int res = 0 1098 1099 if self.thisPtr == NULL or not self.thisPtr: 1100 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 1101 if stringtype_name not in stringtype_name_to_id : 1102 raise RuntimeError("PySndfile::error::set_string called with an unsupported stringtype:{0}".format(stringtype_name)) 1103 1104 my_format = self.major_format_str() 1105 if my_format in max_supported_string_length : 1106 if len(string)> max_supported_string_length[my_format]: 1107 raise RuntimeError("pysndfile::set_string::your string to be written into {} has length {} exceeding the length of strings ({}) supported for reading in libsndfile 1.0.28".format(stringtype_name, len(string), max_supported_string_length[my_format])) 1108 res = self.thisPtr.setString(stringtype_name_to_id[stringtype_name], string) 1109 if res : 1110 raise RuntimeError("PySndfile::error::setting string of type {0}\nerror messge is:{1}".format(stringtype_name, sf_error_number(res))) 1111 1112 def set_strings(self, sf_strings_dict) : 1113 """ 1114 set all strings provided as key value pairs in sf_strings_dict. 1115 If you try to write a stringtype that is not supported by the library 1116 a RuntimeError will be raised. 1117 If you try to write a string with length exceeding the length that 1118 can be read by libsndfile version 1.0.28 a RuntimeError will be raised as well 1119 these limits are stored in the dict max_supported_string_length. 1120 """ 1121 for kk in sf_strings_dict: 1122 self.set_string(kk, sf_strings_dict[kk]) 1123 1124 def get_cue_count(self): 1125 """ 1126 get number of cue markers. 1127 1128 1129 """ 1130 # get number of cue mrks that are present in the file 1131 1132 res = self.thisPtr.get_cue_count() 1133 return res 1134 1135 def get_cue_mrks(self) : 1136 """ 1137 get all cue markers. 1138 1139 Gets list of tuple of positions and related names of embedded markers for aiff and wav files, 1140 due to a limited support of cue names in libsndfile cue names are not retrieved for wav files. 1141 1142 """ 1143 # get number of cue mrks that are present in the file 1144 cdef SF_CUES sf_cues 1145 1146 res = self.thisPtr.command(C_SFC_GET_CUE, &sf_cues, sizeof(sf_cues)) 1147 if res == 0: 1148 return [] 1149 1150 mrks = [] 1151 for ii in range(sf_cues.cue_count): 1152 mrks.append((sf_cues.cue_points[ii].sample_offset, sf_cues.cue_points[ii].name.decode("ASCII"))) 1153 1154 return mrks 1155 1156 1157 def error(self) : 1158 """ 1159 report error numbers related to the current sound file 1160 """ 1161 if self.thisPtr == NULL or not self.thisPtr: 1162 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 1163 return self.thisPtr.error() 1164 def strError(self) : 1165 """ 1166 report error strings related to the current sound file 1167 """ 1168 if self.thisPtr == NULL or not self.thisPtr: 1169 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 1170 return self.thisPtr.strError() 1171 1172 def seek(self, sf_count_t offset, int whence=C_SEEK_SET, mode='rw'): 1173 """ 1174 Seek into audio file: similar to python seek function, taking only in 1175 account audio data. 1176 1177 :param offset: <int> 1178 the number of frames (eg two samples for stereo files) to move 1179 relatively to position set by whence. 1180 :param whence: <int> 1181 only 0 (beginning), 1 (current) and 2 (end of the file) are 1182 valid. 1183 :param mode: <string> 1184 If set to 'rw', both read and write pointers are updated. If 1185 'r' is given, only read pointer is updated, if 'w', only the 1186 write one is (this may of course make sense only if you open 1187 the file in a certain mode). 1188 1189 :return: <int> the number of frames from the beginning of the file 1190 1191 *Notes* 1192 1193 * Offset relative to audio data: meta-data are ignored. 1194 1195 * if an invalid seek is given (beyond or before the file), an IOError is 1196 raised; note that this is different from the seek method of a File object. 1197 1198 """ 1199 1200 if self.thisPtr == NULL or not self.thisPtr: 1201 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 1202 1203 cdef sf_count_t pos 1204 if mode == 'rw': 1205 # Update both read and write pointers 1206 pos = self.thisPtr.seek(offset, whence) 1207 elif mode == 'r': 1208 whence = whence | C_SFM_READ 1209 pos = self.thisPtr.seek(offset, whence) 1210 elif mode == 'w': 1211 whence = whence | C_SFM_WRITE 1212 pos = self.thisPtr.seek(offset, whence) 1213 else: 1214 raise ValueError("mode should be one of 'r', 'w' or 'rw' only") 1215 1216 if pos == -1: 1217 msg = "libsndfile error during seek:: {0}".format(self.thisPtr.strError()) 1218 raise IOError(msg) 1219 return pos 1220 1221 def rewind(self, mode="rw") : 1222 """\ 1223 rewind read/write/read and write position given by mode to start of file 1224 """ 1225 cdef sf_count_t pos 1226 cdef int whence = C_SEEK_SET 1227 1228 if self.thisPtr == NULL or not self.thisPtr: 1229 raise RuntimeError("PySndfile::error::no valid soundfilehandle") 1230 1231 if mode == 'rw': 1232 # Update both read and write pointers 1233 pos = self.thisPtr.seek(0, whence) 1234 elif mode == 'r': 1235 whence = whence | C_SFM_READ 1236 pos = self.thisPtr.seek(0, whence) 1237 elif mode == 'w': 1238 whence = whence | C_SFM_WRITE 1239 pos = self.thisPtr.seek(0, whence) 1240 else: 1241 raise ValueError("mode should be one of 'r', 'w' or 'rw' only") 1242 1243 if pos == -1: 1244 msg = "libsndfile error while rewinding:: {0}".format(self.thisPtr.strError()) 1245 raise IOError(msg) 1246 return pos 1247 1248cdef _construct_format(major, encoding) : 1249 """ 1250 construct a format specification for libsndfile from major format string and encoding string 1251 """ 1252 cdef int major_id = fileformat_name_to_id[major] 1253 cdef int enc_id = encoding_name_to_id[encoding] 1254 return major_id | enc_id 1255 1256def construct_format(major, encoding) : 1257 """ 1258 construct a format specification for libsndfile from major format string and encoding string 1259 """ 1260 return _construct_format(major, encoding) 1261 1262