/* Copyright (c) 2019 Dan Wilcox. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ /* soundfile formats and helper functions */ #pragma once #include "m_pd.h" #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> #endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #ifdef _WIN32 #include <io.h> #endif #include <string.h> #include <limits.h> #include <errno.h> /* GLIBC large file support */ #ifdef _LARGEFILE64_SOURCE #define lseek … # if HAVE_OFF64_T #define off_t … # else #define off_t … # endif #endif /* MSVC doesn't define or uses different naming for these Posix types */ #ifdef _MSC_VER #include <BaseTsd.h> typedef SSIZE_T ssize_t; #define off_t … #endif /* _MSC_VER */ /* choose appropriate size if SSIZE_MAX is not defined */ #ifndef SSIZE_MAX #ifdef _WIN64 #define SSIZE_MAX … #else /* _WIN32 */ #define SSIZE_MAX … #endif #endif /* SSIZE_MAX */ /** should be large enough for all file type min sizes */ #define SFHDRBUFSIZE … #define SFMAXFRAMES … #define SFMAXBYTES … /** sound file read/write debug posts */ //#define DEBUG_SOUNDFILE /* ----- soundfile ----- */ /** soundfile file descriptor, backend type, and format info note: headersize and bytelimit are signed as they are used for < 0 comparisons, hopefully ssize_t is large enough "headersize" can also be thought of as the audio data byte offset */ t_soundfile; /** clear soundfile struct to defaults, does not close or free */ void soundfile_clear(t_soundfile *sf); /** copy src soundfile info into dst */ void soundfile_copy(t_soundfile *dst, const t_soundfile *src); /** returns 1 if bytes need to be swapped due to endianness, otherwise 0 */ int soundfile_needsbyteswap(const t_soundfile *sf); /** generic soundfile errors */ t_soundfile_errno; /** returns a soundfile error string, otherwise calls C strerror */ const char* soundfile_strerror(int errnum); /* ----- soundfile type ----- */ /** returns 1 if buffer is the beginning of a supported file header, size will be at least minheadersize this may be called in a background thread */ t_soundfile_isheaderfn; /** read format info from soundfile header, returns 1 on success or 0 on error note: set sf_bytelimit = sound data size, optionally set errno this may be called in a background thread */ t_soundfile_readheaderfn; /** write header to beginning of an open file from an info struct returns header bytes written or < 0 on error note: optionally set errno this may be called in a background thread */ t_soundfile_writeheaderfn; /** update file header data size, returns 1 on success or 0 on error this may be called in a background thread */ t_soundfile_updateheaderfn; /** returns 1 if the filename has a supported file extension, otherwise 0 this may be called in a background thread */ t_soundfile_hasextensionfn; /** appends the default file extension, returns 1 on success this may be called in a background thread */ t_soundfile_addextensionfn; /** returns the type's preferred sample endianness based on the requested endianness (0 little, 1 big, -1 unspecified) and bytes per sample (-1 unspecified) returns 1 for big endian, 0 for little endian */ t_soundfile_endiannessfn; /* type implementation for a single file format */ t_soundfile_type; /** add a new type implementation returns 1 on success or 0 if max types has been reached */ int soundfile_addtype(const t_soundfile_type *t); /* ----- read/write helpers ----- */ /** seek to offset in file fd and read size bytes into dst, returns bytes written on success or -1 on failure */ ssize_t fd_read(int fd, off_t offset, void *dst, size_t size); /** seek to offset in file fd and write size bytes from dst, returns number of bytes written on success or -1 if seek or write failed */ ssize_t fd_write(int fd, off_t offset, const void *src, size_t size); /* ----- byte swappers ----- */ /** returns 1 if system is bigendian */ int sys_isbigendian(void); /** swap 8 bytes and return if doit = 1, otherwise return n */ uint64_t swap8(uint64_t n, int doit); /** swap a 64 bit signed int and return if doit = 1, otherwise return n */ int64_t swap8s(int64_t n, int doit); /** swap 4 bytes and return if doit = 1, otherwise return n */ uint32_t swap4(uint32_t n, int doit); /** swap a 32 bit signed int and return if doit = 1, otherwise return n */ int32_t swap4s(int32_t n, int doit); /** swap 2 bytes and return if doit = 1, otherwise return n */ uint16_t swap2(uint16_t n, int doit); /** swap a 4 byte string in place if doit = 1, otherwise do nothing */ void swapstring4(char *foo, int doit); /** swap an 8 byte string in place if doit = 1, otherwise do nothing */ void swapstring8(char *foo, int doit);