Mercurial > hg > aim92
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stitch/source.c Fri May 20 15:19:45 2011 +0100 @@ -0,0 +1,681 @@ +/* + 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 ;