Recreating a horse/fourses oscillator.....

Rodrigo's icon

Bit of an oddball question here.

I'm trying to recreate a 'horse' oscillator by ciat-lonbarde/shbobo. It was originally in an analog circuit by Peter Blasser (http://www.ciat-lonbarde.net/fyrall/paperz/fourses/index.html).

It's a bit funky to understand, but the simple explanation is as follows (from his newer digital instrument (shbobo.net).
(more info on all the different opcodes here : https://docs.google.com/document/d/1SexTfdaEcz6AtdOrBkiTWPSAK-jKj-NwFLZM0K0v6UQ/pub
)

horse [horse] nume nume deno deno mul add
Description: an oscillator with independently settable rise and fall and upper/lower boundaries
nume: sets the rate at which the oscillator rises
deno: sets the rate at which the oscillator falls
nume: sets the oscillator’s upper boundary (height)
deno: sets the oscillator’s lower boundary (depth)

So reducing that down, it's basically a sawtooth waveform that you can vary it's orientation (phase?). I can visualise what that means, but I've not done that in Max. In his version the up/down ramps are controllable/modulated independently.

Next is the upper/lower boundary thing. It's not really DC offset, just having the upper and lower halves of the waveform have different limits. I know how to limit/clip the waveform, but not asymmetrically, though this isn't clipping, it's scaling.

Anyone have any thoughts or suggestions as to what objects to look at for recreating something like this?

Roman Thilenius's icon

these "fourses paperz" are definetly the most scientific schemata i ever saw.
i would probably use [jit.lcd] to build this type of oscillator.

Rodrigo's icon

lol.

i was hesitant to post the paper bit of it, but rest assured, it's analog (and digital) counterpart sound pretty effing good.

do you mean manually draw the waveform in jit.lcd?

ideally id just produce four numbers, one for each of the parameters (up ramp, down ramp, top boundary, bottom boundary), which can then get modulated independently.

Lance Ford Jones's icon

I read the second link first and was thinking "I wish I had an image or diagram of this" and then I looked at the first link - what moon of what planet was this found on? :-)

This looks really interesting. Do you have a sound sample you could post?

NOTE: There was a little problem with the first link:
http://www.ciat-lonbarde.net/fyrall/paperz/fourses/index.html

Rodrigo's icon

Yeah, funky guy. Smart as a whip though, just a very...esoteric design approach.

Not exactly a clear demo but at 2:20 in this vide you can see me controlling the fourses:
https://vimeo.com/21839786

The fourses instrument also has a bunch of 'horse' oscillators all intermodulated, so it's a quite layered/complex sound overall. The cell of recreating something like that would be the single horse oscillator.

There's also this video which has the designer (Peter) and myself performing together, and he's using the digital instrument (likely with some horse/fourses in there, but I can't point out exactly where).
https://vimeo.com/63028340

woyteg's icon

interesting and funny stuff!! I tried doing something like what you descibed as horse in gen.
Both of these versions are by far not perfect, maybe i even misunderstood a lot there, but maybe you can do something with it. Found it interesting and will work a bit more on it maybe, but since i have to go to sleep now, I thought i send what i have in a tired nonsense post.
The Fourse stuff actually looks much more interesting than the horse one though!

Max Patch
Copy patch and select New From Clipboard in Max.

cheers!

Rodrigo's icon

That sounds pretty slick, though I'm not sure I understand the parameters.

From the drawings and his explanation the upspeed/downspeed effect the orientation of a sawtooth. Either ramp down, or ramp up, and gradations in between. Modulating them independently would be effect pitch and timbre, as there's no direct control over period. The period/pitch is a byproduct of the combination of the up/downramp.

The lower/upper limit, I think, is where the the up/downspeed terminate. I imagine that to mean that having a lower limit of -1 and upper limit of 1 will make a regular waveform.

In fact, a couple recipes:

upspeed 100 / downspeed 100 / lowlimit -1 / uplimit 1 = triangle wave at 200hz
upspeed 10000 / downspeed 440 / lowlimit 0 / uplimit 2 = ramp down sawtooth at 440hz with DC offset of 1 (between 0 and 2)

It's possible my math is wrong there, but I think that's how the parameters are supposed to function.

woyteg's icon

Ahhh i seee.(still awake, more confusion to add)
I thought about this pitch independent of ramp speed and amplitude stuff.. I thought it would be possible to independently control them at least within given limits if one accepts that the oscillator would halt at max/min levels..
I think what you descibe should actually be a lot easier. mmh.. I'll give that another try tomorrow

Roman Thilenius's icon

modulating that part of an analog synthesizer in maxmsp which requires you to create some kind of dynamic wavetable is always the hardest part. it is not possible to think straight in lego, you must find out step by step which kind of process will work best for a certain situation. this is why i have neveer really made an attempt to create something" analog modelling", leave alone something from an existent device.

Rodrigo's icon

Would it require wavetable? In my noobish max thinking I was thinking I could event brute force it by using line~ for each part of the ramp, then scale~ to control each half of the orientation (though there's no split~ object).

I think the analog thing sounds great, and don't mean to fully recreate it, but just to step towards that sound world and then do something more max-y with it.

Wetterberg's icon

line~ might be fun, since we have the curve aspect to it now, too - I guess from the description that the basic circuit is related to the Serge DUSG http://clsound.com/Serge_Dual_Universal_Slope_Generator_files/DUSG-filtered.jpg

- which is essentially a heavily modded envelope, in some respects, but more precisely it's a voltage controlled slew.

...so that's why I'd attempt to start with a pulse train of sorts, scale it, and then slide~ or similar to get the underlying waveform.

Wetterberg's icon

hmmm. Been thinking about this a little bit. Obviously if you drive it with a pulse it will be synced, and you'll lose this free-running "sum time of slopes = frequency" aspect.

Some sort of feedback network of logic gates might be in order. Oh man, this sounds like good fun, actually.

woyteg's icon
Max Patch
Copy patch and select New From Clipboard in Max.

quit and dirty solution

ak's icon
Max Patch
Copy patch and select New From Clipboard in Max.

nice! below an easier way to obtain hysteresis in Gen.

Rodrigo's icon

That seems to work really nicely, though the uplim/lolim seem to both do the same thing (scale the overall signal, rather than each 'side' of it).

Nevermind, getting rid of dcblock did the trick. Awesome!

Rodrigo's icon

Ok, using Andrzej's version, and the text code description of a fourses (below) I recreated a fourses (four horses).

I had to use tapin/tapout as connecting directly killed audio processing. Probably possible to do all four horses inside of a gen to have single sample feedback, but this at least shows something. It's pretty slick sounding in some settings, and I have to say, sounds quite similar to the 'real' one, though the real one has even more things going on.

Text code:
([horse a] ([corp b]) 56 100 ([horse b]))
([horse b] 55 ([corp]) ([horse a]) ([horse c]))
([horse c] ([corp]) 54 ([horse b]) ([horse d]))
([horse d] 10 ([corp b]) ([horse c]) -100)

(corp is the radio antenna, so those are modulators).
Each horse takes 4 variables : upspeed, downspeed, uplim, lolim

Max Patch
Copy patch and select New From Clipboard in Max.

Here's the (sloppy) patch.

Wetterberg's icon
Max Patch
Copy patch and select New From Clipboard in Max.

Rodrigo, how's this? I tried to copy over the interconnects from yours into an all-gen thing.
(this is the first I've ever done in gen, so I'm hoping it's approved - at least it looks pretty on the inside! :) )

Wetterberg's icon
Max Patch
Copy patch and select New From Clipboard in Max.

hmm. On second thought, this one with [dcblock] on just the outputs, not the inter-feedback is a lot better to work with:

Rodrigo's icon

That's super awesome...as shit!

I kind of like the un-dcblocked, and uncompressed version. It does get a bit wild, but I think that's part of the charm of it.

So responsive and chaotic. Very sweet sounding.

Wetterberg's icon

I like it chaotic, don't get me wrong (you tend to get that with four oscs in a feedback loop) but the dcblocked one just has a ton more sweetspots.

Max Patch
Copy patch and select New From Clipboard in Max.

here's a quick edit with the last presets on it, too:

There's definitely a tweak that needs to get made: Control of each feedback point. Just a * and an input for each, to make this whole thing immensely more playable.

Rodrigo's icon

Hmm, I see what you mean. The dc can push it waaay out of audible range.

Control over feedback would have a nice impact on it. Looking through the fourses doc some more, it looks like there are two sets of these, and the text seems to imply that they sah each other:

"The intersexon freezes the angle of the ZI at the rhythm of the HAI"
(with the ZI and HAI being a 'fourses')

Also looks like any given osc can be be normal, inverted, squared normal, and squared inversion. Not sure how/when that happens.

Lokua's icon

Dude, it's hard to see at first but if you look a little more closely at the diagram you'll see that you need actual HORSES. Them, and some cyclops-penis crystal geometries. You're welcome.

Rodrigo's icon

Well, obviously!

Actually probing inside the gen it looks that intermodulating after the history object is only intermodulating values of 1 and 2, rather than the actual outputs.

However, when I change all the intermodulations to the += object, it locks the system up.

I basically started off by removing all the outer connections to the modulation points, to be able to control it with very few items 'from the outside', and it wasn't working well. So I probed.

Wetterberg's icon

okay, I think I'm going off on a tangent here, but would people mind if the inputs were normal non-signal connections? That would make it easier to manage - I'm up to 24 inputs (added feedback attenuation at all points), and as far as I remember gen~ only allows 16.

Wetterberg's icon

>Also looks like any given osc can be be normal, inverted, squared normal, and squared inversion. Not sure how/when that happens.

yeah, if you look at the waveform drawings they're all squared off. (I'm skipping that part completely)

Rodrigo's icon

I broke it up to audiorate stuff for intermodulation, but if it's all happening inside gen, it's a moot point.

Wetterberg's icon
Max Patch
Copy patch and select New From Clipboard in Max.

okay, this is about as far as I can bear to take it:

It's got a presentation mode and such, and some nice feedback controls, deliberately made difficult to mute completely, hehe. Hope someone finds it useful.

Rodrigo's icon

Is there a missing genfile or something? It's through up a bunch of gen~ : patchcord outlet out of range messages, and the gen~ bit is the default gen patcher when one instantiates gen.

Wetterberg's icon

ah shit, newb mistake, yeah. Hang on, lemme rip it out and put it in without the file.

Wetterberg's icon
Max Patch
Copy patch and select New From Clipboard in Max.

there - should work?

roger.carruthers's icon

"Could not find gen patcher rod_horse"
Also with earlier versions "operator/abstraction latch not found in gen domain dsp.gen" - where are the gen objects kept?
Cheers
Roger

Rodrigo's icon

@wetterberg,

that's awesome!
Do you mind if I wrap an interface/UI for the shnth on this and share it on the shnth/shbobo docs? (crediting you of course)

Wetterberg's icon

not at all - do remember to credit Andrzej as well for the gen :)

It's a shame, I was a tester on the shbobo (?), but the hardware didn't function with my computer :( What a great little box.

Rodrigo's icon

Looks like I might have to unpack a bunch of the parameters to do signal rate smooth as using wild modulation inputs it gets reaaaally step/blippy.

I can't seem to find how many ins you can have in the help or reference. You sure it's 16?

Wetterberg's icon

yep, just tested it. 16.

I quite dig it as is, but I'm wondering if the smoothing can't be applied internally? Isn't ithere a quick mix + history trick to get cheap lpf'ing?

Rodrigo's icon

Hmm, that would be ideal. Coming in with the shbobo data, which is only 255unit resolution, and at 10ms, sounds pretty shit controlling anything.

roger.carruthers's icon

Any idea about that latch abstraction? My curiosity is peaked..
Cheers
Roger

ak's icon

@roger: update to 6.1.x (or in this very case [latch] can be simulated with [sah 0] )

Rodrigo's icon

So is there a line~ equivalent in genland?

Like +=/history and some logic to go to the new value over x amount of samples or something?

bertrandfraysse's icon
Max Patch
Copy patch and select New From Clipboard in Max.

here is the mix + history trick to smooth transitions.

Rodrigo's icon

That works really well! Though with a patch that's 24 inlets deep, it's made a brutal mess of the gen code. Now time to tidy....

Wetterberg's icon
Max Patch
Copy patch and select New From Clipboard in Max.

I hope you don't mind I had a quick go at it - not what I'd call... "tidy", but it's readable, at least.

Wetterberg's icon

wow, this patch is inexpensive! It's a steady 3-4% cpu here, even after all that audio-rate smoothing. I'm loving it!

If you crank up the smoothing to max it creeps along in a lovely way, it takes what seems like over a minute to get to its destination...

stkr's icon

hi rodrigo and all,
thanks very much for this thread - has been a lot of fun to follow. wish i had more time right now to join in.

Max Patch
Copy patch and select New From Clipboard in Max.

just a couple contributions here from me. first of all, i think you need to start using subpatches and/or abstractions in gen~, especially as there is so much repeated here. secondly, here are a couple more effective parameter smoothers; i use my 'pSmoothC' all the time in gen~, as it does not impose ramp times but cleverly smooths, but if you want 'line' functionality i include that here too (it is an example posted to the forum by graham wakefield some time ago).

.

Wetterberg's icon

haha, I was hoping you'd chime in.

In this particular case I actively sought to present all objects straight away. This is the first patch I've done in gen~ (and I only did a tiny bit of it, the copious copying of objects).

Smoothers, eh? Will investigate! Thanks for sharing, man.

Rodrigo's icon

@stkr
I didn't even know you could do subpatch/abstractions in gen... That's super handy.

Before I set off replacing everything in the patch with the abstractions, have you started to do the same wetterberg? I started tidying the patch last night only to see you posted one this morning, so I don't want to duplicate work!

Wetterberg's icon

okay, I'm diving into modularizing the gen~  section. Hey devs, I'll buy you a beer if you let us encapsulate soon... I never realized how important that is for reducing complexity.

Also, it seems I'll need additional [history] objects or other delays to do the feedback, as soon as I've got things packed away?

Wetterberg's icon

yeah I'm terribly sorry, I didn't know your status there. Also, time zones suck.

Right now the subpatch thing is really kicking my ass on this one.

Rodrigo's icon

No no it's fine. I didn't think to post it 'in progress' last night, so it's on me. Curious to see how the compartmentalised version would look.

Also being able to do comment comments in gen like you can in codebox would be super useful. For a gen file as chunky as this one, being able to label things would be great.

Wetterberg's icon
Max Patch
Copy patch and select New From Clipboard in Max.

okay, how about this for a prettied up subpatch rig? I've tried to stick everything in subpatchers, so as to avoid big zip files and such for abstractions:

Rodrigo's icon

Nice! Super tidy

Here's the patch I've been working on so far. Not much in terms of GUI. It's all pushed onto the shnth.

Max Patch
Copy patch and select New From Clipboard in Max.

The antennas control the feedback, buttons randomize the osc range values, and I'm still working out how to implement the bars.

Wetterberg's icon

aw shit yeah. Looks great. I'd love to see some up close performance things done with it.

Wetterberg's icon

oh btw, Rodrigo, could you update the thread title to be a [sharing] one? :)

Rodrigo's icon

There doesn't appear to be an edit button on my of my posts. I've noticed this across the forum that there appears to be an edit window of time, then the edit button goes away.
Unless there's something I'm missing...

artmusicsouth's icon

I want to hear this!

This looks so awesome but I keep getting this message :

"operator/abstraction latch not found in gen domain dsp.gen"

I do not have gen installed. Is that the issue?

Rodrigo's icon

Apparently you need to install 6.1.1
You don't need the full license of gen to use it, only to edit it. But latch, apparently, is new.

Rodrigo's icon

Here's the done patch. You can use it without a Shnth by clicking in the bottom left. That randomizes a bunch of values. Not as expressive as using the Shnth as a controller, but still gives you an idea of what's what.

I want to try to expand it, and get some random repatching stuff going on, but not sure how to incorporate matrix~ into the mix, as you can only have 16 I/O in a gen, and looks like you can't have send~/receive~ inside of gen, so I don't know how it would be possible to randomly repatch a bunch of the stuff inside, but one thing at a time.

5426.c7fourses.maxpat
Max Patch
Wetterberg's icon

does anybody have a [codebox] version of matrix~? That'd be handy...!

jvkr's icon

Came across that intriguing image and realized I'd seen it before.
Here is an implementation in codebox, the simplest version possible.

History sawS(0.9);
History sawA(0.6);
History sawT(0.4);
History sawB(0.1);

History addS(0.011);
History addA(0.01);
History addT(0.009);
History addB(0.0103);

if (sawS >= 1) {
    addS = -abs(addS);
}

if (sawA >= sawS) {
    addS = abs(addS);
    addA = -abs(addA);
}

if (sawT >= sawA) {
    addA = abs(addA);
    addT = -abs(addT);
}

if (sawB >= sawT) {
    addT = abs(addT);
    addB = -abs(addB);
}

if (sawB
    addB = abs(addB);
}

out1 = sawS;
out2 = sawA;
out3 = sawT;
out4 = sawB;

sawS = clip(sawS + addS, sawA, 1);
sawA = clip(sawA + addA, sawT, sawS);
sawT = clip(sawT + addT, sawB, sawA);
sawB = clip(sawB + addB, 0, sawT);

oli larkin's icon

ported this to run on the web with iPlug2: https://olilarkin.github.io/fourses/

Wetterberg's icon

Bumping this lovely thread because I found a CeReNeM video of James Bradbury using it for further research:

https://www.youtube.com/watch?v=Ro30O9u7l8M

James Bradbury's icon

Funny enough, I've come back to the thread to learn more...!

Rodrigo's icon

I too am down for revisiting this as I now have the euro version, and it's stripped back in terms of what it does, but it could make for a great thing to implement in a broader system.