ref: 40fd453a7e61979c3bab7fe0455fb08417b69ffb
dir: /src/misc.c/
/* * July 5, 1991 * Copyright 1991 Lance Norskog And Sundry Contributors * This source code is freely redistributable and may be used for * any purpose. This copyright notice must be maintained. * Lance Norskog And Sundry Contributors are not responsible for * the consequences of using this software. */ /* * Sound Tools miscellaneous stuff. */ #include "st_i.h" #include <math.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <string.h> #include <ctype.h> #ifdef HAVE_ERRNO_H #include <errno.h> #endif /* for fstat */ #include <sys/stat.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #ifdef HAVE_BYTESWAP_H #include <byteswap.h> #endif const char *st_sizes_str[] = { "NONSENSE!", "bytes", "shorts", "24 bits", "longs", "NONSENSE", "NONSENSE", "NONSENSE", "long longs" }; const char *st_size_bits_str[] = { "NONSENSE!", "8-bits", "16-bits", "24-bits", "32-bits", "NONSENSE", "NONSENSE", "NONSENSE", "64-bits" }; const char *st_encodings_str[] = { "NONSENSE!", "unsigned", "signed (2's complement)", "u-law", "a-law", "floating point", "adpcm", "ima_adpcm", "gsm", "inversed u-law", "inversed A-law", "MPEG audio (layer I, II or III)", "Vorbis" }; static const char readerr[] = "Premature EOF while reading sample file."; static const char writerr[] = "Error writing sample file. You are probably out of disk space."; /* Utilities */ /* Read in a buffer of data of length len and each element is size bytes. * Returns number of elements read, not bytes read. */ st_ssize_t st_readbuf(ft_t ft, void *buf, size_t size, st_ssize_t len) { return fread(buf, size, len, ft->fp); } /* Write a buffer of data of length len and each element is size bytes. * Returns number of elements writen, not bytes writen. */ st_ssize_t st_writebuf(ft_t ft, void *buf, size_t size, st_ssize_t len) { return fwrite(buf, size, len, ft->fp); } st_size_t st_filelength(ft_t ft) { struct stat st; fstat(fileno(ft->fp), &st); return (st_size_t)st.st_size; } int st_flush(ft_t ft) { return fflush(ft->fp); } st_size_t st_tell(ft_t ft) { return (st_size_t)ftell(ft->fp); } int st_eof(ft_t ft) { return feof(ft->fp); } int st_error(ft_t ft) { return ferror(ft->fp); } void st_rewind(ft_t ft) { rewind(ft->fp); } void st_clearerr(ft_t ft) { clearerr(ft->fp); } /* Read and write known datatypes in "machine format". Swap if indicated. * They all return ST_EOF on error and ST_SUCCESS on success. */ /* Read n-char string (and possibly null-terminating). * Stop reading and null-terminate string if either a 0 or \n is reached. */ int st_reads(ft_t ft, char *c, st_ssize_t len) { char *sc; char in; sc = c; do { if (st_readbuf(ft, &in, 1, 1) != 1) { *sc = 0; st_fail_errno(ft,errno,readerr); return (ST_EOF); } if (in == 0 || in == '\n') { break; } *sc = in; sc++; } while (sc - c < len); *sc = 0; return(ST_SUCCESS); } /* Write null-terminated string (without \0). */ int st_writes(ft_t ft, char *c) { if (st_writebuf(ft, c, 1, strlen(c)) != strlen(c)) { st_fail_errno(ft,errno,writerr); return(ST_EOF); } return(ST_SUCCESS); } /* Read byte. */ int st_readb(ft_t ft, uint8_t *ub) { if (st_readbuf(ft, ub, 1, 1) != 1) { st_fail_errno(ft,errno,readerr); return(ST_EOF); } return ST_SUCCESS; } /* Write byte. */ int st_writeb(ft_t ft, uint8_t ub) { if (st_writebuf(ft, &ub, 1, 1) != 1) { st_fail_errno(ft,errno,writerr); return(ST_EOF); } return(ST_SUCCESS); } /* Read word. */ int st_readw(ft_t ft, uint16_t *uw) { if (st_readbuf(ft, uw, 2, 1) != 1) { st_fail_errno(ft,errno,readerr); return (ST_EOF); } if (ft->swap) *uw = st_swapw(*uw); return ST_SUCCESS; } /* Write word. */ int st_writew(ft_t ft, uint16_t uw) { if (ft->swap) uw = st_swapw(uw); if (st_writebuf(ft, &uw, 2, 1) != 1) { st_fail_errno(ft,errno,writerr); return (ST_EOF); } return(ST_SUCCESS); } /* Read double word. */ int st_readdw(ft_t ft, uint32_t *udw) { if (st_readbuf(ft, udw, 4, 1) != 1) { st_fail_errno(ft,errno,readerr); return (ST_EOF); } if (ft->swap) *udw = st_swapdw(*udw); return ST_SUCCESS; } /* Write double word. */ int st_writedw(ft_t ft, uint32_t udw) { if (ft->swap) udw = st_swapdw(udw); if (st_writebuf(ft, &udw, 4, 1) != 1) { st_fail_errno(ft,errno,writerr); return (ST_EOF); } return(ST_SUCCESS); } /* Read float. */ int st_readf(ft_t ft, float *f) { if (st_readbuf(ft, f, sizeof(float), 1) != 1) { return(ST_EOF); } if (ft->swap) *f = st_swapf(*f); return ST_SUCCESS; } /* Write float. */ int st_writef(ft_t ft, float f) { float t = f; if (ft->swap) t = st_swapf(t); if (st_writebuf(ft, &t, sizeof(float), 1) != 1) { st_fail_errno(ft,errno,writerr); return (ST_EOF); } return (ST_SUCCESS); } /* Read double. */ int st_readdf(ft_t ft, double *d) { if (st_readbuf(ft, d, sizeof(double), 1) != 1) { return(ST_EOF); } if (ft->swap) *d = st_swapd(*d); return ST_SUCCESS; } /* Write double. */ int st_writedf(ft_t ft, double d) { if (ft->swap) d = st_swapd(d); if (st_writebuf(ft, &d, sizeof(double), 1) != 1) { st_fail_errno(ft,errno,writerr); return (ST_EOF); } return (ST_SUCCESS); } /* generic swap routine. Swap l and place in to f (datatype length = n) */ void st_swapb(char *l, char *f, int n) { register int i; for (i= 0; i< n; i++) f[i]= l[n-i-1]; } /* Byte swappers, use libc optimized macro's if possible */ #ifndef HAVE_BYTESWAP_H uint16_t st_swapw(uint16_t uw) { return ((uw >> 8) | (uw << 8)) & 0xffff; } uint32_t st_swapdw(uint32_t udw) { return (udw >> 24) | ((udw >> 8) & 0xff00) | ((udw << 8) & 0xff0000L) | (udw << 24); } #endif /* return swapped 32-bit float */ float st_swapf(float f) { union { uint32_t dw; float f; } u; u.f= f; u.dw= (u.dw>>24) | ((u.dw>>8)&0xff00) | ((u.dw<<8)&0xff0000L) | (u.dw<<24); return u.f; } uint32_t st_swap24(uint32_t udw) { return (udw >> 16) | (udw & 0xff00) | ((udw << 16) & 0xff0000L); } double st_swapd(double df) { double sdf; st_swapb((char *)&df, (char *)&sdf, sizeof(double)); return (sdf); } /* dummy format routines for do-nothing functions */ int st_format_nothing(ft_t ft) { return(ST_SUCCESS); } st_ssize_t st_format_nothing_io(ft_t ft, st_sample_t *buf, st_ssize_t len) { return(0); } int st_format_nothing_seek(ft_t ft, st_size_t offset) { st_fail_errno(ft, ST_ENOTSUP, "operation not supported"); return(ST_EOF); } /* dummy effect routine for do-nothing functions */ int st_effect_nothing(eff_t effp) { return(ST_SUCCESS); } int st_effect_nothing_drain(eff_t effp, st_sample_t *obuf, st_size_t *osamp) { /* Inform no more samples to drain */ *osamp = 0; return(ST_EOF); } /* here for linear interp. might be useful for other things */ st_sample_t st_gcd(st_sample_t a, st_sample_t b) { if (b == 0) return a; else return st_gcd(b, a % b); } st_sample_t st_lcm(st_sample_t a, st_sample_t b) { /* parenthesize this way to avoid st_sample_t overflow in product term */ return a * (b / st_gcd(a, b)); } #ifndef HAVE_STRCASECMP /* * Portable strcasecmp() function */ int strcasecmp(const char *s1, const char *s2) { for (; toupper(*s1) == toupper(*s2); ++s1, ++s2) { if (*s1 == '\0') return(0); } return ((*(unsigned char *)s1 < *(unsigned char *)s2) ? -1 : +1); } #endif #ifndef HAVE_STRDUP /* * Portable strdup() function */ char *strdup(const char *s) { char *dups; dups = (char *)malloc(strlen(s)+1); strcpy(dups, s); return dups; } #endif #ifndef HAVE_RAND /* * Portable random generator as defined by ANSI C Standard. * Don't ask me why not all C libraries include it. */ static long rand_seed = 1; int rand(void) { rand_seed = (rand_seed * 1103515245L) + 12345L; return ((unsigned int)(rand_seed/65536L) % 32768L); } void srand(unsigned int seed) { rand_seed = seed; } #endif /* Util to set initial seed so that we are a little less non-random */ void st_initrand(void) { time_t t; time(&t); srand(t); } st_sample_t st_clip24(st_sample_t l) { if (l >= ((st_sample_t)1 << 23)) return ((st_sample_t)1 << 23) - 1; else if (l <= -((st_sample_t)1 << 23)) return -((st_sample_t)1 << 23) + 1; else return l; } /* This was very painful. We need a sine library. */ void st_sine(int *buf, st_ssize_t len, int max, int depth) { st_ssize_t i; int offset; double val; offset = max - depth; for (i = 0; i < len; i++) { val = sin((double)i/(double)len * 2.0 * M_PI); buf[i] = (int) ((1.0 + val) * depth / 2.0); } } void st_triangle(int *buf, st_ssize_t len, int max, int depth) { st_ssize_t i; int offset; double val; offset = max - 2 * depth; for (i = 0; i < len / 2; i++) { val = i * 2.0 / len; buf[i] = offset + (int) (val * 2.0 * (double)depth); } for (i = len / 2; i < len ; i++) { val = (len - i) * 2.0 / len; buf[i] = offset + (int) (val * 2.0 * (double)depth); } } const char *st_version() { static char versionstr[20]; sprintf(versionstr, "Version %d.%d.%d", (ST_LIB_VERSION_CODE & 0xff0000) >> 16, (ST_LIB_VERSION_CODE & 0x00ff00) >> 8, (ST_LIB_VERSION_CODE & 0x0000ff)); return(versionstr); } #ifndef HAVE_STRERROR #ifdef __cplusplus extern "C" int sys_nerr; extern "C" char *sys_errlist[]; #else extern int sys_nerr; extern char *sys_errlist[]; #endif /* strerror function */ char *strerror(int errcode) { static char nomesg[30]; if (errcode < sys_nerr) return (sys_errlist[errcode]); else { sprintf (nomesg, "Undocumented error %d", errcode); return (nomesg); } } #endif /* Implements traditional fseek() behavior. Meant to abstract out * file operations so that they could one day also work on memory * buffers. * Offset is in bytes as apposed to st_seek() which is in samples. */ int st_seeki(ft_t ft, st_size_t offset, int whence) { if( ft->seekable == 0 ){ /* * If a stream peel off chars else * EPERM "Operation not permitted" */ if(whence == SEEK_CUR ){ while ( offset > 0 && !feof(ft->fp) ) { getc(ft->fp); offset--; } if(offset) st_fail_errno(ft,ST_EOF,"offset past eof"); else ft->st_errno = ST_SUCCESS; } else { st_fail_errno(ft,ST_EPERM,"File not seekable"); } } else { if( fseek(ft->fp,offset,whence) == -1 ) st_fail_errno(ft,errno,strerror(errno)); else ft->st_errno = ST_SUCCESS; } /* Empty the st file buffer */ if( ft->st_errno == ST_SUCCESS ){ ft->file.count = 0; ft->file.pos = 0; ft->file.eof = 0; } return(ft->st_errno); }