The GLAME Development Manual


Next: , Up: (dir)

The GLAME Development Manual

This text documents the internals of GNU/Linux Audio Mechanics (GLAME) Version 2.0.1 (26 April 2002), a capable and easily extensible free sound editor. This manual describes GLAME's internal design programming API for the benefit of developers.

More recent versions of this document as well as additional information about GLAME might be available via the project's homepage at http://glame.sourceforge.net.

This document is also available as a gzipped PostScript file: http://glame.sourceforge.net/manual-dev.ps.gz

Copyright © 2000, 2001 Richard Günther, Daniel Kobras See Copying, for details.

==How to extend GLAME==

==References==


Next: , Previous: Top, Up: Top

1 Copying

Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.

Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the sections entitled “Copying” and “GNU General Public License” are included exactly as in the original, and provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.

Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Free Software Foundation.


Next: , Previous: Copying, Up: Top

2 Filter API

NOTE
This is not a guide on filter programming! Look for this in the filter tutorial (see Filter Tutorial).

The filter subsystem has three independent APIs, one for the filter registry, one for filter programming and one for using the filters and connecting them to so called filter networks.

If you have any questions related to this document, please quote the relevant lines and send your comments per e-mail to glame-devel@glame.sourceforge.net (c/o richi).


Next: , Up: Filter API

2.1 Introducing the Filter Subsystem

The filter subsystem introduces the concepts of filters and networks of filters. The basic idea is to have streams transporting arbitrary data with attached properties floating through a network. This network comprises of so called filters which are connected to each other through filter pipes. The filters may modify the data in the streams and its properties. A filter can even merge two or more streams into one stream or split one stream into any number of streams containing the same data and the same properties by reference. To tune the operations on the stream each filter may be assigned a number of parameters. Each filter pipe can be assigned a number of parameters at both ends, too.

The API from the design philosophy standpoint is a cloning objects out of another one. There is one main object, the filter_t which contains filter_port_ts through which filters get connected using filter_pipe_ts. A filter_t can be used both as container for other filters and as working part of another group of filters, called filter network. This means that you can set up a network of filters, and in turn convert this filter network into an abstract filter which you can use in another filter network by instantiating it.


Next: , Previous: Introducing the Filter Subsystem, Up: Filter API

2.2 The Filter Objects


Next: , Up: The Filter Objects

2.2.1 The Filter Object

The filter_t object represents an instance of a filter. A filter generally consists of a set of ports, parameters and child filters. Filters on the same level in the hierarchy may be connected using pipes. Filters are accessible to the user as plugins as soon as they are registered as such. Plugins are used as reference instances from which actual filters are cloned.

The following functions, often implemented using macros, are available to obtain parts of the filter_t object.

— Function: const char * filter_name (filter_t *f)

Using this function you get access to the filters name which is used to uniquely identify it among the childs of its parent filter.

— Function: filter_paramdb_t * filter_paramdb (filter_t *f)

Using this function you get access to the filters parameter database. You will need it to add, remove or query filter parameters using the API provided by the filter parameter subsystem.

— Function: filter_portdb_t * filter_portdb (filter_t *f)

Using this function you get access to the filters port database. You will need it to add, remove or query filter ports using the API provided by the filter port subsystem.

— Function: glsig_emitter_t * filter_emitter (filter_t *f)

Using this function you get access to the filter scope signal emitter. Through this emitter you can receive signals sent out by the components of this filter. You can use the glame signal API to register signal handlers.

— Function: gldb_t * filter_propertydb (filter_t *f)

Using this function you get access to the filters property database. You will need it to add, remove or query filter properties using the API provided by the filter_set_property() and filter_get_property() functions.

— Function: int filter_nrnodes (filter_t *f)

Use this function to obtain the number of child filters associated with the filter f.

A filter in a set of connected filters may be in an inconsistent state, so an error number and string are provided to notify the outer world. Also macros to set and query this state are provided.

— Function: int filter_errno (filter_t *f)

The filter error number returned by this function represents the actual state of the filter and is usually zero which means no error. For more information refer to the filter_errstr() function.

— Function: const char * filter_errstr (filter_t *f)

Using this function you get access to a human readable error string of the filter.

— Function: int filter_has_error (filter_t *f)

If this function returns a non-zero value the filter is in an inconsistent state.

— Function: void filter_set_error (filter_t *f, const char *msg)

Flags the filter with an error and the message msg.

— Function: void filter_clear_error (filter_t *f)

Clears a previously set error condition and marks the filter as in a consistent state.

To query the role of a filter in a simple manner the following macros will help you. Others are defined, but the ones mentioned here are the only ones you are supposed to use.

— Function: int FILTER_IS_PLUGIN (filter_t *f)

Returns a non-zero value, if this filter instance is registered as a plugin.

— Function: int FILTER_IS_PART_OF_NETWORK (filter_t *f)

Returns a non-zero value, if this filter instance is a child of another filter instance.

— Function: int FILTER_IS_NETWORK (filter_t *f)

Returns a non-zero value, if this filter instance has childs.

— Function: int FILTER_IS_NODE (filter_t *f)

Returns a non-zero value, if this filter instance does not have childs.

— Function: int FILTER_IS_LAUNCHED (filter_t *f)

Returns a non-zero value, if this filter instance is busy.

To actually create a filter instance, to delete such or register it as a plugin the following functions are provided.

— Function: filter_t * filter_creat (filter_t *template)

To create a new filter instance either the existing instance template is cloned, or in case NULL is provided a minimal one is created from scratch. The new filter instance is returned on success, NULL on error.

— Function: filter_t * filter_instantiate (plugin_t *p)

The other way to create a new filter instance is to instantiate a previously registered filter instance – a plugin. The new filter instance is returned on success, NULL on error.

— Function: void filter_delete (filter_t *f)

This function deletes a filter instance and all its sub-objects such as ports, parameters, pipes and child filters.

— Function: int filter_set_property (filter_t *f, const char *label, const char *value)

Sets the property named label to the value value. Properties of filters are for free use by the user and contents are saved/restored by filter_to_string(). Returns 0 on success, -1 on error.

— Function: const char * filter_get_property (filter_t *f, const char *label)

Returns the value of the property named label or NULL, if no such property does exist.

— Function: int filter_register (filter_t *f, plugint_t *p)

This function tries to associate the given filter instance with the provided plugin. On success, zero is returned, -1 on error.

— Function: char * filter_to_string (filter_t *f)

filter_to_string() saves the current state of the filter into a string and returns a pointer to it. NULL is returned on error. You have to free() the returned string later. Use this function to save and potentially recreate a constructed network of which this filter is the container. The string representation is executable scheme code.

— Function: int filter_add_node (filter_t *net, filter_t *f, const char *name)

This function inserts the filter instance f into the (now turned into a network) filter instance net using the name name which you can use later to query the inserted filter out of the network. If name is not unique inside the network it gets adjusted. Returns 0 on success and -1 on error.

— Function: int filter_remove (filter_t *f)

This function removes the filter instance f from its network thereby breaking all connections to/from it. Returns 0 on success and -1 on error.

— Function: int filter_expand (filter_t *f)

This function expands the network f which has to be a member of a network itself thereby emptying the network and moving all nodes up one level. Returns 0 on success and -1 on error.

— Function: filter_t * filter_collapse (const char *name, filter_t **nodes)

Collapses all nodes in the NULL terminated array of filters into a newly created network which is added using name to the parent of the nodes. Returns the created network on success and NULL on error.

— Function: filter_t * filter_get_node (filter_t *net, const char *name)

Queries the network net for a filter uniquely named name and returns that instance. Returns NULL, if there is no such named instance inside the network.

— Iterator: filter_foreach_node (filter_t *net, filter_t *f) { }

You can iterate through all filter instances inside the network net using the following iterator (which acts like a for statement with the second parameter as running variable). Note that you may not delete instances in this loop!


Next: , Previous: The Filter Object, Up: The Filter Objects

2.2.2 Basics on Databases

Both filter ports and filter parameters are organized using databases which can store arbitrary key/object pairs. Keys have to be unique strings and objects can be queried specifying the right key. Also usually an iterator is provided to iterate through all items in the database.

All databases are homogenly typed, i.e. only one kind of object can be stored in a database. For each such special database a database type exists (filterparamdb_t and filterportdb_t) with the corresponding object types (filter_param_t and filter_port_t).

In addition to these first class object databases there are databases which store strings – the property databases which exist in each of plugin_t, filter_param_t and filter_port_t.

For general notes on how to access the databases see GLAME Database Interface.


Next: , Previous: Basics on Databases, Up: The Filter Objects

2.2.3 The Filter Parameter Object

The filter_param_t object defines and contains a parameter used at the filter and the filter pipe scope. To access parts of its structure the following functions are provided.

— Function: const char * filterparam_label (filter_param_t *param)

Access the parameters label as used in the database.

— Function: filter_t * filterparam_filter (filter_param_t *param)

Access the filter the parameter or its pipe is attached to.

— Function: glsig_emitter_t * filterparam_emitter (filter_param_t *param)

Gets you access to the parameters signal emitter through which all signals are propagated upwards.

— Function: filter_pipe_t * filterparam_get_sourcepipe (filter_param_t *param)
— Function: filter_pipe_t * filterparam_get_destpipe (filter_param_t *param)

If you know that the parameter is attached to a database embedded into a filter pipe and you even know the end to which it is attached, you may use this functions to get access to this pipe.

— Function: int filterparam_type (filter_param_t *param)

Query the type of the parameter.

— Function: void * filterparam_val (filter_param_t *param)

Get a generic pointer to the actual value of the parameter.

To access a parameter value of a specified type the following helpers are provided. First check the actual type of the parameter, then use this non-typechecking functions.

— Function: long filterparam_val_long (filter_param_t *param)

Get the integer value of a long typed parameter.

— Function: const char * filterparam_val_string (filter_param_t *param)

Get the string value of a string typed parameter.

— Function: double filterparam_val_double (filter_param_t *param)

Get the float value of a double typed parameter.

As nearly every object, the filter parameter object has a property database whose elements you may access or modify using the following functions.

— Function: const char * filterparam_get_property (filter_param_t *param, const char *label)

Get the value of the property stored in the parameters property database using the specified label.

— Function: int filterparam_set_property (filter_param_t *param, const char *label, const char *value)

Set or add the property label to the provided value. Returns 0 on success, -1 on error.

To define parameters and to set their values the following functions are provided.

— Function: int filterparam_set (filter_param_t *param, const void *val)

To change the value of a parameter use the following function. Note that on a successful change 0 is returned and a GLSIG_PARAM_CHANGED signal is emitted. -1 is returned on an error such as memory shortage or a rejected change by the set() method of the param.

— Function: int filterparam_set_long (filter_param_t *param, long val)
— Function: int filterparam_set_double (filter_param_t *param, double val)
— Function: int filterparam_set_string (filter_param_t *param, const char *val)

These functions are simple type-safe wrappers around the filterparam_set() function.

— Function: int filterparam_from_string (filter_param_t *param, const char *val)

As filterparam_set() the following function tries to set the parameters value, but this time using the value encoded in the provided string. This is the counterpart to the filterparam_to_string() function.

— Function: char * filterparam_to_string (const filter_param_t *param)

To generate a string representation of the parameters value use the following function. The returned string has to be freed by the caller. NULL is be returned on error.

— Function: void filterparam_delete (filter_param_t *param)

Delete a parameter out of its database.

— Function: int filterparam_redirect (filter_param_t *source, filter_param_t *dest)

Redirects parameter set/query operations (by copy!) to the specified parameter. Note that this is only useful for redirections of externally visible parameters from a macro filter to one of its direct cilds. Returns 0 on success, -1 on error.

— Function: filter_param_t * filterparamdb_add_param (filter_paramdb_t *db, const char *label, int type, const void *val, ...)

To add a new parameter (i.e. define it) use the following function through which you specify the parameters label, its type and its default value (see below for some convenience wrappers). Also any number of key/value pairs may be optionally specified and are stored into the parameters property database. You have to "finish" the property list by a FILTERPARAM_END argument even if you did not specify any property.

— Function: filter_param_t * filterparamdb_add_param_long (filter_paramdb_t *db, const char *label, int type, long val, ...)
— Function: filter_param_t * filterparamdb_add_param_double (filter_paramdb_t *db, const char *label, int type, double val, ...)
— Function: filter_param_t * filterparamdb_add_param_string (filter_paramdb_t *db, const char *label, int type, const char *val, ...)

To ease the use of the filterparamdb_add_param() function with respect to specifying the default parameter value, the following wrappers are provided which take a typed fourth parameter. Nothing else changes.

— Function: filter_param_t * filterparamdb_get_param (filter_paramdb_t *db, const char *label)

To query a parameter out of the filter parameter database use the following function. If NULL is returned, the parameter does not exist.

— Function: void filterparamdb_delete_param (filter_paramdb_t *db, const char *label)

To delete a parameter use the following function. If the paramter does not exist, nothing is done.

— Iterator: filterparamdb_foreach_param (filter_paramdb_t *db, filter_param_t *param) { }

You can iterate through all parameters of a database using the following iterator (which acts like a for statement with the second parameter as running variable). Note that you may not delete parameters in this loop!

— Function: int filterparamdb_nrparams (filter_paramdb_t *db)

To just query the number of parameters stored in a parameter database use the following function.


Next: , Previous: The Filter Parameter Object, Up: The Filter Objects

2.2.4 The Filter Port Object

— Function: const char * filterport_label (filter_port_t *port)

Returns the label of the specified port.

— Function: int filterport_type (filter_port_t *port)

Returns the type of the specified port. Supported port types are FILTER_PORTTYPE_ANY, FILTER_PORTTYPE_SAMPLE and FILTER_PORTTYPE_FFT.

— Function: filter_paramdb_t * filterport_paramdb (filter_port_t *port)

Using this function you get access to the ports parameter database which is used to initialize the pipe parameter database on the ports end.

— Function: int filterport_is_input (filter_port_t *port)

Returns 1, if the specified port is an input port, or 0, if this is not the case.

— Function: int filterport_is_output (filter_port_t *port)

Returns 1, if the specified port is an output port, or 0, if this is not the case.

— Function: glsig_emitter_t * filterport_emitter (filter_port_t *port)

Gets you access to the ports signal emitter through which all signals originating from any connected pipe are propagated upwards.

— Function: filter_t * filterport_filter (filter_port_t *port)

Returns the filter to which the specified port is attached to.

— Function: const char * filterport_get_property (filter_port_t *port, const char *label)

Gets the value of the property specified by label out of the ports property database or NULL, if there is no such property.

— Function: int filterport_set_property (filter_port_t *port, const char *label, const char *value)

Sets the property label to the specified value. Returns 0 on success, -1 on error.

— Function: int filterport_nrpipes (filter_port_t *port)

Returns the number of connected pipes.

— Function: filter_pipe_t * filterport_get_pipe (filter_port_t *port)

Returns a connected pipe or NULL if no pipes are available. Use this in conjunction with filterport_next_pipe() to iterate through all connected pipes.

— Function: filter_pipe_t * filterport_next_pipe (filter_port_t *port, filter_pipe_t *pipe)

Returns the next connected pipe after pipe of the specified port. Returns NULL, if no further pipe is available.

— Function: Iterator filterport_foreach_pipe (filter_port_t *port, filter_pipe_t *pipe)

A different way to iterate through all available pipes is using this iterator. But you may not delete pipes while iterating.

— Function: int filterport_redirect (filter_port_t *source, filter_port_t *dest)

Redirects connections to this port to another port. Useful only for redirecting externally visible ports of a macro filter to one of its direct childs. Returns -1 on error, 0 on success.

— Function: void filterport_delete (filter_port_t *port)

Delete a port out of its database.

The API which handles defining/setting/querying ports. All this is done using a filter port database handle, which you can get using filter_portdb().

— Function: filter_port_t * filterportdb_add_port (filter_portdb_t *db, const char *label, int type, int flags, ...)

To add a new port (i.e. define it) use the following function through which you specify the port label, its type and flags. Also any number of key/value pairs may be optionally specified and are stored into the ports property database. You have to "finish" the property list by a FILTERPARAM_END argument even if you did not specify any property.

— Function: filter_port_t * filterportdb_get_port (filter_portdb_t *db, const char *label)

To query a port out of the filter port database use the following function. If NULL is returned, the port does not exist.

— Function: void filterportdb_delete_port (filter_portdb_t *db, const char *label)

To delete a port use the following function. If the paramter does not exist, nothing is done.

— Function: Iterator filterportdb_foreach_port ( filter_portdb_t *db, filter_port_t *port)

You can iterate through all ports of a database using the following iterator (which acts like a for statement with the second parameter as running variable). Note that you may not delete ports in this loop!

— Function: int filterportdb_nrports (filter_portdb_t *db)

To just query the number of ports stored in a port database use the following function.


Previous: The Filter Port Object, Up: The Filter Objects

2.2.5 The Filter Pipe Object

The filter pipe object represents a connection between two filter port objects.

— Function: int filterpipe_type (filter_pipe_t *pipe)

Query the pipes type.

— Function: glsig_emitter_t * filterpipe_emitter (filter_pipe_t *pipe)

Using this function you get access to the pipes signal emitter. See the glsignal manual for instructions on what to do with this.

— Function: filter_port_t * filterpipe_source (filter_pipe_t *pipe)

Query the pipes source port.

— Function: filter_port_t * filterpipe_dest (filter_pipe_t *pipe)

Query the pipes destination port.

— Function: filter_paramdb_t * filterpipe_sourceparamdb (filter_pipe_t *pipe)

Query the parameter database attached to the source end of the pipe.

— Function: filter_paramdb_t * fitlerpipe_destparamdb (filter_pipe_t *pipe)

Query the parameter database attached to the destination end of the pipe.

— Function: void filterpipe_settype_sample (filter_pipe_t *pipe, int rate, float hangle)

Sets the pipe type to sample and the sample pipe properties to the specified values.

— Function: int filterpipe_sample_rate (filter_pipe_t *pipe)
— Function: float filterpipe_sample_hangle (filter_pipe_t *pipe)

For a sample typed pipe you have to query the pipes properties using these functions. The properties are the sample rate and the horizontal angle of the stream.

— Function: void filterpipe_settype_fft (filter_pipe_t *pipe, int rate, float hangle, int bsize, int osamp)

Sets the pipes type to FFT and the FFT pipe properties to the specified values.

— Function: int filterpipe_fft_rate (filter_pipe_t *pipe)
— Function: float filterpipe_fft_hangle (filter_pipe_t *pipe)
— Function: int filterpipe_fft_bsize (filter_pipe_t *pipe)
— Function: int filterpipe_fft_osamp (filter_pipe_t *pipe)

For an FFT typed pipe you have to query the pipes properties using these functions. The properties are the sample rate and the horizontal angle of the stream. The blocksize and the oversampling factor specify the FFT.

— Function: filter_pipe_t * filterport_connect (filter_port_t *source, filter_port_t *dest)

Connect the two ports source and dest with a pipe, returns the created pipe on success, or NULL on error.

— Function: void filterpipe_delete (filter_pipe_t *pipe)

Breaks a previously established connection and deletes the associated pipe.


Next: , Previous: The Filter Objects, Up: Filter API

2.3 Filter Networks

Constructing filter networks and reusing them as filters is one of the powerful tools of GLAME. In this section you learn how to use networks of filters you have constructed (see the previous section on how to do this, look for filter_add_node() and filterport_connect).

First there are operations to actually do work using a filter network. They usually will launch lots of threads and while a filter network is operating you may not modify its structure.

— Function: filter_launchcontext_t * filter_launch (filter_t *net, int bufsize)

filter_launch() asynchronously starts the init phase of a previously constructed filter using a set of filter threads. filter_launch() returns NULL if there were any problems launching the filter or a handle on success. Errors in the initialisation process of the filters' f() methods are not reported by filter_launch() but can instead be obtained by using filter_wait() or filter_start(). Processing of the data is not started until filter_start() is called. You need to specify a hint for the buffersize used by the network.

— Function: void filter_launchcontext_unref (filter_launchcontext_t *handle)

This frees the handle returned by filter_launch() if you dont need it anymore.

— Function: int filter_start (filter_launchcontext_t *handle)

With filter_start() you can start processing data on a previously launched filter. The function returns -1 if any error occured in the process of starting or in the filter threads.

— Function: int filter_wait (filter_launchcontext_t *handle)

filter_wait() waits for a previously launched filter to finish processing. filter_wait() returns 0 if the filter terminated regularly, and -1 if there were any errors, either in waiting for the filter or in processing the filter.

— Function: int filter_is_ready (filter_launchcontext_t *handle)

filter_is_ready() queries if the network has finished processing. Instead of filter_wait() this does not block. Returns 1, if the network has finished, 0 if it is still operating, -1 on error.

— Function: void filter_terminate (filter_launchcontext_t *handle)

filter_terminate kills a previously launched filter. It doesn't wait for it to finish processing all data.


Previous: Filter Networks, Up: Filter API

2.4 The Filter Programming API

The filter programming API consists of functions to receive, create and forward buffers, of functions to access the connections made to the filters ports, and of functions to get and set the filters parameters. The filter programming API also defines the semantics of the methods provided by the filters itself as they are used by the filter network. The filter programming API is designed to be thread safe.


Next: , Up: The Filter Programming API

2.4.1 Filter Methods

Let's start with defining the semantics of the methods a filter and its subobjects (ports and parameters) can provide. The methods are stored in the operated on structures, respectively filter_t, filter_port_t, filter_param_t, but only the f() method inside the filter_t structure is mandatory. You have to set all other methods explicitly—sane defaults are provided for them.

— Method: int f (filter_t *n)

f() is the main method of every filter, it's the only mandatory method. f() does the filter work, i.e. it gets launched as thread once the filter starts operating. See below for what to do in this method. You have to return -1 if you don't like anything of the setup, which will terminate the whole network, or 0 if everything was ok and you are finished with processing.

Required parts of the f() method are an initialization section which must be ended by a call of the FILTER_AFTER_INIT macro and a cleanup section which FILTER_BEFORE_CLEANUP has to precede. In the initialization section you may not use any functions which may block on the network. You may return -1 at any point during the initialization indicating an error. Once your code hits FILTER_AFTER_INIT, returning 0 is mandatory though. In the init section, use macro FILTER_DO_CLEANUP for a jump to the cleanup section, FILTER_ERROR_RETURN(const char *) to return with an error message set to the specified string, FILTER_ERROR_CLEANUP(const char *) for the equivalent that quits through the cleanup section like FILTER_DO_CLEANUP.

In the main processing loop (if there is such in your filter) you are required to call FILTER_CHECK_STOP from time to time to check for an abort request. If such occured processing is continued after FILTER_BEFORE_STOPCLEANUP which should preceede FILTER_BEFORE_CLEANUP for obvious reasons. You should in general finish the f() method by calling FILTER_RETURN instead of just return 0; to ensure proper return value in case of an error.

For further advise see the Filter Tutorial.

— Method: int init (filter_t *n)

init() gets called by the filter_add_node() function after allocating a new instance of a filter (the so called node). You may do anything with the private field of the node and attach signal handlers to the nodes emitter, everything else is strictly private. If you return -1 the node is deleted and filter_add_node() will return an error. If everything is ok you should return 0.

— Method: int connect (filter_port_t *port, filter_pipe_t *p)

connect() is invoked by the filterport_connect() function. connect() gets called at each connection request to a port, first the corresponding connect() method for the output port is called, if that succeeded, the one for the input port. Any side of the connection may reject the connection by returning -1 or accept it by returning 0. You should set up the pipe type and the corresponding fields in the type-specific union using the appropriate macros if being the source end of the pipe. You may modifiy the pipe's source or destination if you are the source or destination, i.e. perform redirections—but be careful. After the connection has been created a GLSIG_PIPE_CHANGED signal is raised on the new pipe.

— Method: int set (filter_param_t *p, const void *val)

The set() method can be used to check a value which is to be setted against some conditions. The method is invocated before the change takes place and you may reject the change by returning -1. Returning 0 will do the parameter change and raise a GLSIG_PARAM_CHANGED signal on the parameter.

Each filter has a signal emitter associated to it through which all of the signals from its sub-objects are re-emitted. So you may want to add signal handlers to the filters emitter. Currently there are four signals that are passed along to the filter signal emitter. These are the GLSIG_PARAM_CHANGED, GLSIG_PARAM_DELETED, GLSIG_PIPE_CHANGED and the GLSIG_PIPE_DELETED signal. Native signals sent out by the filters are the GLSIG_FILTER_CHANGED and the GLSIG_FILTER_DELETED signal.

%% FIXME - describe what to do and not to do in those signal handlers


Next: , Previous: Filter Methods, Up: The Filter Programming API

2.4.2 Doing Real Work

Now what to do inside the f() method? Receiving, modifying, creating, and forwarding streams of data which are grouped into buffers is the answer. Buffers generally can be in two states - private and shared. A shared buffer is one with possible greater than one references. Once you send out a buffer possible new references appear and you have to reconsider the state. This leads us to the filter buffer API. A filter buffer is obtained using one of the following functions:

— Function: filter_buffer_t * fbuf_alloc (int size, struct list_head *list)

fbuf_alloc() will allocate a new buffer with space for size bytes. The list parameter is to keep track of allocated buffers for cleanup after failures. You may want to supply &n->launch_context->buffers for list. This function can return NULL if the system is short on memory.

— Function: filter_buffer_t * fbuf_realloc (filter_buffer_t *fb, int size)

fbuf_realloc() lets you change the size of the buffer fb to size. This ensures the buffer is private first (as changing the size is only allowed for private buffers) and if needed copies the buffer. This checking and copying is optimized into one function, so you really should use it if you need to. But beware - needing fbuf_realloc() is a sign of a badly coded algorithm. Its probably only a good idea to use it if it gets called on special cases and makes the code a lot simpler. The only really fast path is shrinking an already private buffer. This function can return NULL if the system is short on memory in which case the provided buffer fb is not modified. On success a reference to the realloced buffer is returned and the provided buffer fb looses one reference.

— Function: filter_buffer_t * fbuf_get (filter_pipe_t *p)

fbuf_get() receives the next filter buffer from the specified input pipe. It will return NULL at EOF. You have to forward the EOF mark. fbuf_get() copes with a NULL p by just returning NULL.

All filter buffers are reference counted to allow zero-copy and copy-on-demand operations. Both fbuf_alloc() and fbuf_get() will return with one reference of the buffer held. To get additional references or to drop one reference use the following functions:

— Function: void fbuf_ref (filter_buffer_t *fb)

fbuf_ref() will get you one additional reference. A reference will protect the buffer from being modified and from being destroyed. Once the reference count drops to zero, you may no longer access it or any of its contents. fbuf_ref() does not copy the buffer. fbuf_ref() ignores NULL fbs.

— Function: void fbuf_unref (filter_buffer_t *fb)

fbuf_unref() will drop one reference. See above for more about references. fbuf_unref ignores NULL fbs.

To get information on a filter buffer and to access its contents, use the following functions which are actually very fast macros:

— Function: int fbuf_size (filter_buffer_t *fb)

fbuf_size() returns the number of bytes in the filter buffer. fbuf_size() returns 0 if fb is NULL.

— Function: char * fbuf_buf (filter_buffer_t *fb)

fbuf_buf() returns a pointer to the buffer's contents.

If you want to modify a buffer directly rather than reading from a received one and storing into a freshly allocated one, you have to make the buffer private. This additional requirement makes copy-on-demand and zero-copy possible. Use fbuf_make_private():

— Function: filter_buffer_t * fbuf_make_private (filter_buffer_t *fb)

fbuf_make_private() will return a private copy of the provided buffer which you may modify. fbuf_lock() will not copy the buffer if you are the sole user of the buffer, i.e. the reference count is one. For a NULL fb fbuf_mark_private() returns NULL.

To forward a filter buffer you have to hold one reference for each output pipe you send the buffer to. Buffer sending is done using the following function:

— Function: void fbuf_queue (filter_pipe_t *p, filter_buffer_t *fb)

fbuf_queue() queues the specified filter buffer to the specified pipe. One reference gets eaten by this operation. fbuf_queue() copes with a NULL p by unref'ing fb.

For extended protocols on top of the fbuf API have a look into Working on SAMPLEs.


Previous: Doing Real Work, Up: The Filter Programming API

2.4.3 Working on SAMPLEs

There are two extended protocol defined at the moment. Those are the sbuf protocol which is just a very simple SAMPLE-only transportation protocol with no fields in the header actually used and the fft protocol which shares all properties with the sbuf protocol apart from the pipe type and the pipe properties. So only the functions with parameters or semantics different from their fbuf_* equivalents are listed here. As for the rest, you may assume that wrappers exist with the appropriate sbuf_* name but the same parameters and semantics as described in the fbuf_* sections.

— Function: filter_buffer_t * sbuf_alloc (int size, filter_node_t *n)

sbuf_alloc() allocates a new buffer containing space for size numbers of SAMPLEs and assigns the buffer to the filter node n.

— Function: int sbuf_size (filter_buffer_t *fb)

sbuf_size() returns the size of the buffer as number of SAMPLEs.

— Function: SAMPLE * sbuf_buf (filter_buffer_t *fb)

sbuf_buf() returns a pointer to the buffer containing the SAMPLEs.


Next: , Previous: Filter API, Up: Top

3 Filter Tutorial

This part of the document is about how to write filters for GLAME. It only covers parts of this at the moment, but will evolve into a decent filter programming tutorial with your help.


Next: , Up: Filter Tutorial

3.1 Talking about parameters, properties and protocols...

When talking about filters in the following sections, we'll make use of various flavours of parameters and properties. Some filters export hooks to dynamically tune their internal behaviour. We call them parameters. Parameters generally are user-settable, while properties are only modified by the filters. But for terminal confusion, properties can be influenced by parameters of course.

We have parameters at three places: the filternode parameters, the pipe source parameters and the pipe destination parameters. In the following we will not make a difference between pipe source and destination parameters, we just call them pipe parameters. Remember though, that each pipe has two sets of parameters, one at the source end and one at the destination end.

As indicated by the name, filternode parameters are local to the filternode, the instance of a filter for which the parameter was defined. A good example for a filternode parameter is the frequency range of a bandpass filter. Pipe parameters are local to a pipe which is an instance of two ports—therefore two sets of parameters exist for a single pipe, each defined at one of the ports. Pipe parameters are local to the pipe, i.e. on automatic ports multiple sets of parameters exist. Pipe parameters are not port parameters. Pipe parameters are commonly used for e.g. gain values.

Pipe properties provide information shared between all data floating through the pipe. Pipe properties remain constant during a run of the filter network. Buffer properties—the information coded into the filter buffer headers—are local to a buffer and are not required to be constant in any way. Sampling rate is probably the most common example of a pipe property. A buffer property for example could be a timestamp.

Buffer property definitions are local to a filter protocol. Filter protocols expose additional per-buffer information to the filters by prepending a protocol specific header to the buffer. Multiple buffer properties can be defined in one header.


Next: , Previous: Parameter Definition, Up: Filter Tutorial

3.2 Now what is this whole filter stuff anyway?

In GLAME there are four different kinds of filters. For each you have to care about different methods to ensure correct operation. The first three share (by definition) the following property: they all use nothing but SAMPLEs as their inputs/outputs.

So to begin with the fourth kind of filter, the one operating on types different from SAMPLE as well. For this kind you may need to re-implement every method in the filter struct. If you want to implement such a complex filter, contact glame-devel@lists.sourceforge.net for advice.

The first kind of filters summarizes those which have no input at all. This is the class of generators. Generators have to ensure that the pipes connected to them are assigned the correct type and type parameters. Therefore they all need to provide the connect_out() method. If they do have filter parameters which affect the output type/parameters, they also have to provide the fixup_param() method. Example for this class of filters are the sine filter in waveform.c and the read_file_f() filter in file_io.c.

The second kind of filters comprises of those which have no output. This is the class of sinks. Sinks don't have to care about all that much. Everything they need to setup can be done in the main filter method. So usually those filters do not provide another method apart from f(). An example for this class of filters is the drop_f() filter in basic.c.

The third kind of filters are the inbetween filters which require connected input and output channels. Let's call them effects. Effects have to provide a connect_out() method, if they change any of the pipe properties (i.e. what comes out is different from what comes in, like in a resample case). They also have to provide the fixup_param() and the fixup_pipe() methods if there are dependencies between the filter or port parameters and the output pipe properties or between the input pipe properties and the output pipe properties (different from a one-to-one mapping).


Next: , Previous: Filter Categories, Up: Filter Tutorial

3.3 What do I need to have in a glame filter set?

You need the following functions and methods:

<your_filtersetname>_register()
A filter register function of the name <your_filtersetname>_register() which returns 0 on success and -1 on any error.
f()
The main filter method f(). You need this for each filter contained in the filter set.
other filter methods
You may need to include other filter specific methods, too. See above for generic hints on which methods you may need.


Next: , Previous: Filter Skeleton, Up: Filter Tutorial

What does the f() function have to look like? Are there any restrictions?

Yes, of course there are!

f() should begin with checking the current setup for suitability: look at the parameters and input types/formats. And it should set up all necessary local things. After this initialisation the macro FILTER_AFTER_INIT; has to appear! Before this macro you may simply return -1 to denote an error, returning with no error is not allowed. After FILTER_AFTER_INIT; you should do the actual filter work, i.e. accept and send data through the ports. The main part of the filter and the cleanup part (freeing of all allocated local data, etc.) have to be separated by placing the macro FILTER_BEFORE_CLEANUP;. Neither in the main part, nor in the cleanup part may you just return with a return value of -1 (i.e. just fail). Instead you have to cleanup yourself, including sending EOFs to your output ports. So basically you may fail in the initialisation part, but nowhere else. The cleanup section must end with a call to FILTER_RETURN.

For your convenience, there's a set of macros to ease the task of meeting those constraints. FILTER_DO_CLEANUP; is used to jump from the init section to the cleanup section. It does not make the filter fail, however. To return with an error, use FILTER_ERROR_RETURN(msg_string);. FILTER_ERROR_CLEANUP(msg_string); makes the filter fail as well but jumps to the cleanup section first. Obviously, FILTER_ERROR_RETURN(); and FILTER_ERROR_CLEANUP(); may only be used in the init section. FILTER_DO_CLEANUP; can be handy in the main loop.

Another section primitive is the FILTER_CHECK_STOP; macro which you should use inside all operating loops to check for external stop, pause or terminate queries. The corresponding cleanup section after FILTER_BEFORE_STOPCLEANUP; is jumped to if a terminating request has to be fulfilled.

Typical code looks like this:

     static int myfilter_f(filternode_t *n)
     {
     	(...)	/* Initalisations, setups... */
     
     	if (!(bar = (bar_t *)malloc(sizeof(bar_t))))
     		FILTER_ERROR_RETURN("Not enough memory for bar!");
     
     	if (!(baz = open(mydev, myflags)))
     		FILTER_ERROR_CLEANUP("Unable to open device!");
     
     	FILTER_AFTER_INIT;
     
     	while (a < b) {
     		FILTER_CHECK_STOP;
     		(...) /* Do real work */
     	}
     
     	FILTER_BEFORE_STOPCLEANUP;
     	FILTER_BEFORE_CLEANUP;
     
     	if (baz != -1)
     		close(baz);
     	free(bar);
     	FILTER_RETURN;
     }

You may not use any of the ?buf_*() functions in the init section (DEADLOCK!!!) (Well, ?buf_alloc() is allowed, if you really need it)

For more complex filters which require some sort of backlog of sample data or which modify an input stream the following issues have to be cared about:

You should not allocate a ringbuffer or backlog storage via malloc, neither should you simply copy the data—this is not necessary. In fact it is completely broken. You should instead just keep all the sbuf's around that you need later (of course ref'ing and unref'ing them at the appropriate time)

If your filter in principle would support in-place read-modify-write of the data you should not allocate new buffers for the output using sbuf_alloc(). Instead you should grab the source buffer and do a sbuf_make_private() on it taking the returned pointer as the “new” input buffer which you may modify now and queue as output.

Once again, as this is a vital point: If you do any modification of any buffer (including those which you just allocated privately using sbuf_alloc() or friends) you must get the write-enabled buffer by calling sbuf_make_private() and use the return value as the buffer to be written to!


Next: , Previous: Main Filter Method, Up: Filter Tutorial

3.4 Examples

To clarify the reference counting and locking issues, in the following several valid and invalid example uses of the API are given. They are valid for each of the filter buffer protocols such as the sbuf protocol.

Valid just-forward buffers from input to output:

     buf = fbuf_get(in);
     fbuf_queue(out, buf);

This is valid because fbuf_get() will get us a reference on the filter buffer and fbuf_queue() eats it, i.e. the reference gets forwarded, too.

Invalid attempt to forward a buffer to two outputs:

     buf = fbuf_get(in);
     fbuf_queue(out1, buf);
     fbuf_queue(out2, buf);

This is invalid because you don't have any reference left after the first fbuf_queue(), i.e. there is no reference you can forward to the second fbuf_queue().

Valid but possibly ineffective just-forwarding:

     buf = fbuf_get(in);
     fbuf_ref(buf);
     fbuf_queue(out, buf);
     fbuf_unref(buf);

While being valid, this example illustrates ineffective use of references. Since you don't need to touch the buffer after fbuf_queue(), you don't need to get an additional reference and neither drop it again afterwards. Such use will cause a fbuf_make_private() in the destination filter to potentially copy the buffer while a perfectly valid zero-copy operation was possible.

Invalid modifying and forwarding of a buffer:

     buf = fbuf_get(in);
     fbuf_ref(buf);
     fbuf_buf(buf)[0] = 1;
     fbuf_unref(buf);
     fbuf_queue(out, buf);

This is invalid as the additional fbuf_ref() does not provide you with a private modifable buffer, but just ensures that nobody else does write to or destroy the buffer (which one can't anyway as you are holding a reference already—the one got by fbuf_get()). The correct solution is to do:

     buf = fbuf_get(in);
     buf = fbuf_make_private(buf);
     fbuf_buf(buf)[0] = 1;
     fbuf_queue(out, buf);


Previous: Examples, Up: Filter Tutorial

3.5 Speeeed

For now look into src/hash/glsimd.h if you can find useful streamed (SIMD) operations you can use. Those usually exist in efficient assembler versions.


Next: , Previous: Filter Tutorial, Up: Top

4 Conversion Layer

The GLAME conversion layer is meant to provide a uniform and efficient API for conversion of audio data between different formats. It will mainly be useful to the various i/o plugins, i.e. plugins doing audio i/o, file i/o, swapfile i/o and the like. The conversion layer is capable of interleaving and de-interleaving audio streams. It also performs endianness and type conversions of individual samples. The user has to supply information on the layout of source and destination data, and the conversion layer will internally try to find the most optimized conversion path. Use of extended features of current hardware like 3Dnow, ISSE, or AltiVec is completely hidden from the caller.

This documentation describes the externally visible API the conversion layer presents to its callers. If you are about to write a new i/o plugin for GLAME, you should probably go on reading. If you want to hack up another optimised conversion routine for the processor of your choice, have a look at the source instead.

Warning!
This is the rare case of a design preceeding its implementation. This documentation is provided here for discussion among developers. The API cannot actually be used yet.

Send comments on the conversion layer or this documentation to glame-devel@glame.sourceforge.net (c/o nold).


Next: , Up: Conversion Layer

4.1 Prototypes

All types and methods used by the GLAME conversion layer are prefixed by gcv_. Prototypes can be obtained via

     #include <glame_conv.h>


Next: , Previous: Prototypes, Up: Conversion Layer

4.2 Versioning

As the GLAME conversion layer de facto presents an ABI to third-party plugins, it uses its own version scheme to denote changes in its interface structure. The version comprises of two numbers, generation and revision. The revision is incremented whenever an additional feature is added that doesn't break existing users. Incrementing the generation count indicates a change in interface layout that is not backward-compatible.

To obtain the version numbers of the conversion layer, call

— Function: unsigned int gcv_get_generation (gcv_version_t ver)
— Function: unsigned int gcv_get_revision (gcv_version_t ver)

to get generation and revision respectively.

This documentation describes the GLAME conversion layer interface generation 1, revision 0.


Next: , Previous: Versioning, Up: Conversion Layer

4.3 Describing the data layout

The GLAME conversion layer so far only handles tightly packed streams of audio data, i.e. padding is not supported yet. Furthermore, if there are multiple streams of audio data, each stream must carry the same number of interleave channels. Sample properties have to be equal among all data as well. Therefore a chunk of audio data is described by the following properties:

For example, a typical stereo chunk of the form ABABABAB... is described as one stream, two channels interleaved. Sample properties might be width 16 bit, type unsigned integer, little endian. (That's the most common layout of Wave/PCM files actually.)

Users of the conversion layer have to specify the layout of the source data, as well as the desired target layout. This is done using the following methods.

— Function: gcv_layout_t gcv_get_layout (void)
— Function: void gcv_drop_layout (gcv_layout_t layout)

Gets an uninitialised layout handle, or drops all ressources associated to a valid layout handle, respectively.

— Function: int gcv_set_streams (gcv_layout_t layout, unsigned int num_stream)

Sets the number of individual audio streams on layout to num_stream. layout needs to be a valid layout handle returned by gcv_get_layout(). -1 is returned on error, 0 on success.

— Function: int gcv_set_channels (gcv_layout_t layout, unsigned int num_ch)

Sets the number of interleaved audio channels per stream. layout needs to be a valid layout handle returned by gcv_get_layout(). -1 is returned on error, 0 on success.

— Function: int gcv_set_width (gcv_layout_t layout, unsigned int width)

Sets the width of a single audio sample on layout to width bits. layout needs to be a valid layout handle returned by gcv_get_layout(). -1 is returned on error, 0 on success.

— Function: int gcv_set_type (gcv_layout_t layout, gcv_type_t type)

Sets the type of a single audio sample on layout to type. layout needs to be a valid layout handle returned by gcv_get_layout(). -1 is returned on error, 0 on success. gcv_type_t is defined in glame_conv.h and may be one of

GCV_TYPE_INT
for integer values;
GCV_TYPE_UINT
for unsigned integer values;
GCV_TYPE_FLOAT
for (signed) floating point values.

— Function: int gcv_set_endian ( gcv_layout_t layout, gcv_endian_t endian)

Sets the endianness of a single audio sample on layout to endian. layout needs to be a valid layout handle returned by gcv_get_layout(). -1 is returned on error, 0 on success. gcv_endian_t is defined in glame_conv.h and may be one of

GCV_BIG_ENDIAN
GCV_LITTLE_ENDIAN
GCV_NATIVE_ENDIAN

The latter describing that the data is formatted in a machine's native endianness, which is determined at compile time.


Next: , Previous: Describing the data layout, Up: Conversion Layer

4.4 Getting your custom-tailored conversion routine

Once layout of source and target data are set up, a set of conversions between the two of them has to be found. This step is performed transparently to the user when the layouts are registered with the conversion layer.

— Function: gcv_conv_t gcv_get_conversion (gcv_layout_t source, gcv_layout_t target)
— Function: void gcv_drop_conversion (gcv_conv_t cv)

Gets a new handle on a conversion from source to target, or drops all associated ressources respectively. gcv_get_conversion returns a valid handle on success, or NULL on error.

FIXME
We need another option to tell whether the conversion may be destructive. Ought not to scribble on an mmap()ed soundfile! Requiring the caller to copy to a safe buffer probably ain't the best calling convention in this case.


Previous: Getting your custom-tailored conversion routine, Up: Conversion Layer

4.5 Invoking data conversions

The conversion layer operates from memory to memory only. Writing to or reading directly from files may be achieved via mmap(). Sockets are currently unsupported and must be handled via bounce buffers. This limitation might be dropped in future versions. Internally, bounce buffers are only allocated when necessary, i.e. if source and target layout match, the input buffer is passed on unmodified, so there's no need to special case in calling code.

— Function: ( char **) gcv_do_conversion (char **out, char **in, unsigned int spc, gcv_conv_t cv)

Converts data from in to out according to previously registered layout settings defined via cv. spc is the number of samples per channel to be converted. in is an array of pointers to the input data streams. The array's size has to match the number of streams given in the source layout. out is an array of pointers to memory locations that shall be filled with the converted data. The array's size has to match the number of streams given in the target layout. If out is NULL, the target buffers will be allocated internally by gcv_do_conversion, and a pointer to a NULL-terminated array of pointers to the target buffers is returned. Calling code is responsible to free all buffers and the array itself in this case. gcv_do_conversion returns NULL if an error was encountered, or a pointer to the array of pointers to the target buffers on success.


Next: , Previous: Conversion Layer, Up: Top

5 Swapfile API

If you have any questions related to the covered (or uncovered but related) topics in this document, please quote the questionable part of this document and send the questions per e-mail to glame-devel@glame.sourceforge.net (c/o richi).


Next: , Up: Swapfile API

5.1 Introduction

This is the documentation for the swapfile subsystem of GNU/Linux Audio Mechanics (GLAME). Swapfile was designed not specifically for GLAME but with the idea of storing of and operating on large datasets, specifically audio streams.

Swapfile provides a store for multiple independent sets of (not necessarily) one-dimensional data. Swapfile supports transparent and unlimited undo and redo of all operations.

The swapfile is modeled after a unix filesystem with some additional features and some restrictions. First, the namespace of the filesystem is flat, i.e. there are no directories. And the namespace is rather corse, a file is identified by a unique number, a long. Also unlike files on normal filesystems a swapfile file cannot be memory mapped without restrictions on size and offset. This is due to the advanced features which are the capability to share parts of the file with other files in a copy on write manner and the sw_sendfile operation which allows cutting, inserting and overwriting one file with the contents of another file without actually moving any data. Because of this features the internal structure of a file cannot consist of a set of equally sized and aligned blocks, it rather consists of a sequence of randomly sized clusters. The memory mapping restriction is such that only a complete cluster can be mapped.


Next: , Previous: Introduction, Up: Swapfile API

5.2 Swapfile User Interface

So let's jump into listing the functions of the swapfile API and document the semantics.


Next: , Up: Swapfile User Interface

5.2.1 Initialisation

To initialize the swapfile subsystem you have to open an existing swapfile which in turn you may create using either the gmkswap utility or the swapfile_creat function. After finishing operation you should close it again using swapfile_close.

— Function: int swapfile_open (char *name, int flags)

swapfile_open() opens the swapfile with the specified name and the specified flags (no flags are defined yet, use 0). Returns -1 if it was not possible to open the swapfile or the swapfile is in an inconsistent state.

— Function: void swapfile_close (void)

swapfile_close() closes the swapfile and updates the metadata state of the on-disk version of the swapfile. This puts the swapfile into a consistent state.

— Function: int swapfile_creat (char *name, size_t size)

Tries to create an empty swapfile on name of the specified size.

— Function: int swapfile_fsck (char *name, int force)

Checks the swapfile on name for consistency and tries to correct all errors. Useful in case of an unclean swapfile or with force specified as 1 rather than 0. Returns 0 on success and -1 on error (which usually means non correctable errors).


Next: , Previous: Initialisation, Up: Swapfile User Interface

5.2.2 Namespace Operations

— Function: int sw_unlink (long name)

Deletes a name from the filesystem. Like unlink(2).

— Function: SWDIR* sw_opendir ()

Open the (flat) swapfile directory for reading. The stream is positioned at the first file. Like opendir(3), but without directory specification for obvious reason.

— Function: long sw_readdir (SWDIR* dir)

As the namespace is rather simple the equivalent to readdir(3) is just returning the names, no directory entry. Anything else is like readdir(3). If no further entries are available, -1 is returned.

— Function: int sw_closedir (SWDIR* dir)

Like closedir(3).


Previous: Namespace Operations, Up: Swapfile User Interface

5.2.3 File Operations

— Function: swfd_t sw_open (long name, int flags)

Open a file like open(2) - flags can be O_CREAT, O_EXCL, O_RDWR, O_RDONLY, O_WRONLY with same semantics as open(2). Returns a file descriptor on success, -1 on error.

— Function: int sw_close (swfd_t fd)

Closes a file descriptor. Like close(2).

— Function: int sw_ftruncate (swfd_t fd, off_t length)

Changes the size of the file fd like ftruncate(2).

— Function: ssize_t sw_sendfile (swfd_t out_fd, swfd_t in_fd, size_t count, int mode)

Tries to copy count bytes from the current position of in_fd to the current position of out_fd (updating both file pointer positions). The actual number of copied bytes is returned, or -1 on an error.

Two different modes are supported (may be or'ed together): SWSENDFILE_INSERT inserts into, rather than overwrites or extends the destination file, SWSENDFILE_CUT removes copied data from the source file rather than leaving it unmodified. The destination file descriptor may be SW_NOFILE, in that case no data is actually written (useful with SWSENDFILE_CUT).

— Function: off_t sw_lseek (swfd_t fd, off_t offset, int whence)

Update the file pointer position like lseek(2).

— Function: ssize_t sw_read (swfd_t fd, void *buf, size_t count)

Like read(2), read count bytes from the current filepointer position to the array pointed to by buf.

— Function: ssize_t sw_write (swfd_t fd, const void *buf, size_t count)

Like write(2), write count bytes from buf starting at the current filepointer position.

— Function: int sw_fstat (swfd_t fd, struct sw_stat *buf)

Obtain information about the file - works like fstat(2), but with different struct stat. Also included is information about the actual (file pointer position, see sw_lseek) cluster which can be mapped using sw_mmap.

          struct sw_stat {
          	long name;           /* file name */
          	size_t size;         /* file size in bytes */
          	int mode;            /* active protection */
          	off_t offset;        /* current file pointer position */
          	off_t cluster_start; /* start of current cluster */
          	off_t cluster_end;   /* end of current cluster */
          	size_t cluster_size; /* size of current cluster */
          };
     

— Function: void *sw_mmap (void *start, int prot, int flags, swfd_t fd)

Maps the actual (file pointer position, see sw_lseek and sw_fstat) cluster into memory with parameters like mmap(2) - no size or offset need to be specified as they are determined by the actual cluster offset and size.

— Function: int sw_munmap (void *start)

Unmaps a previously mapped part of a file. Like munmap(2).


Next: , Previous: Swapfile User Interface, Up: Swapfile API

5.3 TXN User Interface

This is the transaction API which can be used to implement undoing and redoing operations. For operations to be transactioned, i.e. recorded on execution those operations need to be transaction aware. See the section on TXN Programming Interface on how to make your own operations transaction aware.

All transactions have to be named by an unique transaction id. A new transaction can be started by txn_begin which will give you a new transaction id to which subtransactions can be attached. So usually any transaction aware operation gets such parent transaction identifier as argument. Note that ending a transaction via txn_end does not free the transaction. This is because you want to be able to use the transaction for undoing or redoing the operations. If you dont need to do this it is wise to delete the transaction via txn_delete to free the memory associated with it.

You may miss a txn_redo function for redoing a transaction. This is by purpose as redo is just another kind of undo. Because of this analogy the txn_undo operation returns a new transaction which can be used to undo this undo operation, i.e. providing a transaction which does the redo operation.

— Function: txnid_t txn_start (txnid_t parent)

Start a new transaction as child of the provided parent transaction (can be TXN_NONE if the transaction should be a independend one). Returns a transaction id or -1 on error. On error either the specified parent transaction does not exist, it has already an active child (violates transaction may not cross) or there is insufficient memory to allocate internal data structures.

— Function: int txn_end (txnid_t id)

End the specified transaction. Returns 0 on success and -1 on error. On error either the specified transaction does not exist, it is already ended or it has active child transactions.

— Function: int txn_abort (txnid_t id)

Abort the specified transaction thereby aborting active child transactions and undoing all previous work. txn_abort itself is not undoable. Returns 0 on success, -1 on error which is usually an invalid supplied transaction id or an inactive transaction.

— Function: txnid_t txn_undo (txnid_t id)

Undo applies the reverse transaction as a new transaction, so txn_undo(txn_undo(id)) restores state after id, simply deleting the returned transaction id prevents redo, deleting the original id after txn_undo prevents undo after redo.

— Function: int txn_delete (txnid_t id)

Delete the specified (inactive) transaction and free all memory associated with it. Returns 0 on success and -1 on error which means you have supplied either an invalid or an active transaction.

— Function: void txn_abort_and_delete_all ()

Abort all active and delete all inactive transactions. This is mainly for cleanup purposes before program end or after crash. Note that this is not thread-safe by design, but you have to ensure proper locking yourself or hope to be lucky... (which is usually ok in case of normal program termination).


Next: , Previous: TXN User Interface, Up: Swapfile API

5.4 TXN Programming Interface

Well, for now you have to learn by reading existing transaction aware code which boils down to the swapfile subsystem. Well, for the impatient I have at least the following very brief tutorial cut&pasted from the txn.h headerfile:

     struct my_txn_op {
           struct txn_op op;
           ... data to undo/delete my transaction
     };
     int my_operation(txnid_t parent_tid, params...)
     {
           struct my_txn_op *op = malloc(sizeof(struct my_txn_op));
           txnid_t my_tid;
           ... initialization stuff for my_operation
           my_tid = txn_start(parent_tid);
           ... my operation
           op->op.undo = my_txn_undo;
           op->op.del = my_txn_delete;
           op->... stuff to be able to undo/delete the transaction
           txn_finish(my_tid, &op->op);
           ... stuff
     }

But there are at least two useful functions in the transaction API that will help you making your operations transaction aware.

— Function: int txn_finish (txnid_t id, struct txn_op *ops)

Finishes a transaction by providing the necessary undo and delete operations. Will fail if child transactions are there. The transaction will be ended as in txn_end(txn_start(id)).

— Function: int txn_finish_unimplemented (txnid_t id, const char *message)

Finishes a transaction using an implementation that throws an exception, if the undo operation is required. The supplied message is written to stderr and a SIGSEGV will be raised.


Previous: TXN Programming Interface, Up: Swapfile API

5.5 PMAP Programming Interface

This one I consider not that important, so either you have to consult the headerfile for documentation or wait for me to have lots of spare time.


Next: , Previous: Swapfile API, Up: Top

6 GLAME Project Structure Management

The project structure management including track metadata and coupling with the swapfile/filter API.

The structure is build out of gpsm-items which can be either groups (gpsm_grp_t) or swapfile files (gpsm_swfile_t). Think of the structure as of a tree with leafs all being swapfile files (or equivalent types, if they ever will appear) and the interior nodes being groups. Groups (generic: items) have horizontal (samples) and vertical (tracks) extend, items have horizontal (samples) and vertical (track) positions.

Usage of the gpsm API is by the various GUI widgets that handle the swapfile and the filters such as the swapfile gui and the timeline gui. Also use by the scheme scripts is the preferred way to work on the swapfile. Consistent updating of all interfaces can be realized by registering appropriate signal handlers to the gpsm-items emitter. Signals are sent out by all gpsm API functions and have to be sent out manually by everyone operating on the swapfile/gpsm-items _not_ using the gpsm API functions.


Next: , Up: GLAME Project Structure Management

6.1 Generic operations on items

Every item in the project tree has information of its parent, a signal emitter where you can attach handlers to, a label and last but not least a 2D position and a 2D size. Those elements can be accessed using the following functions:

— Function: gpsm_item_t * gpsm_item_parent (gpsm_item_t *item)

Returns the parent item of the provided item or NULL, if the item is the root of a gpsm tree.

— Function: glsig_emitter_t * gpsm_item_emitter (gpsm_item_t *item)

Returns the signal emitter of the provided item.

— Function: const char * gpsm_item_label (gpsm_item_t *item)

Returns the label of the provided item. Note that the result is strictly read-only.

— Function: long gpsm_item_hposition (gpsm_item_t *item)
— Function: long gpsm_item_vposition (gpsm_item_t *item)
— Function: long gpsm_item_hsize (gpsm_item_t *item)
— Function: long gpsm_item_vsize (gpsm_item_t *item)

These functions return the actual position (horizontal or vertical) or the actual size (horizontal or vertical) of the provided item. Both horizontal position and size are measured in samples. Both vertical position and size are measured in tracks. Positions and sizes are positive or zero.

Common operations you can carry out on an items are item destruction, insertion and removal, setting of the label and flattening.

— Function: void gpsm_item_destroy (gpsm_item_t *item)

Destroys the provided gpsm item. The item is first removed from its group, if necessary and then destructed in child-first order. Appropriate signals are send out for this operation, namely GPSM_SIG_ITEM_REMOVE (and the GPSM_SIG_GRP_REMOVEITEM signal to the items group) if removal is required and GPSM_SIG_ITEM_DESTROY.

— Function: int gpsm_grp_insert (gpsm_grp_t *group, gpsm_item_t *item, long hposition, long vposition)

Inserts the specified gpsm-item into the group at the specified position. Random (non-overlapping) h-/v-positioning is performed if you pass -1 to h-/v-position. May fail, as overlapping items are not allowed. Returns 0 on success and -1 on error. Appropriate signals are send out for this operation, namely GPSM_SIG_GRP_NEWITEM to the group.

— Function: void gpsm_item_remove (gpsm_item_t *item)

Removes the specified gpsm-item from its current group. The items position will be (0,0) after this operation. If the item was not member of a group this is a NOP. Appropriate signals are send out for this operation, namely GPSM_SIG_ITEM_REMOVE and the GPSM_SIG_GRP_REMOVEITEM signal to the items group.

— Function: void gpsm_item_set_label (gpsm_item_t *item, const char *label)

Updates the label of the specified gpsm-item. Note that this will cause a GPSM_SIG_ITEM_CHANGED signal to be send out.

— Function: void gpsm_flatten (gpsm_item_t *item)

Flattens a gpsm item, that is, out of a possible deep tree of horizontally and vertically spreaded swfiles make a set of vertically aligned (read: starting at position zero and ending at the maximum position) swfiles. Returns a new group with new swfiles, one for each vertical track. The data is COWed from the original tree. In the special case of providing a swfile as item a new group with a COW copy of this item is returned (without paying attention to hposition of the item). On failure NULL is returned. Note that this feature greatly simplifies operations such as play and export (i.e. where you only want to _read_ from the files).


Next: , Previous: Generic operations on items, Up: GLAME Project Structure Management

6.2 The group item

Group items form the back of the gpsm tree, they contain an arbitrary number of items positioned relative to their parent. You can access a groups items via the following generic iterators:

— Iterator: gpsm_grp_foreach_item (gpsm_grp_t *group, gpsm_item_t *item) { }

You can iterate through all items contained in the specified group using the iterator (which acts like a for statement with the second parameter as running variable). Note that you may not delete instances in this loop!

— Iterator: gpsm_grp_safe_foreach_item (gpsm_grp_t *group, void *dummy, gpsm_item_t *item) { }

You can iterate through all items contained in the specified group using the iterator (which acts like a for statement with the second parameter as running variable). You may delete the actual item within this iterator, but you have to specify another dummy pointer to use for this to work.

There are a few operations specialized to work on group items only, namely group creation and tree searching.

— Function: gpsm_grp_t * gpsm_newgrp (const char *label)

Creates a new empty gpsm group with the specified label. You have to insert it into a gpsm group yourself. Returns a gpsm group or NULL on error.

— Function: gpsm_grp_t * gpsm_find_grp_label (gpsm_grp_t *root, gpsm_item_t *start, const char *label)

Find a gpsm-grp by label in the subtree specified by root. The search is started at the item start (or at the root, if you specify NULL). You can find all occurences by specifying the previous result as start. Returns a gpsm-grp, if found or NULL, if not.

— Function: gpsm_swfile_t * gpsm_find_swfile_label (gpsm_grp_t *root, gpsm_item_t *start, const char *label)

Find a gpsm-swfile by label in the subtree specified by root. The search is started at the item start (or at the root, if you specify NULL). You can find all occurences by specifying the previous result as start. Returns a gpsm-swfile, if found or NULL, if not.

— Function: gpsm_swfile_t * gpsm_find_swfile_filename (gpsm_grp_t *root, gpsm_item_t *start, long filename)

Find a gpsm-swfile by filename in the subtree specified by root. The search is started at the item start (or at the root, if you specify NULL). You can find all occurences by specifying the previous result as start. Returns a gpsm-swfile, if found or NULL, if not. */

— Function: gpsm_swfile_t * gpsm_find_swfile_vposition (gpsm_grp_t *root, gpsm_item_t *start, long vposition)

Find a gpsm-swfile by vposition in the subtree specified by root. The search is started at the item start (or at the root, if you specify NULL). You can find all occurences by specifying the previous result as start. Returns a gpsm-swfile, if found or NULL, if not.


Next: , Previous: The group item, Up: GLAME Project Structure Management

6.3 The swfile item

The swfile items are the leafs of the gpsm tree, they are the connection between the backing store and the different views. Swfiles provide a swapfile filename, a samplerate and a position which can be accessed using the following functions:

— Function: long gpsm_swfile_filename (gpsm_swfile_t *swfile)

Returns the swapfile filename of the gpsm swfile item.

— Function: int gpsm_swfile_samplerate (gpsm_swfile_t *swfile)

Returns the samplerate of the gpsm swfile item.

— Function: float gpsm_swfile_position (gpsm_swfile_t *swfile)

Returns the stream position of the gpsm swfile item.

There exist a quite large number of specialized operations on swfile items, including file creation, copying and linking, setting of the data and notifying gpsm and its users about changes to the swapfile file data.

— Function: gpsm_swfile_t * gpsm_newswfile (const char *label)

Creates a new spare swapfile to operate with. You have to insert it into a gpsm group yourself. Returns a gpsm-swfile or NULL on error.

— Function: gpsm_swfile_t * gpsm_swfile_cow (gpsm_swfile_t *swfile)

Creates a new swapfile with contents from the swapfile specified by the gpsm-swfile. Returns a gpsm-swfile or NULL on error.

— Function: gpsm_swfile_t * gpsm_swfile_link (gpsm_swfile_t *swfile)

Creates a new gpsm-swfile with the swapfile of the specified gpsm-swfile as backing store. Returns a gpsm-swfile or NULL on error.

— Function: void gpsm_swfile_set (gpsm_swfile_t *swfile, int samplerate, float position)
— Function: void gpsm_swfile_set_samplerate (gpsm_swfile_t *swfile, int samplerate)
— Function: void gpsm_swfile_set_position (gpsm_swfile_t *swfile, float position)

Updates the samplerate and/or position of the specified gpsm-swfile. Note that this information is per gpsm-swfile, not per swapfile! Note that this will cause a GPSM_SIG_ITEM_CHANGED signal to be send out.

— Function: void gpsm_notify_swapfile_change (long filename, long pos, long size)
— Function: void gpsm_notify_swapfile_cut (long filename, long pos, long size)
— Function: void gpsm_notify_swapfile_insert (long filename, long pos, long size)

After you've done an operation on a swapfile such as modifying or cutting/inserting via sw_sendfile() you have to notify the GPSM about this change. The swfiles sizes will be updated and appropriate signals will be send out. Note that it is generally better to make changes to a swapfile through gpsm functions (which dont exist at the moment...).

— Function: void gpsm_invalidate_swapfile (long filename)

If you have done changes to a swapfile which you cannot (or would not like to) specify explicitly you can tell gpsm and its users to start from scratch with this file. Note that this is a costly operation and it is generally better to use the finer grained notify functions above.


Next: , Previous: The swfile item, Up: GLAME Project Structure Management

6.4 GPSM signals and their semantics

There are a vast number of signals send out by the gpsm subsystem which are described syntactically and semantically here. Signal names are constructed with the prefix GPSM_SIG the infix denoting the type of object and the type of the first argument it is sent to such as ITEM, SWFILE and GRP and a suffix denoting the semantics. A list of available signals follows.

The first group is the signals sent to all type of items (thus the ITEM infix).

GPSM_SIG_ITEM_CHANGED
GPSM_SIG_ITEM_CHANGED has one parameter, the gpsm-item. The signal will be sent out after a change to any of the items data elements. Note that GPSM_SIG_ITEM_CHANGED delivery is not suppressed, if the change has a semantically more specific signal like one of the GPSM_SIG_GRP_* or GPSM_SIG_SWFILE_* signals. Also a GPSM_SIG_ITEM_CHANGED signal is sent out on item re-position.
GPSM_SIG_ITEM_DESTROY
GPSM_SIG_ITEM_DESTROY has one parameter, the gpsm-item. The signal will be sent out before item destruction. Note that items attached to a group will generally recieve a GPSM_SIG_GRP_REMOVEITEM signal before destruction, i.e. gpsm_item_destroy() will remove them first, then destruct.
GPSM_SIG_ITEM_REMOVE
GPSM_SIG_ITEM_REMOVE has one parameter, the gpsm-item. The signal will be sent out before item removal from its group. The GPSM_SIG_GRP_REMOVEITEM signal will be send out to the group after this signal.

The second group is the signals sent to groups only (thus the GRP infix). Both GPSM_SIG_GRP_NEWITEM and GPSM_SIG_GRP_REMOVEITEM have two parameters, the gpsm-grp as the first and the gpsm-item to be inserted/removed as second one. The GPSM_SIG_GRP_REMOVEITEM signal is sent out before item removal and after the item recieved the GPSM_SIG_ITEM_REMOVE signal, the NEWITEM signal after item addition.

NOTE: If the actual item is a group it is certainly possible for it to contain children!

NOTE2: You may want to attach/remove signal handlers to the item (and the possible childrens of a group)

GPSM_SIG_GRP_NEWITEM
GPSM_SIG_GRP_REMOVEITEM

The third and last group is the signals sent out to swfiles only (thus the SWFILE infix). The GPSM_SIG_SWFILE_* have three parameters, the first is the gpsm-swfile itself, the second is a long position, the third a long size specifying position and size of the inserted / cutted / changed data in samples. This signal is sent _after_ the actual operation was carried out on the swapfile.

GPSM_SIG_SWFILE_INSERT
GPSM_SIG_SWFILE_CUT
GPSM_SIG_SWFILE_CHANGED


Previous: GPSM signals and their semantics, Up: GLAME Project Structure Management

6.5 Undo and redo support

GPSM provides an easy way to support undo and redo at the scope of a GPSM group (or a single swfile). To be able to do this you need to manually save the state of a group before operating on it, undo and redo then can automatically roll back to these saved states.

The maximum number of saved states can be configured by using the following function (it is safe to call it before or after gpsm_init()):

— Function: int gpsm_set_max_saved_ops (int max)

Changes (or just queries, if max < 0) the maximum number of states saved for undo/redo. Returns the actual set value.

The following functions treating with undo and redo are available:

— Function: int gpsm_op_prepare (gpsm_item_t *item)

Save the current state of the provided subtree for later undo. Returns 0 on success, -1 on failure.

— Function: int gpsm_op_can_undo (gpsm_item_t *item)

Returns 1 if undo is pending for the subtree item and can be undone at this point, else returns 0.

— Function: int gpsm_op_undo (gpsm_item_t *item)

Rolls back to the latest saved state of the provided subtree. Returns 0 on success, -1 on error (such as no undo pending or possible). Saves the actual state for later redo.

— Function: int gpsm_op_undo_and_forget (gpsm_item_t *item)

Rolls back to the latest saved state of the provided subtree. Returns 0 on success, -1 on error (such as no undo pending or possible). Does not save the actual state for later redo.

— Function: int gpsm_op_can_redo (gpsm_item_t *item)

Returns 1 if redo is pending for the subtree item and can be redone at this point, else returns 0.

— Function: int gpsm_op_redo (gpsm_item_t *item)

Rolls back to the state before the previous undo to the provided subtree. Returns 0 on success, -1 on error (such as no redo pending or possible). Saves the actual state for later undo.

— Function: int gpsm_op_redo_and_forget (gpsm_item_t *item)

Rolls back to the state before the previous undo to the provided subtree. Returns 0 on success, -1 on error (such as no redo pending or possible). Does not save the actual state for later undo.

— Function: int gpsm_op_forget (gpsm_item_t *item)

Kills off the latest saved state of the provided subtree. Returns 0 on success, -1 on error (no pending undo or redo).


Next: , Previous: GLAME Project Structure Management, Up: Top

7 Plugin Interface

The plugin interface is very simple. There are actually two functions, one to add paths to the existing plugin path list and one to query the handle of a plugin.

— Function: int plugin_add_path (const char *path)

This function will add path to the list of paths used to search plugins.

— Function: int plugin_load (const char *filename)

plugin_load() will try to register all available plugins out of the specified file filename. If the specified file could not be opened or is not a valid plugin file, -1 is returned. On success, that is after registering zero or more plugins, 0 is returned.

— Function: plugin_t * plugin_get (const char *name)

This function will return a handle to the plugin with the name name. If the plugin is not already loaded it will be loaded from one of the paths in the path list. plugin_get() returns NULL if the plugin can't be found or an error occured during its initialization phase.

To manually add a plugin not contained in some shared library you should call the following function.

— Function: plugin_t * plugin_add (const char *name)

This function will add a new empty plugin to the database. You should populate its database using the plugin_set() function. On success a plugin handle is returned, NULL is returned on failure.

To access parts of the plugin the following wrapper macros should be used on the plugin_t handle.

— Function: const char * plugin_name (plugin_t *p)

This function returns the plugin's name.

— Function: int plugin_set (plugin_t *p, const char *key, void *val)
— Function: void * plugin_query (plugin_t *p)

Using these functions you can set and query key/value pairs either stored through dynamic library symbols or through a little per plugin database. plugin_query() returns NULL, if there is no information about the specified key. As a general rule of dumb you should start your keywords with a '!' to prevent conflicts with dynamic symbols. Standard keywords are accessible using the defines PLUGIN_DESCRIPTION, PLUGIN_PIXMAP, PLUGIN_CATEGORY and the internally used keywords PLUGIN_FILTER and PLUGIN_PARENT.

To browse through all registered plugins you can use the following function.

— Function: plugin_t * plugin_next (plugin_t *p)

plugin_next() gets you the next plugin in the database or the first one if you supply NULL. NULL is returned if no further plugins are available.

If you want to create a plugin, your dynamic object should contain the following standard symbols with the described information attached. The targeted subsystem may require additional defined symbols. Please refer to the subsystems' documentation for information about those symbol names and required contents. You should substitute the plugins name for the plugin prefix of the symbols to prevent symbol name clashes.

plugin_register
A function of type (int (*)(plugin_t *p)) which does everything necessary to register anything in the plugin to any subsystem.
plugin_set
This optional symbol of the type char * should contain a list of additional plugin names inside the object file seperated by spaces. You will need a seperate _register symbol for each of the specified additional plugin names. Use the PLUGIN_SET macro to create a symbol like that. Provide two arguments, the first should be an identifier matching the file name without filename extension, the second one should be the space seperated plugin list string.


Next: , Previous: Plugin Interface, Up: Top

8 GLAME Database Interface

The purpose for this generic small database framework is to be able to have many databases with a very small footprint for their hook and reasonable minimum item size. The item query time is O(N). Note that there is no locking internal to a database - at least no guaranteed one, so you may want to have per database mutexes.

Only one "type" of items may be stored in the database - type is destinguished by the database operations, the copy and the delete operation. These operate on all items and such either need to find about the items type themself or assume equal types.

Note that embedding a gldb_t * rather than a struct db_ops * in the item does allow more flexibility such as a single linked list implementation or some other tricky use of the db/item framework.

The presented framework is not intended for direct use but rather for use as a basis for own item types with corresponding wrappers to the gldb API.


Next: , Up: GLAME Database Interface

8.0.1 The Basic GLAME Database Types

Still to be documented.


Next: , Previous: The Basic GLAME Database Types, Up: GLAME Database Interface

8.0.2 The Internal gldb Operations

Still to be documented.


Next: , Previous: The Internal gldb Operations, Up: GLAME Database Interface

8.0.3 The GLAME Database API

The external visible API of a generic database is the following (see the src/hash/gldb.h file):

— Function: void gldb_init (gldb_t *db)
— Function: void gldb_delete (gldb_t *db)
— Function: int gldb_copy (gldb_t *dest, gldb_t *source)
— Function: int gldb_nritems (gldb_t *db)

These function operate on a whole database, respectively initialize an empty database, deletes all items of a database, copies all items from one database to another and tells about the number of items in the database.

— Function: void gldb_init_item (gldb_item_t *item)
— Function: void gldb_delete_item (gldb_item_t *item)
— Function: gldb_item_t * gldb_copy_item (gldb_item_t *item)

These functions operate on a database item, respectively initializing it, deleting it or creating a copy of it.

— Function: int gldb_add_item (gldb_t *db, gldb_item_t *item, const char *label)
— Function: void gldb_remove_item (gldb_item_t *item)
— Function: gldb_item_t * gldb_query_item (gldb_t *db, const char *label)

These functions can be used to add an item with the specified label to the database, remove it out of the database, or to query a database item by specifying the label that was given at addition time.

— Iterator: gldb_foreach_item (gldb_t *db, gldb_item_t *item) { }

Using this iterator you can iterate through all items stored in the specified database. You may not remove items while iterating, though.


Previous: The GLAME Database API, Up: GLAME Database Interface

8.0.4 Existing GLAME Database Specializations

Two generic specializations exist, the string database and the WORM database. Also the filter parameter database and the filter port database are specializations of the generic GLAME database framework, but they are not covered in this document.


Next: , Up: Existing GLAME Database Specializations

Still to be documented.


Previous: The String Database, Up: Existing GLAME Database Specializations

Still to be documented.


Next: , Previous: GLAME Database Interface, Up: Top

9 GLAME Signal Interface

Generic signals via callbacks (glsig_handler_t), issuable from a glsig_emitter. Signal masks are supported, as is a hierarchy of the signal emitters.

WARNING! No explicit threading support is included, i.e. do your own locking (you have to protect the emitter against concurrent addition and removal of handlers and emit of signals). Also a handler will be invoked in the thread context of the emitter, not in the one which added the handler. If you want to emit signals from real signal handlers you have to ensure yourself that your handlers are signal safe - also they should be reentrant as parallel invocation from different threads is not protected against.

Brief description of the available API follows:

— void: (glsig_callb_t) (glsig_handler_t *, long, va_list)

The type of the used callback functions through which signals are supposed to be handled.

— Function: INIT_GLSIG_EMITTER ( glsig_emitter_t *emitter)

Inits an emitter. No signal handlers are attached initially.

— Function: glsig_handler_t * glsig_add_handler ( glsig_emitter_t *emitter, long sigmask, glsig_callb_t *cb, void *priv)

Adds a signal handler to the emitter using the specified sigmask and the callback handler. The priv data is stored in the handlers ->priv field which you should access using glsig_handler_private().

— Function: glsig_handler_t * glsig_add_redirector ( glsig_emitter_t *emitter, long sigmask, glsig_emitter_t *dest)

Adds a redirector to the emitter. All signals raised from the emitter matching the specified signal mask will be raised again from the dest emitt

— Function: void glsig_emit ( glsig_emitter_t *emitter, int sig, ...)

Emits the signal sig from the emitter and provides the varargs to the callbacks. Signals are emitted bottom to top in the hierarchy. It is safe to remove your signal handler during execution.

— Function: int glsig_copy_handlers ( glsig_emitter_t *dest, glsig_emitter_t *source)

Copies all handlers from one emitter to another - same "private" data, of course. Can return -1 on memory shortage. Redirectors are not copied.

— Function: int glsig_copy_redirectors ( glsig_emitter_t *dest, glsig_emitter_t *source)

Copies all redirectors from one emitter to another - same "private" data, of course. Can return -1 on memory shortage. Normal handlers are not copied.

— Function: void glsig_delete_handler ( glsig_handler_t *handler)

Removes and destroyes the specified handler from its emitter.

— Function: void glsig_delete_all ( glsig_emitter_t *emitter)

Removes and destroyes all signal handlers from the specified emitter. Use with care.

— Function: void glsig_handler_exec ( glsig_handler_t *h, int sig, ...)

Executes the specified signal handler. Usually you dont want to use this, instead use glsig_emit().

Inside signal handlers you may access the passed parameters (which you should know by type and count) with the following macros.

— Function: void GLSIGH_GETARGS1 ( va_list va, type1 var1)
— Function: void GLSIGH_GETARGS2 ( va_list va, type1 var1, type2 var2)
— Function: void GLSIGH_GETARGS3 ( va_list va, type1 var1, type2 var2, type3 var3)
— Function: void GLSIGH_GETARGS4 ( va_list va, type1 var1, type2 var2, type3 var3, type4 var4)

These macros initialize the provided variables with the passed parameters. Beware that passing types with sizeof(type) not equal to sizeof(void *) is not safe on compilers other than gcc.


Previous: GLAME Signal Interface, Up: Top

Function and Type Index

Table of Contents