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