tomwalters@0
|
1 /*
|
tomwalters@0
|
2 source.c
|
tomwalters@0
|
3 ========
|
tomwalters@0
|
4
|
tomwalters@0
|
5 New super minimal source system.
|
tomwalters@0
|
6
|
tomwalters@0
|
7 John Holdsworth, 2nd January 1989.
|
tomwalters@0
|
8
|
tomwalters@0
|
9 edited: MAA 3-8-1993
|
tomwalters@0
|
10 new options "review_aid" and "frameno_aid"
|
tomwalters@0
|
11
|
tomwalters@0
|
12 */
|
tomwalters@0
|
13
|
tomwalters@0
|
14 #if 0
|
tomwalters@0
|
15
|
tomwalters@0
|
16 What is a Source?
|
tomwalters@0
|
17 =================
|
tomwalters@0
|
18
|
tomwalters@0
|
19 Sources are a suggested style for coding computational processes on
|
tomwalters@0
|
20 continuous data streams. Making the extra effort to code according to
|
tomwalters@0
|
21 this style allows such processes to be easilly cascaded while still
|
tomwalters@0
|
22 able to operate on data streams of indefinite length. This is done by
|
tomwalters@0
|
23 performing the processing of the data stream in segments and passing
|
tomwalters@0
|
24 intermediate results systematically between processing stages using a
|
tomwalters@0
|
25 simple convention.
|
tomwalters@0
|
26
|
tomwalters@0
|
27 A source is like a file, in that it specifies the source of stream of
|
tomwalters@0
|
28 data. The data can be read in segments of user-defined size, like
|
tomwalters@0
|
29 reading from a file. For example, the routines sread() and sseek()
|
tomwalters@0
|
30 operate on Sources the same way that fread() and fseek() operate on
|
tomwalters@0
|
31 file streams. (sseek() operations on sources can only move forward in
|
tomwalters@0
|
32 a data stream).
|
tomwalters@0
|
33
|
tomwalters@0
|
34 Sources are different from files in that they do not necessarilly
|
tomwalters@0
|
35 just read data from disk. A Source may generally be a transformation
|
tomwalters@0
|
36 of data, or some simple processing operation on data. In addition, the
|
tomwalters@0
|
37 data may originate in any way the user may specify. The data may come
|
tomwalters@0
|
38 from a previous (cascaded) "Source".
|
tomwalters@0
|
39
|
tomwalters@0
|
40 The structured type "Source" contains enough information to generate
|
tomwalters@0
|
41 a stream of data. One way of processing a stream of data is to perform
|
tomwalters@0
|
42 a simple data-processing operation on another stream of data.
|
tomwalters@0
|
43 The input stream can be specified using a source.
|
tomwalters@0
|
44 Composite data-processing functions can be built up by cascading a
|
tomwalters@0
|
45 number of elementary functions.
|
tomwalters@0
|
46
|
tomwalters@0
|
47 If data is processed in large enough segments, the overhead of
|
tomwalters@0
|
48 performing the processing task in stages is not significant.
|
tomwalters@0
|
49
|
tomwalters@0
|
50
|
tomwalters@0
|
51 How to use sources
|
tomwalters@0
|
52 ==================
|
tomwalters@0
|
53
|
tomwalters@0
|
54 There are two distinct phases in working with sources, analogous to
|
tomwalters@0
|
55 opening a file (eg fopen()), and reading the file (eg fread()).
|
tomwalters@0
|
56
|
tomwalters@0
|
57 The first phase uses "setup" functions, analogous to fopen().
|
tomwalters@0
|
58 (See io.c for sources which read from disk. See model.c for sources
|
tomwalters@0
|
59 which perform specialised auditory-modelling processes).
|
tomwalters@0
|
60 Setup functions always return a Source. They may take one or more
|
tomwalters@0
|
61 sources as arguments, as a specification of the input to the process
|
tomwalters@0
|
62 the source performs. The user may define his own setup routine for
|
tomwalters@0
|
63 any new process. This routine intialises the source structure with
|
tomwalters@0
|
64 a pointer to a callback function, which performs the data processing
|
tomwalters@0
|
65 when the source is used.
|
tomwalters@0
|
66
|
tomwalters@0
|
67 The second phase uses pull/fill/roll functions, analogous to fread().
|
tomwalters@0
|
68 Unlike the fread function, Sources do not require you to supply a
|
tomwalters@0
|
69 buffer for the data to be "read" into.
|
tomwalters@0
|
70 There are three types of operation that can be performed on sources
|
tomwalters@0
|
71 depending on whether the users wishes to supply the data buffer.
|
tomwalters@0
|
72 (These three operations are referred to as "methods", in the style of
|
tomwalters@0
|
73 object-oriented programming. Sources are thought of as "objects").
|
tomwalters@0
|
74
|
tomwalters@0
|
75 The Pull() method returns a pointer to a buffer which has been
|
tomwalters@0
|
76 allocated by the source itself.
|
tomwalters@0
|
77 In the following example, the buffer will contain the next 100 bytes
|
tomwalters@0
|
78 of processed data.
|
tomwalters@0
|
79
|
tomwalters@0
|
80 /* declarations */
|
tomwalters@0
|
81 char *buffer ;
|
tomwalters@0
|
82 Source source = OpenSource( somehow ) ;
|
tomwalters@0
|
83 ByteCount bytes = 100 ;
|
tomwalters@0
|
84
|
tomwalters@0
|
85 /* call to "pull" 100 bytes of data out of Source "source" */
|
tomwalters@0
|
86 buffer = Pull( source, bytes ) ;
|
tomwalters@0
|
87
|
tomwalters@0
|
88
|
tomwalters@0
|
89 If the user has a buffer available for data and would prefer the data
|
tomwalters@0
|
90 be directly tranfered into it, the Fill() method can be used instead of
|
tomwalters@0
|
91 the Pull() method. The Fill method returns the address of the buffer
|
tomwalters@0
|
92 the user provides in case it is of use for the programmer.
|
tomwalters@0
|
93
|
tomwalters@0
|
94 /* declarations */
|
tomwalters@0
|
95 char buffer[100] ;
|
tomwalters@0
|
96 Source source = OpenSource( somehow ) ;
|
tomwalters@0
|
97 ByteCount bytes = 100 ;
|
tomwalters@0
|
98
|
tomwalters@0
|
99 /* call to "fill" the user's buffer with 100 bytes of data */
|
tomwalters@0
|
100 (void) Fill( source, bytes, buffer ) ;
|
tomwalters@0
|
101
|
tomwalters@0
|
102
|
tomwalters@0
|
103 In addition there is one further method of calling data from a source
|
tomwalters@0
|
104 that works like Pull(), but keeps a given number of bytes from the
|
tomwalters@0
|
105 previous call in the buffer.
|
tomwalters@0
|
106 The pointer returned by roll points to the start of the new data, as
|
tomwalters@0
|
107 in pull, but the space immediately before the pointer is still valid
|
tomwalters@0
|
108 and contains a specified number of bytes of data kept from the previous
|
tomwalters@0
|
109 call.
|
tomwalters@0
|
110 Bytes at the end of the buffer can be kept for the following roll call.
|
tomwalters@0
|
111
|
tomwalters@0
|
112 /* declarations */
|
tomwalters@0
|
113 char *buffer ;
|
tomwalters@0
|
114 Source source = OpenSource( somehow ) ;
|
tomwalters@0
|
115 ByteCount bytes = 100 ;
|
tomwalters@0
|
116
|
tomwalters@0
|
117 /* call to "pull" 100 bytes of data out of Source "source" */
|
tomwalters@0
|
118 buffer = Roll( source, bytes, 50 ) ;
|
tomwalters@0
|
119
|
tomwalters@0
|
120 /* "pull" another 100 bytes out of the source. */
|
tomwalters@0
|
121 /* The last 50 bytes of the previous call will be kept in the */
|
tomwalters@0
|
122 /* buffer, and will immediately precede the new 100 bytes. */
|
tomwalters@0
|
123 buffer = Roll( source, &bytes, 50 ) ;
|
tomwalters@0
|
124
|
tomwalters@0
|
125
|
tomwalters@0
|
126 In order for Roll to work properly though it MUST be the only call
|
tomwalters@0
|
127 made on a given source. This is as it retains more information
|
tomwalters@0
|
128 between calls than the Pull() and Fill() methods.
|
tomwalters@0
|
129
|
tomwalters@0
|
130
|
tomwalters@0
|
131 More recent versions are defined as: PullSome, FillSome, RollSome.
|
tomwalters@0
|
132 In these methods, a pointer to the number of bytes (eg. &bytes) is
|
tomwalters@0
|
133 used, so that the source can indicate that less data was available
|
tomwalters@0
|
134 than was requested.
|
tomwalters@0
|
135
|
tomwalters@0
|
136 Remember also that requesting a negative number of bytes is interpreted
|
tomwalters@0
|
137 as requesting a skip without processing of the negative of that number
|
tomwalters@0
|
138 of bytes. This works as most processing sources will simply ignore
|
tomwalters@0
|
139 a request to process a negative number of bytes but will pass on the
|
tomwalters@0
|
140 request to their input sources which may which to actually act on the
|
tomwalters@0
|
141 skip operation.
|
tomwalters@0
|
142
|
tomwalters@0
|
143 More importantly A request for zero bytes it taken to mean that the
|
tomwalters@0
|
144 source is not required anymore and should close itself and free any
|
tomwalters@0
|
145 resources it is using. If the request is passed on to any input sources
|
tomwalters@0
|
146 a close operation cascades the close request to it's' input sources. This
|
tomwalters@0
|
147 means in order to close a cascade of process only the final source need be closed.
|
tomwalters@0
|
148 N.B. The close operation is only performed if the number of bytes requested is
|
tomwalters@0
|
149 zero not if the number of bytes returned is zero.
|
tomwalters@0
|
150
|
tomwalters@0
|
151
|
tomwalters@0
|
152
|
tomwalters@0
|
153 ...ctd jwh
|
tomwalters@0
|
154
|
tomwalters@0
|
155 Writing new sources
|
tomwalters@0
|
156 ===================
|
tomwalters@0
|
157
|
tomwalters@0
|
158 At the lowest level a source is a pointer to a struct which contains
|
tomwalters@0
|
159 pointers to three functions or methods to deal with the three types
|
tomwalters@0
|
160 of request that can be issued to a source. Pull(), Fill(),and Roll()
|
tomwalters@0
|
161 are #defines macros that convert the not quite C language calls into
|
tomwalters@0
|
162 full C calls passing the source pointer as the first argument then
|
tomwalters@0
|
163 the arguments the user specifies.
|
tomwalters@0
|
164
|
tomwalters@0
|
165 For example:
|
tomwalters@0
|
166
|
tomwalters@0
|
167 buffer = PullSome( source, bytes ) ;
|
tomwalters@0
|
168
|
tomwalters@0
|
169 Becomes:
|
tomwalters@0
|
170
|
tomwalters@0
|
171 buffer = source->methods->pull( source, bytes ) ;
|
tomwalters@0
|
172
|
tomwalters@0
|
173 The #define macros is used simply as a convienience.
|
tomwalters@0
|
174
|
tomwalters@0
|
175 The basic Source typedefs are as follows :
|
tomwalters@0
|
176
|
tomwalters@0
|
177 typedef struct _methods {
|
tomwalters@0
|
178 Pointer (*pull)(), (*fill)(), (*roll)() ;
|
tomwalters@0
|
179 } Methods ;
|
tomwalters@0
|
180 typedef struct _source {
|
tomwalters@0
|
181 Methods methods ; Pointer buffer ; ByteCount bsize, valid ;
|
tomwalters@0
|
182 } Source ;
|
tomwalters@0
|
183
|
tomwalters@0
|
184 All sources must point to a structure containing at least this information
|
tomwalters@0
|
185 for Pull(), Fill() and Roll() operations to work on all sources.
|
tomwalters@0
|
186
|
tomwalters@0
|
187 To create a source the user initialises a static variable of type struct _methods with
|
tomwalters@0
|
188 the three routines written to support the three basic source operations.
|
tomwalters@0
|
189 A pointer to this structure is then used to initialise the methods field of
|
tomwalters@0
|
190 the struct _source section of the source's' state. A pointer to this structure
|
tomwalters@0
|
191 becomes the new source.
|
tomwalters@0
|
192
|
tomwalters@0
|
193 The function setSource() is provided to perform this minimal setup of
|
tomwalters@0
|
194 a new source and to initialise the other fields in the source
|
tomwalters@0
|
195 structure. The pointer to the new Source structure is allocated outside
|
tomwalters@0
|
196 setSource and passed to it in order to alow the possibility of it containing
|
tomwalters@0
|
197 more than the basic source information.
|
tomwalters@0
|
198
|
tomwalters@0
|
199 #endif
|
tomwalters@0
|
200
|
tomwalters@0
|
201 #include <stdio.h> /* added: MAA 3-8-1993*/
|
tomwalters@0
|
202 #include "stitch.h"
|
tomwalters@0
|
203 #include "source.h"
|
tomwalters@0
|
204 #include "options.h" /* added: MAA 3-8-1993*/
|
tomwalters@0
|
205
|
tomwalters@0
|
206 #ifndef DEBUG
|
tomwalters@0
|
207 #define DEBUG 0
|
tomwalters@0
|
208 #endif
|
tomwalters@0
|
209
|
tomwalters@0
|
210
|
tomwalters@0
|
211 /*
|
tomwalters@0
|
212 initialise new Source structure
|
tomwalters@0
|
213
|
tomwalters@0
|
214 */
|
tomwalters@0
|
215
|
tomwalters@0
|
216 Source setSource( source, puller, filler, roller, name )
|
tomwalters@0
|
217 struct _source *source ;
|
tomwalters@0
|
218 Pointer (*puller)(), (*filler)(), (*roller)() ;
|
tomwalters@0
|
219 char *name ;
|
tomwalters@0
|
220 {
|
tomwalters@0
|
221 Source returned ;
|
tomwalters@0
|
222 Source (*opener)() = 0 ;
|
tomwalters@0
|
223
|
tomwalters@0
|
224 source->pull = puller ;
|
tomwalters@0
|
225 source->fill = filler ;
|
tomwalters@0
|
226 source->roll = roller ;
|
tomwalters@0
|
227 source->open = opener ;
|
tomwalters@0
|
228
|
tomwalters@0
|
229 source->type = "void" ;
|
tomwalters@0
|
230 source->name = name ;
|
tomwalters@0
|
231
|
tomwalters@0
|
232 source->opened = 0 ;
|
tomwalters@0
|
233 source->returned = (Pointer) 0 ;
|
tomwalters@0
|
234 #if DEBUG
|
tomwalters@0
|
235 printf( "Creating %s\n", SourceName( source ) ) ;
|
tomwalters@0
|
236 #endif
|
tomwalters@0
|
237 _SPTR( returned ) = source ;
|
tomwalters@0
|
238
|
tomwalters@0
|
239 return ( returned ) ;
|
tomwalters@0
|
240 }
|
tomwalters@0
|
241
|
tomwalters@0
|
242 Source typeSource( source, type )
|
tomwalters@0
|
243 Source source ;
|
tomwalters@0
|
244 char *type ;
|
tomwalters@0
|
245 {
|
tomwalters@0
|
246 _SPTR( source )->type = type ;
|
tomwalters@0
|
247
|
tomwalters@0
|
248 return ( source ) ;
|
tomwalters@0
|
249 }
|
tomwalters@0
|
250
|
tomwalters@0
|
251 char *sourceType( source )
|
tomwalters@0
|
252 Source source ;
|
tomwalters@0
|
253 {
|
tomwalters@0
|
254 return ( _SPTR( source )->type ) ;
|
tomwalters@0
|
255 }
|
tomwalters@0
|
256
|
tomwalters@0
|
257 char *sourceName( source )
|
tomwalters@0
|
258 Source source ;
|
tomwalters@0
|
259 {
|
tomwalters@0
|
260 return ( _SPTR( source )->name ) ;
|
tomwalters@0
|
261 }
|
tomwalters@0
|
262
|
tomwalters@0
|
263 Pointer deleteSource( source )
|
tomwalters@0
|
264 Source source ;
|
tomwalters@0
|
265 {
|
tomwalters@0
|
266 #if DEBUG
|
tomwalters@0
|
267 printf( "Deleteing %s\n", SourceName( source ) ) ;
|
tomwalters@0
|
268 #endif
|
tomwalters@0
|
269 Delete( source ) ;
|
tomwalters@0
|
270
|
tomwalters@0
|
271 return ( (Pointer) 0 ) ;
|
tomwalters@0
|
272 }
|
tomwalters@0
|
273
|
tomwalters@0
|
274
|
tomwalters@0
|
275 #if 00
|
tomwalters@0
|
276 struct _source_operators NameOfClass = {
|
tomwalters@0
|
277 setSource, deleteSource,
|
tomwalters@0
|
278 typeSource, sourceType,
|
tomwalters@0
|
279 sourceName
|
tomwalters@0
|
280 } ;
|
tomwalters@0
|
281 #endif
|
tomwalters@0
|
282
|
tomwalters@0
|
283
|
tomwalters@0
|
284 /* MAA: 3-8-1993 */
|
tomwalters@0
|
285
|
tomwalters@0
|
286 void sinkSource( source, framebytes, frames )
|
tomwalters@0
|
287 Source source ;
|
tomwalters@0
|
288 int framebytes ;
|
tomwalters@0
|
289 long frames ;
|
tomwalters@0
|
290 {
|
tomwalters@0
|
291 long frame ;
|
tomwalters@0
|
292
|
tomwalters@0
|
293
|
tomwalters@0
|
294 extern *reviewstr;
|
tomwalters@0
|
295 extern *framenumberstr;
|
tomwalters@0
|
296
|
tomwalters@0
|
297 for( frame=0 ; frame<frames ; frame++ ) {
|
tomwalters@0
|
298
|
tomwalters@0
|
299 if ( isON (framenumberstr) || isON (reviewstr) ){
|
tomwalters@0
|
300 fprintf(stderr, " %i ", frame+1);
|
tomwalters@0
|
301 fflush(stderr);}
|
tomwalters@0
|
302
|
tomwalters@0
|
303 (void) Pull( source, framebytes ) ;
|
tomwalters@0
|
304
|
tomwalters@0
|
305 if ( isON (reviewstr)) {
|
tomwalters@0
|
306 fflush(stdin);getchar();}
|
tomwalters@0
|
307 }
|
tomwalters@0
|
308 return ;
|
tomwalters@0
|
309 }
|
tomwalters@0
|
310
|
tomwalters@0
|
311
|
tomwalters@0
|
312
|
tomwalters@0
|
313 void CloseSource( source )
|
tomwalters@0
|
314 Source source ;
|
tomwalters@0
|
315 {
|
tomwalters@0
|
316 (void) Pull( source, 0 ) ;
|
tomwalters@0
|
317
|
tomwalters@0
|
318 return ;
|
tomwalters@0
|
319 }
|
tomwalters@0
|
320
|
tomwalters@0
|
321 void sinkAndCloseSource( source, framebytes, frames )
|
tomwalters@0
|
322 Source source ;
|
tomwalters@0
|
323 int framebytes ;
|
tomwalters@0
|
324 long frames ;
|
tomwalters@0
|
325 {
|
tomwalters@0
|
326 SinkSource( source, framebytes, frames ) ;
|
tomwalters@0
|
327
|
tomwalters@0
|
328 CloseSource( source ) ;
|
tomwalters@0
|
329
|
tomwalters@0
|
330 return ;
|
tomwalters@0
|
331 }
|
tomwalters@0
|
332
|
tomwalters@0
|
333 /* tapping derived source */
|
tomwalters@0
|
334
|
tomwalters@0
|
335 typedef struct {
|
tomwalters@0
|
336 struct _source parent ;
|
tomwalters@0
|
337 Pointer state ;
|
tomwalters@0
|
338 void (*callback)(), (*close)() ;
|
tomwalters@0
|
339 Source input ;
|
tomwalters@0
|
340 } *TappingSource ;
|
tomwalters@0
|
341
|
tomwalters@0
|
342 static Pointer tapping_callback( source, bytes, buffer, last )
|
tomwalters@0
|
343 TappingSource source ;
|
tomwalters@0
|
344 ByteCount *bytes ;
|
tomwalters@0
|
345 Pointer buffer ;
|
tomwalters@0
|
346 int last ;
|
tomwalters@0
|
347 {
|
tomwalters@0
|
348 source->callback( source->state, bytes, buffer, buffer+*bytes ) ;
|
tomwalters@0
|
349
|
tomwalters@0
|
350 if( !last )
|
tomwalters@0
|
351 return ( buffer ) ;
|
tomwalters@0
|
352 else {
|
tomwalters@0
|
353 if( source->close != (void ( * )()) 0 )
|
tomwalters@0
|
354 source->close( source->state ) ;
|
tomwalters@0
|
355
|
tomwalters@0
|
356 return ( DeleteSource( source ) ) ;
|
tomwalters@0
|
357 }
|
tomwalters@0
|
358 }
|
tomwalters@0
|
359
|
tomwalters@0
|
360 static Pointer tappingPuller( source, bytes )
|
tomwalters@0
|
361 TappingSource source ;
|
tomwalters@0
|
362 ByteCount *bytes ;
|
tomwalters@0
|
363 {
|
tomwalters@0
|
364 register int last = *bytes == 0 ;
|
tomwalters@0
|
365 Pointer buffer = PullSome( source->input, bytes ) ;
|
tomwalters@0
|
366
|
tomwalters@0
|
367 #if DEBUG
|
tomwalters@0
|
368 printf( "\"%s\" pull tapping %d from \"%s\"\n", SourceName( source ), *bytes, SourceName( source->input ) ) ;
|
tomwalters@0
|
369 #endif
|
tomwalters@0
|
370
|
tomwalters@0
|
371 return ( tapping_callback( source, bytes, buffer, last ) ) ;
|
tomwalters@0
|
372 }
|
tomwalters@0
|
373
|
tomwalters@0
|
374 static Pointer tappingFiller( source, bytes, buffer )
|
tomwalters@0
|
375 TappingSource source ;
|
tomwalters@0
|
376 ByteCount *bytes ;
|
tomwalters@0
|
377 Pointer buffer ;
|
tomwalters@0
|
378 {
|
tomwalters@0
|
379 register int last = *bytes == 0 ;
|
tomwalters@0
|
380
|
tomwalters@0
|
381 FillSome( source->input, bytes, buffer ) ;
|
tomwalters@0
|
382
|
tomwalters@0
|
383 #if DEBUG
|
tomwalters@0
|
384 printf( "\"%s\" fill tapping %d from \"%s\"\n", SourceName( source ), *bytes, SourceName( source->input ) ) ;
|
tomwalters@0
|
385 #endif
|
tomwalters@0
|
386
|
tomwalters@0
|
387 return ( tapping_callback( source, bytes, buffer, last ) ) ;
|
tomwalters@0
|
388 }
|
tomwalters@0
|
389
|
tomwalters@0
|
390 static Pointer tappingRoller( source, bytes, keep )
|
tomwalters@0
|
391 TappingSource source ;
|
tomwalters@0
|
392 ByteCount *bytes, keep ;
|
tomwalters@0
|
393 {
|
tomwalters@0
|
394 register int last = *bytes == 0 ;
|
tomwalters@0
|
395 Pointer buffer = RollSome( source->input, bytes, keep ) ;
|
tomwalters@0
|
396
|
tomwalters@0
|
397 #if DEBUG
|
tomwalters@0
|
398 printf( "\"%s\" roll tapping %d from \"%s\"\n", SourceName( source ), *bytes, SourceName( source->input ) ) ;
|
tomwalters@0
|
399 #endif
|
tomwalters@0
|
400
|
tomwalters@0
|
401 return ( tapping_callback( source, bytes, buffer, last ) ) ;
|
tomwalters@0
|
402 }
|
tomwalters@0
|
403
|
tomwalters@0
|
404 Source newTappingSource( state, callback, close, input, name )
|
tomwalters@0
|
405 Pointer state ;
|
tomwalters@0
|
406 void (*callback)(), (*close)() ;
|
tomwalters@0
|
407 Source input ;
|
tomwalters@0
|
408 char *name ;
|
tomwalters@0
|
409 {
|
tomwalters@0
|
410 DeclareNew( TappingSource, source ) ;
|
tomwalters@0
|
411
|
tomwalters@0
|
412 source->state = state ;
|
tomwalters@0
|
413 source->callback = callback ;
|
tomwalters@0
|
414 source->close = close ;
|
tomwalters@0
|
415 source->input = input ;
|
tomwalters@0
|
416
|
tomwalters@0
|
417 return ( SetSource( source, tappingPuller, tappingFiller, tappingRoller, name ) ) ;
|
tomwalters@0
|
418 }
|
tomwalters@0
|
419
|
tomwalters@0
|
420 /* rollable derived source */
|
tomwalters@0
|
421
|
tomwalters@0
|
422 typedef struct {
|
tomwalters@0
|
423 struct _source parent ;
|
tomwalters@0
|
424 Pointer buffer ;
|
tomwalters@0
|
425 ByteCount bsize, valid ;
|
tomwalters@0
|
426 Source input ;
|
tomwalters@0
|
427 } *RollableSource ;
|
tomwalters@0
|
428
|
tomwalters@0
|
429 Pointer DeleteRollableSource( source )
|
tomwalters@0
|
430 RollableSource source ;
|
tomwalters@0
|
431 {
|
tomwalters@0
|
432 if( source->bsize != 0 )
|
tomwalters@0
|
433 Delete( source->buffer ) ;
|
tomwalters@0
|
434
|
tomwalters@0
|
435 return ( DeleteSource( source ) ) ;
|
tomwalters@0
|
436 }
|
tomwalters@0
|
437
|
tomwalters@0
|
438 static Pointer rollablePuller( source, bytes )
|
tomwalters@0
|
439 RollableSource source ;
|
tomwalters@0
|
440 ByteCount *bytes ;
|
tomwalters@0
|
441 {
|
tomwalters@0
|
442 #if DEBUG
|
tomwalters@0
|
443 printf( "rollable \"%s\" pulling %d from \"%s\"\n", SourceName( source ), *bytes, SourceName( source->input ) ) ;
|
tomwalters@0
|
444 #endif
|
tomwalters@0
|
445
|
tomwalters@0
|
446 return ( RollSome( source->input, bytes, 0 ) ) ;
|
tomwalters@0
|
447 }
|
tomwalters@0
|
448
|
tomwalters@0
|
449 static Pointer rollableFiller( source, bytes, buffer )
|
tomwalters@0
|
450 RollableSource source ;
|
tomwalters@0
|
451 ByteCount *bytes ;
|
tomwalters@0
|
452 Pointer buffer ;
|
tomwalters@0
|
453 {
|
tomwalters@0
|
454 register int last = *bytes == 0 ;
|
tomwalters@0
|
455
|
tomwalters@0
|
456 FillSome( source->input, bytes, buffer ) ;
|
tomwalters@0
|
457
|
tomwalters@0
|
458 source->valid = *bytes ;
|
tomwalters@0
|
459
|
tomwalters@0
|
460 #if DEBUG
|
tomwalters@0
|
461 printf( "rollable \"%s\" filling %d from \"%s\"\n", SourceName( source ), *bytes, SourceName( source->input ) ) ;
|
tomwalters@0
|
462 #endif
|
tomwalters@0
|
463
|
tomwalters@0
|
464 if( !last )
|
tomwalters@0
|
465 return ( buffer ) ;
|
tomwalters@0
|
466 else
|
tomwalters@0
|
467 return ( DeleteRollableSource( source ) ) ;
|
tomwalters@0
|
468 }
|
tomwalters@0
|
469
|
tomwalters@0
|
470 static Pointer rollableRoller( source, bytes, keep )
|
tomwalters@0
|
471 RollableSource source ;
|
tomwalters@0
|
472 ByteCount *bytes, keep ;
|
tomwalters@0
|
473 {
|
tomwalters@0
|
474 register int last = *bytes == 0 ;
|
tomwalters@0
|
475 Pointer oldBuffer = source->buffer ;
|
tomwalters@0
|
476 ByteCount toStore = *bytes + keep ;
|
tomwalters@0
|
477
|
tomwalters@0
|
478 if( source->bsize < toStore ) {
|
tomwalters@0
|
479
|
tomwalters@0
|
480 source->buffer = Allocate( toStore, "source.c for retaining buffer" ) ;
|
tomwalters@0
|
481
|
tomwalters@0
|
482 source->bsize = toStore ;
|
tomwalters@0
|
483 }
|
tomwalters@0
|
484
|
tomwalters@0
|
485 if( oldBuffer == (Pointer) 0 )
|
tomwalters@0
|
486 ZeroArray( (char *) source->buffer, keep ) ;
|
tomwalters@0
|
487 else {
|
tomwalters@0
|
488 CopyArray( (char *) oldBuffer+source->valid-keep, (char *) source->buffer, keep ) ;
|
tomwalters@0
|
489
|
tomwalters@0
|
490 if( oldBuffer != source->buffer )
|
tomwalters@0
|
491 Delete( oldBuffer ) ;
|
tomwalters@0
|
492 }
|
tomwalters@0
|
493
|
tomwalters@0
|
494 FillSome( source->input, bytes, source->buffer + keep ) ;
|
tomwalters@0
|
495
|
tomwalters@0
|
496 source->valid = keep + *bytes ;
|
tomwalters@0
|
497
|
tomwalters@0
|
498 if( !last )
|
tomwalters@0
|
499 return ( source->buffer + keep ) ;
|
tomwalters@0
|
500 else
|
tomwalters@0
|
501 return ( DeleteRollableSource( source ) ) ;
|
tomwalters@0
|
502 }
|
tomwalters@0
|
503
|
tomwalters@0
|
504 Source newRollableSource( input )
|
tomwalters@0
|
505 Source input ;
|
tomwalters@0
|
506 {
|
tomwalters@0
|
507 DeclareNew( RollableSource, source ) ;
|
tomwalters@0
|
508
|
tomwalters@0
|
509 source->buffer = (Pointer) 0 ;
|
tomwalters@0
|
510
|
tomwalters@0
|
511 source->bsize = 0 ;
|
tomwalters@0
|
512 source->valid = 0 ;
|
tomwalters@0
|
513
|
tomwalters@0
|
514 source->input = input ;
|
tomwalters@0
|
515
|
tomwalters@0
|
516 return ( SetSource( source, rollablePuller, rollableFiller, rollableRoller, "rollable" ) ) ;
|
tomwalters@0
|
517 }
|
tomwalters@0
|
518
|
tomwalters@0
|
519 /* all other sources don't support rolling */
|
tomwalters@0
|
520
|
tomwalters@0
|
521 Pointer nonRoller( source, bytes, keep )
|
tomwalters@0
|
522 Source source ;
|
tomwalters@0
|
523 ByteCount *bytes, keep ;
|
tomwalters@0
|
524 {
|
tomwalters@0
|
525 stitch_error( "Sorry rolling not availiable on source \"%s\"\n", SourceName( source ) ) ;
|
tomwalters@0
|
526
|
tomwalters@0
|
527 return ( Pull( source, bytes ) ) ;
|
tomwalters@0
|
528 }
|
tomwalters@0
|
529
|
tomwalters@0
|
530
|
tomwalters@0
|
531
|
tomwalters@0
|
532 /* for compatability */
|
tomwalters@0
|
533
|
tomwalters@0
|
534 typedef struct _auto_source {
|
tomwalters@0
|
535 struct _fillable_source parent ; Pointer state ; void (*callback)() ;
|
tomwalters@0
|
536 } *AutoSource ;
|
tomwalters@0
|
537
|
tomwalters@0
|
538 static Pointer autoFiller( source, bytes, buffer )
|
tomwalters@0
|
539 AutoSource source ;
|
tomwalters@0
|
540 ByteCount *bytes ;
|
tomwalters@0
|
541 Pointer buffer ;
|
tomwalters@0
|
542 {
|
tomwalters@0
|
543 register int last = *bytes == 0 ;
|
tomwalters@0
|
544
|
tomwalters@0
|
545 source->callback( source->state, *bytes, buffer ) ;
|
tomwalters@0
|
546
|
tomwalters@0
|
547 if( !last )
|
tomwalters@0
|
548 return ( buffer ) ;
|
tomwalters@0
|
549 else
|
tomwalters@0
|
550 return ( DeleteFillableSource( source ) ) ;
|
tomwalters@0
|
551 }
|
tomwalters@0
|
552
|
tomwalters@0
|
553 Source stdAutoSource( state, callback )
|
tomwalters@0
|
554 Pointer state ;
|
tomwalters@0
|
555 void (*callback)() ;
|
tomwalters@0
|
556 {
|
tomwalters@0
|
557 DeclareNew( AutoSource, source ) ;
|
tomwalters@0
|
558
|
tomwalters@0
|
559 source->state = state ;
|
tomwalters@0
|
560 source->callback = callback ;
|
tomwalters@0
|
561
|
tomwalters@0
|
562 return ( SetFillableSource( source, autoFiller, "stdAuto" ) ) ;
|
tomwalters@0
|
563 }
|
tomwalters@0
|
564
|
tomwalters@0
|
565 typedef struct _self_source {
|
tomwalters@0
|
566 struct _pullable_source parent ; Pointer state, (*callback)() ;
|
tomwalters@0
|
567 } *SelfSource ;
|
tomwalters@0
|
568
|
tomwalters@0
|
569 static Pointer selfGenerator( source, bytes )
|
tomwalters@0
|
570 SelfSource source ;
|
tomwalters@0
|
571 ByteCount *bytes ;
|
tomwalters@0
|
572 {
|
tomwalters@0
|
573 register int last = *bytes == 0 ;
|
tomwalters@0
|
574 Pointer ptr = source->callback( source->state, *bytes ) ;
|
tomwalters@0
|
575
|
tomwalters@0
|
576 if( !last )
|
tomwalters@0
|
577 return ( ptr ) ;
|
tomwalters@0
|
578 else
|
tomwalters@0
|
579 return ( DeleteSource( source ) ) ;
|
tomwalters@0
|
580 }
|
tomwalters@0
|
581
|
tomwalters@0
|
582 Source stdSelfSource( state, callback )
|
tomwalters@0
|
583 Pointer state ;
|
tomwalters@0
|
584 Pointer (*callback)() ;
|
tomwalters@0
|
585 {
|
tomwalters@0
|
586 DeclareNew( SelfSource, source ) ;
|
tomwalters@0
|
587
|
tomwalters@0
|
588 source->state = state ;
|
tomwalters@0
|
589 source->callback = callback ;
|
tomwalters@0
|
590
|
tomwalters@0
|
591 return ( SetPullableSource( source, selfGenerator, "stdSelf" ) ) ;
|
tomwalters@0
|
592 }
|
tomwalters@0
|
593
|
tomwalters@0
|
594 Source stdStaticSource( ptr )
|
tomwalters@0
|
595 Pointer ptr ;
|
tomwalters@0
|
596 {
|
tomwalters@0
|
597 return ( NewStaticSource( ptr ) ) ;
|
tomwalters@0
|
598 }
|
tomwalters@0
|
599
|
tomwalters@0
|
600 Source stdSlaveSource( source )
|
tomwalters@0
|
601 Source source ;
|
tomwalters@0
|
602 {
|
tomwalters@0
|
603 return ( NewSlaveSource( source ) ) ;
|
tomwalters@0
|
604 }
|
tomwalters@0
|
605
|
tomwalters@0
|
606 Pointer oldPull( source, bytes )
|
tomwalters@0
|
607 struct _source *source ;
|
tomwalters@0
|
608 ByteCount bytes ;
|
tomwalters@0
|
609 {
|
tomwalters@0
|
610 ByteCount tmp = bytes ;
|
tomwalters@0
|
611
|
tomwalters@0
|
612 return ( source->pull( source, &tmp ) ) ;
|
tomwalters@0
|
613 }
|
tomwalters@0
|
614
|
tomwalters@0
|
615 Pointer oldFill( source, bytes, buffer )
|
tomwalters@0
|
616 struct _source *source ;
|
tomwalters@0
|
617 ByteCount bytes ;
|
tomwalters@0
|
618 Pointer buffer ;
|
tomwalters@0
|
619 {
|
tomwalters@0
|
620 ByteCount tmp = bytes ;
|
tomwalters@0
|
621 Pointer bptr = buffer ;
|
tomwalters@0
|
622
|
tomwalters@0
|
623 do {
|
tomwalters@0
|
624 tmp = buffer + bytes - bptr ;
|
tomwalters@0
|
625
|
tomwalters@0
|
626 source->fill( source, &tmp, bptr ) ;
|
tomwalters@0
|
627 bptr += tmp ;
|
tomwalters@0
|
628
|
tomwalters@0
|
629 } while( bptr < buffer + bytes && tmp != 0 ) ;
|
tomwalters@0
|
630
|
tomwalters@0
|
631 return ( buffer ) ;
|
tomwalters@0
|
632 }
|
tomwalters@0
|
633
|
tomwalters@0
|
634 Pointer oldRoll( source, bytes, keep )
|
tomwalters@0
|
635 struct _source *source ;
|
tomwalters@0
|
636 ByteCount bytes, keep ;
|
tomwalters@0
|
637 {
|
tomwalters@0
|
638 ByteCount tmp = bytes ;
|
tomwalters@0
|
639
|
tomwalters@0
|
640 return ( source->roll( source, &tmp, keep ) ) ;
|
tomwalters@0
|
641 }
|
tomwalters@0
|
642
|
tomwalters@0
|
643 #if 00
|
tomwalters@0
|
644 static struct _source convertors = { oldPull, oldFill, oldRoll } ;
|
tomwalters@0
|
645 struct _source *call_conversions = &convertors ;
|
tomwalters@0
|
646 #endif
|
tomwalters@0
|
647
|
tomwalters@0
|
648 /* for binding multiple sources */
|
tomwalters@0
|
649
|
tomwalters@0
|
650 #if !defined(PC) && !defined(DSP32)
|
tomwalters@0
|
651 #include <varargs.h>
|
tomwalters@0
|
652
|
tomwalters@0
|
653 Source *BindSources( va_alist )
|
tomwalters@0
|
654 va_dcl
|
tomwalters@0
|
655 {
|
tomwalters@0
|
656 Source *inputs ;
|
tomwalters@0
|
657 va_list argp ;
|
tomwalters@0
|
658 int count, c ;
|
tomwalters@0
|
659
|
tomwalters@0
|
660 va_start( argp ) ;
|
tomwalters@0
|
661
|
tomwalters@0
|
662 for( count=0 ; _SPTR( va_arg( argp, Source ) ) != (struct _source *) 0 ; count++ )
|
tomwalters@0
|
663 ;
|
tomwalters@0
|
664
|
tomwalters@0
|
665 inputs = NewArray( Source, count+1, "for binding inputs in source.c" ) ;
|
tomwalters@0
|
666
|
tomwalters@0
|
667 va_end( argp ) ;
|
tomwalters@0
|
668 va_start( argp ) ;
|
tomwalters@0
|
669
|
tomwalters@0
|
670 for( c=0 ; c<=count ; c++ )
|
tomwalters@0
|
671 inputs[c] = va_arg( argp, Source ) ;
|
tomwalters@0
|
672
|
tomwalters@0
|
673 va_end( argp ) ;
|
tomwalters@0
|
674
|
tomwalters@0
|
675 return ( inputs ) ;
|
tomwalters@0
|
676 }
|
tomwalters@0
|
677 #endif
|
tomwalters@0
|
678
|
tomwalters@0
|
679 struct _source notRealySource ;
|
tomwalters@0
|
680
|
tomwalters@0
|
681 Source EmptySource ;
|