#if defined (HAVE_CONFIG_H) # include "config.h" #endif #include /* check for standard C headers */ #if STDC_HEADERS # include # include #else # ifndef HAVE_STRCHR # define strchr index # define strrchr rindex # endif char *strchr (), *strrchr (); #endif #ifdef HAVE_MALLOC_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef DMALLOC #include #endif #include #include "sndfile.h" MODULE(sndfile) FUNCTION(sndfile,sndfile_vars,argc,argv) { if (argc != 0) return __FAIL; return mktuplel (52, mkint(SFM_READ), mkint(SFM_WRITE), mkint(SFM_RDWR), mkint(SF_FORMAT_WAV), mkint(SF_FORMAT_AIFF), mkint(SF_FORMAT_AU), mkint(SF_FORMAT_RAW), mkint(SF_FORMAT_PAF), mkint(SF_FORMAT_SVX), mkint(SF_FORMAT_NIST), mkint(SF_FORMAT_VOC), mkint(SF_FORMAT_IRCAM), mkint(SF_FORMAT_W64), mkint(SF_FORMAT_PCM_S8), mkint(SF_FORMAT_PCM_16), mkint(SF_FORMAT_PCM_24), mkint(SF_FORMAT_PCM_32), mkint(SF_FORMAT_PCM_U8), mkint(SF_FORMAT_FLOAT), mkint(SF_FORMAT_DOUBLE), mkint(SF_FORMAT_ULAW), mkint(SF_FORMAT_ALAW), mkint(SF_FORMAT_IMA_ADPCM), mkint(SF_FORMAT_MS_ADPCM), mkint(SF_FORMAT_GSM610), mkint(SF_FORMAT_G721_32), mkint(SF_FORMAT_G723_24), mkint(SF_FORMAT_G723_40), mkint(SF_FORMAT_DWVW_12), mkint(SF_FORMAT_DWVW_16), mkint(SF_FORMAT_DWVW_24), mkint(SF_FORMAT_DWVW_N), mkint(SF_ENDIAN_FILE), mkint(SF_ENDIAN_LITTLE), mkint(SF_ENDIAN_BIG), mkint(SF_ENDIAN_CPU), mkint(SF_FORMAT_SUBMASK), mkint(SF_FORMAT_TYPEMASK), mkint(SF_FORMAT_ENDMASK), mkint(SFC_GET_LOG_INFO), mkint(SFC_CALC_SIGNAL_MAX), mkint(SFC_CALC_NORM_SIGNAL_MAX), mkint(SFC_CALC_MAX_ALL_CHANNELS), mkint(SFC_CALC_NORM_MAX_ALL_CHANNELS), mkint(SFC_SET_NORM_FLOAT), mkint(SFC_SET_NORM_DOUBLE), mkint(SFC_GET_NORM_FLOAT), mkint(SFC_GET_NORM_DOUBLE), mkint(SFC_SET_ADD_PEAK_CHUNK), mkint(SFC_SET_UPDATE_HEADER_AUTO), mkint(SFC_UPDATE_HEADER_NOW), mkint(SFC_FILE_TRUNCATE)); } typedef struct { SNDFILE *sf; int mode, rate, channels, format; sf_count_t frames; } snd_file; DESTRUCTOR(sndfile,SndFile,x) { snd_file *v = (snd_file*)x; if (v->sf) sf_close(v->sf); free(v); } FUNCTION(sndfile,sf_open,argc,argv) { char *name; long mode, rate, channels, format; double drate; expr *xv; int n; if (argc == 3 && isstr(argv[0], &name) && isint(argv[1], &mode)) { snd_file *v = malloc(sizeof(snd_file)); SF_INFO info; if (!v) return __ERROR; memset(&info, 0, sizeof(info)); if (istuple(argv[2], &n, &xv) && n == 3) { if (isfloat(xv[0], &drate)) rate = (long)drate; else if (!isint(xv[0], &rate)) goto skip; if (isint(xv[1], &channels) && isint(xv[2], &format)) { info.samplerate = rate; info.channels = channels; info.format = format; } } skip: if ((v->sf = sf_open(name, mode, &info))) { v->mode = mode; v->rate = info.samplerate; v->channels = info.channels; v->format = info.format; v->frames = info.frames; return mkobj(type(SndFile), v); } else { free(v); return __FAIL; } } else return __FAIL; } FUNCTION(sndfile,sf_close,argc,argv) { snd_file *v; if (argc == 1 && isobj(argv[0], type(SndFile), (void**)&v) && v->sf) { sf_close(v->sf); v->sf = NULL; return mkvoid; } else return __FAIL; } FUNCTION(sndfile,sf_format_check,argc,argv) { int n; expr *xv; if (argc == 1 && istuple(argv[0], &n, &xv) && n == 3) { SF_INFO info; double drate; long rate, channels, format; if (isfloat(xv[0], &drate)) rate = (long)drate; else if (!isint(xv[0], &rate)) return __FAIL; if (isint(xv[1], &channels) && isint(xv[2], &format)) { info.samplerate = rate; info.channels = channels; info.format = format; } else return __FAIL; if (sf_format_check(&info)) return mktrue; else return mkfalse; } else return __FAIL; } FUNCTION(sndfile,sf_frames,argc,argv) { snd_file *v; if (argc == 1 && isobj(argv[0], type(SndFile), (void**)&v) && v->sf) return mkint((long)v->frames); else return __FAIL; } FUNCTION(sndfile,sf_info,argc,argv) { snd_file *v; if (argc == 1 && isobj(argv[0], type(SndFile), (void**)&v) && v->sf) return mktuplel(3, mkint(v->rate), mkint(v->channels), mkint(v->format)); else return __FAIL; } typedef struct bstr { long size; unsigned char *v; } bstr_t; static expr mkbstr(long size, void *v) { bstr_t *m; if ((m = malloc(sizeof(bstr_t)))) { m->size = size; m->v = (unsigned char*)v; return mkobj(type(ByteStr), m); } else { if (v) free(v); return __ERROR; } } FUNCTION(sndfile,sf_read_short,argc,argv) { snd_file *v; long n; if (argc == 2 && isobj(argv[0], type(SndFile), (void**)&v) && v->sf && (v->mode & SFM_READ) && isint(argv[1], &n) && n >= 0) { sf_count_t res; long bytes = n*v->channels*sizeof(short); short *mv = NULL, *mv1; if (n > 0) { if (!(mv = malloc(bytes))) return __ERROR; release_lock(); res = sf_readf_short(v->sf, mv, n); acquire_lock(); if (res < 0) { free(mv); return __FAIL; } else if (res < n) { bytes = res*v->channels*sizeof(short); if (res == 0) { free(mv); mv = NULL; } else if ((mv1 = realloc(mv, bytes))) mv = mv1; } } return mkbstr(bytes, mv); } else return __FAIL; } FUNCTION(sndfile,sf_read_int,argc,argv) { snd_file *v; long n; if (argc == 2 && isobj(argv[0], type(SndFile), (void**)&v) && v->sf && (v->mode & SFM_READ) && isint(argv[1], &n) && n >= 0) { sf_count_t res; long bytes = n*v->channels*sizeof(int); int *mv = NULL, *mv1; if (n > 0) { if (!(mv = malloc(bytes))) return __ERROR; release_lock(); res = sf_readf_int(v->sf, mv, n); acquire_lock(); if (res < 0) { free(mv); return __FAIL; } else if (res < n) { bytes = res*v->channels*sizeof(int); if (res == 0) { free(mv); mv = NULL; } else if ((mv1 = realloc(mv, bytes))) mv = mv1; } } return mkbstr(bytes, mv); } else return __FAIL; } FUNCTION(sndfile,sf_read_float,argc,argv) { snd_file *v; long n; if (argc == 2 && isobj(argv[0], type(SndFile), (void**)&v) && v->sf && (v->mode & SFM_READ) && isint(argv[1], &n) && n >= 0) { sf_count_t res; long bytes = n*v->channels*sizeof(float); float *mv = NULL, *mv1; if (n > 0) { if (!(mv = malloc(bytes))) return __ERROR; release_lock(); res = sf_readf_float(v->sf, mv, n); acquire_lock(); if (res < 0) { free(mv); return __FAIL; } else if (res < n) { bytes = res*v->channels*sizeof(float); if (res == 0) { free(mv); mv = NULL; } else if ((mv1 = realloc(mv, bytes))) mv = mv1; } } return mkbstr(bytes, mv); } else return __FAIL; } FUNCTION(sndfile,sf_read_double,argc,argv) { snd_file *v; long n; if (argc == 2 && isobj(argv[0], type(SndFile), (void**)&v) && v->sf && (v->mode & SFM_READ) && isint(argv[1], &n) && n >= 0) { sf_count_t res; long bytes = n*v->channels*sizeof(double); double *mv = NULL, *mv1; if (n > 0) { if (!(mv = malloc(bytes))) return __ERROR; release_lock(); res = sf_readf_double(v->sf, mv, n); acquire_lock(); if (res < 0) { free(mv); return __FAIL; } else if (res < n) { bytes = res*v->channels*sizeof(double); if (res == 0) { free(mv); mv = NULL; } else if ((mv1 = realloc(mv, bytes))) mv = mv1; } } return mkbstr(bytes, mv); } else return __FAIL; } FUNCTION(sndfile,sf_write_short,argc,argv) { snd_file *v; bstr_t *m; if (argc == 2 && isobj(argv[0], type(SndFile), (void**)&v) && v->sf && (v->mode & SFM_WRITE) && isobj(argv[1], type(ByteStr), (void**)&m)) { sf_count_t res; long n = m->size/v->channels/sizeof(short); if (n > 0) { release_lock(); res = sf_writef_short(v->sf, (short*)m->v, n); acquire_lock(); } else res = 0; if (res < 0) return __FAIL; else return mkint((long)res); } else return __FAIL; } FUNCTION(sndfile,sf_write_int,argc,argv) { snd_file *v; bstr_t *m; if (argc == 2 && isobj(argv[0], type(SndFile), (void**)&v) && v->sf && (v->mode & SFM_WRITE) && isobj(argv[1], type(ByteStr), (void**)&m)) { sf_count_t res; long n = m->size/v->channels/sizeof(int); if (n > 0) { release_lock(); res = sf_writef_int(v->sf, (int*)m->v, n); acquire_lock(); } else res = 0; if (res < 0) return __FAIL; else return mkint((long)res); } else return __FAIL; } FUNCTION(sndfile,sf_write_float,argc,argv) { snd_file *v; bstr_t *m; if (argc == 2 && isobj(argv[0], type(SndFile), (void**)&v) && v->sf && (v->mode & SFM_WRITE) && isobj(argv[1], type(ByteStr), (void**)&m)) { sf_count_t res; long n = m->size/v->channels/sizeof(float); if (n > 0) { release_lock(); res = sf_writef_float(v->sf, (float*)m->v, n); acquire_lock(); } else res = 0; if (res < 0) return __FAIL; else return mkint((long)res); } else return __FAIL; } FUNCTION(sndfile,sf_write_double,argc,argv) { snd_file *v; bstr_t *m; if (argc == 2 && isobj(argv[0], type(SndFile), (void**)&v) && v->sf && (v->mode & SFM_WRITE) && isobj(argv[1], type(ByteStr), (void**)&m)) { sf_count_t res; long n = m->size/v->channels/sizeof(double); if (n > 0) { release_lock(); res = sf_writef_double(v->sf, (double*)m->v, n); acquire_lock(); } else res = 0; if (res < 0) return __FAIL; else return mkint((long)res); } else return __FAIL; } FUNCTION(sndfile,sf_seek,argc,argv) { snd_file *v; long n, whence; if (argc == 3 && isobj(argv[0], type(SndFile), (void**)&v) && v->sf && isint(argv[1], &n) && isint(argv[2], &whence) && (n = sf_seek(v->sf, n, whence)) >= 0) return mkint(n); else return __FAIL; } FUNCTION(sndfile,sf_command,argc,argv) { snd_file *v; long cmd; if (argc == 3 && isobj(argv[0], type(SndFile), (void**)&v) && v->sf && isint(argv[1], &cmd)) { switch (cmd) { case SFC_GET_LOG_INFO: { char msg[2048]; sf_command(v->sf, cmd, msg, sizeof(msg)); return mkstr(strdup(msg)); } case SFC_CALC_SIGNAL_MAX: case SFC_CALC_NORM_SIGNAL_MAX: { double max; if (!sf_command(v->sf, cmd, &max, sizeof(max))) return mkfloat(max); else return __FAIL; } case SFC_CALC_MAX_ALL_CHANNELS: case SFC_CALC_NORM_MAX_ALL_CHANNELS: { double *max = malloc(v->channels*sizeof(double)); if (!max) return __ERROR; if (!sf_command(v->sf, cmd, max, v->channels*sizeof(double))) { expr *xv = xvalloc(v->channels); int i; if (!xv) { free(max); return __ERROR; } for (i = 0; i < v->channels; i++) xv[i] = mkfloat(max[i]); free(max); return mktuplev(v->channels, xv); } else return __FAIL; } case SFC_SET_NORM_FLOAT: case SFC_SET_NORM_DOUBLE: if (istrue(argv[2]) && sf_command(v->sf, cmd, NULL, SF_TRUE) == SF_TRUE || isfalse(argv[2]) && sf_command(v->sf, cmd, NULL, SF_FALSE) == SF_FALSE) return mkvoid; else return __FAIL; case SFC_GET_NORM_FLOAT: case SFC_GET_NORM_DOUBLE: if (sf_command(v->sf, cmd, NULL, 0)) return mktrue; else return mkfalse; case SFC_SET_ADD_PEAK_CHUNK: case SFC_SET_UPDATE_HEADER_AUTO: { int flag; if (istrue(argv[2])) flag = SF_TRUE; else if (isfalse(argv[2])) flag = SF_FALSE; else return __FAIL; if (sf_command(v->sf, cmd, NULL, flag) == flag) return mkvoid; else return __FAIL; } case SFC_UPDATE_HEADER_NOW: sf_command(v->sf, cmd, NULL, 0); return mkvoid; case SFC_FILE_TRUNCATE: { long n; sf_count_t frames; if (!isint(argv[2], &n) || n < 0) return __FAIL; frames = n; if (sf_command(v->sf, cmd, &frames, sizeof(frames))) return __FAIL; else return mkvoid; } default: return __FAIL; } } else return __FAIL; } FUNCTION(sndfile,sf_perror,argc,argv) { snd_file *v; if (argc == 1 && isobj(argv[0], type(SndFile), (void**)&v) && v->sf) { sf_perror(v->sf); return mkvoid; } else return __FAIL; } FUNCTION(sndfile,sf_strerror,argc,argv) { snd_file *v; if (argc == 1 && isobj(argv[0], type(SndFile), (void**)&v) && v->sf) { char msg[1024]; *msg = 0; sf_error_str(v->sf, msg, sizeof(msg)); return mkstr(strdup(msg)); } else return __FAIL; } FUNCTION(sndfile,sf_version,argc,argv) { snd_file *v; if (argc == 0) { char version[1024]; sf_command(NULL, SFC_GET_LIB_VERSION, version, sizeof(version)); return mkstr(strdup(version)); } else return __FAIL; } FUNCTION(sndfile,sf_simple_formats,argc,argv) { snd_file *v; if (argc == 0) { SF_FORMAT_INFO info ; int k, count ; expr *xv; sf_command(NULL, SFC_GET_SIMPLE_FORMAT_COUNT, &count, sizeof(count)); if (!(xv = xvalloc(count))) return __ERROR; for (k = 0; k < count; k++) { info.format = k ; if (sf_command(NULL, SFC_GET_SIMPLE_FORMAT, &info, sizeof(info))) { xvfree(xv); return __FAIL; } xv[k] = mktuplel(3, mkint((long)info.format), mkstr(strdup(info.name)), mkstr(strdup(info.extension))); } return mklistv(count, xv); } else return __FAIL; } FUNCTION(sndfile,sf_major_formats,argc,argv) { snd_file *v; if (argc == 0) { SF_FORMAT_INFO info ; int k, count ; expr *xv; sf_command(NULL, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof(count)); if (!(xv = xvalloc(count))) return __ERROR; for (k = 0; k < count; k++) { info.format = k ; if (sf_command(NULL, SFC_GET_FORMAT_MAJOR, &info, sizeof(info))) { xvfree(xv); return __FAIL; } xv[k] = mktuplel(3, mkint((long)info.format), mkstr(strdup(info.name)), mkstr(strdup(info.extension))); } return mklistv(count, xv); } else return __FAIL; } FUNCTION(sndfile,sf_subtypes,argc,argv) { snd_file *v; if (argc == 0) { SF_FORMAT_INFO info ; int k, count ; expr *xv; sf_command(NULL, SFC_GET_FORMAT_SUBTYPE_COUNT, &count, sizeof(count)); if (!(xv = xvalloc(count))) return __ERROR; for (k = 0; k < count; k++) { info.format = k ; if (sf_command(NULL, SFC_GET_FORMAT_SUBTYPE, &info, sizeof(info))) { xvfree(xv); return __FAIL; } xv[k] = mktuplel(2, mkint((long)info.format), mkstr(strdup(info.name))); } return mklistv(count, xv); } else return __FAIL; }