1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
|
/* 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 /* WINDOWS */
#define L_SET SEEK_SET
#define L_INCR SEEK_CUR
#define PROTECTION
#endif /* UNIX */
#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(snd_susp_type a_susp, snd_list_type snd_list)
{
read_susp_type susp = (read_susp_type) a_susp;
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 = (long) 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 = (long) (susp->cnt - susp->susp.current);
}
snd_list->block_len = (short) 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(snd_susp_type a_susp)
{
read_susp_type susp = (read_susp_type) a_susp;
sf_close(susp->sndfile);
sndread_file_open_count--;
ffree_generic(susp, sizeof(read_susp_node), "read_free");
}
void read_print_tree(snd_susp_type a_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 */
{
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 = ROUND32(*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
susp->sf_info.format |= SF_ENDIAN_BIG;
#endif
#ifdef XL_BIG_ENDIAN
susp->sf_info.format |= SF_ENDIAN_LITTLE;
#endif
}
susp->sndfile = NULL;
if (ok_to_open((const char *) filename, "rb"))
susp->sndfile = sf_open((const char *) filename, SFM_READ,
&(susp->sf_info));
if (!susp->sndfile) {
char error[240];
snprintf(error, 240, "SND-READ: Cannot open file '%s' because of %s",
filename, sf_strerror(susp->sndfile));
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 = susp->sf_info.frames;
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 = 0x7FFFFFFFFFFFFFFF;
} else {
susp->cnt = ROUNDBIG((*dur) * *srate);
}
switch (susp->sf_info.format & SF_FORMAT_TYPEMASK) {
case SF_FORMAT_AIFF: *format = SND_HEAD_AIFF; break;
case SF_FORMAT_IRCAM: *format = SND_HEAD_IRCAM; break;
case SF_FORMAT_AU: *format = SND_HEAD_NEXT; break;
case SF_FORMAT_WAV: *format = SND_HEAD_WAVE; 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_SD2: *format = SND_HEAD_SD2; break;
case SF_FORMAT_FLAC: *format = SND_HEAD_FLAC; break;
case SF_FORMAT_CAF: *format = SND_HEAD_CAF; break;
case SF_FORMAT_RAW: *format = SND_HEAD_RAW; break;
case SF_FORMAT_OGG: *format = SND_HEAD_OGG; break;
case SF_FORMAT_WAVEX: *format = SND_HEAD_WAVEX; 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);
}
}
|