First time here? Check out the FAQ!
x

Loop in "shiftRegister:"

+1 vote
1,460 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) (128,120 points)
edited Nov 27, 2018 by ssc
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
...