/* * Copyright (c) 1983-2013 Martin Atkins, Richard Dobson and Composers Desktop Project Ltd * http://people.bath.ac.uk/masrwd * http://www.composersdesktop.com * This file is part of the CDP System. The CDP System is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The CDP System 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the CDP System; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* * Sound Filing System - Buffered sound system, open/close, etc. * * Portable version * * Copyright M. C. Atkins, 1986, 1987, 1993; RWD 2007,2014 * All Rights Reserved. */ /* RWD: old sfsys functions DEPRECATED and emptied */ /* RWD Dec 2019 fixed SndCloseEx for int64 comps */ #ifdef _DEBUG #include #endif #include #include #include #include #include "sffuncs.h" #ifdef _WIN32 #ifdef _MSC_VER static __inline int cdp_round(double fval) { int result; _asm{ fld fval fistp result mov eax,result /* RWD: need this line? */ } return result; } #else # ifndef __GNUWIN32__ static int cdp_round(double val) { int k; k = (int)(fabs(val)+0.5); if(val < 0.0) k = -k; return k; } # endif #endif #endif /* * This is the main structure describing a procom file */ struct sndfile { int flags; /* various flags */ int fd; /* SFfile/gemfile file descripter */ char *buffer; /* pointer to the buffer */ char *next; /* next entry in buffer to access */ int bufsiz; /* the size of the buffer (in sectors) */ int remain; /* number of samples remaining in buffer */ char *endbuf; /* end of buffer (for short bufs at eof) */ int samptype; /* the type of samples in the file */ int lastread; /* number of bytes obtained from last read */ /* CDP97*/ int true_bufsize; /*for 24bit alignment, etc: adjust buffer downwards*/ int scale_floats; double fscalefac; }; typedef union { int lsamp; /*float fsamp; //any use for this? */ unsigned char bytes[4]; } SND_SAMP; /* * values for sndfile.flags */ #define SNDFLG_WRITTEN (1) /* the buffer must be flushed back to disk */ #define SNDFLG_LASTWR (4) /* last i/o was a write (for sndtell) */ #define SNDFLG_TRUNC (8) /* truncate when closed */ #define SNDFLG_USERBUF (32) /* the buffer was supplied by the user */ #define SNDFLG_ATEND (64) /* the last i/o went over the end of the file */ /* * Various constants/global data */ #define SNDFDBASE (4000) /* sndfd's allocated from here */ #define SNDBUFSIZE (64) /* * global storage */ /* * The array of open sndfiles */ static struct sndfile *sndfiles[MAXSNDFILES]; /* * mapping table from sample type, to size */ /* the possible sample types are now: SAMP_SHORT (0) * 16-bit short integers * SAMP_FLOAT (1) * 32-bit (IEEE) floating point * SAMP_BYTE (2) //recognize 8bit soundfiles? SAMP_LONG (3) // four most likely formats SAMP_2424 (4) SAMP_2432 (5) SAMP_2024 (6) SAMP_MASKED (7) //some weird WAVE_EX format! */ /*RWD.6.99 set this as container-size *private, but sfsys.c needs to have it */ int sampsize[] = { /* SAMP_SHORT */ sizeof(short), /* SAMP_FLOAT */ sizeof(float), /* SAMP_BYTE */ sizeof(unsigned char), /* SAMP_LONG */ sizeof(int), /* SAMP_2424 */ 3 * sizeof(unsigned char), /* SAMP_2432 */ sizeof(int), /* SAMP_2024 */ 3 * sizeof(unsigned char), /* dummy */ 0 /*for masked formats, have to calc from 1st principles...*/ }; /* * Utility routines */ #define getmem(type) ((type *)malloc(sizeof(type))) extern int _rsf_getmaxpeak(int sfd,float *peak); extern int _rsf_getbitmask(int sfd); /* * initialisation/termination routines */ static void rsndallclose(void) { int fd; for(fd = 0; fd < MAXSFNAME; fd++) if(sndfiles[fd] != 0) sndclose(fd + SNDFDBASE); } static void rsndinit() { register int fd; static int inited = 0; if(inited != 0) return; inited++; for(fd = 0; fd < MAXSFNAME; fd++) sndfiles[fd] = 0; atexit(rsndallclose); } /* * map a sndfd onto a sndfiles index, * return 0 on failure */ /*RWD I want a public version of this, for use in ASSERT etc*/ static int mapsndfd(int *sfdp) { *sfdp -= SNDFDBASE; if(*sfdp < 0 || *sfdp >= MAXSNDFILES) { rsferrno = ESFBADADDR; rsferrstr = "sfd is not in valid range"; return 0; } if(sndfiles[*sfdp] == 0) { rsferrno = ESFNOTOPEN; rsferrstr = "sndfile is not open (bad sndfd)"; return 0; } return 1; } /* * do the underlying seek * NOTE * seeks to the end of an sffile are rounded down!! */ static long doseek(struct sndfile *sf, long dist, int whence) { return sfseek(sf->fd, dist, whence); } #ifdef FILE64_WIN static __int64 doseekEx(struct sndfile *sf, __int64 dist, int whence) { return sfseek_buffered(sf->fd, dist, whence); } #else /*RWD Feb 2010 ??? */ //static long //doseekEx(struct sndfile *sf, long dist, int whence) //{ // return sfseek_buffered(sf->fd, dist, whence); //} static __int64 doseekEx(struct sndfile *sf, __int64 dist, int whence) { return sfseek_buffered(sf->fd, dist, whence); } #endif /* * sndfilbuf - fill a buffer, for reading * return true, if an error occurs */ static int sndfilbuf(struct sndfile *sfd) { long want /* = SECSIZE * sfd->bufsiz*/ ; /*RWD: almost a const!*/ long got; int rc = 0; if(sfd->flags & SNDFLG_ATEND) return 0; #ifdef SFSYS_UNBUFFERED want = SECSIZE * sfd->bufsiz; got = sfread(sfd->fd, sfd->buffer, want); /*NB: does conversion of 8bit data*/ #else want = sfd->true_bufsize; /*only difference - supports other sample sizes*/ got = sfread_buffered(sfd->fd, sfd->buffer, want); #endif if(got < 0) { rc = 1; got = 0; } if(got < want) sfd->flags |= SNDFLG_ATEND; sfd->lastread = got; /*bytes of samps*/ sfd->flags &= ~(SNDFLG_WRITTEN|SNDFLG_LASTWR); sfd->endbuf = &sfd->buffer[got]; /*RWD NB all snd funcs think in SAMPLES, of 2 types: SHORTS or FLOATS; all 8bit stuff hidden in sf_calls*/ sfd->remain = got / sampsize[sfd->samptype]; /*RWD : adjust for 8bit files...*/ sfd->next = sfd->buffer; return rc; } /* * sndflsbuf - flush a buffer, after writing * return true, if an error occurs */ static int sndflsbuf(struct sndfile *sfd) { int toput = sfd->endbuf - sfd->buffer; int put; if(sfd->next == sfd->buffer) return 0; if(sfd->flags & SNDFLG_ATEND) return 0; sfd->next = sfd->buffer; sfd->flags &= ~SNDFLG_WRITTEN; sfd->endbuf = sfd->buffer; if(!(sfd->flags&SNDFLG_LASTWR) ) { if(doseek(sfd, -sfd->lastread, 1) < 0) { sfd->flags |= SNDFLG_LASTWR; sfd->remain = (sfd->bufsiz<samptype]; return 1; } } sfd->flags |= SNDFLG_LASTWR; sfd->remain = (sfd->bufsiz<samptype]; toput = (toput+SECSIZE-1)&~(SECSIZE-1); if((put = sfwrite(sfd->fd, sfd->buffer, toput)) < 0) return 1; if(put < toput) { sfd->flags |= SNDFLG_ATEND; sfd->remain = 0; } return 0; } static int sndflsbufEx(struct sndfile *sfd) { int toput = sfd->endbuf - sfd->buffer; int put; if(sfd->next == sfd->buffer) return 0; if(sfd->flags & SNDFLG_ATEND) return 0; sfd->next = sfd->buffer; sfd->flags &= ~SNDFLG_WRITTEN; sfd->endbuf = sfd->buffer; if(!(sfd->flags&SNDFLG_LASTWR) ) { if(doseekEx(sfd,(__int64) -sfd->lastread, 1) < 0) { sfd->flags |= SNDFLG_LASTWR; #ifdef SFSYS_UNBUFFERED sfd->remain = (sfd->bufsiz<samptype]; #else sfd->remain = sfd->true_bufsize / sampsize[sfd->samptype]; #endif return 1; } } sfd->flags |= SNDFLG_LASTWR; #ifdef SFSYS_UNBUFFERED sfd->remain = (sfd->bufsiz<samptype]; toput = (toput+SECSIZE-1)&~(SECSIZE-1); if((put = sfwrite(sfd->fd, sfd->buffer, toput)) < 0) return 1; #else sfd->remain = sfd->true_bufsize / sampsize[sfd->samptype]; if((put = sfwrite_buffered(sfd->fd, sfd->buffer, toput)) < 0) return 1; #endif if(put < toput) { sfd->flags |= SNDFLG_ATEND; sfd->remain = 0; } return 0; } /* * free the sample buffer, if it wasn't supplied by a sndsetbuf */ static void freesndbuf(int fd) { if(sndfiles[fd]->flags & SNDFLG_USERBUF) return; free(sndfiles[fd]->buffer); } /* * free the memory for an open SFfile * used on last close, and failure of creat */ static void freesndfd(int fd) { freesndbuf(fd); free((char *)sndfiles[fd]); sndfiles[fd] = 0; return; } /* * Try to find a snd file descripter * returns -1, if there aren't any */ static int findsndfd() { register int fd = 0; while(sndfiles[fd] != 0) if(++fd >= MAXSNDFILES) { rsferrno = ESFNOSFD; rsferrstr = "Too many sndfiles are already open"; return -1; } rsferrstr = "no memory to open sndfile"; rsferrno = ESFNOMEM; if((sndfiles[fd] = getmem(struct sndfile)) == 0) return -1; if((sndfiles[fd]->buffer = (char*) malloc(SNDBUFSIZE*SECSIZE)) == 0) { free((char *)sndfiles[fd]); sndfiles[fd] = 0; return -1; } sndfiles[fd]->flags = 0; sndfiles[fd]->bufsiz = SNDBUFSIZE; sndfiles[fd]->lastread = 0; sndfiles[fd]->endbuf = sndfiles[fd]->next = sndfiles[fd]->buffer; sndfiles[fd]->true_bufsize = SNDBUFSIZE * SECSIZE; /*may get rounded down for 24bit formats*/ return fd; } /* * The user-accessable routines */ /* * open a sndfile */ int sndopen(const char *fn) { register struct sndfile *sf; int fd; rsndinit(); if((fd = findsndfd()) < 0) return -1; sf = sndfiles[fd]; if((sf->fd = sfopen(fn)) < 0) { freesndfd(fd); return -1; } sf->remain = 0; if(sfgetprop(sf->fd, "sample type", (char *)&sf->samptype, sizeof(int)) != sizeof(int)) { rsferrno = ESFNOSTYPE; rsferrstr = "no sample type defined"; freesndfd(fd); return -1; } #ifdef CDP97 /*RWD only used to rescale floatsams when read into shorts (eg for playback)*/ sf->scale_floats = 0; sf->fscalefac = 1.0; #endif #ifdef NOTDEF if(sndfilbuf(sf)) sf->remain = -1; #endif return fd+SNDFDBASE; } int sndopenEx(const char *fn,int auto_scale, int access) { register struct sndfile *sf; int fd; rsndinit(); if((fd = findsndfd()) < 0) return -1; sf = sndfiles[fd]; if((sf->fd = sfopenEx(fn,access)) < 0) { freesndfd(fd); return -1; } sf->remain = 0; if(sfgetprop(sf->fd, "sample type", (char *)&sf->samptype, sizeof(int)) != sizeof(int)) { rsferrno = ESFNOSTYPE; rsferrstr = "no sample type defined"; freesndfd(fd); return -1; } #ifdef SFSYS_UNBUFFERED if(!(sf->samptype==SAMP_SHORT ||sf->samptype==SAMP_FLOAT)){ rsferrno = ESFBADFORMAT; rsferrstr = "unsupported sample format"; freesndfd(fd); return -1; } #else /*RWD only used to rescale floatsams when read into shorts (eg for playback)*/ sf->scale_floats = 0; sf->fscalefac = 1.0; if(auto_scale && (sf->samptype==SAMP_FLOAT)){ float fac = 0.0f; /* RWD 4:2002: I would prefer to rely on PEAK only for this now... */ if(sfgetprop(sf->fd,"maxamp",(char *)&fac,sizeof(float)) == sizeof(float)){ if(fac > sf->fscalefac){ sf->scale_floats = 1; sf->fscalefac = 0.99995 / (double) fac; } } /*get it from PEAK data if available*/ else if (_rsf_getmaxpeak(sf->fd,&fac) > 0){ if(fac > sf->fscalefac){ sf->scale_floats = 1; sf->fscalefac = 0.99995 / (double) fac; } } /*Could also provide a set_autoscale() func, legal only before first read (like sndsetbuf)*/ } /*adjust internal buffer if reading 24bit formats*/ if(sf->samptype==SAMP_2424 || sf->samptype == SAMP_2024) sf->true_bufsize = (sf->true_bufsize / sampsize[sf->samptype]) * sampsize[sf->samptype]; #endif #ifdef NOTDEF if(sndfilbuf(sf)) sf->remain = -1; #endif /* need superfluous seek to overcome daft OS problems reopening just-closed file */ if(sndseekEx(fd+SNDFDBASE,0,0) != 0) return -1; return fd+SNDFDBASE; } #ifdef NOTDEF /* * user-called routine for sndcreat */ int sndcreat(const char *fn, long size, int stype) { register struct sndfile *sf; int fd; rsndinit(); if(stype != SAMP_SHORT && stype != SAMP_FLOAT) { rsferrno = ESFBADPARAM; rsferrstr = "not a valid sample type"; return -1; } if((fd = findsndfd()) < 0) return -1; sf = sndfiles[fd]; sf->flags |= SNDFLG_TRUNC; sf->samptype = stype; if((sf->fd = sfcreat(fn, size*sampsize[stype], (int *)0)) < 0) { freesndfd(fd); return -1; } if(sfputprop(sf->fd, "sample type", (char *)&sf->samptype, sizeof(int)) < 0) { sfunlink(sf->fd); sfclose(sf->fd); freesndfd(fd); rsferrstr = "can't set sample type"; return -1; } sf->remain = (SECSIZE*sf->bufsiz)/sampsize[stype]; #ifdef NOTDEF if(sndfilbuf(sf)) sf->remain = -1; #endif return fd+SNDFDBASE; } #endif int sndcreat_formatted(const char *fn, int size, int stype,int channels, int srate,cdp_create_mode mode) { register struct sndfile *sf; int fd; rsndinit(); if((fd = findsndfd()) < 0) return -1; sf = sndfiles[fd]; sf->flags |= SNDFLG_TRUNC; sf->samptype = stype; /*RWD NB sampsize[] - no slot for 24bit size yet*/ if((sf->fd = sfcreat_formatted(fn, size*sampsize[stype], (__int64 *)0,channels,srate, stype,mode)) < 0) { freesndfd(fd); return -1; } #ifdef SFSYS_UNBUFFERED /*for 24bit alignment*/ sf->remain = (SECSIZE*sf->bufsiz)/sampsize[stype] #else sf->remain = sf->true_bufsize / sampsize[stype]; #endif #ifdef NOTDEF if(sndfilbuf(sf)) sf->remain = -1; #endif return fd+SNDFDBASE; } /*TODO: TEST THIS WITH SOMETHING....*/ int sndcreat_ex(const char *name, int size,SFPROPS *props,int min_header,cdp_create_mode mode) { register struct sndfile *sf; int fd; int smpsize; rsndinit(); if((fd = findsndfd()) < 0) return -1; sf = sndfiles[fd]; sf->flags |= SNDFLG_TRUNC; /* RWD.6.99 write 24bit formats, etc */ switch(props->samptype){ case(FLOAT32): sf->samptype = SAMP_FLOAT; break; case(SHORT16): sf->samptype = SAMP_SHORT; break; case(INT_32): #ifdef SFSYS_UNBUFFERED error! /*but this is easy,,,,now we have floats set in header*/ #endif sf->samptype = SAMP_LONG; break; case(INT2424): #ifdef SFSYS_UNBUFFERED error! #endif sf->samptype = SAMP_2424; /*adjust sndbuffer with 3-byte alignment*/ sf->true_bufsize = (sf->true_bufsize / sampsize[sf->samptype]) * sampsize[sf->samptype]; break; case(INT2024): #ifdef SFSYS_UNBUFFERED error! #endif sf->samptype = SAMP_2024; /*adjust sndbuffer with 3-byte alignment*/ sf->true_bufsize = (sf->true_bufsize / sampsize[sf->samptype]) * sampsize[sf->samptype]; break; case(SAMP_MASKED): #ifdef SFSYS_UNBUFFERED error! #endif /*don't know how to do this yet...*/ rsferrno = ESFBADPARAM; rsferrstr = "cannot write masked sample type"; return -1; default: rsferrno = ESFBADPARAM; rsferrstr = "unknown sample type"; return -1; break; } /*sf->samptype = (props->samptype == FLOAT32 ? SAMP_FLOAT : SAMP_SHORT);*/ smpsize = sampsize[sf->samptype]; /*need to return to outsize: size / smpsize - check this...*/ if((sf->fd = sfcreat_ex(name, (__int64)size*smpsize, (__int64 *)0, props,min_header,mode)) < 0) { freesndfd(fd); return -1; } #ifdef SFSYS_UNBUFFERED sf->remain = (SECSIZE*sf->bufsiz)/smpsize; #else sf->remain = sf->true_bufsize / smpsize; #endif #ifdef NOTDEF if(sndfilbuf(sf)) sf->remain = -1; #endif return fd+SNDFDBASE; } /* * close a sndfile */ int sndclose(int fd) { /* DEPRECATED! */ return -1; } int sndcloseEx(int fd) { register struct sndfile *sf; int rc = 0; __int64 length, pos; if(!mapsndfd(&fd)) return -1; sf = sndfiles[fd]; if(sf->flags&SNDFLG_TRUNC) { length = sfsize(sf->fd); pos = sndtellEx(fd + SNDFDBASE); //RWD 12-12-19 make sure of 64bit ints in calcs pos *= sampsize[sf->samptype]; if(sf->flags & SNDFLG_WRITTEN ) /* should never exec */ sndflsbufEx(sf); /* rsfsize does it! */ if((rc = sfadjust(sf->fd,pos-length)) < 0) { rsferrno = ESFWRERR; rsferrstr = "can't truncate SFfile"; } } else if(sf->flags & SNDFLG_WRITTEN ) sndflsbufEx(sf); rc |= sfclose(sf->fd); freesndfd(fd); return rc; } /*RWD.6.98 needed for Release98!*/ int sndunlink(int sndfd) { //int size; struct sndfile *sf; (void)sndseekEx(sndfd,0,0); /*RWD.7.98 hack to fix bug when closing empty file*/ if(!mapsndfd(&sndfd)) return -1; sf = sndfiles[sndfd]; return sfunlink(sf->fd); } /* * Return the size (in samples) of a sndfile * NOTE * the first sndseek will flush buffer if necessary */ int sndsizeEx(int sfd) { int oldpos; int size; if((oldpos = sndtellEx(sfd)) < 0) return -1; if((size = sndseekEx(sfd, 0L, 2)) < 0) { size = -1; rsferrno = ESFNOSEEK; rsferrstr = "can't seek to end of file to find size"; } if(sndseekEx(sfd, oldpos, 0) < 0) { rsferrno = ESFNOSEEK; rsferrstr = "can't restore position after finding file size"; return -1; } return size; } /* * seek in a sndfile (of SHORTS or FLOATS) */ int sndseek(int fd, int dist, int whence) { //return sndseekEx(fd,dist,whence); return -1; } int sndseekEx(int fd, int dist, int whence) { register struct sndfile *sf; long bufsize; #ifdef FILE64_WIN __int64 secpos; __int64 newpos; __int64 gotpos; #else __int64 secpos; __int64 newpos = 0; __int64 gotpos; #endif if(!mapsndfd(&fd)) return -1; sf = sndfiles[fd]; #ifdef SFSYS_UNBUFFERED bufsize = sf->bufsiz<true_bufsize; #endif if((sf->flags & SNDFLG_WRITTEN) && sndflsbufEx(sf)) return -1; switch(whence) { case 0: newpos = dist; /*in SAMPLES: NB must deal with 8bit files!*/ break; case 1: newpos = sndtellEx(fd+SNDFDBASE) + dist; break; case 2: newpos = sfsize(sf->fd); /*size-specific:SHORTSAMS, from datachunksize*/ newpos = (newpos / sampsize[sf->samptype]) + dist; /*make non-size-specific*/ break; } if(newpos < 0) newpos = 0; newpos *= sampsize[sf->samptype]; /* byte offset */ /*restore size-specific for doseek*/ /*RWD.6.99 still need to do this - not a SECSIZE calc, but just cdp_round to our buffersize*/ secpos = (newpos/bufsize)*bufsize; /* cdp_round down */ /*RWD 2007: NB for FILE64_WIN doseekEx takes and returns __int64 */ if((gotpos = doseekEx(sf, secpos, 0)) < 0)/*NB seek might be truncated */ /*gotpos = non-size-specific*/ return -1; sf->flags &= ~SNDFLG_ATEND; if(sndfilbuf(sf)) { /* if sndfilbuf fails... */ sf->next = sf->buffer; sf->remain = 0; return -1; } if(gotpos < secpos) { newpos -= sf->remain; /*RWD 2007 !!! remain supposed to count ~samples~ */ sf->remain = 0; } #ifdef FILE64_WIN sf->next = &sf->buffer[(unsigned long)newpos % bufsize]; #else sf->next = &sf->buffer[(unsigned long)newpos%bufsize]; #endif newpos /= sampsize[sf->samptype]; sf->remain = (sf->endbuf - sf->next)/sampsize[sf->samptype]; #ifdef FILE64_WIN return (long) newpos; #else return (long) newpos; #endif } /* * Where are we in the present sndfile * NOTE * This does not need to flush buffers, etc */ int sndtell(int fd) { return -1; } /*RWD 2007 FIXME for 64bit reads: */ /* doseekEx must return unsigned long, or __int64 value */ int sndtellEx(int fd) { struct sndfile *sf; #ifdef FILE64_WIN __int64 off; #else //long off; __int64 off; #endif if(!mapsndfd(&fd)) return -1; sf = sndfiles[fd]; if((off = doseekEx(sf, 0L, 1)) < 0) { /*NB: must return cnt of samples * sizeof(type=SHORTS or FLOATS)*/ rsferrno = ESFNOSEEK; rsferrstr = "can't seek to find present position in file"; return -1; } if(sf->flags & SNDFLG_LASTWR) /*RWD.5.1.99 fails for short sndfiles within a buffer*/ #ifdef SFSY_UNBUFFERED off += sf->bufsiz<true_bufsize; #endif if(sf->flags & SNDFLG_ATEND) off = sfsize(sf->fd); /*bytes, of SHORTS or FLOATS samps*/ off /= sampsize[sf->samptype]; #ifdef FILE64_WIN return (int)(off - ( (sf->remain < 0) ? 0 : sf->remain)); #else return (int)(off - ( (sf->remain < 0) ? 0 : sf->remain)); #endif } /* * let the user supply a larger buffer */ /*RWD.6.99 NB bufsize is in SECTORS - may need new version for new formats...*/ int sndsetbuf(int sfd, char *buf, int bufsize) { struct sndfile *sf; if(!mapsndfd(&sfd)) return -1; sf = sndfiles[sfd]; if(sf->remain != 0) { rsferrno = ESFLOSEDATA; rsferrstr = "sndsetbuf would lose data"; return -1; } freesndbuf(sfd); sf->buffer = buf; sf->bufsiz = bufsize; #ifdef CDP97 sf->true_bufsize = sf->bufsiz << LOGSECSIZE; #endif sf->flags |= SNDFLG_USERBUF; return 0; } /* * snd I/O routines */ /* * fgetfloat - read the next float */ int fgetfloat(float *fp, int sfd) { register struct sndfile *sfp; if(!mapsndfd(&sfd)) return -1; sfp = sndfiles[sfd]; if(sfp->remain < 0) return 0; if(sfp->remain-- == 0) { if(sndfilbuf(sfp)) return -1; if(sfp->remain-- <= 0) return 0; } if(sfp->samptype == SAMP_FLOAT) { *fp = *(float *)sfp->next; sfp->next += sizeof(float); } else { *fp = (float)(*(short *)sfp->next) / (float)MAXSHORT; sfp->next += sizeof(short); } return 1; } int fgetfloatEx(float *fp, int sfd,int expect_floats) { register struct sndfile *sfp; long lword = 0; long mask; /*we need signed ints*/ SND_SAMP ssamp; if(!mapsndfd(&sfd)) return -1; sfp = sndfiles[sfd]; if(sfp->remain < 0) return 0; if(sfp->remain-- == 0) { if(sndfilbuf(sfp)) return -1; if(sfp->remain-- <= 0) return 0; } ssamp.lsamp = 0; switch(sfp->samptype){ case(SAMP_FLOAT): *fp = *(float *)sfp->next; sfp->next += sizeof(float); break; case(SAMP_SHORT): *fp = (float)(*(short *)sfp->next) / (float)MAXSHORT; sfp->next += sizeof(short); break; case(SAMP_LONG): if(expect_floats){ *fp = *(float *)sfp->next; sfp->next += sizeof(float); } else{ *fp = (float)((double) (*(int *)sfp->next) / (float)MAXINT); sfp->next += sizeof(int); } break; case(SAMP_2432): /*mask the word first*/ lword = *(long *)sfp->next; lword &= 0xffffff00; *fp = (float)((double)lword / MAXINT); sfp->next += sizeof(int); break; case(SAMP_2024): /*need to mask it?*/ ssamp.lsamp = 0; mask = _rsf_getbitmask(sfp->fd); if(mask==0) return -1; #ifdef LSBFIRST ssamp.bytes[1] = sfp->next[0]; ssamp.bytes[2] = sfp->next[1]; ssamp.bytes[3] = sfp->next[2]; #else ssamp.bytes[0] = sfp->next[0]; ssamp.bytes[1] = sfp->next[1]; ssamp.bytes[2] = sfp->next[2]; #endif *fp = (float)((double)(ssamp.lsamp & mask) / MAXINT); sfp->next += 3; break; case(SAMP_2424): #ifdef LSBFIRST ssamp.bytes[1] = sfp->next[0]; ssamp.bytes[2] = sfp->next[1]; ssamp.bytes[3] = sfp->next[2]; #else ssamp.bytes[0] = sfp->next[0]; ssamp.bytes[1] = sfp->next[1]; ssamp.bytes[2] = sfp->next[2]; #endif *fp = (float)((double)(ssamp.lsamp) / MAXINT); sfp->next += 3; break; default: rsferrno = ESFBADPARAM; rsferrstr = "attempted to read unknown sample format"; return -1; /*do others later...*/ break; } return 1; } /* * fputfloat - write the next float */ int fputfloat(float *fp, int sfd) { register struct sndfile *sfp; if(!mapsndfd(&sfd)) return -1; sfp = sndfiles[sfd]; if(sfp->flags&SNDFLG_ATEND) return 0; sfp->flags |= SNDFLG_WRITTEN; #ifdef CDP97 /* sndtell checks this*/ sfp->flags |= SNDFLG_LASTWR; #endif if(sfp->samptype == SAMP_FLOAT) { *(float *)sfp->next = *fp; sfp->next += sizeof(float); } else { /* *(short *)sfp->next = (short) floor(0.5 + *fp * MAXSHORT);*/ *(short *)sfp->next = (short) cdp_round( *fp * MAXSHORT); sfp->next += sizeof(short); } if(sfp->next > sfp->endbuf) sfp->endbuf = sfp->next; if(--sfp->remain == 0) { if(sndflsbuf(sfp)) return -1; } return 1; } /*RWD.7.99 replace floor calc with cdp_round(): more accurate!*/ int fputfloatEx(float *fp, int sfd) { register struct sndfile *sfp; SND_SAMP ssamp; if(!mapsndfd(&sfd)) return -1; sfp = sndfiles[sfd]; if(sfp->flags&SNDFLG_ATEND) return 0; sfp->flags |= SNDFLG_WRITTEN; #ifdef CDP97 /* sndtell checks this*/ sfp->flags |= SNDFLG_LASTWR; #endif ssamp.lsamp = 0; switch(sfp->samptype){ case(SAMP_FLOAT): *(float *)sfp->next = *fp; sfp->next += sizeof(float); break; case(SAMP_SHORT): /* *(short *)sfp->next = (short)floor(0.5 + *fp * MAXSHORT);*/ *(short *)sfp->next = (short) cdp_round( *fp * MAXSHORT); sfp->next += sizeof(short); break; case(SAMP_2024): /*ssamp.lsamp = (int) floor(0.5 + *fp * MAXINT);*/ ssamp.lsamp = (int) cdp_round(*fp * MAXINT); #ifdef LSBFIRST sfp->next[0] = ssamp.bytes[1] & 0xf0; sfp->next[1] = ssamp.bytes[2]; sfp->next[2] = ssamp.bytes[3]; #else sfp->next[0] = ssamp.bytes[0] & 0xf0; sfp->next[1] = ssamp.bytes[1]; sfp->next[2] = ssamp.bytes[2]; #endif sfp->next += 3; break; case(SAMP_2424): /*ssamp.lsamp = (int) floor(0.5 + *fp * MAXINT);*/ ssamp.lsamp = (int) cdp_round(*fp * MAXINT); #ifdef LSBFIRST sfp->next[0] = ssamp.bytes[1]; sfp->next[1] = ssamp.bytes[2]; sfp->next[2] = ssamp.bytes[3]; #else sfp->next[0] = ssamp.bytes[0]; sfp->next[1] = ssamp.bytes[1]; sfp->next[2] = ssamp.bytes[2]; #endif sfp->next += 3; break; case(SAMP_LONG): /* *(long *)sfp->next = (long) floor(0.5 + *fp * MAXINT);*/ *(int *)sfp->next = (int) cdp_round(*fp * MAXINT); sfp->next += sizeof(int); break; case(SAMP_2432): /*ssamp.lsamp = (int) floor(0.5 + *fp * MAXINT);*/ ssamp.lsamp = (int) cdp_round(*fp * MAXINT); ssamp.bytes[0] = 0; *(int *)sfp->next = ssamp.lsamp; sfp->next += sizeof(int); break; default: rsferrno = ESFBADPARAM; rsferrstr = "attempted to write unknown sample format"; return -1; /*do others later...*/ break; } if(sfp->next > sfp->endbuf) sfp->endbuf = sfp->next; if(--sfp->remain == 0) { if(sndflsbufEx(sfp)) return -1; } return 1; } /* * fgetfbuf - get a sequence of float-sams */ int fgetfbuf(float *fp, int n, int sfd) { register struct sndfile *sfp; int chunk; int cnt = 0; if(!mapsndfd(&sfd)) return -1; sfp = sndfiles[sfd]; if(sfp->samptype == SAMP_SHORT) { sfd += SNDFDBASE; while(cnt < n && fgetfloat(fp++, sfd) > 0) cnt++; return cnt; } while(cnt < n) { if(sfp->remain == 0) { if(sndfilbuf(sfp) || sfp->remain == 0) return cnt; } chunk = n - cnt; if(chunk > sfp->remain) chunk = sfp->remain; memcpy((char *)fp, sfp->next, chunk*sizeof(float)); sfp->remain -= chunk; sfp->next += chunk*sizeof(float); cnt += chunk; fp += chunk; } return cnt; } /*RWD.6.99 probably the tidiest way of dealing with old floatsam files * expect_float must be non-zero to trigger */ int fgetfbufEx(float *fp, int n, int sfd,int expect_floats) { register struct sndfile *sfp; int chunk; int cnt = 0; if(!mapsndfd(&sfd)) return -1; sfp = sndfiles[sfd]; if(sfp->samptype==SAMP_FLOAT || ((sfp->samptype==INT_32) && expect_floats)){ while(cnt < n) { if(sfp->remain == 0) { if(sndfilbuf(sfp) || sfp->remain == 0) return cnt; } chunk = n - cnt; if(chunk > sfp->remain) chunk = sfp->remain; memcpy((char *)fp, sfp->next, chunk*sizeof(float)); sfp->remain -= chunk; sfp->next += chunk*sizeof(float); cnt += chunk; fp += chunk; } } else{ sfd += SNDFDBASE; while(cnt < n && (fgetfloatEx(fp++, sfd,expect_floats) > 0)) cnt++; /*return cnt;*/ } return cnt; } /* * fputfbuf - put a sequence of float-sams */ int fputfbuf(float *fp, int n, int sfd) { register struct sndfile *sfp; int chunk; int cnt = 0; if(!mapsndfd(&sfd)) return -1; sfp = sndfiles[sfd]; if(sfp->samptype == SAMP_SHORT) { sfd += SNDFDBASE; while(cnt < n && fputfloat(fp++, sfd) > 0) cnt++; return cnt; } while(cnt < n) { sfp->flags |= SNDFLG_WRITTEN; #ifdef CDP97 /* sndtell checks this*/ sfp->flags |= SNDFLG_LASTWR; #endif chunk = n - cnt; if(chunk > sfp->remain) chunk = sfp->remain; memcpy(sfp->next, (char *)fp, chunk*sizeof(float)); sfp->remain -= chunk; sfp->next += chunk*sizeof(float); if(sfp->next > sfp->endbuf) sfp->endbuf = sfp->next; cnt += chunk; fp += chunk; if(sfp->remain == 0) { if(sndflsbuf(sfp)) return -1; if(sfp->remain == 0) return cnt; } } return cnt; } int fputfbufEx(float *fp, int n, int sfd) { register struct sndfile *sfp; int chunk; int cnt = 0; if(!mapsndfd(&sfd)) return -1; sfp = sndfiles[sfd]; if(sfp->samptype == SAMP_SHORT) { sfd += SNDFDBASE; while(cnt < n && fputfloatEx(fp++, sfd) > 0) cnt++; return cnt; } if(sfp->samptype == SAMP_FLOAT){ while(cnt < n) { sfp->flags |= SNDFLG_WRITTEN; #ifdef CDP97 /* sndtell checks this*/ sfp->flags |= SNDFLG_LASTWR; #endif chunk = n - cnt; if(chunk > sfp->remain) chunk = sfp->remain; memcpy(sfp->next, (char *)fp, chunk*sizeof(float)); sfp->remain -= chunk; sfp->next += chunk*sizeof(float); if(sfp->next > sfp->endbuf) sfp->endbuf = sfp->next; cnt += chunk; fp += chunk; if(sfp->remain == 0) { if(sndflsbufEx(sfp)) return -1; if(sfp->remain == 0) return cnt; } } } else { sfd += SNDFDBASE; while(cnt < n && fputfloatEx(fp++, sfd) > 0) cnt++; return cnt; } return cnt; } /* * fgetshort - read the next short */ int fgetshort(short *sp, int sfd) { register struct sndfile *sfp; if(!mapsndfd(&sfd)) return -1; sfp = sndfiles[sfd]; if(sfp->remain < 0) return 0; if(sfp->remain-- == 0) { if(sndfilbuf(sfp)) return -1; if(sfp->remain-- <= 0) return 0; } if(sfp->samptype == SAMP_FLOAT) { #ifdef CDP97 if(sfp->scale_floats==1) /* *sp = (short)(floor(0.5 + (sfp->fscalefac * (*(float *)sfp->next * MAXSHORT)))); */ *sp = (short) cdp_round((sfp->fscalefac * (*(float *)sfp->next * MAXSHORT))); else #endif *sp = (short) cdp_round( *(float *)sfp->next * MAXSHORT); sfp->next += sizeof(float); } else { /*RWD does this read 8bit words properly ?*/ *sp = *(short *)sfp->next; sfp->next += sizeof(short); } return 1; } /* RWD.7.99 use cdp_round() instead of floor(): later, try shoft/truncate and/or dithering! */ int fgetshortEx(short *sp, int sfd,int expect_floats) { struct sndfile *sfp; int lword = 0; int mask; SND_SAMP ssamp; if(!mapsndfd(&sfd)) return -1; sfp = sndfiles[sfd]; if(sfp->remain < 0) return 0; if(sfp->remain-- == 0) { if(sndfilbuf(sfp)) return -1; if(sfp->remain-- <= 0) return 0; } ssamp.lsamp = 0; switch(sfp->samptype){ case(SAMP_FLOAT): #ifdef CDP97 if(sfp->scale_floats==1) /* *sp = (short)(floor(0.5 + (sfp->fscalefac * (*(float *)sfp->next * MAXSHORT))));*/ *sp = (short) cdp_round((sfp->fscalefac * (*(float *)sfp->next * MAXSHORT))); else #endif /* *sp = (short)floor(0.5 + *(float *)sfp->next * MAXSHORT);*/ *sp = (short) cdp_round( *(float *)sfp->next * MAXSHORT); sfp->next += sizeof(float); break; case(SAMP_SHORT): *sp = *(short *)sfp->next; sfp->next += sizeof(short); break; case(SAMP_LONG): if(expect_floats){ #ifdef CDP97 if(sfp->scale_floats==1) /* *sp = (short)(floor(0.5 + (sfp->fscalefac * (*(float *)sfp->next * MAXSHORT))));*/ *sp = (short) cdp_round((sfp->fscalefac * (*(float *)sfp->next * MAXSHORT))); else #endif /* *sp = (short)floor(0.5 + *(float *)sfp->next * MAXSHORT);*/ *sp = (short) cdp_round( *(float *)sfp->next * MAXSHORT); sfp->next += sizeof(float); } else{ *sp = (short)( (*(int *)sfp->next) >> 16); sfp->next += sizeof(int); } break; case(SAMP_2432): /*mask the word first*/ lword = *(int *)sfp->next; lword &= 0xffffff00; *sp = (short)(lword >> 16); sfp->next += sizeof(int); break; case(SAMP_2024): /*need to mask it?*/ mask = _rsf_getbitmask(sfp->fd); if(mask==0) return -1; ssamp.bytes[1] = sfp->next[0]; ssamp.bytes[2] = sfp->next[1]; ssamp.bytes[3] = sfp->next[2]; *sp = (short)((ssamp.lsamp & mask) >> 16); sfp->next += 3; break; case(SAMP_2424): ssamp.bytes[1] = sfp->next[0]; ssamp.bytes[2] = sfp->next[1]; ssamp.bytes[3] = sfp->next[2]; *sp = (short)(ssamp.lsamp >> 16); sfp->next += 3; break; default: rsferrno = ESFBADPARAM; rsferrstr = "attempted to read unknown sample format"; return -1; /*do others later...*/ break; } return 1; } /* * fputshort - write the next short */ int fputshort(short *sp, int sfd) { register struct sndfile *sfp; if(!mapsndfd(&sfd)) return -1; sfp = sndfiles[sfd]; if(sfp->flags&SNDFLG_ATEND) return 0; sfp->flags |= SNDFLG_WRITTEN; #ifdef CDP97 /* sndtell checks this*/ sfp->flags |= SNDFLG_LASTWR; #endif if(sfp->samptype == SAMP_FLOAT) { *(float *)sfp->next = (float)*sp / (float)MAXSHORT; sfp->next += sizeof(float); } else { *(short *)sfp->next = *sp; sfp->next += sizeof(short); } if(sfp->next > sfp->endbuf) sfp->endbuf = sfp->next; if(--sfp->remain == 0) { if(sndflsbuf(sfp)) return -1; } return 1; } int fputshortEx(short *sp, int sfd) { register struct sndfile *sfp; SND_SAMP ssamp; if(!mapsndfd(&sfd)) return -1; sfp = sndfiles[sfd]; if(sfp->flags&SNDFLG_ATEND) return 0; sfp->flags |= SNDFLG_WRITTEN; #ifdef CDP97 /* sndtell checks this*/ sfp->flags |= SNDFLG_LASTWR; #endif ssamp.lsamp = 0; switch(sfp->samptype){ case(SAMP_FLOAT): *(float *)sfp->next = (float)*sp / (float)MAXSHORT; sfp->next += sizeof(float); break; case(SAMP_SHORT): *(short *)sfp->next = *sp; sfp->next += sizeof(short); break; case(SAMP_2024): /*no need to mask; 16 bits anyway!*/ case(SAMP_2424): ssamp.lsamp = (int) ((*sp) << 16); sfp->next[0] = ssamp.bytes[1]; sfp->next[1] = ssamp.bytes[2]; sfp->next[2] = ssamp.bytes[3]; sfp->next += 3; break; case(SAMP_LONG): case(SAMP_2432): ssamp.lsamp = (int) ((*sp) << 16); *(int *)sfp->next = ssamp.lsamp; sfp->next += sizeof(int); break; default: rsferrno = ESFBADPARAM; rsferrstr = "attempted to write unknown sample format"; return -1; /*do others later...*/ break; } if(sfp->next > sfp->endbuf) sfp->endbuf = sfp->next; if(--sfp->remain == 0) { if(sndflsbufEx(sfp)) return -1; } return 1; } /* * fgetsbuf - get a sequence of short-sams */ int fgetsbuf(short *sp, int n, int sfd) { register struct sndfile *sfp; int chunk; int cnt = 0; if(!mapsndfd(&sfd)) return -1; sfp = sndfiles[sfd]; if(sfp->samptype == SAMP_FLOAT) { sfd += SNDFDBASE; while(cnt < n && fgetshort(sp++, sfd) > 0) cnt++; return cnt; } /*RWD: now, may be either SHORTS or BYTES samples!*/ while(cnt < n) { if(sfp->remain == 0) { if(sndfilbuf(sfp) || sfp->remain == 0) return cnt; } chunk = n - cnt; if(chunk > sfp->remain) chunk = sfp->remain; memcpy((char *)sp, sfp->next, chunk*sizeof(short)); sfp->remain -= chunk; sfp->next += chunk*sizeof(short); cnt += chunk; sp += chunk; } return cnt; } int fgetsbufEx(short *sp, int n, int sfd,int expect_floats) { register struct sndfile *sfp; int chunk; int cnt = 0; if(!mapsndfd(&sfd)) return -1; sfp = sndfiles[sfd]; switch(sfp->samptype){ case(SAMP_SHORT): while(cnt < n) { if(sfp->remain <= 0) { /*RWD.6.99 was == 0*/ if(sndfilbuf(sfp) || (sfp->remain == 0)) return cnt; } chunk = n - cnt; if(chunk > sfp->remain) chunk = sfp->remain; memcpy((char *)sp, sfp->next, chunk*sizeof(short)); sfp->remain -= chunk; sfp->next += chunk*sizeof(short); cnt += chunk; sp += chunk; } break; default: sfd += SNDFDBASE; while(cnt < n && fgetshortEx(sp++, sfd,expect_floats) > 0) cnt++; break; } return cnt; } /* * fputsbuf - put a sequence of short-sams */ int fputsbuf(short *sp, int n, int sfd) { register struct sndfile *sfp; int chunk; int cnt = 0; if(!mapsndfd(&sfd)) return -1; sfp = sndfiles[sfd]; if(sfp->samptype == SAMP_FLOAT) { sfd += SNDFDBASE; while(cnt < n && fputshort(sp++, sfd) > 0) cnt++; return cnt; } while(cnt < n) { sfp->flags |= SNDFLG_WRITTEN; #ifdef CDP97 /* sndtell checks this*/ sfp->flags |= SNDFLG_LASTWR; #endif chunk = n - cnt; if(chunk > sfp->remain) chunk = sfp->remain; memcpy(sfp->next, (char *)sp, chunk*sizeof(short)); sfp->remain -= chunk; sfp->next += chunk*sizeof(short); if(sfp->next > sfp->endbuf) sfp->endbuf = sfp->next; cnt += chunk; sp += chunk; if(sfp->remain == 0) { if(sndflsbuf(sfp)) return -1; if(sfp->remain == 0) return cnt; } } return cnt; } int fputsbufEx(short *sp, int n, int sfd) { register struct sndfile *sfp; int chunk; int cnt = 0; if(!mapsndfd(&sfd)) return -1; sfp = sndfiles[sfd]; switch(sfp->samptype){ case(SAMP_SHORT): while(cnt < n) { sfp->flags |= SNDFLG_WRITTEN; #ifdef CDP97 /* sndtell checks this*/ sfp->flags |= SNDFLG_LASTWR; #endif chunk = n - cnt; if(chunk > sfp->remain) chunk = sfp->remain; memcpy(sfp->next, (char *)sp, chunk*sizeof(short)); sfp->remain -= chunk; sfp->next += chunk*sizeof(short); if(sfp->next > sfp->endbuf) sfp->endbuf = sfp->next; cnt += chunk; sp += chunk; if(sfp->remain == 0) { if(sndflsbufEx(sfp)) return -1; if(sfp->remain == 0) return cnt; } } break; default: sfd += SNDFDBASE; while(cnt < n && fputshortEx(sp++, sfd) > 0) cnt++; break; } return cnt; } /* * The property stuff, for sndfiles */ int sndgetprop(int sfd, char *prop, char *dest, int lim) { if(!mapsndfd(&sfd)) return -1; return sfgetprop(sndfiles[sfd]->fd, prop, dest, lim); } int sndputprop(int sfd, char *prop, char *src, int size) { if(!mapsndfd(&sfd)) return -1; if(strcmp(prop, "sample type") == 0) { rsferrno = ESFNOSTYPE; rsferrstr = "can't change sample type on sndfile"; return -1; } return sfputprop(sndfiles[sfd]->fd, prop, src, size); } int sndrmprop(int sfd, char *prop) { if(!mapsndfd(&sfd)) return -1; if(strcmp(prop, "sample type") == 0) { rsferrno = ESFNOSTYPE; rsferrstr = "can't remove sample type on sndfile"; return -1; } return sfrmprop(sndfiles[sfd]->fd, prop); } int snddirprop(int sfd, int (*func)(char *propname, int propsize)) { if(!mapsndfd(&sfd)) return -1; return sfdirprop(sndfiles[sfd]->fd, func); } /*RWD OCT97*/ int sndgetwordsize(int sfd) { if(!mapsndfd(&sfd)) return -1; return sfgetwordsize(sndfiles[sfd]->fd); } /*recognise shortcuts in WIN32*/ #if defined CDP97 && defined _WIN32 /*TODO: add arg for full targetname*/ int snd_is_shortcut(int sfd) { if(!mapsndfd(&sfd)) return -1; return sf_is_shortcut(sndfiles[sfd]->fd,NULL); } #endif /*RWD.5.99*/ int snd_fileformat(int sfd, fileformat *pfmt) { if(!mapsndfd(&sfd)) return -1; return sfformat(sndfiles[sfd]->fd,pfmt); } int sndgetchanmask(int sfd) { if(!mapsndfd(&sfd)) return -1; return sfgetchanmask(sndfiles[sfd]->fd); } int snd_getchanformat(int sfd, channelformat *chformat) { if(!mapsndfd(&sfd)) return -1; return sf_getchanformat(sndfiles[sfd]->fd,chformat); } int sndreadpeaks(int sfd,int channels,CHPEAK peakdata[],int *peaktime) { if(!mapsndfd(&sfd)) return -1; return sfreadpeaks(sndfiles[sfd]->fd,(int) channels,peakdata,peaktime); } int sndputpeaks(int sfd,int channels,const CHPEAK peakdata[]) { if(!mapsndfd(&sfd)) return -1; return sfputpeaks(sndfiles[sfd]->fd,channels,peakdata); } const char * snd_getfilename(int sfd) { if(!mapsndfd(&sfd)) return NULL; return sf_getfilename(sndfiles[sfd]->fd); } extern int sf_makepath(char path[], const char* sfname); int snd_makepath(char path[], const char* sfname) { return sf_makepath(path,sfname); }