Environments:
=============

1. What is an Environment?
2. How do the interfaces look?
3. How do I create/use one?
4. How do I implement items?

/*
Documentation TODO: add more details:
 - Guis and aRts (probably seperate document), GuiFactory, GenericGuiFactory,...
 - the dataDirectory (sections 2,3,4)
 - how items react on changes of active (section 4)
*/

  1. What is an Environment?
  --------------------------

Programs like sequencers often require complex structures with lots of
parameters to configure running inside aRts, to create music. For instance
for composing a song, you might require

 - several effects
 - several synthetic instruments
 - several audio tracks
 - a mixer

While with artscontrol, the users can setup much of this themselves manually,
the problem is that this has to be done over and over again. That is, if they
save the song, the settings of their effects, instruments and the mixer will
not be saved with it.

The main idea of the new interfaces in Arts::Environment is that the sequencer
can save the environment required to create a song along with the the song, so
that the users will find themselves surrounded by the same effects,
instruments,... with the same settings again, once they load the song again.

So, conceptually, we can imagine the environment as a "room", where a user
works in to create a song. They needs to install the things inside the room
they need. Initially, the room will be empty. Now, the user thinks: oh, I am
going to need this nice 24 channel mixer. *plop* - it appears in the room.
Now they think: I need some sampler which can play my piano.  *plop* - it
appears in the room.

Now they starts working, adding the "items" they need. Finally, if they stop
working on the song, they can pack all what is in the environment in a little
box, and whenever they starts working on the song again, they can start where
they left off. They can even take the environment to a friend, and continue
working on the song there.

Note that there might be other tasks (such as creating a film, playing an
mp3 with noatun,...) which will have similar requirements of saving the
current state, so the concept of environments is not limited to songs.

  2. How do the interfaces look?
  ------------------------------

There are two main things in the Environment, that is

Arts::Environment::Container    this interface is where you put all your stuff
                                you need to create a song

Arts::Environment::Item         this is an item that works inside an
                                environment

  2.1 The Container interface:
  ----------------------------

Initially "Container"s are empty when created. If you create items, you need
to tell the container about it.

	void addItem(Item item);        
	Item createItem(string name);

You can create the Item yourself and use addItem afterwards, or you can tell
the container to create an Item (by name), and return it to you. Then it will
automatically be put into the environment.

You can list the items that are currently inside an environment with the
attribute 

	readonly attribute sequence<Item> items;

and remove them with

	void removeItem(Item item);

Finally, the more interesting aspect is that you can save the whole
environment to a list of strings, and restore it from there.

	sequence<string> saveToList();
   	void loadFromList(sequence<string> strlist);

If you load it, all items will be created that were created in the environment
you saved.


There are two more special items. Here are two remaining problems to explain
you the purpose of these (you can skip these explaination if you want get
the basic idea first):

 * the "sample data problem"

Consider you have a song where you use these spectacular "boom" sound you just
sampled. Now you save it to a list of strings, and take it to a friend. There
are two things that could happen up to now:

1. the "boom" sound doesn't get put into that list of strings, so when you play
the song on your friends computer it might be missing

2. the "boom" sound gets saved as string list - this would probably be really
really inefficient for both, loading and saving

So we introduce a 

	attribute string dataDirectory;

where song specific data can be saved. The general idea is that items should
access data from anywhere on your harddisc. However, if you execute a special
operation (such as "pack the environment"), all data used in the environment
should get copied into the dataDirectory, and the data should be used from
there in the future.

The details of this are not quite done yet.

 * the "outside world object" problem

Suppose you use an environment and some items use objects that are not items
of the environment. A typical example might be objects which refer to an
Arts::StereoEffectStack outside the environment. Such objects could be saved,
but they need to know how to restore themselves to "the same" StereoEffectStack
again (which will not be restored by the environment).

The general idea to solve this is the context. In the context the user can
name non-environment objects and say: "well, here is a StereoEffectStack my
items will refer to, and it is named 'OutputEffectStack'". Upon serialization,
the environment would not care about the OutputEffectStack, and each item
which needs to refer to it would only save that it needs to put the items
in something called 'OutputEffectStack' again.

The same way, up on restore, items could lookup the 'OutputEffectStack' again
and insert StereoEffects in there.

The details of this are not quite done yet.

  2.2 The Item interface:
  -----------------------

Most functions in the Item interface are not too relevant for users. Upon
insertion, the environment uses

	void setContainer(Container container);

to tell the Item in which environment it lives. It also uses setContainer(
Container::null()) once the Item gets removed. Which container the Item
is in can be seen in the

    readonly attribute Container parent;

Upon serialization, the container uses

	sequence<string> saveToList();
    void loadFromList(sequence<string> strlist);

to save or restore the data. Finally, you can see if the item is currently
inside a Container with the

	readonly attribute boolean active;

There is some trick here: the problem is that you will probably want to hold
references to items (or parts of items) in some situations. But if you do so,
and for instance display the item on the GUI, you will still display the item
if it was removed from the environment. And you will (by reference counting)
prevent it from disappearing.

So... if you hold a reference, watch whether the item is still active, using

  connect(item, "active_changed", ...)

and do release the references you hold if it is not. I.e. if you have a mixer
window on the screen, and the mixer gets inactive, close it. (See also: change
notification documentation).

  3. How do I create/use one?
  ---------------------------

First of all, creation. Usually, you will hold your environments on the
sound server. So creating will look like:

	/* lookup sound server (use an existing one, if you have one) */
    Arts::SoundServer server = Reference("global:Arts_SoundServer");
	if(server.isNull())
		/* error handling -> no sound server running */;

	/* create the object on the server */
	Arts::Environment::Container container =
        Arts::DynamicCast(server.createObject("Arts::Environment::Container"));
	if(container.isNull())
		/* error handling -> environment container could not be created */;

Good, now we have an environment. What to do now? We could add a mixer. This
would work like

	Arts::Environment::MixerItem mixer =
		Arts::DynamicCast(container.createItem("Arts::Environment::MixerItem"));
	if(mixer.isNull())
		/* error handling -> no mixer */;

Cool. A mixer. What do we do with that. Hm... setting the channel count would
be nice, for instance.

	mixer.channelCount(8); /* an eight channel mixer */

And finally, we could display a GUI for it, using the KDE gui embedding thing.

	Arts::GenericGuiFactory guiFactory;
    Arts::Widget widget = guiFactory.createGui(mixer);
    if(!widget.isNull())
    {
		KArtsWidget *kartswidget = new KArtsWidget(widget);
		kartswidget->show();
    }
    else
    {
		/* error handling -> no gui available for this item */
    }

NOTE: for GenericGuiFactory to work, it needs to know what toolkit you are
using. For KDE, you need to add the line

    ObjectManager::the()->provideCapability("kdegui");

somewhere in your application (only do this once).

You can try using saveToList or loadFromList on the container, too. A classical
piece of code which does this is, copied from artscontrol:

void EnvironmentView::load()		/* load from file DEFAULT_ENV_FILENAME */
{
    ifstream infile(DEFAULT_ENV_FILENAME);
    string line;
    vector<string> strseq;
 
    while(getline(infile,line))
        strseq.push_back(line);
 
    defaultEnvironment().loadFromList(strseq); /* we'd use "container" here */
}
 
void EnvironmentView::save()
{
    vector<string> *strseq;
    strseq = defaultEnvironment().saveToList(); /* we'd use "container" here */
 
    ofstream outfile(DEFAULT_ENV_FILENAME);
    for(vector<string>::iterator i = strseq->begin(); i != strseq->end(); i++)
        outfile << *i << endl;
    delete strseq;
}

/* remark about loading:
Of course, after loading the environment, you might want to look at
container.items, to be able to display the guis again. To find out if an
item is a mixer, you can do Arts::Environment::MixerItem m =
Arts::DynamicCast(item); - or if you want to get the type in a generic
way, you can use string typename = item._interfaceName(); */

Finally, if we're tired of using our mixer, we can remove it again, using

	container.removeItem(mixer);

  4. How do I implement items?
  ----------------------------

Basically, you derive an interface from Arts::Environment::Item, like this:

	// this code is in the .idl file:
	interface MyItem : Arts::Environment::Item {
		/* methods/attributes here */
	};

and your implementation from Arts::Environment::Item_impl, like this:

    // this code is in the .cpp file:
    #include "artsmodules.h"
    #include "env_item_impl.h"
    
    class MyItem_impl : virtual public MyItem_skel,
					    virtual public Arts::Environment::Item_impl
    {
    public:
	    void loadFromList(const vector<string>& list)
	    {
		    /* you need to implement this... */
	    }
	    vector<string> *saveToList()
	    {
		    /* ... and that */
	    }
    };
    REGISTER_IMPLEMENTATION(MyItem_impl); /* register your implementation */

If you want your item to have a Gui, implement a GuiFactory that can create
a gui for the item.
