/* sndread.c -- read sound files */ /* CHANGELOG * * 29Jun95 RBD ULAW fixed problems with signed chars * 28Apr03 dm explicitly declare sndread_file_open_count as int * 24Jul08 RBD & Judy Hawkins -- replace snd with PortAudio and libsndfile */ #include "switches.h" #include "stdio.h" #include "string.h" #ifdef UNIX #include "sys/file.h" #else /* #include */ #ifdef WINDOWS #include #include "io.h" #else #include #endif #define L_SET SEEK_SET #define L_INCR SEEK_CUR #define PROTECTION #endif #ifndef mips #include "stdlib.h" #endif #include "sndfile.h" #include "xlisp.h" #include "sound.h" #include "sndfmt.h" #include "falloc.h" #include "sndread.h" #include "multiread.h" /* file.h doesn't define O_RDONLY under RS6K AIX */ #ifndef O_RDONLY #define O_RDONLY 0 #endif static int sndread_file_open_count = 0; void read__fetch(susp, snd_list) register read_susp_type susp; snd_list_type snd_list; { long n; /* jlh Changed type to long, trying to make move_samples_... work */ sample_block_type out; register sample_block_values_type out_ptr; /* allow up to 4 bytes/sample: jlh -- does this need to be 8? */ /* FIX -- why 8? for doubles? Maybe it should be sizeof(sample). I think this buffer was here to allow you to input any format and convert to float. The assumption was no sample would be longer than 4 bytes and after conversion, samples would be 4 byte floats. */ long in_count; /* jlh Trying to make move_samples_... work */ falloc_sample_block(out, "read__fetch"); out_ptr = out->samples; snd_list->block = out; in_count = sf_readf_float(susp->sndfile, out_ptr, max_sample_block_len); n = in_count; /* don't read too many */ if (n > (susp->cnt - susp->susp.current)) { n = susp->cnt - susp->susp.current; } snd_list->block_len = n; susp->susp.current += n; if (n == 0) { /* we didn't read anything, but can't return length zero, so convert snd_list to pointer to zero block */ snd_list_terminate(snd_list); } else if (n < max_sample_block_len) { /* this should close file and free susp */ snd_list_unref(snd_list->u.next); /* if something is in buffer, terminate by pointing to zero block */ snd_list->u.next = zero_snd_list; } } /* read__fetch */ void read_free(read_susp_type susp) { sf_close(susp->sndfile); sndread_file_open_count--; ffree_generic(susp, sizeof(read_susp_node), "read_free"); } void read_print_tree(read_susp_type susp, int n) { } LVAL snd_make_read( unsigned char *filename, /* file to read */ time_type offset, /* offset to skip (in seconds) */ time_type t0, /* start time of resulting sound */ long *format, /* AIFF, IRCAM, NeXT, etc. */ long *channels, /* number of channels */ long *mode, /* sample format: PCM, ALAW, etc. */ long *bits, /* BPS: bits per sample */ long *swap, /* swap bytes */ double *srate, /* srate: sample rate */ double *dur, /* duration (in seconds) to read */ long *flags, /* which parameters have been set */ long *byte_offset) /* byte offset in file of first sample */ { register read_susp_type susp; /* srate specified as input parameter */ sample_type scale_factor = 1.0F; sf_count_t frames; double actual_dur; falloc_generic(susp, read_susp_node, "snd_make_read"); memset(&(susp->sf_info), 0, sizeof(SF_INFO)); susp->sf_info.samplerate = ROUND(*srate); susp->sf_info.channels = *channels; switch (*mode) { case SND_MODE_ADPCM: susp->sf_info.format = SF_FORMAT_IMA_ADPCM; break; case SND_MODE_PCM: if (*bits == 8) susp->sf_info.format = SF_FORMAT_PCM_S8; else if (*bits == 16) susp->sf_info.format = SF_FORMAT_PCM_16; else if (*bits == 24) susp->sf_info.format = SF_FORMAT_PCM_24; else if (*bits == 32) susp->sf_info.format = SF_FORMAT_PCM_32; else { susp->sf_info.format = SF_FORMAT_PCM_16; *bits = 16; } break; case SND_MODE_ULAW: susp->sf_info.format = SF_FORMAT_ULAW; break; case SND_MODE_ALAW: susp->sf_info.format = SF_FORMAT_ALAW; break; case SND_MODE_FLOAT: susp->sf_info.format = SF_FORMAT_FLOAT; break; case SND_MODE_UPCM: susp->sf_info.format = SF_FORMAT_PCM_U8; *bits = 8; break; } if (*format == SND_HEAD_RAW) susp->sf_info.format |= SF_FORMAT_RAW; if (*swap) { /* set format to perform a byte swap (change from cpu endian-ness) */ /* write the code so it will only compile if one and only one ENDIAN setting is defined */ #ifdef XL_LITTLE_ENDIAN long format = SF_ENDIAN_BIG; #endif #ifdef XL_BIG_ENDIAN long format = SF_ENDIAN_LITTLE; #endif susp->sf_info.format |= format; } susp->sndfile = sf_open((const char *) filename, SFM_READ, &(susp->sf_info)); if (!susp->sndfile) { char error[240]; sprintf(error, "SND-READ: Cannot open file '%s'", filename); xlfail(error); } if (susp->sf_info.channels < 1) { sf_close(susp->sndfile); xlfail("Must specify 1 or more channels"); } /* report samplerate from file, but if user provided a double * as sample rate, don't replace it with an integer. */ if ((susp->sf_info.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) { *srate = susp->sf_info.samplerate; } /* compute dur */ frames = sf_seek(susp->sndfile, 0, SEEK_END); actual_dur = ((double) frames) / *srate; if (offset < 0) offset = 0; /* round offset to an integer frame count */ frames = (sf_count_t) (offset * *srate + 0.5); offset = ((double) frames) / *srate; actual_dur -= offset; if (actual_dur < 0) { sf_close(susp->sndfile); xlfail("SND-READ: offset is beyond end of file"); } if (actual_dur < *dur) *dur = actual_dur; sf_seek(susp->sndfile, frames, SEEK_SET); /* return to read loc in file */ /* initialize susp state */ susp->susp.sr = *srate; susp->susp.t0 = t0; susp->susp.mark = NULL; susp->susp.print_tree = read_print_tree; /*jlh empty function... */ susp->susp.current = 0; susp->susp.log_stop_cnt = UNKNOWN; /* watch for overflow */ if (*dur * *srate + 0.5 > (unsigned long) 0xFFFFFFFF) { susp->cnt = 0x7FFFFFFF; } else { susp->cnt = ROUND((*dur) * *srate); } switch (susp->sf_info.format & SF_FORMAT_TYPEMASK) { case SF_FORMAT_WAV: *format = SND_HEAD_WAVE; break; case SF_FORMAT_AIFF: *format = SND_HEAD_AIFF; break; case SF_FORMAT_AU: *format = SND_HEAD_NEXT; break; case SF_FORMAT_RAW: *format = SND_HEAD_RAW; break; case SF_FORMAT_PAF: *format = SND_HEAD_PAF; break; case SF_FORMAT_SVX: *format = SND_HEAD_SVX; break; case SF_FORMAT_NIST: *format = SND_HEAD_NIST; break; case SF_FORMAT_VOC: *format = SND_HEAD_VOC; break; case SF_FORMAT_W64: *format = SND_HEAD_W64; break; case SF_FORMAT_MAT4: *format = SND_HEAD_MAT4; break; case SF_FORMAT_MAT5: *format = SND_HEAD_MAT5; break; case SF_FORMAT_PVF: *format = SND_HEAD_PVF; break; case SF_FORMAT_XI: *format = SND_HEAD_XI; break; case SF_FORMAT_HTK: *mode = SND_HEAD_HTK; break; case SF_FORMAT_SDS: *mode = SND_HEAD_SDS; break; case SF_FORMAT_AVR: *mode = SND_HEAD_AVR; break; case SF_FORMAT_WAVEX: *format = SND_HEAD_WAVE; break; case SF_FORMAT_SD2: *format = SND_HEAD_SD2; break; case SF_FORMAT_FLAC: *format = SND_HEAD_FLAC; break; case SF_FORMAT_CAF: *format = SND_HEAD_CAF; break; default: *format = SND_HEAD_NONE; break; } *channels = susp->sf_info.channels; switch (susp->sf_info.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8: *bits = 8; *mode = SND_MODE_PCM; break; case SF_FORMAT_PCM_16: *bits = 16; *mode = SND_MODE_PCM; break; case SF_FORMAT_PCM_24: *bits = 24; *mode = SND_MODE_PCM; break; case SF_FORMAT_PCM_32: *bits = 32; *mode = SND_MODE_PCM; break; case SF_FORMAT_PCM_U8: *bits = 8; *mode = SND_MODE_UPCM; break; case SF_FORMAT_FLOAT: *bits = 32; *mode = SND_MODE_FLOAT; break; case SF_FORMAT_DOUBLE: *bits = 64; *mode = SND_MODE_DOUBLE; break; case SF_FORMAT_ULAW: *bits = 8; *mode = SND_MODE_ULAW; break; case SF_FORMAT_ALAW: *bits = 8; *mode = SND_MODE_ALAW; break; case SF_FORMAT_IMA_ADPCM: *bits = 16; *mode = SND_MODE_ADPCM; break; case SF_FORMAT_MS_ADPCM: *bits = 16; *mode = SND_MODE_ADPCM; break; case SF_FORMAT_GSM610: *bits = 16; *mode = SND_MODE_GSM610; break; case SF_FORMAT_VOX_ADPCM: *bits = 16; *mode = SND_MODE_ADPCM; break; case SF_FORMAT_G721_32: *bits = 16; *mode = SND_MODE_ADPCM; break; case SF_FORMAT_G723_24: *bits = 16; *mode = SND_MODE_ADPCM; break; case SF_FORMAT_G723_40: *bits = 16; *mode = SND_MODE_ADPCM; break; case SF_FORMAT_DWVW_12: *bits = 12; *mode = SND_MODE_DWVW; break; case SF_FORMAT_DWVW_16: *bits = 16; *mode = SND_MODE_DWVW; break; case SF_FORMAT_DWVW_24: *bits = 24; *mode = SND_MODE_DWVW; break; case SF_FORMAT_DWVW_N: *bits = 32; *mode = SND_MODE_DWVW; break; case SF_FORMAT_DPCM_8: *bits = 8; *mode = SND_MODE_DPCM; break; case SF_FORMAT_DPCM_16: *bits = 16; *mode = SND_MODE_DPCM; break; default: *mode = SND_MODE_UNKNOWN; break; } sndread_file_open_count++; #ifdef MACINTOSH if (sndread_file_open_count > 24) { nyquist_printf("Warning: more than 24 sound files are now open\n"); } #endif /* report info back to caller */ if ((susp->sf_info.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) { *flags = SND_HEAD_CHANNELS | SND_HEAD_MODE | SND_HEAD_BITS | SND_HEAD_SRATE | SND_HEAD_LEN | SND_HEAD_TYPE; } if (susp->sf_info.channels == 1) { susp->susp.fetch = read__fetch; susp->susp.free = read_free; susp->susp.name = "read"; return cvsound(sound_create((snd_susp_type)susp, t0, *srate, scale_factor)); } else { susp->susp.fetch = multiread_fetch; susp->susp.free = multiread_free; susp->susp.name = "multiread"; return multiread_create(susp); } }