Documentation Wiki rss-feed

Belcanto syntax

The bulk of a Belcanto script is instructions to the EigenD agents. When you read these instructions it’s fairly easy to see roughly what’s going on, but it’s more difficult to see how you might adapt these scripts and ensure you get the results you want. This document is intended to go some way to explaining the syntax of Belcanto.

Broad principles

There are two key elements to programming EigenD: actions, and things on which those actions are performed.

Actions are represented in Belcanto by “verbs”. Verbs are things like “set”, “listen”, “add”. For example, you might tell a keygroup agent:

base note to 1 set

The verb is always at the end of a phrase. Verbs might not be single words. The metronome agent has a “toggle start” verb.

But to perform actions you need things on which those actions should be performed. In Belcanto these things are represented by “noun phrases”. Noun phrases are things like “base note” and “1” in the phrase

base note to 1 set

In this phrase

scheduler from kgroup 1 output 11 un connect

the noun phrases are “scheduler” and “kgroup 1 output 11”. The verb is “un connect” (two words).

The other words we’ve seen here (“to” and “from”) are marker-words used to separate noun phrases from each other. They are called “roles”, and there are many of these.

How agents get instructions

It would be inefficient and potentially chaotic if all Belcanto instructions were sent to all agents. They don’t do much co-ordination between each other, after all. Therefore the approach to instructing agents is:

  1. select some agents
  2. send some instructions to them
  3. select some other agents
  4. send some more instructions to them

...and so on.

We say the selected agents are in a “conversation” and agents join the conversation, or are told to listen. See more about this in The Belcanto Introduction.

Consider the following script fragment (from Drummer Inline Effect):

empty join
talker 19 listen
drummer audio unit listen
eigenbrowser listen
drummer audio unit plugin when 12 browse

The first line creates an empty conversation. Then three agents are told to listen (those agents being talker 19, dummer audio unit, and eigenbrowser). And finally an instruction is sent to all three of them. Any further instructions will also be sent to all three of them, and that will continue until the conversation participants are changed (e.g. by emptying out the conversation with another “empty join”).

The instruction is sent to all agents in the conversation. Any agent that doesn’t understand it simply ignores it. Any agent that does understand it acts on it, of course. This approach, and the independent nature of agents, explains the rather disconcerting phenomenon of no error messages: any agent which doesn’t understand an instruction can reasonably imagine that another agent might, so having it report an error would be mistaken.

You can also use the "hey" construct in front of any verb. This establishes a temporary conversation just for the next verb.

sampler rig 1 scaler hey 
octave to 1 set

Verbs

Because each agent is an independent program it needs to implement its own actions and its own syntax around those actions. (Although in practice there’s a lot of commonality because they tend to use the same underlying libraries.)

Each agent’s implementation of a verb may therefore require or allow a different pattern of noun phrases and marker-words. For example, the console mixer agent allows the "set" verb with this format:

[something] send to [something] set

whereas the usual format for the "set" verb is:

[something] to [something] set

Therefore, just because you know the pattern of a verb for one agent you can’t assume the same verb in another agent will allow the same pattern.

This is worth explaining from another angle: there is no universal syntax in Belcanto in the same way that you might expect in most formal programming languages. Instead, each verb in each agent has its own pattern or patterns of acceptable noun phrases and marker-words.

Noun phrases

As we’ve said, actions have to act on things. In EigenD these things are called “atoms”, and we identify atoms using “noun phrases”.

There is a whole universe of atoms, and they are arranged in hierarchies, and when we select an atom we also select all its child-atoms.

For example, a recorder agent is an atom that sits at the top of a hierarchy. Within this hierarchy are different child atoms of the recorder agent, which include its pressure input, its ten auxiliary outputs and more. The recorder agent has the name “recorder”, which is a noun phrase, and when we use the phrase “recorder” we identify it and all its child atoms (i.e. all its inputs and outputs and anything else it might have).

Actually, this is a slight over-simplification. The recorder has called itself “recorder”, but since agents are independent and don’t particularly co-ordinate, another recorder agent will also have called itself recorder. And any other agent or thing in the EigenD universe is also free to call itself “recorder” if it wants. If we say “recorder listen”, which one are we referring to?

Belcanto generally assumes that you mean a singular unless you tell it otherwise with "all". So, if there are many recorders, "recorder" by itself will not resolve to any agents. You need to say "all recorder".

There is a further bit of simplification here. Suppose you had 2 recorders,

recorder 1
auxiliary recorder 2

Then if you say just "recorder" Belcanto will pick recorder 1. "all recorder" will pick both. This is because of the exact match between your words and the name of the recorder.

This presents another problem. How do we refer to a particular atom? Fortunately EigenD gives things its own names, which are numbers, and things with otherwise the same name will have different number-names. So if we have two recorders EigenD may name them 1 and 2, and we can then refer to them as “recorder 1” and “recorder 2” respectively.

As you add words to a noun phrase, Belcanto uses them to refine the possible things you are referring to.

For example, with the above two recorders, if I say:

auxiliary key input

Then I'm referring to the key input of auxilliary recorder 1. Belcanto has started with the auxilliary recorder, then started looking inside that recorder.

This is fine, as long as things are unambiguous. If I say:

auxilliary recorder input

This won't resolve, because a recorder has many inputs. Belcanto uses the same rules as above to decide which inputs I am talking about. If there has been a single input on the recorder called just "input" it would have picked that.

If I want to refer to all of them, I need to say:

auxilliary recorder all input

Normally, Noun phrases need to start with the name of the agent, then select something inside the agent. For agents that are listening in a conversation, you can talk about things inside them directly.

empty join
scaler create
it listen
interpreter listen
scale identify

Will identify the scale inside the scaler. This is useful if you want to setup a load of different values inside an agent, for instance.

Rigs

Agents inside Rigs are slightly special. If a Rig contains 'scaler 1' then

scaler 1 hey

will fail. You need to say (for instance)

piano rig 1 scaler 1 hey

If you add a rig to a conversation:

piano rig 1 listen

then you can simply address the agents within the rig as normal.

Other types of Noun

Noun Phrases don't have to refer to atoms. Sometimes a list of words is just that; a list of words. This is another reason that Belcanto has problems giving sensible error messages. If I say:

keygroup 1 hey
output 17 create

Output 17 is not yet a real thing. The create action just takes a list of words as argument.

Many verbs take patterns of words and numbers as argument. The interpreter matches these patterns when considering verbs. Sometimes it needs to look things up or substitute words.

Tips and Tricks

Here is an incomplete list of other noun phrase tricks and insights:

  • "identify"

    As of release 2.0.48, there is an 'identify' verb. If you use this in commander, it will print a list of all the matching atoms. I hope this will make things more discoverable, and its good for experimenting with Belcanto.

  • "it" refers to the last thing you created.

    recorder create
    it to recorder 12 name ify
    it identify
    
  • You can refine "it"

    keygroup create
    recorder create
    it recorder identify
    it keygroup identify
    
  • any refers to any object of the right type.

    any recorder identify
    
  • You can use a comma to explicitly signal the end of a noun phrase if you think it wouldn’t be obvious to the interpreter or the reader.