( Store | load ) stream state from file

Hello there,

Is there a way to store and eventually restore the state of a stream from a file ?

The goal is for the stream to survive a complete scide reboot. i.e. to restore the stream in the very same state it was before shutting down.

// Recall/load state ?
a = Pseq((0..99)).asStream;
11.rand.do({a.next.postln});
// Store state ?

You could use seeded randomness. This in itself doesnā€™t store the state as such, but it ensures that the pattern produces the same values every time. You can search for ā€˜Random Seedā€™ and Pseed in the help files.

Thanks @Thor_Madsen, Yes of course, using a stored pseudorandom seed is an avenue but still, no storage of the state. Iā€™m talking specifically about storing the state of a stream. i.e. The ability to continue a stream exactly where it was left off after a complete shutdown and restart of the sclang process. Pseq is quite the minimalest example I could use here for clarity sake.

Maybe this slightly adjusted example given by @Eric_Sluyter in a related thread could be helpful? It would still require you to used seeded randomness afaik. I should mention that I donā€™t have any experience using stream.fastForward myself.

(
f = { |pattern, start = 0|
  var stream = pattern.asStream;
  fork {
    stream.fastForward(start).wait;
    EventStreamPlayer(stream).play;
  }
};

i = 0;
p = Pbind(
	\degree, 
	Pseq([0, 1, 2, 3, 4], inf).trace, 
	\dur, 0.5,
	\iterationCounter, Pfunc{i = i + 1}
);
)

a = p.play;
a.stop

f.(p, i); // start from where 'a' stopped.

Thanks for your answer but still, there is no storage of the state. I could sort of reverse engineer ā€œwhereā€ I am in the stream and store|retrieve that as in your example yet it is very crude. Iā€™m looking for a way to dump or somehow extract the state of a Stream maybe made of multiple intertwined (maybe random) patterns and even that same stream could have been influenced by none repeatable events e.g. human interventions in some probability of the stream.

a = Pseq((0..99)).asStream;
11.rand.do({a.next.postln});
a.dump > file.txt;
1 Like

So I take it there is no infrastructure proper to do soā€¦

Not that I know of, noā€¦

Thanks @Thor_Madsen :slight_smile:

For the record, my goal is to continue an experience for a specific public many days later. Say an itinerant interactive SC setup that moves between crowds. Sort of a ā€œLetā€™s pickup where we left offā€, artistically ā€œLetā€™s take into account where we were and move on from thereā€ [with our many entangled patterns]. ā€œPepper this next live show with (some of) the last experience we sharedā€.

I think the fundamental issue is that a pattern is not a static thing and its ā€˜recipeā€™ can change while the pattern is playing, e.g using Pdefn, Pdefs, Pfunc etc. The pattern does not retain any information about itā€™s prior ā€˜recipesā€™, if you change a key using Pdefn there is not tracking inside the pattern of what the Pdefn was before you changed it. The best thing I can think of is to collect over the patterns and place each event in a list (you can do this inside \callback or \finish) and use Pbind.source.postcs to inspect the latest definition of the pattern. With this information you might be able to get close to what you are after. Other people with more experience than me might have better ideas.

persisting process state can be a bit complicated

image based virtual machines (some smalltalks, some lisps) will do this

also operating systems

perhaps virtualbox (or vmware or &etc) running a minimal linux/supercollider system could be stopped and re-started where it left off?

iā€™ve not tried such a thing though (linux does suspend and resume supercollider/jack properly on actual hardware, so it might work on a virtual machine)

Side note: if you simply want to store an object to a file and later restore it, you can use the Archive class.

1 Like

Thank you so much @shiihs !
So far not a success in my example but hey, the Archive class is now in my tool box for sure.

I tried the following :

(
a = Pseq((0..99)).asStream;
30.do({a.next.postln});
)
a.postcs;
Archive.global.put(\a, a);
Archive.write();
// Reboot interpreter pretty please.
Archive.read();
a = Archive.global.at(\a);
a.postcs;
a.next(); // Returns nil

You cannot in any way archive a Routine, not including state anyway.

Routines canā€™t even be copied.

I see this as a data representation problem. If you can represent the state as data, and the rules to move to the next state are unambiguous, then you can save and restore the data at will. Cellular automata work like this, as could genetic algorithms. Those arenā€™t the only options, just a couple of ideas. I realize this is too abstract / high-level but itā€™s the best I can do at the moment.

I think that this thread is hoping that stream internals will be available in some way to save you from the task of conceiving a data representation suitable to the stream behaviors that you want to pause/resume. They simply arenā€™t. You will have to give up the idea of Routines doing the design work for you ā€“ there is no end-run around this. It is a solvable problem but might not be easy.

hjh

I see @jamshark70. Thank you for the very clear (and somewhat terminal) response !

Btw what I mean by this is, it should be achievable to have a process with a recordable and restorable state, but you will have to create the data structure suitable to your needs. Itā€™s only the case that routines arenā€™t the way to do that ā€“ the broader problem isnā€™t meant to be terminal, not at all.

hjh

Yes I understand. Of course if I design and manage a comprehensive data structure, yes. I somehow though that the internal state of a routine could be a trivial thing to export and archive. I seems not to be the case.