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