filled in lots of daunting details regarding structural assets.

StructFactury still very preliminary. Now able to fill the table with mock queries.
TODO: fix assertion failure...
This commit is contained in:
Fischlurch 2008-02-10 17:23:16 +01:00
parent 531d432f02
commit d33242b8cb
17 changed files with 518 additions and 141 deletions

View file

@ -50,10 +50,11 @@
#include "common/typelistutil.hpp"
#include "common/singletonsubclass.hpp"
//TODO: is it sensible to bring in the types explicitly here? (it's not necessary, but may be convienient...)
#include "proc/mobject/session/track.hpp"
#include "proc/asset/procpatt.hpp"
#include "proc/asset/port.hpp"
#include "proc/asset/track.hpp"
#include <string>
#include <tr1/memory>
@ -89,9 +90,8 @@ namespace cinelerra
{
};
typedef const char * const Symbol;
template
< const Symbol SYM, // Predicate symbol
typename SIG = bool(string) // Signature
@ -101,6 +101,17 @@ namespace cinelerra
};
/**
* the "backside" interface towards the classes participating
* in the configuration system (the config system will be
* delivering instances of these classes for a given query).
* This one currently is just brainstorming. The idea is that
* a participating class would provide such and TypeHandler
* implementing the predicates which make sense for this special
* type of object. Registering such a TypeHandler should create
* the necessary handler functions to be installed into
* the Prolog system.
*/
template<class TY>
class TypeHandler
{
@ -112,13 +123,25 @@ namespace cinelerra
template<Symbol SYM, typename SIG>
TY make (Pred<SYM,SIG> capability, TY& refObj =NIL);
};
/**
* the "frontside" interface: the Proc-Layer code can
* use this QueryHandler to retrieve instances of the
* type TY fulfilling the given Query. To start with,
* we use a mock implementation-
* @see cinelerra::query::LookupPreconfigured
* @see cinelerra::query::MockTable
*/
template<class TY>
class QueryHandler
{
protected:
virtual ~QueryHandler() { }
public:
/** try to find or create an object of type TY
* fulfilling the given query.
* @return empty shared-ptr if not found,
*/
virtual shared_ptr<TY> resolve (const Query<TY>& q) = 0;
};
@ -173,6 +196,7 @@ namespace cinelerra
* rule based config query system
*/
typedef cinelerra::typelist::Types < mobject::session::Track
, asset::Track
, asset::Port
, const asset::ProcPatt
> ::List

View file

@ -26,22 +26,33 @@
#include <string>
#include <typeinfo>
namespace cinelerra
{
using std::string;
/* ==== comon definitions for rule based queries ==== */
typedef const char * const Symbol;
/**
* Generic query interface for retrieving objects matching
* some capability query
*/
template<class STRU>
template<class OBJ>
class Query : public std::string
{
public:
Query (string predicate="") : string(predicate) {}
Query (const string& predicate="") : string(predicate) {}
const string asKey() const
{
return string(typeid(OBJ).name())+": "+*this;
}
};

View file

@ -38,22 +38,83 @@ namespace cinelerra
namespace query
{
using asset::Struct;
using asset::Port;
using asset::PPort;
using asset::ProcPatt;
using asset::PProcPatt;
namespace
{
typedef std::pair<const string, any> AnyPair;
/** helper to simplify creating mock table entries, wrapped correctly */
template<class TY>
AnyPair entry (const string& query, typename WrapReturn<TY>::Wrapper& obj)
{
return AnyPair ( Query<TY> (query).asKey()
, any(obj));
}
/** helper especially for creating structural assets from a capability query */
template<class STRU>
AnyPair entry_Struct(Symbol caps)
{
typedef typename WrapReturn<STRU>::Wrapper Ptr;
Query<STRU> query(caps);
Ptr obj = Struct::create (query);
return AnyPair(query, obj);
}
}
/** hard coded answers to configuration queries */
void
MockTable::fill_mock_table ()
{
// for baiscporttest.cpp ---------
answer_->insert (entry_Struct<const ProcPatt> ("stream(teststream)"));
}
MockConfigRules::MockConfigRules ()
{
WARN (config, "using a mock implementation of the ConfigQuery interface");
}
MockTable::MockTable ()
MockTable::MockTable ()
: answer_(new Tab())
{
TODO ("build the preconfigured table");
fill_mock_table ();
}
/** this is the (preliminary/mock) implementation
* handling queries for objects of a specific type
* and with capabilities or properties defined by
* the query. The real implementation would require
* a rule based system (Ichthyo plans to use YAP Prolog),
* while this dummy implementation simply relies on a
* table of pre-fabricated objects. Never fails.
* @return smart ptr (or similar) holding the object,
* maybe an empty smart ptr if not found
*/
const any&
MockTable::fetch_from_table_for (const string& queryStr)
{
UNIMPLEMENTED ("fetch a preconfigured object from the table");
static const any NOTFOUND;
Tab::iterator i = answer_->find (queryStr);
if (i == answer_->end())
return NOTFOUND;
else
return i->second;
}

View file

@ -39,15 +39,18 @@
#define CINELERRA_MOCKCONFIGRULES_H
#include "common/configrules.hpp"
#include "common/util.hpp"
#include <boost/scoped_ptr.hpp>
#include <boost/any.hpp>
#include <string>
#include <map>
namespace cinelerra
{
using std::string;
//using std::string;
namespace query
@ -55,10 +58,13 @@ namespace cinelerra
using asset::ProcPatt;
using asset::PProcPatt;
using util::isnil;
using boost::any;
using boost::any_cast;
/** a traits-class to define the smart-ptr to wrap the result */
template<class TY>
struct WrapReturn { typedef shared_ptr<TY> Wrapper; };
@ -73,9 +79,17 @@ namespace cinelerra
*/
class MockTable : public cinelerra::ConfigRules
{
typedef std::map<string,any> Tab;
typedef boost::scoped_ptr<Tab> PTab;
PTab answer_;
protected:
MockTable ();
const any& fetch_from_table_for (const string& queryStr);
private:
void fill_mock_table ();
};
@ -93,8 +107,11 @@ namespace cinelerra
virtual Ret
resolve (const Query<TY>& q)
{
TODO ("handle mismatch and not-found case");
return any_cast<Ret> (fetch_from_table_for (q));
const any& entry = fetch_from_table_for (q.asKey());
if (!isnil (entry))
return any_cast<Ret> (entry);
else
return Ret(); // default-constructed empty smart ptr
}
};

View file

@ -1,35 +0,0 @@
/*
BuildInstruct - Instructions for building some configuration of render nodes.
Copyright (C) CinelerraCV
2007, Hermann Vosseler <Ichthyostega@web.de>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
#include "proc/asset/buildinstruct.hpp"
#include "proc/asset/procpatt.hpp"
#include "proc/asset/proc.hpp"
namespace asset
{
/** */
} // namespace asset

View file

@ -21,9 +21,18 @@
*/
/** @file buildinstruct.hpp
** Helper classes used by asset::ProcPatt to represent the processing informations.
** Consider these classes as owned by ProcPatt. Non-inline functions go to procpatt.cpp
**
*/
#ifndef ASSET_BUILDINSTRUCT_H
#define ASSET_BUILDINSTRUCT_H
#include <boost/variant.hpp>
#include <string>
using std::string;
@ -36,36 +45,74 @@ namespace asset
class Proc;
class ProcPatt;
typedef shared_ptr<const asset::Proc> PProc;
typedef shared_ptr<const asset::ProcPatt> PProcPatt;
/**
* (Interface) building instructions to be executed by the Builder
* on the render node network under construction.
*/
class BuildInstruct
static Symbol CURRENT = "current";
struct DoAttach
{
};
class DoRecurse : public BuildInstruct
{
protected:
const ProcPatt* subPattern;
};
class DoAttach : public BuildInstruct
{
public:
const Proc* nodes;
vector<PProc> nodes;
/** identifying the point where the nodes should be attached */
const string point;
string point;
DoAttach (Symbol where = CURRENT)
: point(where)
{ }
DoAttach (PProc& node, Symbol where = CURRENT)
: point(where)
{
nodes.push_back(node);
}
};
struct DoRecurse
{
PProcPatt subPattern_;
explicit DoRecurse (PProcPatt& pattern) : subPattern_(pattern) {}
};
class DoConditional
{
// How to do this? we need some context to test the condition...
};
typedef boost::variant< DoAttach, DoRecurse, DoConditional > InstructEntry;
/**
* (Interface) building instructions to be executed by the Builder
* on the render node network under construction. The purpose of this
* "micro language" is to be able to store in the configuration or session
* how certain parts of the model should be assembled. One important example
* is how to build a source reading chain to read and decode frames from a
* media file. Another example being a global audio Pipe, comprised of an
* EQ plugin, a fader and a panner.
* \par
* Build instructions are tightliy coupled to asset::ProcPatt and always
* created from there.
* @see ProcPatt::attach
* @see ProcPatt::operator+=
*
*/
struct BuildInstruct
: public InstructEntry
{
template<typename T>
BuildInstruct (T& instr) : InstructEntry(instr) {}
};
} // namespace asset
#endif

View file

@ -118,8 +118,8 @@ namespace asset
{
try
{
IdHashtable::const_iterator i = table.begin();
IdHashtable::const_iterator e = table.end();
IdHashtable::iterator i = table.begin();
IdHashtable::iterator e = table.end();
for ( ; i!=e ; ++i )
i->second->dependants.clear();

View file

@ -69,6 +69,7 @@ namespace asset
protected:
Port (PProcPatt& wiring, string portID="", wstring shortDesc =wstring(), wstring longDesc =wstring()) ;
friend class StructFactory;
friend class StructFactoryImpl;
public:
const string& getPortID() const { return portID_; }

View file

@ -46,6 +46,9 @@ namespace asset
class Proc;
class ProcFactory;
typedef shared_ptr<const Proc> PProc;
template<>
class ID<Proc> : public ID<Asset>

View file

@ -22,8 +22,12 @@
#include "proc/asset/procpatt.hpp"
#include "proc/asset/buildinstruct.hpp"
#include "proc/asset/proc.hpp"
#include "proc/assetmanager.hpp"
#include "proc/asset/buildinstruct.hpp"
#include "common/util.hpp"
using util::isnil;
namespace asset
{
@ -45,14 +49,20 @@ namespace asset
}
/** */
ProcPatt::ProcPatt (const string& properties, const vector<BuildInstruct>& instr)
ProcPatt::ProcPatt (const string& properties)
: Struct (createPatternIdent (properties)),
propDescriptor_ (properties),
instructions (instr)
propDescriptor_ (properties)
{
TODO ("verify building instructions, maybe preprocess...");
}
/** @internal used for creating a clone */
ProcPatt::ProcPatt (const string& props, const InstructionSequence& instructs)
: Struct (createPatternIdent (props)),
propDescriptor_ (props),
instructions_ (instructs)
{ }
/** query the currently defined properties of this
processing pattern for a stream-ID predicate */
@ -67,17 +77,59 @@ namespace asset
/** create a new ProcPatt asset as a literal copy
* of this one. The new ProcPatt can then be customized
* independently of the original one. This allows using
* some ProcPatt as a template for creatind more
* some ProcPatt as a template for creating more
* spezialized patterns.
*/
shared_ptr<ProcPatt>
ProcPatt::newCopy (string newID) const
{
TODO ("implement the Pattern-ID within the propDescriptor!");
ProcPatt* pP = new ProcPatt (this->propDescriptor_, this->instructions);
ProcPatt* pP = new ProcPatt (this->propDescriptor_, this->instructions_);
return AssetManager::instance().wrap (*pP);
}
/** extend the processing instructions to add some Effect
* @param where denotes the insertion point where to attach the Effect
* @param node prototype of the Effect to be inserted when building.
*/
ProcPatt&
ProcPatt::attach(Symbol where, PProc& node)
{
DoAttach *last (0);
if ( !isnil (instructions_)
&& (last = boost::get<DoAttach> (&(instructions_.back())))
&& last->point==where
)
// instead of adding a new build instruct entry,
// we can extend the list in the last "DoAttach" entry.
last->nodes.push_back(node);
else
{
DoAttach entry(node, where);
instructions_.push_back(BuildInstruct(entry));
}
TODO ("declare dependency??");
return *this;
}
/** extend the processing instructions by reference to another
* ProcPatt, which will be "executed" at this point while building.
* This allowes for using simple PorcPatt instances as building blocks
* to define more complicated patterns.
*/
ProcPatt&
ProcPatt::operator+= (PProcPatt& toReuse)
{
DoRecurse entry(toReuse);
instructions_.push_back(BuildInstruct (entry));
TODO ("declare dependency??");
return *this;
}
} // namespace asset

View file

@ -24,6 +24,7 @@
#ifndef ASSET_PROCPATT_H
#define ASSET_PROCPATT_H
#include "common/query.hpp"
#include "proc/asset/struct.hpp"
#include <vector>
@ -34,26 +35,38 @@ using std::vector;
namespace asset
{
class BuildInstruct;
using cinelerra::Symbol;
class Proc;
class ProcPatt;
class BuildInstruct;
typedef shared_ptr<const asset::Proc> PProc;
typedef shared_ptr<const asset::ProcPatt> PProcPatt;
typedef vector<BuildInstruct> InstructionSequence;
/**
* special type of structural Asset
* "Processing Pattern" is a structural Asset
* representing information how to build some part
* of the render engine's processing nodes network.
*/
class ProcPatt : public Struct
{
string propDescriptor_;
vector<BuildInstruct> instructions;
InstructionSequence instructions_;
ProcPatt (const string& props, const InstructionSequence& instructs);
protected:
ProcPatt (const string& properties, const vector<BuildInstruct>& instr);
explicit ProcPatt (const string& propDescriptor);
friend class StructFactoryImpl;
public:
const string& queryStreamID() const;
shared_ptr<ProcPatt> newCopy (string newID) const;
ProcPatt& attach (Symbol where, PProc& node);
ProcPatt& operator+= (PProcPatt& toReuse);
};

View file

@ -27,78 +27,64 @@
#include "proc/asset/track.hpp"
#include "proc/asset/port.hpp"
#include "proc/mobject/session.hpp"
#include "common/configrules.hpp"
#include "proc/asset/structfactoryimpl.hpp"
#include "common/query.hpp"
#include "common/util.hpp"
#include "nobugcfg.h"
using mobject::Session;
using cinelerra::query::normalizeID;
using cinelerra::ConfigRules;
using cinelerra::query::QueryHandler;
namespace asset
{
/****** NOTE: not implemented yet. What follows is a hack to build simple tests *******/
namespace // common Struct Asset implementation details
{
/** @internal derive a sensible asset ident tuple when creating
* a track asset based on a query
* @todo define the actual naming scheme of struct assets
*/
const Asset::Ident
createTrackIdent (const Query<Track>& query)
{
string name ("track-" + query); // TODO something sensible here; append number, sanitize etc.
TODO ("track naming scheme??");
Category category (STRUCT,"tracks");
return Asset::Ident (name, category );
}
typedef std::pair<string,string> PortIDs;
PortIDs
createPortIdent (const Query<Port>& query)
{
string name ("port-" + query); // TODO get some more sensible dummy values
TODO ("port naming scheme??");
return PortIDs (name, "mpeg"); // dummy stream type
}
}
/****** NOTE: not really implemented yet. What follows is partially a hack to build simple tests *******/
StructFactory Struct::create; ///< storage for the static StructFactory instance
/** storage for the static StructFactory instance */
StructFactory Struct::create;
/** using private implementation detail class */
StructFactory::StructFactory ()
: impl_(new StructFactoryImpl(*this))
{ }
/** Factory method for Structural Asset instances. ....
/** Factory method for Structural Asset instances.
* First tries to relove the asset by issuing an capability query.
* If unsuccessfull, use some internally specialized ctor call.
* @todo work out the struct asset naming scheme!
* @return an Struct smart ptr linked to the internally registered smart ptr
* created as a side effect of calling the concrete Struct subclass ctor.
*/
template<>
shared_ptr<Track>
StructFactory::operator() (const Query<Track>& query)
template<class STRU>
shared_ptr<STRU>
StructFactory::operator() (const Query<STRU>& capabilities)
{
TODO ("actually evaluate the query...");
Track* pT = new Track (createTrackIdent (query));
return AssetManager::instance().wrap (*pT);
QueryHandler<STRU>& typeHandler = ConfigRules::instance();
shared_ptr<STRU> res = typeHandler.resolve (capabilities);
if (res)
return res;
// create new one, since the
// ConfigQuery didn't yield any result
STRU* pS = impl_->fabricate(capabilities);
return AssetManager::instance().wrap (*pS);
}
/** Similar instance for Port Query....
* @todo better a generic implementation utilizing ConfigQuery....
*/
template<>
shared_ptr<Port>
StructFactory::operator() (const Query<Port>& query)
{
TODO ("actually evaluate the query...");
PortIDs ids (createPortIdent (query));
return operator() (ids.first, ids.second);
}
/** Factory method for creating Ports explicitly.
@ -122,4 +108,27 @@ namespace asset
} // namespace asset
/**************************************************/
/* explicit instantiations of the factory methods */
/**************************************************/
#include "proc/asset/struct.hpp"
#include "proc/asset/procpatt.hpp"
#include "proc/asset/track.hpp"
#include "proc/asset/port.hpp"
namespace asset
{
template shared_ptr<Port> StructFactory::operator() (const Query<Port>& query);
template shared_ptr<Track> StructFactory::operator() (const Query<Track>& query);
template PProcPatt StructFactory::operator() (const Query<const ProcPatt>& query);
} // namespace asset

View file

@ -40,11 +40,14 @@
#include "proc/asset.hpp"
#include "common/query.hpp"
#include "common/factory.hpp"
#include "common/singleton.hpp"
#include<string>
#include <boost/scoped_ptr.hpp>
#include <string>
using std::string;
using std::wstring;
using boost::scoped_ptr;
namespace asset
@ -53,6 +56,7 @@ namespace asset
class Struct;
class StructFactory;
class StructFactoryImpl;
class Port;
@ -102,14 +106,21 @@ namespace asset
*/
class StructFactory : public cinelerra::Factory<asset::Struct>
{
scoped_ptr<StructFactoryImpl> impl_;
protected:
StructFactory ();
friend class Struct;
public:
typedef shared_ptr<asset::Struct> PType;
template<class STRU>
shared_ptr<STRU> operator() (const Query<STRU>& query); ////////////TODO define actual operation
shared_ptr<STRU> operator() (const Query<STRU>& query); ////////////TODO actually do something sensible here
shared_ptr<Port> operator() (string portID, string streamID);
};

View file

@ -0,0 +1,161 @@
/*
STRUCTFACTORYIMPL.hpp - crating structural assets (impl details)
Copyright (C) CinelerraCV
2007, Hermann Vosseler <Ichthyostega@web.de>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file structfactoryimpl.hpp
** Private implementation details of creating various structural assets.
** @internal to be used by struct.cpp
**
** @see ConfigQuery
**
*/
#ifndef ASSET_STRUCTFACTORYIMPL_H
#define ASSET_STRUCTFACTORYIMPL_H
#include "common/configrules.hpp"
#include "common/error.hpp"
#include <boost/format.hpp>
using boost::format;
using asset::Query;
using cinelerra::query::CINELERRA_ERROR_CAPABILITY_QUERY;
namespace asset
{
template<class STRU>
struct Traits
{
static Symbol namePrefix;
static Symbol catFolder;
};
template<> Symbol Traits<Track>::namePrefix = "track-";
template<> Symbol Traits<Track>::catFolder = "tracks";
template<> Symbol Traits<Port>::namePrefix = "port-";
template<> Symbol Traits<Port>::catFolder = "ports";
template<> Symbol Traits<ProcPatt>::namePrefix = "patt-";
template<> Symbol Traits<ProcPatt>::catFolder = "build-templates";
/**
* Implementation deatils, esp. concerning how configuration
* queries are resolved and when to create new objects automatically.
* @todo better use a general struct traits class, esp.for creating the Ident
*/
class StructFactoryImpl
{
/** @internal derive a sensible asset ident tuple when creating
* structural asset instances based on a capability query
* @todo define the actual naming scheme of struct assets
*/
template<class STRU>
const Asset::Ident
createIdent (const Query<STRU>& query)
{
string name (Traits<STRU>::namePrefix + query); // TODO something sensible here; append number, sanitize etc.
TODO ("struct asset naming scheme??");
Category cat (STRUCT, Traits<STRU>::catFolder);
return Asset::Ident (name, cat );
}
typedef std::pair<string,string> PortIDs;
PortIDs
createPortIdent (const Query<Port>& query)
{
string name (Traits<Port>::namePrefix + query); // TODO get some more sensible dummy values
TODO ("port naming scheme??");
TODO ("actually extract the port stream type from the query...");
return PortIDs (name, "data"); // dummy stream type
}
/** used for issuing recursive create calls to top level */
StructFactory& recursive_create_;
public:
StructFactoryImpl (StructFactory& interface)
: recursive_create_(interface)
{ }
/** make a new structural asset instance.
* default/fallback impl. throws.
*/
template<class STRU>
STRU* fabricate (const Query<STRU>& caps)
{
throw cinelerra::error::Config ( str(format("The following Query could not be resolved: %s.") % caps)
, CINELERRA_ERROR_CAPABILITY_QUERY );
}
};
/* ============= specialisations =========================== */
template<>
Track*
StructFactoryImpl::fabricate (const Query<Track>& caps)
{
TODO ("actually extract properties/capabilities from the query...");
return new Track (createIdent (caps));
}
template<>
ProcPatt*
StructFactoryImpl::fabricate (const Query<ProcPatt>& caps)
{
TODO ("actually extract properties/capabilities from the query...");
return new ProcPatt (createIdent (caps));
}
template<>
Port*
StructFactoryImpl::fabricate (const Query<Port>& caps)
{
PortIDs ids (createPortIdent (caps));
return recursive_create_ (ids.first, ids.second).get();
}
} // namespace asset
#endif

View file

@ -39,7 +39,7 @@ namespace asset
{
protected:
Track (const Asset::Ident& idi);
friend class StructFactory;
friend class StructFactoryImpl;
};

View file

@ -48,7 +48,7 @@ namespace mobject
/** initialize the most basic internal defaults. */
DefsManager::DefsManager () throw()
{
TODO ("setup basic defaults of the session");
}

View file

@ -2349,8 +2349,10 @@ We need a way of addressing existing [[ports|Port]]. Besides, as the Ports and T
//Note, we have yet to specify how exactly the building and rendering will work together with the backend. There are several possibilities how to structure the Playlist//
</pre>
</div>
<div title="Port" modifier="Ichthyostega" modified="200801062330" created="200801062110" tags="def decision" changecount="4">
<pre>Ports play an central role within the Proc Layer, because for everything placed and handled within the EDL, the final goal is to get it transformed into data which can be retrieved at some port. Ports are special facilities, rather like inventory, separate and not treated like all the other objects.
<div title="Port" modifier="Ichthyostega" modified="200802101340" created="200801062110" tags="def decision" changecount="5">
<pre>{{red{''NOTE'': I am considering to rename &quot;Port&quot; &amp;rarr; &quot;Pipe&quot;}}}
Ports play an central role within the Proc Layer, because for everything placed and handled within the EDL, the final goal is to get it transformed into data which can be retrieved at some port. Ports are special facilities, rather like inventory, separate and not treated like all the other objects.
We don't distinguish between &quot;input&quot; and &quot;output&quot; ports &amp;mdash; rather, ports are thought to be ''hooks for making connections to''. By following this line of thought, each port has an input side and an output side and is in itself something like a ''Bus'' or the starting point for building a ''processing chain''. Other processing entities like effects and transitions can be placed (attached) at the port, resulting them to be appended to form this chain. Likewise, we can place [[wiring requests|WiringRequest]] to the port, meaning we want it connected to another destination port. The [[Builder]] may generate further wiring requests to fulfil the placement of other entities.
Thus Ports are the basic building blocks of the whole render network. We distinguish ''global available'' Ports, which are like the sum groups of a mixing console, and the ''lokal port'' or [[source port|ClipSourcePort]] of the individual clips, which exist only within the duration of the corresponding clip. The design //limits the possible kinds of ports // to these two types &amp;mdash; thus we can build local processing chains at clips and global processing chains at the global ports of the session and that's all we can do. (because of the flexibility which comes with the concept of [[placements|Placement]], this is no real limitation)