< Back to IRCAM Forum

Sequence of events in process with loops

Hey, I’m trying to figure out why things happen in the order that they do. If I run the following code:
@proc_def ::testings($z, $d)

{  
	@local $first, $second  
	$first := $z  
	$second := $d  
	loop myloop 15ms  
	{  
		$first := $first + 1  
		print $first  
	}  
	until ($first = 15)  

	print "This is the end"  
}

the sentence “This is the end” will be printed BEFORE $first = 15 which in my mind is counter-intuitive but perhaps I’ve been gone from coding for a bit too long?

I’ll be using this to program a sequence of movements with a series of loops imbedded in different ifs, and it doesn’t work at all.

Thanks for the help!

EDIT: while looking at the score in ascograph, I also see that if I use until or while, the words don’t turn blue. Is it perhaps related to that?

Hello Maladie.

Action in Antescofo are launched in parallel. So the print “this is the end” is launched simultaneously with the loop.

If you want to trigger the print at the end of the loop, you can use the +=> continuation operator:

  
loop myloop 15ms  
{  
		$first := $first + 1  
		print $first  
}  
until ($first = 15)  
+=>   
print "This is the end"

The construction

  • a b launches actions a and b simultaneously
<li><code>a 5 b</code> launches actions  <code>b</code> 5 beats after the start of <code>a</code> </li>  

<li><code>a => b</code> launches actions  <code>b</code> at the end of <code>a</code> </li>  
<li><code>a +=> b</code> launches actions  <code>b</code> at the end of <code>a</code> and its children (a process is a example of compound action that span children actions: for hese compound actions, the end of the action does not coincide necessarily with the end of all derived actions). </li>  

Some comments on simultaneity in Antescofo: the language follows the synchronous hypothesis used in the development of real-time embedded systems assuming that computations occurring at the same date are performed in a specific and well defined order. This hypothesis may seem odd at first sight: one has to postulate instantaneous action, i.e. actions that take no time to be performed, to make possible a sequence of actions all occurring at the same date.

But the success of the synchronous hypothesis in the field of real-time systems demonstrate the usefulness of this hypothesis: at a certain abstraction level, we may assume that an action takes no time to be performed (i.e. the execution time is negligible at this abstraction level) and relying on a sequential execution model (the sequence of actions is performed in a specific and well determined order) leads to a deterministic and predictable behavior.

For example, the following program

  
print 1  
print 2

triggers the two prints in the same instant, in parallel. However, in the instant, the print are atomic action. There execution are well ordered and follows the order of appearance in the score. The net result is that the two print do not mixe and 1 is always printed before 2, as expected.

Thanks for the help, that has made things clearer but I’m not completely sure about the syntax of it between different loops and ifs.
For example:

if ($path = 1)  
		{   
			print "in path 1"  
			loop L 50ms  
			{   
				$y := $y - 1  
				::send_out($note, $x, $y)  
			} until($y <= -20)   
			+=>  
			$path := 2  
			print "path 1 over"  
		}   

		+=> if ($path = 2)  
		{   
			print "in path 2"  
			loop L 50ms  
			{   
				$y := $y + 1  
				$x := $x - 0.4  
				::send_out($note, $x, $y)  
			}  
			until($y = $max_y && $x <= ($mid_x * -1))  
			$path := 3  
		}

Path 2 is never entered and I’m guessing it’s because the program is testing if path := 2 at the same time as path := 1, correct? How would one then write it with proper syntax so that the process is followed sequentially (by order of the ifs and loops, and not specifically timed in s or ms or beats)?

Thanks a lot, Antescofo seems simple at first, but it has a lot of nifty things!

You are right: the continuation with if ($path = 2) apply here to the if construct, not to the loop. You can use curly brackets to have the intended meaning:

  
if ($path = 1)  
{   
	print "in path 1"  
	loop L 50ms  
	{   
	     $y := $y - 1  
	     ::send_out($note, $x, $y)  
	} until($y <= -20)   
	+=>  
	{	  
             $path := 2  
	     print "path 1 over"  
	     +=>   
             if ($path = 2)  
	     {   
		print "in path 2"  
		loop L 50ms  
		{   
		       $y := $y + 1  
			$x := $x - 0.4  
			::send_out($note, $x, $y)  
		}  
		until($y = $max_y && $x <= ($mid_x * -1))  
		$path := 3  
	}  
}

Obviously, such construction are really needed here only if you don’t really know the duration of a sequence of action. If the objectives is to start action bat the end of action aand acton c at the end of action b, and you know that a has a duration of da and b of db, then you simply write

  
   a  
  da  
   b  
  db  
   c   

Duration can be expression, so they can be computed.

If the problem is to trigger an acton depending of the value of the variable $path you can use a switch and/or a whenever:

  
   whenever ($path)  
   {  
        swicth ($path):  
        {  
            case 1: ::process_1()  
            case 2: ::process_2()  
            ; ...  
        }  
   }  

the action to perform are encapsulated in a process which is spanned when the variable $path is updated. Anywhere in the code, if you have an assignment:

  
   $path := ...  

the whenever is activated and launch the corresponding process.

Other approaches are possible and we can details it if you explain the behavior you have in mind.

That makes everything a lot clearer. Thank you very much for taking the time to explain the concepts, I had been away from programming for awhile as well so it made it all slightly harder. And indeed, I will not know the duration of each clause which is why I want to use the +=>.

Thanks and have a lovely evening!

Playing with your example let me to discover a bug in the implementation of the continuation +=> : in some case, the continuation of a if is incorrect (it can be triggered before the end of all childrens). This bug will be corrected in the next release. Thank for your patience.

Glad I could be of service then haha! So far the instances where I’ve tried +=> work fine with switches and such.

An unrelated question. In the aborting processes section of the manual, it’s written that it’s possible to give a name to calling a process by using
$variable_name := ::process_name()

Will this line of text only name the process, or is it actually calling it AND naming it?

Yes: it calls the process and records this call for further use, like killing this process instance.

Calling a process is an expression: ::process_name() returns a value of type exe which represent the process instance. In some language this value is called a process identifier. As for any other kind of value, this value can be assigned to a variable. but you can also record it in a dictionary:

  
    $dico := MAP{}  
    $dico := @insert($dico, "first call", ::process_name())  
    ; later you can refer it using the given key:   
    abort $dico("first call")

You can test an exe to know if the process instance is still alive:

  
   $p := ::P()  
   ; ...  
   if ($p)  
   {  
       print "Process ::P is still running"  
   }  
   else  
   {  
       print "process ::P has finished or has been terminated"  
   }

Killing an already terminated process is not a problem. But accessing the variable of a dead process raises an error.

Do not confuse exe which refers to a process instance and a proc which refers to the process itself. This reference is done through the name of the process. A proc can assigned to a variable, given as an argument to a process or a function, and it can be aborted. In this case, the abort is applied to all instances of this proc. So

  
   $pp := ::proc_name  
   ; ...  
   $p := :: $pp() ; instantiate the proc which is referred by $pp  
   ; ...  
   abort $pp ; abort all instance of the proc referred by $pp, that is, all instances of ::proc_name

Makes perfect sense, thank you!