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 ;