1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-20 14:20:06 +02:00
2010-01-24 09:19:39 +00:00

298 lines
10 KiB
C

/* 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);
}
}