Replacing repetitions in a stream with rests?

There is an object in RTC-lib for PureDate called anti-bis that can filter out repetitions in a stream of numbers. Is there an existing way to do that in SC? What I’d like to be able to do is to replace a repeated value with a different fixed value, usually a rest. Something like:

Prand((0..9),inf).asStream.nextN(10)

-> [ 1, 1, 2, 4, 4, 7, 2, 9, 5, 6 ]

Instead, something like

Pantibis(Prand((0..9),inf), Rest()).asStream.nextN(10)

-> [ 1, Rest(), 2, 4, Rest(), 7, 2, 9, 5, 6 ]

or

Pantibis(Prand((0..9),inf), 99).asStream.nextN(10)

-> [ 1, 99, 2, 4, 99, 7, 2, 9, 5, 6 ]

The closest answer I have found on the list involves PIdev from miSCellaneous_lib:

https://scsynth.org/t/controlling-repetition-rate-in-randomness/917

but it doesn’t quite seem to do what I’m looking for. Or does it?

I’m not aware of a built-in pattern that does this.

Prout would be a good candidate, without changing the class library:

(
~antibis = Prout { |inval|
	var previous;
	while {
		inval.notNil
	} {
		if(inval == previous) {
			inval = Rest(inval).yield;
		} {
			previous = inval;
			inval = inval.yield;
		};
	};
	inval
};
)

p = (~antibis <> Pdup(Pwhite(1, 3, inf), Pxrand((0..7), inf))).asStream;

p.next;

(Usually we chain event patterns, but pattern composition does work for value patterns too!)

Or, this function could be made into a filter pattern with only a couple of small changes.

Pantibis : FilterPattern {
	embedInStream { |inval|
		var stream = pattern.asStream;
		var previous, next;
		while {
			next = stream.next(inval);
			next.notNil
		} {
			if(next == previous) {
				inval = Rest(next).yield;
			} {
				previous = next;
				inval = next.yield;
			};
		};
		^inval
	}
}

(I didn’t test the pattern version.)

hjh

2 Likes

Thanks James!

Unfortunately, thinking about it this morning I realise I have asked the wrong question. I may have to come back to this, but let me keep going see if I can figure out what I am trying to do myself!

Maybe I am missing some vital information on the question, but isn’t a Pxrand essentially build to avoid the same number in a raw? Again apologies if that oversimplifies the inquiry at hand.

Yes, you’re correct! But what I am trying to do is to build my own custom walking machine, basically this:

I’ll probably end up having to ask someone here how to do it, but for now I think it would be good for me to struggle on by myself.

This will throw a warning after receiving the same value but will continue after the second time.

(
var oldVal;
x = {
	|val|
	if ( oldVal != val, {
		("no dups were found" + val).postln;
	}, {
		("dup value received").warn;
		val = \rest;
	});
	oldVal = val;
	val.postln;
}
)

x.value(4)

That’s a very cool sequence!

I don’t have a lot of ideas for now, because the crucial logic is hidden in pd intchoose.

You could try the Prout layout above – this is a really nice way to apply some function in a stream while keeping local state. Take out the specific logic and put in your own – can experiment freely without recompiling the classlib:

Prout { |inval|
	... initialize state...
	while {
		... get new data...
		newData.notNil
	} {
		... do your stuff...
		inval = theOutput.yield;
	}
	inval  // should return inval at end
}

hjh

Thanks for the Prout framework. I made some more progress myself using Pbrown as a template:

https://diode.zone/w/cXECMSkRaeYgbTvqBDLbG8

https://gist.github.com/tedthetrumpet/027fd8c5f1ea645b285d3f90642dbe40

but am still stuck on trying to remove repeated jumps of the same interval and replace them with rests.

As it happens, also today Karsten Juschus did an implementation of this idea in for me Strudel KarstenJ – Developer from Chemnitz so I will be looking at that as well. Frustratingly, though, probably won’t have time to do any more work on this in either language until Monday.

Just to clear my head up a bit: with Prout, is ‘inval’ some kind of reserved word with a special meaning? Or is it just a conventional term for a value that is passed in and eventually returned? The way, in a SynthDef, we might conventionally have a variable called ‘sig’?

What is ‘inval’ short for? Am I thinking ‘initial’ value or something more like ‘internal’ value?

1 Like

Discussed in the pattern guide: Pattern Guide Reference 01: Pattern Internals | SuperCollider 3.12.2 Help

Prout is almost exactly the same, except that the embedInStream method needs to return with ^inval while a Prout just needs to have inval as the last expression (function return value).

If you look at the syntax, you can see it’s declared as an argument. This means you can call it anything you want (i.e., not a reserved word). I suggest to be consistent in the naming, though – it’s confusing enough as it is. (For instance, there are some patterns which inexplicably use “inevent” as a variable and “event” for the input event :astonished: … breaking the convention makes code reading just that little bit extra hard. So at this point, I always use “inval” for the argument.)

hjh