summaryrefslogtreecommitdiff
path: root/nyqsrc/sndread.c
diff options
context:
space:
mode:
Diffstat (limited to 'nyqsrc/sndread.c')
-rw-r--r--nyqsrc/sndread.c297
1 files changed, 297 insertions, 0 deletions
diff --git a/nyqsrc/sndread.c b/nyqsrc/sndread.c
new file mode 100644
index 0000000..5087abb
--- /dev/null
+++ b/nyqsrc/sndread.c
@@ -0,0 +1,297 @@
+/* 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 <unistd.h> */
+#ifdef WINDOWS
+#include <sys/stat.h>
+#include "io.h"
+#else
+#include <stat.h>
+#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);
+ }
+}
+
+
+
+