Load and save patterns in JSON Files

Hi,
in order to keep the code lean and to reset patterns, I was hoping to store pattern values in an external file. I was messing around with a json file.
The Json file

{
    "dis" :
    {
        "instrument": "dissent",
			"dur": "1",
			"degree": "Pseq([0, Pseq([Rest(0)], 7)], inf)",
    }
}

With this code I load the file and parse it with parseYAML.

//the path to the json file
~jsonPath =  "data/SynthJson01.json";

(
var f, file;
f = File(~jsonPath, "r");
~reset = Dictionary.new;
file = f.readAllString.parseYAML;
file.postln;
file["dis"].keysValuesDo{|k, v|
	~reset.put(k.asSymbol, v);
};
//the pattern I want to build from the file
~dis = Pbindef(\dis, *~reset.asPairs);
)

parseYAML gives me a nice Dictionary and the patterns seem to be constructed. Since Json is based on Strings, I wonder how to control the values of the ~reset dictionary. For the numeric values I could use value.asFloat. But what about this pair?
"degree": "Pseq([0, Pseq([Rest(0)], 7)], inf)"
Pseq is a “Pseq” or a function. I cannot do value.asFunction. In the Dictionary the key-value pairs don’t have quotes but the Pbindef comes all in quotes and that does not work in the Pbindef.

-> Dictionary[ (instrument -> dissent), (sus -> 0.9), (degree -> a Function), (dur -> 1), (atk -> 1.5) ]
-> Pbindef('dis', "instrument", "dissent", "atk", "1.5", "dur", "1", "sus", "0.9", "degree", "Pseq([0, Pseq([Rest(0)], 7)], inf)", 'sus', "0.9", 'instrument', "dissent", 'degree', Pseq([0, Pseq([Rest(0)], 7)], inf) , 'dur', "1", 'atk', "1.5")
  1. Where can I transform the String values of the json file into workable values for the pattern?
  2. Vice verca: Is it possible to save a Dictionary into a Json File?

thank you for looking into it
Qoris

For clean code: considered using String.parseJSON instead of parseYAML :slight_smile:

I would go into a bit different direction and consider using an external sc(d) file which you can load as well (as JSON are a pain to escape).

Consider you have the file

(
dis: (
	instrument: \default,
	dur: 0.25,
	legato: 0.2,
	degree: Pseq((0..10), inf),
),
)

saved as ~/tmp/foo.sc.

Then you can load it into a variable via

q = q ? ();
q[\patternDict] = thisProcess.interpreter.compileFile("~/tmp/foo.sc".absolutePath).value;

and use it in a Pbindef via

Pbindef(\foo, *q[\patternDict][\dis].asPairs).play;

Hope this helps :slight_smile:

PS: If you want to save an Event as JSON I have written something hacky once: quarks-web/quarkToJson.scd at main · capital-G/quarks-web · GitHub

2 Likes

Thank you so much, this is awesome.
I reckon there is a typo with the

q = q ? ();

at least I just did
q = ();

I noticed that it seems to be important to use an absolote path or else the file won’t load.
But wow, what a elegant solution.,

1 Like

Nah, q = q ? () is a common writing an is short for checking if the variable q has already an value and if not set it to an empty dictionary. This comes in handy if you re-evaluate the line your whole dictionary does not get deleted but if it does not exist it will get created, see Symbolic Notations | SuperCollider 3.11.2 Help under Conditional execution operators [another nice read is Syntax Shortcuts | SuperCollider 3.11.2 Help btw]

Glad this helped you :slight_smile:

PS: You can use thisProcess.nowExecutingPath to construct a relative path for your file based on your current document.

I don’t know the differences, but I use this shorter method (I return my value at the end of the file tho) :

var currentDir = thisProcess.nowExecutingPath.dirname ++ "/";
var something = this.executeFile( ( currentDir ++ "my_file.scd" ).standardizePath );