1 /*-------------- Telecommunications & Signal Processing Lab ---------------
2                              McGill University
3 
4 Routine:
5   int AFposition (AFILE *AFp, long int offs)
6 
7 Purpose:
8   Position an audio file to a given sample offset
9 
10 Description:
11   This routine positions a file to a given position.
12 
13 Parameters:
14   <-  int AFposition
15       Error indication, zero for no error
16    -> AFILE *AFp
17       Audio file pointer for an audio file opened by AFopnRead
18    -> long int offs
19       Offset into the file in samples.  If offs is negative or beyond the
20       end-of-file, no action is taken. If offs is beyond the current file
21       position, the position is moved to offs either by seeking (random access
22       binary file) or by reading (non-random access or text data). If offset
23       is before offs, move by seeking (random access binary file) or by
24       rewinding and reading (random access text file).
25 
26 Author / revision:
27   P. Kabal  Copyright (C) 2003
28   $Revision: 1.2 $  $Date: 2003/05/09 01:11:34 $
29 
30 -------------------------------------------------------------------------*/
31 
32 #include <string.h>
33 
34 #include <libtsp.h>
35 #include <libtsp/nucleus.h>
36 #include <libtsp/AFdataio.h>
37 #include <libtsp/AFmsg.h>
38 #define AF_DATA_LENGTHS
39 #include <libtsp/AFpar.h>
40 
41 #define MINV(a, b)	(((a) < (b)) ? (a) : (b))
42 
43 #define FREAD(buf,size,nv,fp)	(int) fread ((char *) buf, (size_t) size, \
44 					     (size_t) nv, fp)
45 #define AFSEEK(AFp,boff)	AFseek ((AFp)->fp, (AFp)->Start + (boff), NULL)
46 
47 static int
48 AF_skipNRec (AFILE *AFp, long int N);
49 static int
50 AF_skipNVal (AFILE *AFp, long int N);
51 
52 
53 int
AFposition(AFILE * AFp,long int offs)54 AFposition (AFILE *AFp, long int offs)
55 
56 {
57   int Lw, ErrCode;
58 
59 /*
60   Notes:
61   offs  < 0           Nop
62         < AFp->Isamp  seek
63        == AFp->Isamp  Nop
64         < AFp->Nsamp  seek or read
65        >= AFp->Nsamp  Nop
66   AFp->Nsamp == AF_NSAMP_UNDEF, the file is not random access
67                 (on encountering EOF, the value of AFp->Nsamp is set)
68              == value, can be either random access or not
69 */
70   ErrCode = 0;
71 
72   /* Quick exit */
73   if (offs == AFp->Isamp || offs < 0L ||
74       (AFp->Nsamp != AF_NSAMP_UNDEF && offs >= AFp->Nsamp))
75     return ErrCode;
76 
77   Lw = AF_DL[AFp->Format];
78   if (Lw > 0) {
79 
80 /* Fixed length records */
81     if (FLseekable (AFp->fp)) {
82       ErrCode = AFSEEK (AFp, Lw * offs);
83       if (! ErrCode)
84 	AFp->Isamp = offs;
85     }
86     else if (offs < AFp->Isamp) {
87       UTwarn ("AFposition: %s", AFM_MoveBack);
88       ErrCode = AF_IOERR;
89     }
90     else
91       ErrCode = AF_skipNVal (AFp, offs - AFp->Isamp);
92   }
93 
94   else {
95 
96 /* Variable length (text) records */
97     if (offs < AFp->Isamp) {
98       if (FLseekable (AFp->fp)) {
99 	ErrCode = AFSEEK (AFp, 0L);	/* Rewinding to start of data */
100 	if (! ErrCode)
101 	  AFp->Isamp = 0L;
102       }
103       else {
104 	UTwarn ("AFposition: %s", AFM_MoveBack);
105 	ErrCode = AF_IOERR;
106       }
107     }
108 
109     /* Move forward to the desired position */
110     if (! ErrCode)
111       ErrCode = AF_skipNRec (AFp, offs - AFp->Isamp);
112   }
113 
114   return ErrCode;
115 }
116 
117 /* Skip N values */
118 
119 #define NBUF	256
120 
121 
122 static int
AF_skipNVal(AFILE * AFp,long int N)123 AF_skipNVal (AFILE *AFp, long int N)
124 
125 {
126   long int nl;
127   int Lw, Nv, Nreq, ErrCode;
128   double Buf[NBUF];
129 
130   Lw = AF_DL[AFp->Format];
131 
132   /* Read N values  */
133   nl = 0L;
134   while (nl < N) {
135     Nreq = (int) MINV ((int) (sizeof Buf) / Lw, N - nl);
136     Nv = FREAD (Buf, Lw, Nreq, AFp->fp);
137     nl += Nv;
138     if (Nv < Nreq)
139       break;
140   }
141   AFp->Isamp += nl;
142 
143   ErrCode = 0;
144   if (nl < N) {
145     if (ferror (AFp->fp)) {
146       UTsysMsg ("AFposition: %s %ld", AFM_ReadErrOffs, AFp->Isamp);
147       ErrCode = AF_IOERR;
148     }
149     else if (AFp->Nsamp != AF_NSAMP_UNDEF) {
150       UTwarn ("AFposition: %s %ld", AFM_UEoFOffs, AFp->Isamp);
151       ErrCode = AF_UEOF;
152     }
153     else
154       AFp->Nsamp = AFp->Isamp;
155   }
156 
157   return ErrCode;
158 }
159 
160 /* Skip N records */
161 
162 
163 static int
AF_skipNRec(AFILE * AFp,long int N)164 AF_skipNRec (AFILE *AFp, long int N)
165 
166 {
167   char *p;
168   int ErrCode;
169   long int nl;
170 
171   /* Read N lines of input */
172   ErrCode = 0;
173   for (nl = 0; nl < N; ++nl) {
174     p = AFgetLine (AFp->fp, &ErrCode);
175     if (p == NULL || AFp->Error)
176       break;
177   }
178   AFp->Isamp += nl;
179 
180   if (nl < N) {
181     if (ErrCode)
182       UTwarn ("AFposition: %s %ld", AFM_ReadErrOffs, AFp->Isamp);
183     else if (AFp->Nsamp != AF_NSAMP_UNDEF) {
184       UTwarn ("AFposition: %s %ld", AFM_UEoFOffs, AFp->Isamp);
185       ErrCode = AF_UEOF;
186     }
187     else
188       AFp->Nsamp = AFp->Isamp;
189   }
190 
191   return ErrCode;
192 }
193