File: sndread.c

package info (click to toggle)
audacity 3.2.4%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 106,704 kB
  • sloc: cpp: 277,038; ansic: 73,623; lisp: 7,761; python: 3,305; sh: 2,715; perl: 821; xml: 275; makefile: 119
file content (300 lines) | stat: -rw-r--r-- 10,716 bytes parent folder | download | duplicates (6)
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);
    }
}