Runing Autocousmatic on updated SC

Hi everyone!

I am trying to run Nick Collins’ Autocousmatic, but it seems that it is not working on SC 3.10.4… I’ve tried to run both the standalone and the source code, with no good results…

https://composerprogrammer.com/autocousmatic.html

I have SCMIR and all the required plugins installed. SCMIR seems to work, although with some small bugs…

I’ve changed some stuff on Autocousmatic that allowed me to go further (basically change some NRT server options ), but still cannot get the final results…

Does anyone have achieved the final renderings of this code ?

Here is the source code with my mods and the error the I am getting when the GUI is displaying

“composing:may take a while”

20707 ?? 0:10.19 scsynth
0
20707 ?? 0:10.19 scsynth
0
20707 ?? 0:10.19 scsynth
0
loading extracted features
loaded extracted features
[ “silences”, List[ ] ]
[ ‘lastnonzero’, nil, FloatArray[ ] ]
finished analysis of /Users/fellipemirandamartins/Desktop/Fellipe/SuperColider/Autocousmatic/Input/jeux1.wav
[ 0 ]
[ 1.0 ]
[ [ 0 ] ]
ERROR: Failed to write OSC score file: Could not open NRTanalysis for writing
CALL STACK:
Exception:reportError
arg this =
Nil:handleError
arg this = nil
arg error =
Thread:handleError
arg this =
arg error =
Thread:handleError
arg this =
arg error =
Object:throw
arg this =
Meta_Score:write
arg this =
arg list = [*6]
arg oscFilePath = “NRTanalysis”
arg clock = nil
var osccmd = nil
var f =
var tempoFactor = nil
Score:write
arg this =
arg oscFilePath = “NRTanalysis”
arg clock = nil
Score:writeOSCFile
arg this =
arg path = “NRTanalysis”
arg from = 0
arg to = 4.7838095426559
arg clock = nil
Score:recordNRT
arg this =
arg oscFilePath = “NRTanalysis”
arg outputFilePath = “/Users/fellipemirandamartins…”
arg inputFilePath = nil
arg sampleRate = 44100
arg headerFormat = “WAV”
arg sampleFormat = “float”
arg options =
arg completionString = “”
arg duration = nil
arg action = nil
Meta_Score:recordNRT
arg this =
arg list =
arg oscFilePath = “NRTanalysis”
arg outputFilePath = “/Users/fellipemirandamartins…”
arg inputFilePath = nil
arg sampleRate = 44100
arg headerFormat = “WAV”
arg sampleFormat = “float”
arg options =
arg completionString = “”
arg duration = nil
arg action = nil
AutocousmaticSoundFile:process2
arg this =
arg outputfilename = “/Users/fellipemirandamartins…”
var temp = nil
var temp2 = nil
var temp3 = nil
var array = nil
var size = nil
var interruptionlength = nil
var outputChannels = 2
var panpos = -0.56321459201162
var score =
var options =
var limit = nil
var a = nil
var playbackrate = 1.0
var envelopes = nil
var outputlength = 4.7838095426559
var sourcelength = 4.2838095426559
var startposition = 0.0
Autocousmatic:processgroup2
arg this =
arg soundfilegroup = [*1]
arg lengthnow = 200.52981109523
arg numbernow = 14
var lengthdone = 0.0
var testok = true
var filenamenow = “/Users/fellipemirandamartins…”
var count = 0
var afiles =
var newfile = nil
var sanitycheck = 0
var iterationtarget = 2
var iterations = 0
var chooseiterations =
var nextsoundfile =
< FunctionDef in Method Autocousmatic:topdowncompose >
arg sectionnow =
var calc = 13.368654073016
ArrayedCollection:do
arg this = [*3]
arg function =
var i = 0
List:do
arg this =
arg function =
< FunctionDef in Method Autocousmatic:topdowncompose >
var timenow = 357.496452364

^^ The preceding error dump is for ERROR: Failed to write OSC score file: Could not open NRTanalysis for writing

All the best,
Fellipe

Here is my modified version of Autocousmatic.sc

//Autocousmatic by Nick Collins (c)2009-2011, released under GNU GPL 3 August 2011
 
 
Autocousmatic { 
	var <>sourcedir, <>tempdir, <>renderdir, <>analysisdir; 
	var <inputfiles; 
	var <>numChannels;
	var <>duration;
	var <>inputsoundfiles; 
	//var <>tempsoundfiles; //all those usable in final mix  
	var <>newsoundfiles; //new filenames those just created 
	var <outputsoundfiles;
	
	//for topdown creation 
	var <>sections;  
	var <>tempfilecounter; //to keep unique temp file numbers  
	
	//set from GUI for next run
	var nextduration, nextnumChannels,nextNumMixes;  
	var statustext;  
	var running; 
	
	 
	*new {|numChannels=2, duration=60.0| 
		 
		^super.new.initAutocousmatic(numChannels, duration);  
	} 
	
	 
	initAutocousmatic {|numchan, dur| 
		 
		//array of soundfiles to operate on 
		//filenames = paths;  
		 
		numChannels= numchan; //num output channels
		 
		duration= dur;  
		
		//make sure directories exist for temporary files 
		"mkdir /tmp/autocousmaticanalysis".systemCmd;  
		
		"mkdir /tmp/autocousmatictemp".systemCmd;
		 
		sourcedir = ""; //"/data/audio/autocousmatic/source";  
		tempdir= "/tmp/autocousmatictemp"; //data/audio/autocousmatic/temp";  
		renderdir= ""; //"/data/audio/autocousmatic/render";  
		analysisdir= "/tmp/autocousmaticanalysis"; //"/data/audio/autocousmatic/analysis/";  
		
		AutocousmaticSoundFile.autocousmatic= this; 
		
		//maximum of 1000, no problem in practice; can also change ServerOptions
		
		//"sounds/*.wav".pathMatch far superior to getPathsInDirectory
//		inputfiles = (sourcedir++"/*").pathMatch; //Cocoa.getPathsInDirectory(sourcedir); 
//		
//		inputfiles.postln;
//		inputsoundfiles= inputfiles.collect{|filename| AutocousmaticSoundFile(filename)}; 
//		
//		//if problems loading any, remove those 
//		inputsoundfiles= inputsoundfiles.select{|val| val.uniqueidentifier.notNil}; 
//		
//		tempfilecounter= 0; 
//		
		nextduration = dur; 
		nextnumChannels = numchan; 
		running = false; 
		nextNumMixes = 1; 
		
		this.gui; 
		
	} 
	 
	 
	clean {
		
		("rm"+tempdir++"/*").unixCmd;
		("rm"+analysisdir++"/*").unixCmd;
		
	} 
	 
	
	//timescales, microsound, gestures, layers and sequences, abrupt and continuous transformation... 
	compose {|maxiterations=1| 
	
	
		//iterate; will look to minimise error from perfection, or else take best version so far within deadline of number of iterations 
		//keep track of diskspace; must delete intermediaries if running out of space, and settle early on version if get stuck. 
		
	
		//material analysis and generation of new combinations; bottom-up
		//psuedo listening assessment as you go; analyse with respect to loudness structure, sensory dissonance, et al. Even Schaeffarian qualities of grain et al, really timbral descriptors 
		//cluster analysis for similarities and differences to exploit? 
		
		
		//top-down; placement in wider structure
		//self assessment by running longer term segments of piece for dramatic connotations; expectancy analysis?
		//will require return to low level material tweaking 			
		
		
		//starting simple; assess input database, generate processed versions, select favourites, place into larger scale top-down determined structure with 
		maxiterations.do {
		
		
		
		}
		
		 
	}  
	
	
	
	//also set number of iterations of processing? 
	//initial tests and basic piece generation 
	compose1 {|number= 200, fromgeneration=0, reanalyse=true, iterations=1|
		var tempfiles, tempfilenames; 
		var totaltempcreated=number; 
		var newgeneration, derivations; //will return [tempfilenames, derivationinfo]
		//final mix can take account of derivation chain, matching similar processes from similar soundfiles together
		
		{
	
		//starting simple; assess input database, generate processed versions, select favourites, place into larger scale top-down determined structure 
		
		if(fromgeneration==0) {
		
		this.analyse(inputsoundfiles); 
		
		//create outputs in tempdir
		//will avoid accidentally picking up stuff from previous runs of the program, program will just overwrite stuff itself
		newgeneration = this.createnewgeneration(inputsoundfiles, number,0); 
		tempfilenames= newgeneration[0]; 
		derivations= newgeneration[1]; 
		
		totaltempcreated= number; 
		
		} {
		
		//must just load up what's there already
		tempfilenames= (tempdir++"/*").pathMatch;
		//derivations =  //but what about this? 
		
		};
		
		
		newsoundfiles = List[]; 
		
		iterations.do{|whichiteration|
		
		//if(whichiteration>=fromgeneration) {
		
		//};
		
		if(whichiteration>0) {
		//can iterate here; take any temp and further process back into temp, 
		//reduces number each generation to avoid over processing
		newgeneration= this.createnewgeneration(tempfiles, number.div(whichiteration+1), newsoundfiles.size); //offsets them 
		tempfilenames= newgeneration[0];
		derivations= newgeneration[1]; 
		}; 
		
		tempfiles= tempfilenames.collect{|filename,i| var newfile= AutocousmaticSoundFile(filename);  newfile.derivation= derivations[i]; newfile}; 
		
		//if problems loading any, remove those 
		tempfiles= tempfiles.select{|val| val.uniqueidentifier.notNil}; 
				
		this.analyse(tempfiles, reanalyse); //false to avoid NRT analysis step if already carried out 
		
		//safety; must have loaded feature data correctly
		tempfiles= tempfiles.select{|val| val.maxamplitude.notNil}; 
		
		//cull any with maxamplitude under -30 dB, or with zero usefulduration
		tempfiles= tempfiles.select{|val| ((val.maxamplitude.ampdb)>(-40)) && (val.usefulduration>0.1) }; 
		//this.cull; //remove any silent or 'unpleasing' soundfiles 
		
		newsoundfiles = newsoundfiles++tempfiles; 
		
		}; 
		
		
		
		//create final mix
		this.mix2; 	
			
		//choice of which soundfile based on proportion of total durations it represents; so can take subsections for processing too 
		//later may further rate by suitability, pliability etc		
	
		}.fork(SystemClock); 
		
	}
	 
	 
	createnewgeneration {|targetsoundfiles, number, offset=0| 
	
		var filenames= List[]; 
		//select anything in input, and process with anything you feel like 
		var derivations= List[]; 
		var derivationbase;
		
		if(offset==0) {derivationbase=0;};  	//if offset 0, getting from original sources
		if(offset>0) {derivationbase=offset-(targetsoundfiles.size);};  //if greater than 0, now at a later generation, must get derivationbase correct to trace
		
		
		number.do {|j|
			var filenamenow; 
			
			filenamenow= tempdir++"/temp"++((offset+j).asString)++".wav"; 
			
			filenames.add(filenamenow); 
			
			//probabilities relative to sizes of files and number of useful access points? 
			//was .choose
			targetsoundfiles.wrapAt(j).process1(filenamenow); 
		
			//applied process 1 on sound file indexed N. If generation 0, applied to sources, else higher generation applies to intermediate files
			//derivation is either to original source list for 1st entry, else for later entries into the master newsoundfiles list
			derivations.add((targetsoundfiles.wrapAt(j).derivation)++[[1, derivationbase+(j%(targetsoundfiles.size))]]); 
		}; 
		
		^[filenames,derivations];
	} 
	 
	 
	//call external program? Or run SC in NRT mode with Logger and feature extraction? 
	analyse {|whichfiles, redoanalysis=true| 
		 
		 //may need routine structure around this to adequately wait
		 whichfiles.do {|filenow|
		 
		 ("started analysis of " ++filenow.filename).postln;
		 
		 filenow.analyse(redoanalysis); 
		 
		 ("finished analysis of " ++filenow.filename).postln;
		 
		 }; 
		 	 
	} 
	 
	//use machine listening model on its own productions 
	selfassess { 
		 
		 
	} 
	 
	 
	 
}

The problem seems to be that AutocousmaticSoundFile assumes that SC’s working directory is a writeable location, but in your system, it isn’t.

I think the way to change it is IDE preferences > Interpreter and choose a working directory here. Then reboot the interpreter. I searched for an SC method call to set the cwd (current working directory) but it looks like there isn’t one.

Autocousmatic should ideally use PathName.tmp +/+ "NRTAnalysis" as its score file path, but it neglects to specify a directory. Formally that’s a bug – software should in general specify full paths and not assume that the cwd is a safe location.

hjh

1 Like

i don’t think it makes sense to say one type of path is always better than the other, that’s a bit like saying floating point numbers are always preferable to integers. for instance, i think most CLI tools i’ve used assume that i want to work in the directory where i run it, and so everything they do is relative to that.

sclang really should have a set cwd function, i think right now it’s just a command line flag. and at least on one platform i recall the default working directory is just the filesystem root / regardless of where you start sclang/IDE.

1 Like

Ah right – in that context, the cwd is often exposed to the user (shell prompt). In context of the above error, the cwd is hidden at that moment from the user (who either never set it, or may have set it months ago and forgotten about it) and assumed optimistically to be writable, which is not quite a user-friendly combination.

For any readers, one easy place to get tripped up with File is that opening the file (IIRC) doesn’t throw an error. You get a File object back, whose isOpen status may be true (ok, proceed) or false (couldn’t open). In the latter case, any file read/write primitives will throw errors (as above) and the reason it may not be clear from the call stack. So I tend to write filesystem access this way:

var file = File(path, "r");  // or "w"
if(file.isOpen) {
    protect {
        ... do the stuff...
    } { file.close };
} {
    "Couldn't open '%'".format(path).warn;  // or .error
};

(protect makes sure the file is closed even if an error occurs during reading or writing.)

Also note that SoundFile.openRead behaves differently (returns nil on error, so the appropriate check is if(soundfile.notNil).

hjh

1 Like

Thanks a lot!!

Although it still doesn’t work… BTW, does Autocousmatic run on your machines ?

I am finding some strange behavior on my SC. I was using SC 3.10.4, mac os mojave, and when cheking

Platform.defaultTempDir;
PathName.tmp;

I was getting:

-> /tmp/

Now I installed 3.11.1 (signed, notarized) and for the code above I am getting:

-> /Users/myusername/Library/Application Support/SuperCollider/tmp/

In both cases I am still having this writing/reading issues. When using others quarks that deals with NRT read/write files, e.g. SPList, I get messages like:

File '/Users/myusername/Library/Application Support/SuperCollider/tmp/splist_tmp_8537.wav' could not be opened: System error : No such file or directory.

Moreover, this SuperCollider and tmp folders (within Application Support) are not being created with the default installation, although the Platform.defaultTempDir by default points to this location… What is the issue here ?

Thanks a lot!
Fellipe

It seems there’s a mistake about the default temp directory on Mac.

I’m not using Mac, so I can’t say what it should be. The current 3.11.1 default makes sense to me – /Users/myusername/Library/Application Support/SuperCollider should be the user application support directory. If macOS no longer recommends a system-wide /tmp directory, it’s reasonable for us to put our own temp directory inside our own application support directory.

But, if we are setting this as a default and not ensuring that the directory exists, I guess that would have to be a bug.

In any case, if Autocousmatic is not using the temp directory, then it won’t matter for this app. As noted, it seems to be using the current working directory. This is, as Brian said, set as a commandline argument to sclang. You can control the value of this argument in IDE > Preferences > Interpreter > Runtime directory. So you should go here and choose a directory that you know your user account can write to. Then reboot the interpreter and try Autocousmatic again.

hjh

@fmiramar

Hey I’m pretty new to SC.
I was using standalone Autocousmatic back in the days but after updating my mac the old 32-bit version started not working.

I tried to create a new build with 3.9 but I had some issues.

I was wondering if you managed to make it work.

Best !

Unfortunately no, I’ve tried few times but no good results…