| I'm sorry this response is lengthy, but it is necessary to get technical.
The design pattern you are asking about (which was suggested by Richard
Dobson, although it was implemented by me) is needed to enable older plugin
opcodes to function with newer versions of Csound. The following explains
why.
The GLOBALS struct is NOT to be hidden from public view. Or rather, we want
the public to see and use the function pointer members, but NOT to see or
use the data members. Why is it declared void *then? To hide the data
members. As long as the structure is undergoing changes and evolution, this
helps maintain backward compatibility (one can still compile and link an
opcode library using an older csound.h that will work with a modern Csound).
The reason the function pointers are members of the globals structure is to
make it a true interface. This means an opcode does not need to LINK with
the csound API, only to declare the order and signatures of the function
pointers in the Csound globals structure. The technical term for such a
table of function pointers is "interface."
In other words, with csoundSomething(csound,args) you need to #include
and link with libcsound.a. If you link with libcsound.a, or if
you reference DATA members of GLOBALS, there is no guarantee your plugin
will work with a later version of Csound.
With csound->Something(csound,args) you only need to #include and
you do NOT need to link with libcsound.a. Csound itself has filled in the
function pointer Something for you - the linker did not need to fill it in.
Your plugin will still work with later versions of Csound because the plugin
knows nothing about the layout of Csound code except for the function
pointers in GLOBALS, which may be added to, but should never change.
The soundfonts opcode library follows this practice - it does not link with
libcsound.a. This is the correct way to use the API for writing opcodes.
Therefore, it is a requirement for all public API functions to be a member
of the GLOBALS struct and to be properly filled in. New functions should be
appended to the list, not inserted at the beginning or in the middle, so
that older plugins will continue to be able to call the right function
pointers off the GLOBALS pointer.
Just to make this absolutely clear:
Every public Csound function should be both a csoundXXX function in csound.h
and an XXX function pointer member of GLOBALS. Every such function should
take as its first argument void* csound which can be type cast to GLOBALS *
(which is really the instance of Csound). Both opcodes AND csound itself
should use these functions, as this is the only way that in future we can
make it possible to create multiple instances of Csound at the same time
that don't screw each other up.
Consequently, the functions that are listed below should be in csound.h AND
in GLOBALS, added to the end of the list if they aren't already in it, i.e.
we should have:
> void (*auxalloc)(long nbytes, AUXCH *auxchp); replaced with:
csoundAuxalloc(void *csound, long nbytes, AUCH *auxchp);
typedef struct globals {
... void (*Auxalloc)(long nbytes, AUXCH *auxchp);
...
} GLOBALS;
GLOBALS cglob = {.... yyy, csoundAuxalloc, zzz};
And similarly for the other functions in the list. Then publicly one can
call either
csoundAuxalloc(csound, nbytes, auxchp);
or
csound->Auxalloc(csound, nbytes, auxchp);
Privately, csound will call
csoundAuxalloc(csound, nbytes, auxchp) after Csound is made multiply
instantiable.
Currently, we only need to enforce this pattern for public functions. In
future, in order to be able to multiply instantiate Csound, the same pattern
will have to be extended to EVERY Csound function (unless it is a static
function that doesn't need to know what instance of Csound is involved in
the call).
============================================
Michael Gogins
gogins at pipeline period com
Irreducible Productions
CsoundVST, an extended version of Csound for programming music and sound
Available at http://sourceforge.net/projects/csound/
============================================
----- Original Message -----
From: "stevenyi"
To: "Csound Developers Discussion List"
Sent: Sunday, November 16, 2003 3:42 AM
Subject: [CSOUND-DEV:3330] Re: Csound API Split, design
> > > Also, in general for design, should functions that are currently being
> > > stored in the GLOBAL struct be there, or should those functions be
> > > redesigned to take in the GLOBAL struct if they need data from it and
> > > then exposed through the API? (i.e. instead of cglob->unquote we get
> > > csoundUnquote(void *csound) )
> >
> > if you are not exporting the symbols and want to call that function from
> > an external host or plugin you need the pointer to the function to be
able
> > to call it!
>
> Okay, I'm a bit confused here, since most of the functions are available
> via the API header. If we're exposing the csound API functions with
> csound.h, why are the function pointers currently in the GLOBALS struct
> there (especially if you want the GLOBAL struct to be hidden from client
> applications)? If you're passed in the GLOBAL as a void *, and you're
> #including the csound.h header, can't you write your code to call the
> csound API functions on the void *? Or in other words, why is currently
> possible to write:
>
> (*cglob->Cleanup)(&cglob)
>
> as well as:
>
> csoundCleanup(&cglob)
>
> Right now, most of the function pointers in GLOBALS are copies of csound
> API functions. The later additions:
>
> void (*auxalloc)(long nbytes, AUXCH *auxchp);
> char *(*getstring)(int, char*);
> void (*die)(char *);
> FUNC *(*ftfind)(MYFLT *);
> int (*initerror)(char *);
> int (*perferror)(char *);
> void *(*mmalloc)(long);
> void (*mfree)(void *);
> void (*dispset)(WINDAT *, MYFLT *, long, char *, int, char *);
> void (*display)(WINDAT *);
> MYFLT (*intpow)(MYFLT, long);
> FUNC *(*ftfindp)(MYFLT *argp);
> FUNC *(*ftnp2find)(MYFLT *);
> char *(*unquote)(char *);
> MEMFIL *(*ldmemfile)(char *);
>
> are all functions that should either be added to the CsoundAPI as they
> are function that should be exposed to client applications and plugins,
> or should be hidden and opcodes that use these functions should be
> rewritten.
>
> Am I misunderstanding your side and the code as well?
>
> Thanks,
> steven
> |