Sophie

Sophie

distrib > Mandriva > cooker > i586 > media > contrib-release-debug > by-pkgid > 29b07848f1f0d261023b5d8e39188a60 > files > 88

glame-debug-2.0.2-0.20070607.rc1.4mdv2011.0.i586.rpm

#ifndef _GPSM_H
#define _GPSM_H

/*
 * gpsm.h
 *
 * Copyright (C) 2001, 2004 Richard Guenther
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

/* 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.
 *  [FIXME: insert nice ascii-art picture of tree here.]
 * 
 * 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.
 */

/*
 * The following will clarify some "boxing" semantics
 * - Boxes around anything fit the exact bounding box, i.e. no
 *   extra space can be at the box "outer" border
 *     [item     item item   ]
 *   is not possible and instead will become
 *     [item     item item]
 *   but
 *     [    item item] 
 *   is ok. Same goes for vertical boxes.
 * - Insertions can happen in two ways:
 *   * at exact position without affecting positions of other
 *     items (but possibly affecting bounding box sizes).
 *     Overlaps with other items are not allowed, so are possible
 *     overlaps of the corrected bounding boxes:
 *       /                  \
 *       | /--------\       |
 *       |  [item] *        |
 *       |  [  item] [ item]|
 *       | \--------/       |
 *       \                  /
 *     insertion at * is not possible, as the surrounding vbox
 *     will overlap with the item in the outermost hbox after that.
 *   * at exact position with moving subsequent items by the size
 *     of the to be inserted item (and all affected items/boxes
 *     because of bounding box enlargement). Insertion at * in the
 *     above example would lead to
 *       /                       \
 *       | /-------------\       |
 *       |  [item   item]        |
 *       |  [  item]      [ item]|
 *       | \-------------/       |
 *       \                       /
 *     which may of course not be what the user has expected.
 *     Note that such insertion is always possible (apart from
 *     failing, if the hbox was not there)
 * - For item removal processes the same two modes are possible.
 *
 *                        HBOX         VBOX
 *     []                  x            x
 *     [  item]            x            x
 *     /     \                          x
 *     \ item/
 *     [ [item  item]]     x            x
 *     / /    \\           x            x
 *     \ \item//
 *
 * FIXME: hbox/vbox ambiguity is really a problem, so we might
 * rather make them explicit (perhaps convertible). I.e. at first
 * qualified insert (FIXME: placement does not care) fix the type.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include "list.h"
#include "glsignal.h"

#ifdef __cplusplus
extern "C" {
#endif

struct gpsm_item_s;
typedef struct gpsm_item_s gpsm_item_t;
struct gpsm_grp_s;
typedef struct gpsm_grp_s gpsm_grp_t;
struct gpsm_swfile_s;
typedef struct gpsm_swfile_s gpsm_swfile_t;


/*
 * Signals sent out by the gpsm-items.
 */

/* 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. */
#define GPSM_SIG_ITEM_CHANGED    (1<<0)

/* 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. */
#define GPSM_SIG_ITEM_DESTROY    (1<<1)

/* 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. */
#define GPSM_SIG_ITEM_REMOVE    (1<<2)

/* 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) */
#define GPSM_SIG_GRP_NEWITEM     (1<<3)
#define GPSM_SIG_GRP_REMOVEITEM  (1<<4)

/* 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. */
#define GPSM_SIG_SWFILE_INSERT   (1<<5)
#define GPSM_SIG_SWFILE_CUT      (1<<6)
#define GPSM_SIG_SWFILE_CHANGED  (1<<7)


#define GPSM_ITEM_TYPE_GRP    0
#define GPSM_ITEM_TYPE_SWFILE 1
#define GPSM_ITEM_IS_GRP(i) (((gpsm_item_t *)(i))->type == GPSM_ITEM_TYPE_GRP)
#define GPSM_ITEM_IS_SWFILE(i) (((gpsm_item_t *)(i))->type == GPSM_ITEM_TYPE_SWFILE)
struct gpsm_item_s {
	struct glame_list_head list;
	gpsm_grp_t *parent;
	glsig_emitter_t emitter;
	int type;

	/* Items have (not necessarily distinct) labels, i.e.
	 * the following is guaranteed to be non-NULL. */
	char *label;

	/* Item positions are _relative_ positions to the direct
	 * parent [or to (0,0) if the parent is NULL]. The item
	 * bounding box is guaranteed to not extend the parents
	 * bounding box and to not overlap with any child of the
	 * parent. */
	long hposition;
	long vposition;
	long hsize;
	long vsize;

	/* FIXME: make size (in s) an explicit member updated
	 * by swfile items and group change signals to handle
	 * groups of different rate swfiles.
	double duration;
	 * FIXME again: change item.hsize to double seconds
	 * and move item.hsize down to swfile? What about
	 * hposition? Well...
	 */
};
struct gpsm_grp_s {
	/* An gpsm-grp is an item with a list containing further
         * items. The gpsm-item positions/sizes are unions of the
         * groups children. */
	gpsm_item_t item;
	struct glame_list_head items;
};
struct gpsm_swfile_s {
	/* An gpsm-swfile is an item with additional information
         * about the swapfile file location/metadata. The gpsm-swfile
         * vsize is always 1. */
	gpsm_item_t item;
	gpsm_swfile_t *next_swfile_hash;
	gpsm_swfile_t **pprev_swfile_hash;
	struct timeval last_op_time;
	long filename;
	int samplerate;
	float position;
};

#define gpsm_item_parent(item) (((gpsm_item_t *)item)->parent)
#define gpsm_item_emitter(item) (&((gpsm_item_t *)item)->emitter)
#define gpsm_item_label(item) (((gpsm_item_t *)item)->label)
#define gpsm_item_hposition(item) (((gpsm_item_t *)item)->hposition)
#define gpsm_item_vposition(item) (((gpsm_item_t *)item)->vposition)
#define gpsm_item_hsize(item) (((gpsm_item_t *)item)->hsize)
#define gpsm_item_vsize(item) (((gpsm_item_t *)item)->vsize)

#define gpsm_grp_foreach_item(grp, item) glame_list_foreach(&((gpsm_grp_t *)(grp))->items, gpsm_item_t, list, item)
#define gpsm_grp_safe_foreach_item(grp, dummy, item) glame_list_safe_foreach(&((gpsm_grp_t *)(grp))->items, gpsm_item_t, list, dummy, item)
#define gpsm_grp_nritems(grp) glame_list_count(&((gpsm_grp_t *)(grp))->items)
#define gpsm_grp_first(grp) glame_list_gethead(&((gpsm_grp_t *)(grp))->items, gpsm_item_t, list)
#define gpsm_grp_next(grp, item) glame_list_getnext(&((gpsm_grp_t *)(grp))->items, ((gpsm_item_t *)(item)), gpsm_item_t, list)

#define gpsm_swfile_filename(swfile) (((gpsm_swfile_t *)swfile)->filename)
#define gpsm_swfile_samplerate(swfile) (((gpsm_swfile_t *)swfile)->samplerate)
#define gpsm_swfile_position(swfile) (((gpsm_swfile_t *)swfile)->position)

/* Standard group names and vpositions. */
#define GPSM_GRP_UNRECOGNIZED_LABEL "[unrecognized tracks]"
#define GPSM_GRP_UNRECOGNIZED_VPOS 1000000
#define GPSM_GRP_DELETED_LABEL "[deleted]"
#define GPSM_GRP_DELETED_VPOS 990000
#define GPSM_GRP_CLIPBOARD_LABEL "[clipboard]"
#define GPSM_GRP_CLIPBOARD_VPOS 980000

/* Type for PLUGIN_GPSMOP callback functions. */
typedef int (*gpsmop_func_t)(gpsm_item_t *, long, long);


/* Initializes the gpsm subsystem using the specified swapfile
 * (the gpsm subsystem metadata is stored in swapfile file 0).
 * Returns 0 on success and -1 on error (which is the sign for
 * swapfile corruption or already initialized gpsm). */
int gpsm_init(const char *swapfile, int maxundo);

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

/* Syncs the gpsm metadata on disk (swapfile) with the gpsm
 * metadata in memory. Also syncs all swapfile data cached. */
void gpsm_sync(void);

/* Syncs the gpsm metadata and the swapfile and closes the
 * subsystem. Further usage will require a call to gpsm_init()
 * again. */
void gpsm_close(void);



/* Returns the gpsm root group (or NULL on non initialized
 * gpsm subsystem). */
gpsm_grp_t *gpsm_root(void);


/* Creates a new spare swapfile to operate with. You have to
 * insert it into a gpsm_grp yourself. Returns a gpsm-swfile
 * or NULL on error. */
gpsm_swfile_t *gpsm_newswfile(const char *label);

/* Creates a new swapfile with contents from the swapfile
 * specified by the gpsm-swfile. Returns a gpsm-swfile or
 * NULL on error. */
gpsm_swfile_t *gpsm_swfile_cow(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. */
gpsm_swfile_t *gpsm_swfile_link(gpsm_swfile_t *swfile);


/* Creates a new empty gpsm-grp. You have to insert it into
 * a gpsm_grp yourself. Returns a gpsm-grp or NULL on error. */ 
gpsm_grp_t *gpsm_newgrp(const char *label);

/* Creates a new group with contents from the group
 * specified by the gpsm-grp. Returns a gpsm-grp or
 * NULL on error. */
gpsm_grp_t *gpsm_grp_cow(gpsm_grp_t *grp);

/* Creates a new gpsm-grp with the swapfiles of the specified
 * gpsm-grp as backing stores. Returns a gpsm-grp or
 * NULL on error. */
gpsm_grp_t *gpsm_grp_link(gpsm_grp_t *grp);


/* Destroys a gpsm-item (gpsm-swfile including the backing store
 * if the gpsm-swfile was the last reference to the swapfile,
 * gpsm-grp including all children). */
void gpsm_item_destroy(gpsm_item_t *item);


/* Checks, if the provided group is a hbox which is specified as
 * a horizontally sorted, non-overlapping set of items.
 * Returns 1 if group is a hbox, else 0. */
int gpsm_grp_is_hbox(gpsm_grp_t *group);

/* Checks, if the provided group is a vbox which is specified as
 * a vertically sorted, non-overlapping set of items.
 * Returns 1 if group is a vbox, else 0. */
int gpsm_grp_is_vbox(gpsm_grp_t *group);


/* Checks, if the item can be placed at the specified position
 * without overlapping with existing ones. Handles pre-removal
 * of the specified item transparently. Returns 1 if the item
 * could be placed, 0 if not. */
int gpsm_item_can_place(gpsm_grp_t *grp, gpsm_item_t *item,
			long hpos, long vpos);

/* Places the specified item at the specified position inside grp.
 * Item move is transparently handeled by first removing the item.
 * Returns 0 on success, -1 on error. */
int gpsm_item_place(gpsm_grp_t *grp, gpsm_item_t *item,
                    long hpos, long vpos);

/* Checks, if the item could be inserted at the specified position
 * into the specified group. Item move is transparently handeled.
 * Returns 1, if insertion would be successful, 0 if not. */
int gpsm_hbox_can_insert(gpsm_grp_t *grp, gpsm_item_t *item,
			 long hpos, long vpos);

/* Checks, if the item could be inserted at the specified position
 * into the specified group. Item move is transparently handeled.
 * Returns 1, if insertion would be successful, 0 if not. */
int gpsm_vbox_can_insert(gpsm_grp_t *grp, gpsm_item_t *item,
			 long hpos, long vpos);

/* Insert (and move following items) item into hbox at the specified
 * hposition (and vposition). Handles item removal prior insertion
 * automatically. Returns 0 on success, -1 on failure which could be
 * indicating illegal overlap. */
int gpsm_hbox_insert(gpsm_grp_t *hbox, gpsm_item_t *item,
		     long hposition, long vposition);

/* Insert (and move following items) item into vbox at the specified
 * vposition (and hposition). Handles item removal prior insertion
 * automatically. Returns 0 on success, -1 on failure which could be
 * indicating illegal overlap. */
int gpsm_vbox_insert(gpsm_grp_t *vbox, gpsm_item_t *item,
		     long hposition, long vposition);

/* 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. Successive
 * items are not moved by this operation. */
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. Successive
 * items are moved by this operation. Returns 0 on success,
 * -1 on failure. */
int gpsm_hbox_cut(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. Successive
 * items are moved by this operation. Returns 0 on success,
 * -1 on failure. */
int gpsm_vbox_cut(gpsm_item_t *item);



/* 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. */
gpsm_grp_t *gpsm_find_grp_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. */
gpsm_swfile_t *gpsm_find_swfile_label(gpsm_grp_t *root, gpsm_item_t *start,
				      const char *label);

/* 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. */
gpsm_swfile_t *gpsm_find_swfile_filename(gpsm_grp_t *root, gpsm_item_t *start,
					 long filename);

/* 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. */
gpsm_swfile_t *gpsm_find_swfile_vposition(gpsm_grp_t *root, gpsm_item_t *start,
					  long vposition);


/* Updates the label of the specified gpsm-item. Note that this will
 * cause a GPSM_SIG_ITEM_CHANGED signal to be send out. */
void gpsm_item_set_label(gpsm_item_t *item, const char *label);

/* Updates the samplerate and 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. */
void gpsm_swfile_set(gpsm_swfile_t *swfile, int samplerate,
		     float position);

/* Updates the samplerate 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. */
void gpsm_swfile_set_samplerate(gpsm_swfile_t *swfile, int samplerate);

/* Updates the 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. */
void gpsm_swfile_set_position(gpsm_swfile_t *swfile, float position);

/* _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...). */
void gpsm_notify_swapfile_change(long filename, long pos, long size);
void gpsm_notify_swapfile_cut(long filename, long pos, long size);
void gpsm_notify_swapfile_insert(long filename, long pos, long size);
void gpsm_invalidate_swapfile(long filename);



/* Undo/redo support.
 */

/* Save the current state of the provided subtree for later undo.
 * Returns 0 on success, -1 on failure. */
int gpsm_op_prepare(gpsm_item_t *item);

/* Returns 1 if undo is pending for the subtree item and can be
 * undone at this point, else returns 0. */
int gpsm_op_can_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/possible).
 * Saves the actual state for later redo. */
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/possible).
 * Does not save the actual state for later redo. */
int gpsm_op_undo_and_forget(gpsm_item_t *item);

/* Returns 1 if redo is pending for the subtree item and can be
 * redone at this point, else returns 0. */
int gpsm_op_can_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. */
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). Does not save the actual state for later undo. */
int gpsm_op_redo_and_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/redo). */
int gpsm_op_forget(gpsm_item_t *item);


/* Useful complex operations.
 */

/* Collects all swfiles in the subtree item and creates a new
 * group with links to them in traversal order. Positions relative
 * to item are retained.
 * Returns NULL on failure (no swfiles), a new group on success. */
gpsm_grp_t *gpsm_collect_swfiles(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). */
gpsm_grp_t *gpsm_flatten(gpsm_item_t *item);

/* Transforms the position of the source item to a position inside
 * the dest group - i.e. both represent the same global position. */
void gpsm_position_transform(gpsm_item_t *source, gpsm_grp_t *dest,
			     long *hpos, long *vpos);

/* Queries a possibly common samplerate of a group.  Returns -1,
 * if there are different samplerates (or no swfiles) in the group. */
int gpsm_group_common_samplerate(gpsm_grp_t *grp);


#ifdef __cplusplus
}
#endif

#endif