1 /*-------------- Telecommunications & Signal Processing Lab ---------------
2 McGill University
3
4 Routine:
5 int AFdReadData (AFILE *AFp, long int offs, double Dbuff[], int Nreq)
6
7 Purpose:
8 Read data from an audio file (return double values)
9
10 Description:
11 This routine returns a specified number of samples at a given sample offset
12 in an audio file. The data in the file is converted to double format on
13 output. The sample data in the file is considered to be preceded and
14 followed by zero-valued samples. Thus if the sample offset is negative or
15 points to beyond the number of samples in the file, the appropriate number
16 of zero-valued samples is returned. The file must have been opened using
17 routine AFopnRead.
18
19 The following program fragment illustrates the use of this routine to read
20 overlapping frames of data. For the simpler case of sequential access to the
21 data without overlap, the variable Lmem should be set to zero.
22
23 AFp = AFopnRead (...);
24 ...
25 Lmem =...
26 Lframe =...
27 Nadv = Lframe-Lmem;
28 offs = -Lmem;
29 while (1) {
30 Nout = AFdReadData (AFp, offs, Dbuff, Lframe);
31 offs = offs+Nadv;
32 if (Nout == 0)
33 break;
34 ...
35 }
36
37 On encountering an error, the default behaviour is to print an error message
38 and halt execution.
39
40 Parameters:
41 <- int AFdReadData
42 Number of data values transferred from the file. On reaching the end of
43 the file, this value may be less than Nreq, in which case the last
44 elements are set to zero. This value can be used by the calling routine
45 to determine when the data from the file has been exhausted.
46 -> AFILE *AFp
47 Audio file pointer for an audio file opened by AFopnRead
48 -> long int offs
49 Offset into the file in samples. If offs is positive, the first value
50 returned is offs samples from the beginning of the data. The file data
51 is considered to be preceded by zeros. Thus if offs is negative, the
52 appropriate number of zeros will be returned. These zeros before the
53 beginning of the data are counted as part of the count returned in Nout.
54 <- double Dbuff[]
55 Array of doubles to receive the Nreq samples
56 -> int Nreq
57 Number of samples requested. Nreq may be zero.
58
59 Author / revision:
60 P. Kabal Copyright (C) 2003
61 $Revision: 1.2 $ $Date: 2003/05/09 01:03:46 $
62
63 -------------------------------------------------------------------------*/
64
65 #include <assert.h>
66 #include <stdlib.h> /* EXIT_FAILURE */
67
68 #include <libtsp.h>
69 #include <libtsp/AFdataio.h>
70 #include <libtsp/AFmsg.h>
71 #include <libtsp/AFpar.h>
72
73 #define MINV(a, b) (((a) < (b)) ? (a) : (b))
74 #define MAXV(a, b) (((a) > (b)) ? (a) : (b))
75
76 /* Reading routines */
77 static int
78 (*AF_Read[NFD])(AFILE *AFp, double Dbuff[], int Nreq) =
79 { NULL, AFdRdMulaw, AFdRdAlaw, AFdRdU1, AFdRdI1,
80 AFdRdI2, AFdRdI3, AFdRdI4, AFdRdF4, AFdRdF8,
81 AFdRdTA };
82
83 /*
84 The option flag ErrorHalt affects error handling.
85 If ErrorHalt is clear, execution continues after an error
86 - Fewer than requested elements are returned. To distinguish between an
87 error and and end-of-file, AFp->Error must be examined.
88 - An unexpected end-of-file is an error
89 - AFp->Error must be zero on input to this routine
90 */
91
92
93 int
AFdReadData(AFILE * AFp,long int offs,double Dbuff[],int Nreq)94 AFdReadData (AFILE *AFp, long int offs, double Dbuff[], int Nreq)
95
96 {
97 int i, Nb, Nv, Nr, Nout;
98
99 /* Check the operation */
100 assert (AFp->Op == FO_RO);
101 assert (! AFp->Error);
102
103 /* Fill in zeros at the beginning of data */
104 Nb = (int) MAXV (0, MINV (-offs, Nreq));
105 for (i = 0; i < Nb; ++i) {
106 Dbuff[i] = 0.0;
107 ++offs;
108 }
109 Nout = Nb;
110
111 /* Position the file */
112 AFp->Error = AFposition (AFp, offs);
113
114 /* The file reading routines expect that the file is positioned at the data
115 to be read. They use the following AFp fields:
116 AFp->fp - file pointer
117 AFp->Swapb - data swap indicator
118 AFp->ScaleF - data scaling factor
119 An error is detected on the outside by calling ferror() or by checking
120 AFp->Error (for text data files).
121
122 Errors: Nr < Nreq - Nb && ferror or AFp->Error set
123 EOF: Nr < Nreq - Nb && ferror and AFp->Error not set
124
125 This routine updates the following AFp values
126 AFp->Error - Set for an error
127 AFp->Isamp - Current data sample. This value is set to the current
128 position before reading and incremented by the number of samples read.
129 AFp->Nsamp - Number of samples (updated if not defined initially and EOF
130 is detected)
131 */
132
133 /* Transfer data from the file */
134 if (AFp->Nsamp == AF_NSAMP_UNDEF)
135 Nv = Nreq - Nout;
136 else
137 Nv = (int) MINV (Nreq - Nout, AFp->Nsamp - offs);
138
139 if (! AFp->Error && Nv > 0) {
140 Nr = (*AF_Read[AFp->Format]) (AFp, &Dbuff[Nb], Nv);
141 Nout += Nr;
142 AFp->Isamp += Nr;
143
144 /* Check for errors */
145 if (Nr < Nv) {
146 if (ferror (AFp->fp)) {
147 UTsysMsg ("AFdReadData - %s %ld", AFM_ReadErrOffs, AFp->Isamp);
148 AFp->Error = AF_IOERR;
149 }
150 else if (AFp->Error)
151 UTwarn ("AFdReadData - %s %ld", AFM_ReadErrOffs, AFp->Isamp);
152 else if (AFp->Nsamp != AF_NSAMP_UNDEF) {
153 UTwarn ("AFdReadData - %s %ld", AFM_UEoFOffs, AFp->Isamp);
154 AFp->Error = AF_UEOF;
155 }
156 else
157 AFp->Nsamp = AFp->Isamp;
158 }
159 }
160
161 /* Zeros at the end of the file */
162 for (i = Nout; i < Nreq; ++i)
163 Dbuff[i] = 0.0;
164
165 if (AFp->Error && (AFoptions ())->ErrorHalt)
166 exit (EXIT_FAILURE);
167
168 return Nout;
169 }
170