tomwalters@0: /* tomwalters@0: source.c tomwalters@0: ======== tomwalters@0: tomwalters@0: New super minimal source system. tomwalters@0: tomwalters@0: John Holdsworth, 2nd January 1989. tomwalters@0: tomwalters@0: edited: MAA 3-8-1993 tomwalters@0: new options "review_aid" and "frameno_aid" tomwalters@0: tomwalters@0: */ tomwalters@0: tomwalters@0: #if 0 tomwalters@0: tomwalters@0: What is a Source? tomwalters@0: ================= tomwalters@0: tomwalters@0: Sources are a suggested style for coding computational processes on tomwalters@0: continuous data streams. Making the extra effort to code according to tomwalters@0: this style allows such processes to be easilly cascaded while still tomwalters@0: able to operate on data streams of indefinite length. This is done by tomwalters@0: performing the processing of the data stream in segments and passing tomwalters@0: intermediate results systematically between processing stages using a tomwalters@0: simple convention. tomwalters@0: tomwalters@0: A source is like a file, in that it specifies the source of stream of tomwalters@0: data. The data can be read in segments of user-defined size, like tomwalters@0: reading from a file. For example, the routines sread() and sseek() tomwalters@0: operate on Sources the same way that fread() and fseek() operate on tomwalters@0: file streams. (sseek() operations on sources can only move forward in tomwalters@0: a data stream). tomwalters@0: tomwalters@0: Sources are different from files in that they do not necessarilly tomwalters@0: just read data from disk. A Source may generally be a transformation tomwalters@0: of data, or some simple processing operation on data. In addition, the tomwalters@0: data may originate in any way the user may specify. The data may come tomwalters@0: from a previous (cascaded) "Source". tomwalters@0: tomwalters@0: The structured type "Source" contains enough information to generate tomwalters@0: a stream of data. One way of processing a stream of data is to perform tomwalters@0: a simple data-processing operation on another stream of data. tomwalters@0: The input stream can be specified using a source. tomwalters@0: Composite data-processing functions can be built up by cascading a tomwalters@0: number of elementary functions. tomwalters@0: tomwalters@0: If data is processed in large enough segments, the overhead of tomwalters@0: performing the processing task in stages is not significant. tomwalters@0: tomwalters@0: tomwalters@0: How to use sources tomwalters@0: ================== tomwalters@0: tomwalters@0: There are two distinct phases in working with sources, analogous to tomwalters@0: opening a file (eg fopen()), and reading the file (eg fread()). tomwalters@0: tomwalters@0: The first phase uses "setup" functions, analogous to fopen(). tomwalters@0: (See io.c for sources which read from disk. See model.c for sources tomwalters@0: which perform specialised auditory-modelling processes). tomwalters@0: Setup functions always return a Source. They may take one or more tomwalters@0: sources as arguments, as a specification of the input to the process tomwalters@0: the source performs. The user may define his own setup routine for tomwalters@0: any new process. This routine intialises the source structure with tomwalters@0: a pointer to a callback function, which performs the data processing tomwalters@0: when the source is used. tomwalters@0: tomwalters@0: The second phase uses pull/fill/roll functions, analogous to fread(). tomwalters@0: Unlike the fread function, Sources do not require you to supply a tomwalters@0: buffer for the data to be "read" into. tomwalters@0: There are three types of operation that can be performed on sources tomwalters@0: depending on whether the users wishes to supply the data buffer. tomwalters@0: (These three operations are referred to as "methods", in the style of tomwalters@0: object-oriented programming. Sources are thought of as "objects"). tomwalters@0: tomwalters@0: The Pull() method returns a pointer to a buffer which has been tomwalters@0: allocated by the source itself. tomwalters@0: In the following example, the buffer will contain the next 100 bytes tomwalters@0: of processed data. tomwalters@0: tomwalters@0: /* declarations */ tomwalters@0: char *buffer ; tomwalters@0: Source source = OpenSource( somehow ) ; tomwalters@0: ByteCount bytes = 100 ; tomwalters@0: tomwalters@0: /* call to "pull" 100 bytes of data out of Source "source" */ tomwalters@0: buffer = Pull( source, bytes ) ; tomwalters@0: tomwalters@0: tomwalters@0: If the user has a buffer available for data and would prefer the data tomwalters@0: be directly tranfered into it, the Fill() method can be used instead of tomwalters@0: the Pull() method. The Fill method returns the address of the buffer tomwalters@0: the user provides in case it is of use for the programmer. tomwalters@0: tomwalters@0: /* declarations */ tomwalters@0: char buffer[100] ; tomwalters@0: Source source = OpenSource( somehow ) ; tomwalters@0: ByteCount bytes = 100 ; tomwalters@0: tomwalters@0: /* call to "fill" the user's buffer with 100 bytes of data */ tomwalters@0: (void) Fill( source, bytes, buffer ) ; tomwalters@0: tomwalters@0: tomwalters@0: In addition there is one further method of calling data from a source tomwalters@0: that works like Pull(), but keeps a given number of bytes from the tomwalters@0: previous call in the buffer. tomwalters@0: The pointer returned by roll points to the start of the new data, as tomwalters@0: in pull, but the space immediately before the pointer is still valid tomwalters@0: and contains a specified number of bytes of data kept from the previous tomwalters@0: call. tomwalters@0: Bytes at the end of the buffer can be kept for the following roll call. tomwalters@0: tomwalters@0: /* declarations */ tomwalters@0: char *buffer ; tomwalters@0: Source source = OpenSource( somehow ) ; tomwalters@0: ByteCount bytes = 100 ; tomwalters@0: tomwalters@0: /* call to "pull" 100 bytes of data out of Source "source" */ tomwalters@0: buffer = Roll( source, bytes, 50 ) ; tomwalters@0: tomwalters@0: /* "pull" another 100 bytes out of the source. */ tomwalters@0: /* The last 50 bytes of the previous call will be kept in the */ tomwalters@0: /* buffer, and will immediately precede the new 100 bytes. */ tomwalters@0: buffer = Roll( source, &bytes, 50 ) ; tomwalters@0: tomwalters@0: tomwalters@0: In order for Roll to work properly though it MUST be the only call tomwalters@0: made on a given source. This is as it retains more information tomwalters@0: between calls than the Pull() and Fill() methods. tomwalters@0: tomwalters@0: tomwalters@0: More recent versions are defined as: PullSome, FillSome, RollSome. tomwalters@0: In these methods, a pointer to the number of bytes (eg. &bytes) is tomwalters@0: used, so that the source can indicate that less data was available tomwalters@0: than was requested. tomwalters@0: tomwalters@0: Remember also that requesting a negative number of bytes is interpreted tomwalters@0: as requesting a skip without processing of the negative of that number tomwalters@0: of bytes. This works as most processing sources will simply ignore tomwalters@0: a request to process a negative number of bytes but will pass on the tomwalters@0: request to their input sources which may which to actually act on the tomwalters@0: skip operation. tomwalters@0: tomwalters@0: More importantly A request for zero bytes it taken to mean that the tomwalters@0: source is not required anymore and should close itself and free any tomwalters@0: resources it is using. If the request is passed on to any input sources tomwalters@0: a close operation cascades the close request to it's' input sources. This tomwalters@0: means in order to close a cascade of process only the final source need be closed. tomwalters@0: N.B. The close operation is only performed if the number of bytes requested is tomwalters@0: zero not if the number of bytes returned is zero. tomwalters@0: tomwalters@0: tomwalters@0: tomwalters@0: ...ctd jwh tomwalters@0: tomwalters@0: Writing new sources tomwalters@0: =================== tomwalters@0: tomwalters@0: At the lowest level a source is a pointer to a struct which contains tomwalters@0: pointers to three functions or methods to deal with the three types tomwalters@0: of request that can be issued to a source. Pull(), Fill(),and Roll() tomwalters@0: are #defines macros that convert the not quite C language calls into tomwalters@0: full C calls passing the source pointer as the first argument then tomwalters@0: the arguments the user specifies. tomwalters@0: tomwalters@0: For example: tomwalters@0: tomwalters@0: buffer = PullSome( source, bytes ) ; tomwalters@0: tomwalters@0: Becomes: tomwalters@0: tomwalters@0: buffer = source->methods->pull( source, bytes ) ; tomwalters@0: tomwalters@0: The #define macros is used simply as a convienience. tomwalters@0: tomwalters@0: The basic Source typedefs are as follows : tomwalters@0: tomwalters@0: typedef struct _methods { tomwalters@0: Pointer (*pull)(), (*fill)(), (*roll)() ; tomwalters@0: } Methods ; tomwalters@0: typedef struct _source { tomwalters@0: Methods methods ; Pointer buffer ; ByteCount bsize, valid ; tomwalters@0: } Source ; tomwalters@0: tomwalters@0: All sources must point to a structure containing at least this information tomwalters@0: for Pull(), Fill() and Roll() operations to work on all sources. tomwalters@0: tomwalters@0: To create a source the user initialises a static variable of type struct _methods with tomwalters@0: the three routines written to support the three basic source operations. tomwalters@0: A pointer to this structure is then used to initialise the methods field of tomwalters@0: the struct _source section of the source's' state. A pointer to this structure tomwalters@0: becomes the new source. tomwalters@0: tomwalters@0: The function setSource() is provided to perform this minimal setup of tomwalters@0: a new source and to initialise the other fields in the source tomwalters@0: structure. The pointer to the new Source structure is allocated outside tomwalters@0: setSource and passed to it in order to alow the possibility of it containing tomwalters@0: more than the basic source information. tomwalters@0: tomwalters@0: #endif tomwalters@0: tomwalters@0: #include /* added: MAA 3-8-1993*/ tomwalters@0: #include "stitch.h" tomwalters@0: #include "source.h" tomwalters@0: #include "options.h" /* added: MAA 3-8-1993*/ tomwalters@0: tomwalters@0: #ifndef DEBUG tomwalters@0: #define DEBUG 0 tomwalters@0: #endif tomwalters@0: tomwalters@0: tomwalters@0: /* tomwalters@0: initialise new Source structure tomwalters@0: tomwalters@0: */ tomwalters@0: tomwalters@0: Source setSource( source, puller, filler, roller, name ) tomwalters@0: struct _source *source ; tomwalters@0: Pointer (*puller)(), (*filler)(), (*roller)() ; tomwalters@0: char *name ; tomwalters@0: { tomwalters@0: Source returned ; tomwalters@0: Source (*opener)() = 0 ; tomwalters@0: tomwalters@0: source->pull = puller ; tomwalters@0: source->fill = filler ; tomwalters@0: source->roll = roller ; tomwalters@0: source->open = opener ; tomwalters@0: tomwalters@0: source->type = "void" ; tomwalters@0: source->name = name ; tomwalters@0: tomwalters@0: source->opened = 0 ; tomwalters@0: source->returned = (Pointer) 0 ; tomwalters@0: #if DEBUG tomwalters@0: printf( "Creating %s\n", SourceName( source ) ) ; tomwalters@0: #endif tomwalters@0: _SPTR( returned ) = source ; tomwalters@0: tomwalters@0: return ( returned ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Source typeSource( source, type ) tomwalters@0: Source source ; tomwalters@0: char *type ; tomwalters@0: { tomwalters@0: _SPTR( source )->type = type ; tomwalters@0: tomwalters@0: return ( source ) ; tomwalters@0: } tomwalters@0: tomwalters@0: char *sourceType( source ) tomwalters@0: Source source ; tomwalters@0: { tomwalters@0: return ( _SPTR( source )->type ) ; tomwalters@0: } tomwalters@0: tomwalters@0: char *sourceName( source ) tomwalters@0: Source source ; tomwalters@0: { tomwalters@0: return ( _SPTR( source )->name ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Pointer deleteSource( source ) tomwalters@0: Source source ; tomwalters@0: { tomwalters@0: #if DEBUG tomwalters@0: printf( "Deleteing %s\n", SourceName( source ) ) ; tomwalters@0: #endif tomwalters@0: Delete( source ) ; tomwalters@0: tomwalters@0: return ( (Pointer) 0 ) ; tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: #if 00 tomwalters@0: struct _source_operators NameOfClass = { tomwalters@0: setSource, deleteSource, tomwalters@0: typeSource, sourceType, tomwalters@0: sourceName tomwalters@0: } ; tomwalters@0: #endif tomwalters@0: tomwalters@0: tomwalters@0: /* MAA: 3-8-1993 */ tomwalters@0: tomwalters@0: void sinkSource( source, framebytes, frames ) tomwalters@0: Source source ; tomwalters@0: int framebytes ; tomwalters@0: long frames ; tomwalters@0: { tomwalters@0: long frame ; tomwalters@0: tomwalters@0: tomwalters@0: extern *reviewstr; tomwalters@0: extern *framenumberstr; tomwalters@0: tomwalters@0: for( frame=0 ; framecallback( source->state, bytes, buffer, buffer+*bytes ) ; tomwalters@0: tomwalters@0: if( !last ) tomwalters@0: return ( buffer ) ; tomwalters@0: else { tomwalters@0: if( source->close != (void ( * )()) 0 ) tomwalters@0: source->close( source->state ) ; tomwalters@0: tomwalters@0: return ( DeleteSource( source ) ) ; tomwalters@0: } tomwalters@0: } tomwalters@0: tomwalters@0: static Pointer tappingPuller( source, bytes ) tomwalters@0: TappingSource source ; tomwalters@0: ByteCount *bytes ; tomwalters@0: { tomwalters@0: register int last = *bytes == 0 ; tomwalters@0: Pointer buffer = PullSome( source->input, bytes ) ; tomwalters@0: tomwalters@0: #if DEBUG tomwalters@0: printf( "\"%s\" pull tapping %d from \"%s\"\n", SourceName( source ), *bytes, SourceName( source->input ) ) ; tomwalters@0: #endif tomwalters@0: tomwalters@0: return ( tapping_callback( source, bytes, buffer, last ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: static Pointer tappingFiller( source, bytes, buffer ) tomwalters@0: TappingSource source ; tomwalters@0: ByteCount *bytes ; tomwalters@0: Pointer buffer ; tomwalters@0: { tomwalters@0: register int last = *bytes == 0 ; tomwalters@0: tomwalters@0: FillSome( source->input, bytes, buffer ) ; tomwalters@0: tomwalters@0: #if DEBUG tomwalters@0: printf( "\"%s\" fill tapping %d from \"%s\"\n", SourceName( source ), *bytes, SourceName( source->input ) ) ; tomwalters@0: #endif tomwalters@0: tomwalters@0: return ( tapping_callback( source, bytes, buffer, last ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: static Pointer tappingRoller( source, bytes, keep ) tomwalters@0: TappingSource source ; tomwalters@0: ByteCount *bytes, keep ; tomwalters@0: { tomwalters@0: register int last = *bytes == 0 ; tomwalters@0: Pointer buffer = RollSome( source->input, bytes, keep ) ; tomwalters@0: tomwalters@0: #if DEBUG tomwalters@0: printf( "\"%s\" roll tapping %d from \"%s\"\n", SourceName( source ), *bytes, SourceName( source->input ) ) ; tomwalters@0: #endif tomwalters@0: tomwalters@0: return ( tapping_callback( source, bytes, buffer, last ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Source newTappingSource( state, callback, close, input, name ) tomwalters@0: Pointer state ; tomwalters@0: void (*callback)(), (*close)() ; tomwalters@0: Source input ; tomwalters@0: char *name ; tomwalters@0: { tomwalters@0: DeclareNew( TappingSource, source ) ; tomwalters@0: tomwalters@0: source->state = state ; tomwalters@0: source->callback = callback ; tomwalters@0: source->close = close ; tomwalters@0: source->input = input ; tomwalters@0: tomwalters@0: return ( SetSource( source, tappingPuller, tappingFiller, tappingRoller, name ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: /* rollable derived source */ tomwalters@0: tomwalters@0: typedef struct { tomwalters@0: struct _source parent ; tomwalters@0: Pointer buffer ; tomwalters@0: ByteCount bsize, valid ; tomwalters@0: Source input ; tomwalters@0: } *RollableSource ; tomwalters@0: tomwalters@0: Pointer DeleteRollableSource( source ) tomwalters@0: RollableSource source ; tomwalters@0: { tomwalters@0: if( source->bsize != 0 ) tomwalters@0: Delete( source->buffer ) ; tomwalters@0: tomwalters@0: return ( DeleteSource( source ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: static Pointer rollablePuller( source, bytes ) tomwalters@0: RollableSource source ; tomwalters@0: ByteCount *bytes ; tomwalters@0: { tomwalters@0: #if DEBUG tomwalters@0: printf( "rollable \"%s\" pulling %d from \"%s\"\n", SourceName( source ), *bytes, SourceName( source->input ) ) ; tomwalters@0: #endif tomwalters@0: tomwalters@0: return ( RollSome( source->input, bytes, 0 ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: static Pointer rollableFiller( source, bytes, buffer ) tomwalters@0: RollableSource source ; tomwalters@0: ByteCount *bytes ; tomwalters@0: Pointer buffer ; tomwalters@0: { tomwalters@0: register int last = *bytes == 0 ; tomwalters@0: tomwalters@0: FillSome( source->input, bytes, buffer ) ; tomwalters@0: tomwalters@0: source->valid = *bytes ; tomwalters@0: tomwalters@0: #if DEBUG tomwalters@0: printf( "rollable \"%s\" filling %d from \"%s\"\n", SourceName( source ), *bytes, SourceName( source->input ) ) ; tomwalters@0: #endif tomwalters@0: tomwalters@0: if( !last ) tomwalters@0: return ( buffer ) ; tomwalters@0: else tomwalters@0: return ( DeleteRollableSource( source ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: static Pointer rollableRoller( source, bytes, keep ) tomwalters@0: RollableSource source ; tomwalters@0: ByteCount *bytes, keep ; tomwalters@0: { tomwalters@0: register int last = *bytes == 0 ; tomwalters@0: Pointer oldBuffer = source->buffer ; tomwalters@0: ByteCount toStore = *bytes + keep ; tomwalters@0: tomwalters@0: if( source->bsize < toStore ) { tomwalters@0: tomwalters@0: source->buffer = Allocate( toStore, "source.c for retaining buffer" ) ; tomwalters@0: tomwalters@0: source->bsize = toStore ; tomwalters@0: } tomwalters@0: tomwalters@0: if( oldBuffer == (Pointer) 0 ) tomwalters@0: ZeroArray( (char *) source->buffer, keep ) ; tomwalters@0: else { tomwalters@0: CopyArray( (char *) oldBuffer+source->valid-keep, (char *) source->buffer, keep ) ; tomwalters@0: tomwalters@0: if( oldBuffer != source->buffer ) tomwalters@0: Delete( oldBuffer ) ; tomwalters@0: } tomwalters@0: tomwalters@0: FillSome( source->input, bytes, source->buffer + keep ) ; tomwalters@0: tomwalters@0: source->valid = keep + *bytes ; tomwalters@0: tomwalters@0: if( !last ) tomwalters@0: return ( source->buffer + keep ) ; tomwalters@0: else tomwalters@0: return ( DeleteRollableSource( source ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Source newRollableSource( input ) tomwalters@0: Source input ; tomwalters@0: { tomwalters@0: DeclareNew( RollableSource, source ) ; tomwalters@0: tomwalters@0: source->buffer = (Pointer) 0 ; tomwalters@0: tomwalters@0: source->bsize = 0 ; tomwalters@0: source->valid = 0 ; tomwalters@0: tomwalters@0: source->input = input ; tomwalters@0: tomwalters@0: return ( SetSource( source, rollablePuller, rollableFiller, rollableRoller, "rollable" ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: /* all other sources don't support rolling */ tomwalters@0: tomwalters@0: Pointer nonRoller( source, bytes, keep ) tomwalters@0: Source source ; tomwalters@0: ByteCount *bytes, keep ; tomwalters@0: { tomwalters@0: stitch_error( "Sorry rolling not availiable on source \"%s\"\n", SourceName( source ) ) ; tomwalters@0: tomwalters@0: return ( Pull( source, bytes ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: tomwalters@0: /* for compatability */ tomwalters@0: tomwalters@0: typedef struct _auto_source { tomwalters@0: struct _fillable_source parent ; Pointer state ; void (*callback)() ; tomwalters@0: } *AutoSource ; tomwalters@0: tomwalters@0: static Pointer autoFiller( source, bytes, buffer ) tomwalters@0: AutoSource source ; tomwalters@0: ByteCount *bytes ; tomwalters@0: Pointer buffer ; tomwalters@0: { tomwalters@0: register int last = *bytes == 0 ; tomwalters@0: tomwalters@0: source->callback( source->state, *bytes, buffer ) ; tomwalters@0: tomwalters@0: if( !last ) tomwalters@0: return ( buffer ) ; tomwalters@0: else tomwalters@0: return ( DeleteFillableSource( source ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Source stdAutoSource( state, callback ) tomwalters@0: Pointer state ; tomwalters@0: void (*callback)() ; tomwalters@0: { tomwalters@0: DeclareNew( AutoSource, source ) ; tomwalters@0: tomwalters@0: source->state = state ; tomwalters@0: source->callback = callback ; tomwalters@0: tomwalters@0: return ( SetFillableSource( source, autoFiller, "stdAuto" ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: typedef struct _self_source { tomwalters@0: struct _pullable_source parent ; Pointer state, (*callback)() ; tomwalters@0: } *SelfSource ; tomwalters@0: tomwalters@0: static Pointer selfGenerator( source, bytes ) tomwalters@0: SelfSource source ; tomwalters@0: ByteCount *bytes ; tomwalters@0: { tomwalters@0: register int last = *bytes == 0 ; tomwalters@0: Pointer ptr = source->callback( source->state, *bytes ) ; tomwalters@0: tomwalters@0: if( !last ) tomwalters@0: return ( ptr ) ; tomwalters@0: else tomwalters@0: return ( DeleteSource( source ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Source stdSelfSource( state, callback ) tomwalters@0: Pointer state ; tomwalters@0: Pointer (*callback)() ; tomwalters@0: { tomwalters@0: DeclareNew( SelfSource, source ) ; tomwalters@0: tomwalters@0: source->state = state ; tomwalters@0: source->callback = callback ; tomwalters@0: tomwalters@0: return ( SetPullableSource( source, selfGenerator, "stdSelf" ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Source stdStaticSource( ptr ) tomwalters@0: Pointer ptr ; tomwalters@0: { tomwalters@0: return ( NewStaticSource( ptr ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Source stdSlaveSource( source ) tomwalters@0: Source source ; tomwalters@0: { tomwalters@0: return ( NewSlaveSource( source ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Pointer oldPull( source, bytes ) tomwalters@0: struct _source *source ; tomwalters@0: ByteCount bytes ; tomwalters@0: { tomwalters@0: ByteCount tmp = bytes ; tomwalters@0: tomwalters@0: return ( source->pull( source, &tmp ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Pointer oldFill( source, bytes, buffer ) tomwalters@0: struct _source *source ; tomwalters@0: ByteCount bytes ; tomwalters@0: Pointer buffer ; tomwalters@0: { tomwalters@0: ByteCount tmp = bytes ; tomwalters@0: Pointer bptr = buffer ; tomwalters@0: tomwalters@0: do { tomwalters@0: tmp = buffer + bytes - bptr ; tomwalters@0: tomwalters@0: source->fill( source, &tmp, bptr ) ; tomwalters@0: bptr += tmp ; tomwalters@0: tomwalters@0: } while( bptr < buffer + bytes && tmp != 0 ) ; tomwalters@0: tomwalters@0: return ( buffer ) ; tomwalters@0: } tomwalters@0: tomwalters@0: Pointer oldRoll( source, bytes, keep ) tomwalters@0: struct _source *source ; tomwalters@0: ByteCount bytes, keep ; tomwalters@0: { tomwalters@0: ByteCount tmp = bytes ; tomwalters@0: tomwalters@0: return ( source->roll( source, &tmp, keep ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: #if 00 tomwalters@0: static struct _source convertors = { oldPull, oldFill, oldRoll } ; tomwalters@0: struct _source *call_conversions = &convertors ; tomwalters@0: #endif tomwalters@0: tomwalters@0: /* for binding multiple sources */ tomwalters@0: tomwalters@0: #if !defined(PC) && !defined(DSP32) tomwalters@0: #include tomwalters@0: tomwalters@0: Source *BindSources( va_alist ) tomwalters@0: va_dcl tomwalters@0: { tomwalters@0: Source *inputs ; tomwalters@0: va_list argp ; tomwalters@0: int count, c ; tomwalters@0: tomwalters@0: va_start( argp ) ; tomwalters@0: tomwalters@0: for( count=0 ; _SPTR( va_arg( argp, Source ) ) != (struct _source *) 0 ; count++ ) tomwalters@0: ; tomwalters@0: tomwalters@0: inputs = NewArray( Source, count+1, "for binding inputs in source.c" ) ; tomwalters@0: tomwalters@0: va_end( argp ) ; tomwalters@0: va_start( argp ) ; tomwalters@0: tomwalters@0: for( c=0 ; c<=count ; c++ ) tomwalters@0: inputs[c] = va_arg( argp, Source ) ; tomwalters@0: tomwalters@0: va_end( argp ) ; tomwalters@0: tomwalters@0: return ( inputs ) ; tomwalters@0: } tomwalters@0: #endif tomwalters@0: tomwalters@0: struct _source notRealySource ; tomwalters@0: tomwalters@0: Source EmptySource ;