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 ;