Supercollider headless autostart and/or single_click.sh

Thank you very much! The “sudo nano …” was golden. But in the end I had no luck and for the moment I just jump on to my pisound via vnc and start supercollider and the scd file manually.
I tried also the approach from Moctezuma.dev.

Thanks again for the great help, also to Giedrius, who helped me out today to get the pi running. great people.

patchbox module install https://github.com/dormirj/sc-module

not really anything to call home about, but for me it works at the moment. i might make it more “proper” some time in the future and think about using some button scripts for osc functions. if you have any suggestions hit me up–

3 Likes

Hi.
Not something to call home about?
It’s great! It works just smooth and now even a rookie like me can have his supercollider code running right after powering his pisound.

Thank you!

2 Likes

hi dormirj,
as you wrote, now I hit you up for two suggestions:

Instead of having to rename the scd file to “main”, it would be good to be able to keep the original scd file name.
Therefore my suggestion is, that only “0_” needs to be placed in front of the original name to be loaded after power on.
E.g. the scd file name is “grain-looper.scd” which would be renamed to “0_grain-looper.scd” instead of “main.scd”.

Building on this an additional feature could be, that one can place other files in the same folder and placing a numbers from 0 to 9 in front of the file name.
With the button one should then be able to cycle through the other files.
E.g. there are 3 scd files in the folder:
“0_grain-looper.scd”
“1_sinus-synth.scd”
“2_reverb-effect.scd”
After power on the file “0_grain-looper.scd” is active. Pressing the button once would make “1_sinus-synth.scd” the active one, pressing again “2_reverb-effect.scd” is active, pressing again “0_grain-looper.scd” is the active one again.

What do you think? Does this makes sense to you? Is it feasible?

Thanks again for your autostart script, it works like a charm.
Best regards,
Sebastian

for me personally, i don’t think it would make much sense, because i intend to have a complex unique instrument rather than a set of switchable smaller effect patches.

that being said, i think it should be feasible. in supercollider it should be pretty easy to collect all files inside a folder and filter them with regular expressions and build and sort an array that starts with the [numeral]_name syntax style. it might be prone to error if you have multiple files starting with one number, or if you have one file that starts with 0 and then one with 3 and none with 1 or 2, but i guess most of these issues could be caught with a bit of clever array usage.

what i’m not yet sure about is how to use the button to directly interact with supercollider, the route i’d have in mind would be to have sc listen for osc messages on some port and then have the button script send an osc message that runs a function inside the main.scd that executes the strg+. command which clears the server from any running synth, have a counter cycle through the possible scripts in the array and load the next one in line.

i’m trying to look a bit more in-depth into this at some point. feel free to ask further questions if my pointers/ideas aren’t clear to you.

best–

p.s.: i’m curious about your grainlooper patch, are you sharing it somewhere?

Good idea on the OSC messages. It’s quite easy to script it to send the messages - the liblo-utils apt package has oscsend command line utility that can be used to send one off OSC messages. SC could listen to the button interactions and perform some logic based on that.

hi dormirj,

this sounds good, but I am not skilled enough in SC with these kind of things.

Because of “complex instrument” vs. “switchable smaller effect patches”: why I am up to this direction is, that I use an akai midi mix together with the pisound. I think about which functions and parameters I want to have in direct access with the limited count of buttons and faders and try to find something that makes an instrument for me.

The names I used were more examples to illustrate my idea, but I am working on an instrument with 8x5s buffers and either based on grainbuf or playbuf.
I will learn how to use github and post the link.

Thanks for your thoughts and ideas.

heya sn_lx, you still active in these forums?

i’m curious if you made any headway on your project, i’ve been using a pretty dirty hacked together sc script to create ambiences of pre-recorded field recordings, using two instances of the supercollider clouds translation, a looper/tapedelay and some distortion also controlled via an akai midimix. maybe the part of how you can assign the midimix controls can be helpful to you.

best,
dormir

hi dormir,

nice to hear from you. I looked briefly into your code. many things to learn for me.
I will try to try it out in the next weeks.
currently I am exploring the midihub together with a digitakt and an external controller, more or less for similar duties I have made my sc program with the akai midimix for: recording something into a buffer and manipulating it, trying to shape something that pleases me - all in that and for the moment.

my pisound setup was:
I used patchbox and as audio interface a tascam dr40, the akai midimix and a thyme.
Together with this sc code:

/*

'main-akai+playbuf+reverb-4-1-6-2'

6 tapemachines
2 warpmachines (slight random position function)
2 reverb groups

group 'left' and 'right' with 3 tapemachines and 1 grain-warp-machine

*/

(
// LEDs (noteOn value) and cc value (every fourth) akai default values
var muteled, recled, bankled, sololed, cc;
muteled = [1, 4, 7, 10, 13, 16, 19, 22]; // note values
recled = [3, 6, 9, 12, 15, 18, 21, 24]; // note values
bankled = [25, 26]; // note values
sololed = [27, 0]; // notevalue

muteled = Array.fill(8, {arg i; Array.with(muteled[i], 1)});
recled = Array.fill(8, {arg i; Array.with(recled[i], 1)});
bankled = Array.fill(2, {arg i; Array.with(bankled[i], 1)});

cc = [16, 20, 24, 28, 46, 50, 54, 58]; // 1st cc value of row. every row has 4 ui elements - akai
// cc = [0, 4, 8, 12, 16, 20, 24, 28]; // 1st cc value of row. every row has 4 ui elements - faderfox ec4
a = Array.fill(8, {arg i; i }); // buffers
b = Array.fill(8, { arg i; i }); // rec synth
c = Array.fill(8, { arg i; i }); // play synth

	s.options.sampleRate = 48000;

s.waitForBoot({

	MIDIClient.init;
	Platform.case (\osx, {~midi = 1; MIDIIn.connectAll}, \linux, {~midi = 0});

	~rate = [
		(-12.midiratio*(-1)),
		(-19.midiratio*(-1)),
		// -1,
		// -0.5,
		-24.midiratio,
		-19.midiratio,
		-12.midiratio,
		-7.midiratio,
		-3.midiratio,
		1,
		3.midiratio,
		7.midiratio];

	// ~rate = [-1, -0.5, -0.25, 0.5, 0.25, 1, 1.25, 1.5, 2];

	~dur = s.sampleRate * 8;
	~dursec = ~dur/s.sampleRate;
	~waitbus = Bus.audio(s);
	~outbus = Bus.audio(s);
	~reverbbus = Bus.audio(s);

	~midinote = {arg led, state; MIDIOut(~midi).noteOn(0, led, state)}; // function to set button lights (LEDs)

	s.freeAll;

	/* Buffer and MIDI setup */

	Buffer.freeAll;

	8.do({arg i; a[i] = Buffer.alloc(s, ~dur)}); // 6 buffers to record external signals

	s.sync;

	/* SynthDefs */

	SynthDef(\play_tape, {
		var sig;
		sig = PlayBuf.ar(1, \bufnum.kr(0), \poti_1.kr(1) * BufRateScale.kr(\bufnum.kr(0)), Impulse.ar((~dursec/\poti_3.kr(1)).reciprocal), ~dur-\poti_2.kr(~dur), 1);
		sig = sig * \fader.kr(0.2);
		Out.ar(\out.kr(~outbus), sig);
	}).add;

	SynthDef(\rec, {
		var sig, play;
		sig = SoundIn.ar(0);
		play = RecordBuf.ar(sig, \bufnum.kr(0), \offset.kr(0), \reclev.kr(1).varlag(0.3), \prelev.kr(1).varlag(0.3), \run.kr(1), \loop.kr(1));
	}).add;

	SynthDef(\play_warp, {
		var sig;
		sig = Warp1.ar(1, \bufnum.kr(0), (\poti_2.kr(0)) * BufRateScale.kr(\bufnum.kr(0)) + LFNoise1.ar(0.6).range(-0.1, 0.1), \poti_1.kr(1), windowSize: \poti_3.kr(0.1), overlaps: 4, windowRandRatio: 0.1);
		sig = sig * \fader.kr(0);
		Out.ar(\out.kr(~outbus), sig);
	}).add;

	SynthDef(\verb, {
		var sig;
		sig = In.ar(~reverbbus);
		sig = GVerb.ar(sig, \roomsize.kr(91), \revtime.kr(0.1), \damp.kr(0.1), drylevel: \drylv.kr(1), earlyreflevel: 0.9, taillevel: \taillevel.kr(0.3));
		sig = sig * 0.4;
		Out.ar(\out.kr(~outbus), sig);
	}).add;

	SynthDef(\outbussynth, {
		var sig;
		sig = In.ar(\in.kr(~outbus));
		sig = Pan2.ar(sig);
		Out.ar(0, sig);
	}).add;

	s.sync;

	/* Synths */
	y = Synth(\verb);
	x = Synth(\outbussynth, addAction: \addToTail);

	// 'rec' synth
	8.do({arg i;
		b[i] = Synth(\rec, [\bufnum, a[i]], addAction: \addToTail);
	});

	// 'play' synths
	[1, 2, 3, 4, 5, 6].do({arg i;
		c[i] = Synth(\play_tape, [\bufnum, a[i]]);
	});

	[0, 7].do({arg i;
		c[i] = Synth(\play_warp, [\bufnum, a[i]]);
	});

	s.sync;

	/* MIDI */
	// LEDs default on
	8.do({arg i; ~midinote.value(muteled[i][0], 1)});
	8.do({arg i; ~midinote.value(recled[i][0], 1)});
	2.do({arg i; bankled[i][1] = 0; ~midinote.value(bankled[i][0], 0)}); // reverb leds off

	// encoder and faders
	MIDIdef.cc(\tapemachines, {arg val, cc_value;
		[1, 2, 3, 4, 5, 6].do({arg i;
			case
			{cc_value == cc[i]} {(c[i]).set(\poti_1, (~rate[val.value.linlin(0, 127, 0, ~rate.size-1)]))} // pitch
			{cc_value == (cc[i]+1)} {(c[i]).set(\poti_2, val.value.linlin(0, 127, ~dur, 100))} // start position
			{cc_value == (cc[i]+2)} {(c[i]).set(\poti_3, val.value.linlin(0, 127, 0.6, 42))} // start reset LFO
			{cc_value == (cc[i]+3)} {(c[i]).set(\fader, val.value.linlin(0, 127, 0, 1.2))} // vol
		})
	});

	MIDIdef.cc(\warpmachines, {arg val, cc_value;
		[0, 7].do({arg i;
			case
			{cc_value == cc[i]} {(c[i]).set(\poti_1, (~rate[val.value.linlin(0, 127, 0, ~rate.size-1)]))} // freqscale
			{cc_value == (cc[i]+1)} {(c[i]).set(\poti_2, val.value.linlin(0, 127, 0, 1))} // pointer to the buffer
			{cc_value == (cc[i]+2)} {(c[i]).set(\poti_3, val.value.linlin(0, 63, 0.1, 1))} // windowsize
			{cc_value == (cc[i]+3)} {(c[i]).set(\fader, val.value.linlin(0, 127, 0, 1.2))} // vol
		})
	});


	//master fader for verb
	MIDIdef.cc(\akaimmix_cc_master, {arg val, cc_value;
		if (cc_value == 62,
			{y.set
				(
					\revtime, val.value.linlin(0, 127, 0.1, 28),
					\taillevel, val.value.linlin(20, 127, 0.2, 0.7),
					\damp, val.value.linlin(0, 50, 0.5, 0.1),
					\drylv, val.value.linlin(50, 127, 1, 0.4)
		)};);
	});

	//buttons
	MIDIdef.noteOn(\akaimmix_btn, {arg val, note_value;
		8.do({arg i;
			case
			// mute btns
			{(note_value == muteled[i][0])} {
				if(muteled[i][1]==0,
					{muteled[i][1]=1; b[(i)].set(\prelev, 1); ~midinote.value(muteled[i][0], 1)},
					{muteled[i][1]=0; b[(i)].set(\prelev, 0.3); ~midinote.value(muteled[i][0], 0)}
			)}
			//rec btns
			{(note_value == recled[i][0])} {
				if(recled[i][1]==0,
					{a[i].zero; recled[i][1]=1; b[(i)].set(\reclev, 1); ~midinote.value(recled[i][0], 1)},
					{recled[i][1]=0; b[(i)].set(\reclev, 0); ~midinote.value(recled[i][0], 0)}
			)}
		})
	});

	// recAll off button (solo)
	MIDIdef.noteOn(\akaisolo, {arg val, note_value;
		case
		{note_value == sololed[0]} {
			if (sololed[1] == 0,
				{
					sololed[1] = 1;
					8.do({arg i;
						recled[i][1]=0; ~midinote.value(recled[i][0], 0); b[i].set(\reclev, 0)});
				}, {
					sololed[1] = 0;
					8.do({arg i;
						a[i].zero;
						recled[i][1]=1; ~midinote.value(recled[i][0], 1); b[i].set(\reclev, 1)});
				}
		)}
	});

	// verb buttons
	MIDIdef.noteOn(\akai_bank, {arg val, note_value;
		case
		{note_value == bankled[0][0]} {
			if (bankled[0][1] == 1,
				{bankled[0][1]=0; 4.do({arg i; c[i].set(\out, ~outbus)}); ~midinote.value(bankled[0][0], 0)},
				{bankled[0][1]=1; 4.do({arg i; c[i].set(\out, ~reverbbus)}); ~midinote.value(bankled[0][0], 1)})}

		{note_value == bankled[1][0]} {
			if (bankled[1][1] == 1,
				{bankled[1][1]=0; 4.do({arg i; c[i+4].set(\out, ~outbus)}); ~midinote.value(bankled[1][0], 0)},
				{bankled[1][1]=1; 4.do({arg i; c[i+4].set(\out, ~reverbbus)}); ~midinote.value(bankled[1][0], 1)})}
	});
}) // s.waitforboot BLOCK
)// all BLOCK

I even tried to use github as you suggested, but did not manage to proceed.

best regards

1 Like

hey again,

very interesting setup. i’ve always wanted to get my hands on a thyme, actually my goalpost is to have something very similar to the functionality of the thyme with my sc-script with the additional possibility to do some granular stuff with the buffers, but it’s nowhere near there yet. i’m still trying to think up good ways to implement a way to add modulation that can be modified and be sent to different places. also there is still something about my use of the caesarlooper for the tape delay and loop thats not completely reliable yet. sometimes i feel like i could use a second or even a third midimix to have control over everything on a “one knob per function” basis.

i haven’t used the warp1 yet, seems interesting. thanks for sharing!

best,
dormir

1 Like