First time here? Check out the FAQ!
x

Loop in "shiftRegister:"

+1 vote
1,099 views

Greetings,

is it possible to somehow get repetitive sequences from the shiftRegister: ?

I wish to "feed" it with random and the be able to loop the sequences.

Something like the "Turing Machine" in Euro Modular or Rob Hordijk`s Benjolin synth.

wishing you all the best 

Rastko

 

 

asked Nov 22, 2018 in Sound Design by rastko-lazic (Practitioner) (410 points)
Could you give a few more details on how you would like it to behave? Do you want to have a button to set all stages to new random values and then loop it for a while?

3 Answers

0 votes

I couldn't immediately see a way to take the output of shiftRegister: and loop it back to its input. So I wrote some script to do something like that and put it in a SoundToGlobalController to affect the pitch of a sample.

The code in the Value parameter of the "freq" STGC looks like this:

I'm sure there's a simpler more elegant way to code this... but this works.

It initialises the shiftRegister with successive notes or values from the values array. Each !Gate will spit out a value from the shiftRegister. If the !MutationRate is set to zero then the shiftRegister will loop without changing. If the !MutationRate is set a bit higher then there's a chance that a value will be changed when written back into the register. If !MutationRate is 1 then it won't sound like it's looping at all and will mutate every step. When a register value mutates it chooses a new value at random from the values array.

 

Here's the Sound.

And here's what it sounds like.

 

 

 

answered Nov 23, 2018 by alan-jackson (Virtuoso) (15,840 points)
edited Nov 23, 2018 by alan-jackson
Is there an easy way to post an answer with syntax highlighting?
Hi Alan and thank you,

this code is still a bit complex for me (big bitt :-)) but this sound behaves exactly as a looping shift register should and I can use it and study it.

Thank you so much for this.

I found another way of repeating patterns from random inputs but I was not able to "inject" new random elements as your code can. Mine randomizes all stages on an event and the beauty is to add a bit off randomness in an existing pattern or have a choice of a new random sequence.

I will post "my" sound when I clean it as I have a problem with polyphony with it. But let's leave that for another post.

In any case, thank you and SSc for helping.

have a great day

rastko
Hee hee yes, this bit of code is tricky. Sorry, I posted it up as if it was nothing but it took me hours and used all my recently acquired ninja kyma skills. For a laugh I can go through it line by line and explain what it does if you like....
Thank you once more and I actually learned a lot from the code.
You don`t have to go line by line as I think I understand.
And again learned a lot

My skills are getting better day by day. It is really a "one step forward two step back" process but I am grateful I have time now and that finally, I will be using the Pacarana more.

wishing you all a great day from Kuala Lumpur

rastko
Ooops, I did it anyway. It was fun to cement it in my mind. It's also amusingly tricky to try and comment some code line by line in a way that makes any kind of sense. Oh well, someone might find it useful.
0 votes

The code does a few things that I've just learnt how to do this year (or even this week).

It uses:

an EventVariable

an EventVariable array

compound CapyTalk expression (the comma thing)

builds a compound CapyTalk expression using SmallTalk

 

The code: 
 

"First we have to declare our variables"

| register registerSize registerValue shiftExpression initialiseExpression values |

"The size of the shift register"
registerSize := 8.

"The array of possible register values.
I'm using the values as multipliers of the sample frequency so they are all
ratios taken from a just scale."

values := #(1 {5/4} {4/3} {3/2} {9/5} 2 {18/8} {12/5}).


"Declaring an EventVariable. HotValues like !MyCoolHotValue are a type of EventVariable and are CapyTalk variables that can change at run-time. HotValues create a control on the VCS. All the other variables in this code like registerSize are SmallTalk variables which means they're only used at the start when the Sound is constructed. Declaring an EventVariable is a way to make a CapyTalk variable that can be used at run-time but doesn't create a VCS fader."

registerValue := EventVariable new initialValue: 0.

"Next I'm declaring an EventVariable array. This is an array we can change at run-time. This is the shift register and being a CapyTalk array means we can shuffle the values along."

register := EventVariable new size: registerSize.

"Now it gets a bit funky! You can have a compound CapyTalk expression if you separate each expression with commas. So you can do something like:

  (!GiveMeARandomNumber nextRandom), (!GiveMeANormalNumber nextNormal)

The multiple expression I want to write shuffles each value of the register along one, which for a shift register with 8 values uses 8 CapyTalk expressions. Take the value from postion two and put it in position 1, Take the value from postion three and put it in position two etc etc. Yawn. So I'd like to write that using a SmallTalk loop to construct that expression. And first I need to save the first value of the shift register into a variable before I shuffle them all along one. This next line is that first part of the multiple expression (that saves the first value) and I'm putting the CapyTalk expression into a SmallTalk variable, shiftExpression.

To access a value from an EventVariable array you use @<. The line below is accessing the first element of the array (position 0). To assign a value to an EventVariable at run-time I have to get it off the stack. I'm using the <+ operation to pop it off the stack."

shiftExpression := registerValue <+ (register @< 0).


"Next is the iterative SmallTalk loop that constructs the large CapyTalk expression using inject: into:. I'm injecting shiftExpression, our CapyTalk expression so far, into the iterative loop and it becomes the :expr variable. On each iteration of the loop the inject: into: construct takes the previous output of the loop and puts it back in as :expr, so you can use it as a way of building up a structure, in this case a complext CapyTalk expression.

Inside the loop is:

    (expr, ((register @< ...
    
which is where it takes the expression so far, adds the comma and then adds another CapyTalk expression on the end."

shiftExpression := (0 to: (registerSize - 2)) inject: shiftExpression into: [:expr :i|
    (expr, ((register @< i) <+ (register @< (i + 1))))].

 

"I want to initialise the shift register with successive values from the values array. Again I'm doing this at run-time so I'm constructing another comma separated CapyTalk expression to assign all 8 values. Here I'm creating the first part of that expression:"

initialiseExpression := (register @< 0) <+ (0 of: values).

"And below I'm using inject: into: again to create the other parts of this CapyTalk expression:"

initialiseExpression := (1 to: (registerSize - 1)) inject: initialiseExpression into: [:expr :i|
    (expr, ((register @< i) <+ ((i mod: (values size)) of: values)))].    

 


"Below I'm stitching everything together into the final complex, multi-part CapyTalk expression, separated by commas."

"First the initialisation code which runs at start up"
((!localTime le: 1) true: (initialiseExpression) false: (nil)),

"This next bit will shift the shift register along one step every time !Gate is switched on"
(!Gate switchedOn
    true:
        (shiftExpression)
    false:
        (nil)),
        
"This bit copies the value that was at the head of the shift register back into the end. But randomly, depending on the setting of !MutationRate, it will select a random element of the values array and write that back into the end instead."

((((!Gate switchedOn nextRandom + 1) / 2) lt: !MutationRate)
            true:
                ((register @< (registerSize -1)) <+ (!Gate switchedOn nextRandomElementOf: values))
            false:
                ((register @< (registerSize -1)) <+ registerValue)),
                
"And finally I leave the value of the first position of the shift register on the stack. This is the value that the CapyTalk expression spits out and is what gets used as the value of the SoundToGlobalController that ultimately sets the frequency of the sample."
                
(register @< 0).


I'm sure there must be a simpler way of doing this.

answered Nov 25, 2018 by alan-jackson (Virtuoso) (15,840 points)
edited Nov 25, 2018 by alan-jackson
Simply wow , thank you
0 votes

Hi Alan,

Thanks for sending the link to your trombone example (beautiful!). And thanks for the instructive code comments.

Rastko, I think you could also use arrays of sample-and-held values in the StepSequencer to arrive at the kind of sequencer you describe where you can introduce a new random value at any stage of the sequence. For example, the array of pitches could be:

{1 to: 8 collect: [ :i | !logFreq + ((!Rand suffix: i) nextRandom * !Interval nn) rounded nn]} 

Here's an example StepSequencer where the buttons — !Rand1 through !Rand8 — randomize the pitch, velocity, duration, timbre values for that stage. (Once the sequence is going, it's also fun to change !Interval to modulate the size of the pitch deviation and !Swing to modulate the size of the duration modulation).

answered Nov 27, 2018 by ssc (Savant) (126,620 points)
edited Nov 27, 2018 by ssc
Hi Rastko,

I think you're going to like where I'm taking the shiftRegister. It's now got three gates signals you can send it. !Reset, !Inject and !Randomise.

!Reset will reset the current element at the front of the register to the "ResetValue" (eg. 0), when that value is copied from the head to the tail of the register.

!Inject will replace the current front element with whatever is in the !InjectValue parameter.

!Randomise will randomly mutate the current front element of the register.

But there's also !ResetAll, !InjectAll and !RandomiseAll which operate on the whole register at once.

!InjectAll takes an array of values in the !InjectAllValues parameter and fills the register with them, repeating them if the array is smaller than the register.

What this lets you do is you can put in a set of values, like a melody or phrase and inject it into the register in one go. If !MutateRate is set to zero then it will just loop around like a sequencer. But if you start nudging up the !MutateRate you can hear your tune slowly disintegrating.

I've been trying this with shift registers with 256 elements and it's working great.

I then used a replicator to make 16 registers, each with 32 elements, panned from left to right. I wired up a midi keyboard to inject values into all 16 registers at the same time by setting !Inject to !KeyDown and !InjectValue to something based on !KeyNumber.

What happens then is when I play a note it's loud, playing on all 16 trombone samples and it loops but the loops slowly disintegrate randomly, each of the 16 trombones mutating with different values so it sounds like a kind of delay where the melody gradually disappears into this rhythmic soup of panned notes.

What I'd like to do next is create a dual shift register that contains an A and B register with a mutate function that copies a value from the B register into the A one. What this would let me do is to set up a melody in the main A register and then hear it descend gradually into randomness, but then inject the same melody into the B register and increase the cross-register mutation so the randomness slowly morphs back to the melody again. Reversing entropy and thereby subverting the energy death of the universe. It's my long term sustainability model.

I'll post up a recording later when I get round to recording it.

Would anybody be interested in a properly encapsulated all-singing-and-dancing productised version of a shift register with a cute logo and everything?

Kyma is rocking out! I'm just imagining trying to make an array of 16 panned shift registers that can cross-mutate each with 256 elements out of eurorack.
Hi Alan ,

Sounds reall really great. You just gave me a lot to learn :-) but please do post the new versions I love love shift registers and they are really usefull for live performances.


Thank you all

rastko
@Alan Have edited my post to properly cite the trombone example (it's still beautiful;) "Reversing entropy and thereby subverting the energy death of the universe. It's my long term sustainability model." (Y)

@Rastko, the uploaded Sound has been fixed now if you'd like to try out the StepSequencer idea.
@ssc , this is so great  thank you !
~~~~
Would anybody be interested in a properly encapsulated all-singing-and-dancing productised version of a shift register with a cute logo and everything?
~~~~

Hell yeah! :)
What I like a lot about this sound is at low values of MutationRate the sequence is quasi musical - a phrase is stated and repeated, then a variation is introduced and repeated and so on. It's a very aesthetically pleasing, evolving kind of random.

If you could add the ability to periodically jump back to a previous iteration and then evolve further from that point it would be even more musical (IMO).
@Sean, I've just added that :)

Actually I've added two "memories" so you can save two separate iterations. You can then randomly mutate into either of the two memories, or between the two. It's really fun!

It also now understands the difference between a special "silence" value and other values. There are now 3 main mutation rates. The probability it will mutate a note into another note. The probability it will mutate a silence into a note and the probability it will change a note into a silence. This means you can play a rhythmic pattern into the register and by just enabling the note mutation it will change your notes but not change the rhythm...

Or you can just enable the silence-to-note mutation and it will occasionally add extra notes to your pattern but leave the melody unchanged.

When you have a pattern you like you can save that into one of the "memories". You can then put the mutate-to-memory rate up fairly high and turn on the other main mutations. What this does is it will randomly change notes, inject extra notes and add silences but keep coming back to the pattern saved in the memory. I'm having a lot of fun playing it. I'll record some audio over the weekend and post it up so you can hear it.
Awesome :D :D :D
Now here is a question that could turn into a feature request for SSC.

Is there any way to save the current contents of an event variable array as a file so it could be recalled later?

Currently I dont think so, but I'm sure it could be done
Hi Alan ,

did you post this? I would love to try it :-)

all the best

Rastko
Hi Rastko,

You mean the two memory version? No I haven't posted that up. I decided I wanted to try and encapsulate it properly and make a more reliable productised version of it.

And that quest has sent me down a number of intriguing rabbit holes of learning which I haven't returned back from yet.

Most of the stuff I've been doing over the last month or so has been tangentially related to the ShiftRegister.

In the Kyma Kata peer learning / practice sessions we built a "CV recorder" Sound. You can move a fader and it records the fader movement and plays it back. We recorded it into wavetable (audio) memory and I think this might be a more scalable approach for the ShiftRegister instead of using large arrays of EventVariables.

(The next Kyma Kata is tomorrow, Monday, 20:00 - 22:00 GMT/UTC, by the way, see: https://kyma.symbolicsound.com/forums/topic/would-you-like-to-be-part-of-the-kyma-kata/#post-1545).

I will eventually come back to the ShiftRegister.
Hi Alan,

no problem I was just curious.

The CV recorder sounds great I was trying to do some midi cc recording but failed :-). Learned a lot.

The Kyma Kata sounds wonderful, I hope I can join the next one.

*edit* Ufff The last one was at 4:00 AM my time :-) let`s see how dedicated I am :-)

Shall join now the Slack.

best

Rastko
...