And now, for SuperCollider users (@spluta and @tedmoore and @groma but also myself at the moment)
The same idea, the script from line 61 is the magic, the rest is just a file-pointer-granulator as example. I will use the structure above for all my patches where I want the findings to be sent to a reaper file (the 5 items described above)
I hope you like it. The other way round already works, I’ll do the parsing example soon.
// loading a file of sounds to check their lenght
(
~sources = Dictionary();
~nbEntry = 0;
FileDialog.new({|selection|
var fileNames = PathName.new(selection[0])
.entries
.select({|f|
[\wav, \WAV, \mp3,\aif].includes(f.extension.asSymbol);});
fileNames.do({arg fp;
SoundFile.use(fp.asAbsolutePath , {
arg file;
~sources[("entry-"++~nbEntry)] = Dictionary.newFrom(["path",fp.asAbsolutePath, "length", file.numFrames]);
});
~nbEntry = ~nbEntry + 1;
});
}, fileMode:2);
)
// check that source dictionary
~sources.postln
~nbEntry.postln
// granulate the file pointers in another dictionary
(
~numItems = 10;
~numtracks = 0;
~minLength = 0.01;
~maxLength = 0.1;
~minDelta = 0.01;
~maxDelta = 0.1;
)
// run the granular process
(
~time = 0;
~itemNb = 0;
~items = Dictionary();
~numItems.do{
var dur, which, track, offset, sourceLen;
which = ~nbEntry.rand;
sourceLen = ~sources[("entry-"++which)]["length"];
if (~numtracks !=0, {track = ~numtracks.rand},{track = which});
dur = ~minLength.rrand(~maxLength);
if (dur > sourceLen, {offset = 0;dur=sourceLen},{offset = (sourceLen - dur).rand});
~items[("item-"++~itemNb)] = Dictionary.newFrom([
"file", ~sources[("entry-"++which)]["path"],
"start", ~time,
"offset", offset,
"length", dur,
"track", track]);
~time = ~time + (~minDelta.rrand(~maxDelta));
~itemNb = ~itemNb + 1;
};
)
//check the first item
~items["item-0"].postln
//this is making the reaper file from that dictionary structure
(
//first create a new file that ends with rpp - it will overwrite if the file exists
f = File.new("/tmp/testgranul.rpp","w+");
if (f.isOpen , {
//sort the input dict per track in a temp dict
var sortedpertrack = Dictionary();
~items.keysValuesDo{|key,val|
sortedpertrack.atFail(val["track"],{sortedpertrack[val["track"]] = Dictionary();});
sortedpertrack[val["track"]].put(key, val);
};
//write the header
f.write("<REAPER_PROJECT 0.1 \"5.99/OSX64\" 1603037150\n\n");
//iterate through the tracks
sortedpertrack.keysValuesDo{|trackname, trackitems|
//write the track header
f.write("<TRACK\nNAME \"" ++ trackname ++ "\"\n");
// iterate through the items in the track
trackitems.keysValuesDo{|itemname, itemdata|
f.write("<ITEM\nPOSITION " ++ itemdata["start"] ++ "\nLENGTH " ++ itemdata["length"] ++ "\nNAME \"" ++ itemname ++ "\"\nSOFFS " ++ itemdata["offset"] ++ "\n<SOURCE WAVE\nFILE \"" ++ itemdata["file"] ++ "\"\n>\n>\n");
};
//write the track footer
f.write(">\n");
};
//write the footer
f.write(">\n");
f.close;
});
)