would an osc going into the FM input produce linear FM or exponential FM ? (/ are frequencies specified in hz or v/oct? can’t yet tell from reading source so far)

if it’s linear then yea that would work for FM synthesis, though having a PM input would be a nice since you wouldn’t need to scale index * modulator frequency (or however it goes)

It’s exponential in MultiOsc, linear in the filter and freq shifter. But that is not the only difference between PM and FM. (I’d say not the most important difference, in this context.) if you attach an envelope to PM input you get pretty much nothing.

yea, I’m reading that frequency is specified exponentially as 0.1/oct

I’d propose an additional liner FM input for all oscillators and also a PM input to sineosc to cover all bases

I can add that all, seems pretty doable

Thanks, I’ll look into it. (Or, if you’re inclined, feel free to make a PR) FM/PM is not my area of expertise.

Just as an aside, also undocumented, after a refactor I made a while back it’s a bit simpler to run R in SuperCollider, for instance on your regular computer. These are the commands involved to set up and control modules similar to the 1_square tutorial script:

(
s.waitForBoot {r=Rrrr.new};
)

r.newCommand("Osc", "PulseOsc");
r.newCommand("SoundOut", "SoundOut");

r.connectCommand("Osc/Out", "SoundOut/Left");
r.connectCommand("Osc/Out", "SoundOut/Right");

r.setCommand("Osc.Range", -1);
r.setCommand("Osc.Range", 0);
r.setCommand("Osc.Range", -2);

r.setCommand("Osc.Tune", -600)
r.setCommand("Osc.Tune", 423)
r.setCommand("Osc.Tune", 0)

r.setCommand("Osc.PulseWidth", 0.25);
r.setCommand("Osc.PulseWidth", 0.5);
r.setCommand("Osc.PulseWidth", 0.75);

Some other features are hidden in the latest version too (visuals = a kind of poll for specific module values). I’ll try to add some docs this weekend.

cool, maybe I’ll try out a PR soon and see how that goes. I have a couple more ideas for modules too

  • slew rate limiter (using VarLag, probably?)
  • decimator
  • panner
  • wide bandpass filter

(progress)

2 Likes

This thread prompted me to have poke around Moln and see what sort of simple FM was currently possible with R.

As a quick experiment, I added a few lines of code to see what would happen. It didn’t take long for things to get wild with cross-modulation :slight_smile:

Moln_FM

Basic controls for FM are in the parameters menu. If I have time, I’ll add a better way to interact with these.
@jah - R is amazing and deep. Thank you!
@andrew - I’m looking forward to your updates!

3 Likes

@liquid_citizen i think u would enjoy my fork rn

image

(srry for the head tilt)

7 Likes

Awesome! FWIW: regarding UI. there’s a moln update coming along that exposes all parameters in script mode (K2 / K3 switches between pages). It’s in this script bundle: https://github.com/antonhornquist/roar (this is alpha stage and requires the latest norns update).

2 Likes

Looking for a little assistance… I’d like to have a separate ADSR for both Amp and Filter Frequency (using MMFilter)

so I have the following but I don’t get any change in filter frequency when I gate the envelope.

Pretty sure i’m missing something obvious but I’m stuck for the moment.

  engine.new("Env", "ADSREnv")
  engine.new("FEnv", "ADSREnv")
  engine.new("EnvFilter", "MMFilter")
  engine.new("Amp", "Amp")
  engine.new("SoundIn", "SoundIn")
  engine.new("SoundOut", "SoundOut")

  engine.connect("SoundIn/Left", "EnvFilter/In")
  engine.connect("SoundIn/Right", "EnvFilter/In")
  engine.connect("EnvFilter/Bandpass", "Amp/In")
  engine.connect("Env/Out", "Amp/Lin")
  engine.connect("FEnv/Out", "EnvFilter/Frequency")
  engine.connect("Amp/Out", "SoundOut/Left")
  engine.connect("Amp/Out", "SoundOut/Right")

-- then later a gate is sent
  engine.set("FEnv.Gate", 1)

Then of course I discover the SC tab in maiden is throwing some errors… Investigating further.

Ok - maybe I need

engine.connect("FEnv/Out", "EnvFilter/FM")

instead?.. but not clear on what the MMFilter FM input is looking for

‘EnvFilter/FM’ ? and set FM = 1 ?

haven’t checked to source or docs but essentially parameters are not interchangeable with inputs, might be getting them mixed up

dorp u just wrote that

yeah - I was mixed up for sure.

but… i think I got it sorted now. EnvFilter/FM is 0 to 1 (formatted as percentage for params).

now to figure out how that interacts with MMFilter.Frequency :thinking:

var frequency = frequencySpec.map(frequencySpec.unmap(param_Frequency) + (sig_FM * param_FM));

I’ve just been skimming the source code and it’s answered most of my q’s - not to bad to search around it even if ya don’t know much SC (= me) : ) the modules themselves are pretty darn simple

but to answer yr q I’m pretty sure across the board Frequency in specified in hertz and added to /FM * .FM (the input is in 0.1/oct and the parameter is range 0-1).

you might’ve solved this already but to control oscillator frequency route a FreqGate to /FM (and set .FM = 1 for tracking)

Hi,

The confusion here is probably due to the fact there’s both an input and parameter named FM for the MMFilter module.

To modulate filter frequency you both need to connect one (or more) signals to the FM input and set how much the incoming signal(s) should modulate the frequency by setting the FM parameter to a non-zero value.

Ie:

engine.new("LFO", "MultiLFO")
engine.new("Osc", "PulseOsc")
engine.new("Filter", "MMFilter")
engine.new("SoundOut", "SoundOut")

engine.connect("LFO/Sine", "Filter/FM")

engine.connect("Osc/Out", "Filter/In")

engine.connect("Filter/Lowpass", "SoundOut/Left")
engine.connect("Filter/Lowpass", "SoundOut/Right")

engine.set("Filter.FM", 0.5)

(remember that inputs are referred to with [ModuleName]/[InputName] notation (ie. Filter/FM) whereas parameters are referred to with [ModuleName].[ParameterName] notation (ie. Filter.FM).

2 Likes

Thanks for chiming in @andrew ! I’ve prioritized adding features over docs for now, but I’m going to shift focus for a bit and will be adding more documentation to existing features.

In the meantime:

What the code block you posted above means is the frequency set via the main frequency parameter (ie engine.set("Filter.Frequency")) is converted from its parameter range (0.1 ... 20000 Hz) to 0 ... 1.0, the external modulating control signal sig_FM typically ranging from -1.0 ... 1.0 (ie. “Filter/FM” in engine.connect("LFO/Sine", "Filter/FM")) is then added to this normalized cutoff frequency control signal (after being attenuated by the FM parameter - the one set in engine.set("Filter.FM")). The resulting control signal is then converted back from the normalized 0 ... 1.0 range to 0.1 ... 20000 Hz and used to control the filter UGen.

The modulation is thus determined both by the original control signal (which varies depending on module), the control signal attenuator and the parameter range mapping. Exactly how it translates is a bit involved.

Users should not really need to worry about details, it should be in the docs.

Anyhow - if you @okyeron want to know what the filter frequency is at any time after modulation (for debugging or visualization purposes) you can use a new undocumented feature called, uh, visuals. Each module can expose one or more visuals which are just data polled back to the lua script layer. The actual frequency of MMFilter has a visual called… yeah… Frequency. If your filter is called Filter use engine.pollvisual(0, "Filter.Frequency") and the poll called poll1 will be used to feedback cutoff frequency to lua layer.

For an example of visuals see bob : https://github.com/antonhornquist/roar/blob/master/bob.lua, r details in https://github.com/antonhornquist/roar/blob/master/lib/r_bob.lua (beware, alpha stage code)

FYI the MMFilter module is feature-wise inspired by this module: http://www.doepfer.de/a100_man/A121_man.pdf

2 Likes

Fantastic. I’ll play with this soon. Thx!!

Docs note - readme still mentions a bandpass filter module (BPFilter) , but that’s not in the lib (anymore?).

Thanks for the heads up! It’s actually in the engine: https://github.com/antonhornquist/r/blob/master/lib/Engine_R.sc#L2127-L2196

… but wasn’t added to the list of specs in the r.lua library. Now fixed, pull the latest from the git repo to get the update.

1 Like

Nice!

I figured it’d been deprecated by MMFilter or something since I didnt see it in the r.lua libarary.

FWIW - here’s the thing I’m working on (an audio gating sequencer thingy):

11 Likes

Cool! :slight_smile:

The separate BP/HP/LP/BR filters will remain in the library even though a multimode-variant is in there. Reason they’re there is performance - the multimode verison runs all filters even though not all are used. So if you only need BP in a script where a lot of other modules are used it’s better to choose the BP one to conserve CPU.

It’s the same reason there’s Sine/Pulse/Sine/Tri oscillators and MultiOsc.

2 Likes

seeing a deluge of these messages in the SC tab in maiden:

"/" as delimiter for module input references is deprecated. Use "*" instead, like so: Delay*DelayTimeModulation.
"/" as delimiter for module input references is deprecated. Use "*" instead, like so: Delay*In.
"/" as delimiter for module input references is deprecated. Use "*" instead, like so: Delay*DelayTimeModulation.
"/" as delimiter for module input references is deprecated. Use "*" instead, like so: Delay*In.

Some of these I’m not using, so are they coming from the engine library?

Hi,

I’ve changed the syntax for inputs. See https://github.com/antonhornquist/r/blob/master/README.md#commands

Earlier, for connect and disconnect commands both outputs and inputs used the / delimiter like so:
connect Osc/Pulse Out/Left

This is now changed - * is the delimiter for inputs like so:
connect Osc/Pulse Out*Left

The earlier behavior still works, but is deprecated. That’s why SuperCollider posts these messages. Just change to the new delimiter and no deprecation warnings will be posted.

EDIT: Reason for the change is it makes the input and output references unique, which was not the case before.

/Anton

1 Like