What form does a file need to be in for "Evaluate File" to work?

Hello!

The topic title pretty much covers it. If I write a series of statements in an .scd file and, in scide, select “Language → Evaluate File”, I’ll inevitably get a syntax error. The only related question I can find to this online is this GH issue:

The person closing the ticket says:

Admittedly this is a tricky point in learning SC. But this convention of separate code blocks to run in sequence is common throughout the documentation.

… but doesn’t actually point to any documentation that might explain how you’re supposed to arrange a file such that “Language → Evaluate File” will work.

Ultimately, I’m trying to get to the point where I can run sclang on a single file and have it set up various instruments that can accept MIDI from a DAW without me having to laboriously and manually execute statements one at a time.

The main thing is to separate stuff with semicolons.
E.g. this will throw a syntax error:

(
s.boot;
)
(
Pbind(
	\instrument,\default,
).play;

but this will evaluate without syntax errors:

(
s.boot;
);
(
Pbind(
	\instrument,\default,
).play;

(you might get an error because the server is still booting while the Pbind is already started)
better style therefore would be to write

(
s.waitForBoot {
	Pbind(
		\instrument,\default,
	).play;	
}
);

Separate with semicolons, yes.

There are two other points to watch out for:

Variable declarations

Declaring variables in any of these ( ) blocks breaks compilation if you have multiple blocks. I had thought it would be OK if variables were declared in the first block only, but this is not the case.

(
var a = 1, b = 2;
(a + b).postln;
);

(
5.postln;
);

ERROR: syntax error, unexpected ';', expecting $end
  in interpreted text
  line 4 char 2:

  );

A nice workaround is to wrap any blocks that declare variables within a function, and evaluate the function. Below, you can run all of it at one time, or you could select one or the other block and run them independently.

(
{
	var a = 1, b = 2;
	(a + b).postln;
}.value;  // <<-- don't forget '.value' here!
);

(
5.postln;
);

// prints:
3
5

Asynchronous operations

(
b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");
);

(
b.numFrames.debug("numFrames");
)

// prints:
nil      // :-O

In an example like this, numFrames won’t be ready right away – you need to wait for it.

If you only want to run the entire file, then it’s pretty easy: fork a routine and s.sync in the middle. The following works – but you can’t run the statements separately anymore. (If you’re loading multiple buffers, you don’t need to .sync each one – you can do several buffers and then s.sync and it will wait for all of the pending commands to finish.)

(
// 'waitForBoot' automatically forks the routine for you
s.waitForBoot {
	b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");
	s.sync;
	b.numFrames.postln;
}
)

// prints:
188893

If you need to run the blocks separately sometimes as well, then it gets tricky. Here’s one way – you can actually run the two ( ) blocks in order or reversed! But this is probably not worth the effort if your main purpose is to run everything all at once.

c = CondVar.new;

(
b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav", action: { c.signalAll });
);

(
fork {
	c.wait { b.numFrames.notNil };
	b.numFrames.postln;
};
)

hjh

2 Likes

Thank you, both. Makes sense!