Norns: dust

thanks for the swift reply! sounds like great future plans!

@lazzarello you can use arrays and array arguments in synthdefs, though there are some limitations. see the help files for SynthDef, Mulltichannel Expansion, Mix, &c.

here’s an example with 3 sinewaves in a phase-modulation loop. (feedback provided by LocalIn/LocalOut.)
demonstrates:

  • array arguments (for freq, mod index, and delay time)
  • building and using arrays of ugens programatically in the synthdef

note the use of the array literal notation (#[])

(warning: gets noisy)

Routine {
	SynthDef.new(\fm3, {
		arg out=0, amp=0.05,
		freqs = #[110, 220, 330],
		mods = #[0.1, 0,1, 0.1],
		delays = #[0.001, 0.001, 0.001],
		freqlag = 0.1, modlag=0.1, delaylag=0.1;

		var mod_in;
		var mod_out;
		var sins;

		mod_in = LocalIn.ar(3);
		sins = freqs.collect({ arg f, i;
			SinOsc.ar(Lag.kr(freqs[i], freqlag), mod_in[(i+1)%3] * Lag.kr(mods[i], modlag))
		});

		mod_out = sins.collect({ arg sin, i;
			DelayC.ar(sin, 0.2, Lag.kr(delays[i], delaylag))
		});
		LocalOut.ar(mod_out);

		Out.ar(out, amp * Mix.new(sins));
	}).send(s);

	s.sync;
	x = Synth.new(\fm3);

	// command-period to stop!
	inf.do ({
		(1 + 1.0.rand).wait;
		x.set(\freqs, Array.fill(3, {200 + 200.rand}).postln);
		x.set(\mods, Array.fill(3, { 2.0.rand}).postln);
		x.set(\delays, Array.fill(3, {0.1.rand}).postln);
	})
}.play;
2 Likes

Weird Lua syntax stuff in my FM7 adventure.

I’m referencing the lib/mark_eats/mollythepoly.lua library. I didn’t recognize a syntax for adding key/value pairs to a table. It looks like this

params:add{type = "control", id = "pulse_width_mod", name = "Pulse Width Mod", controlspec = specs.PW_MOD, action = engine.pwMod}

I got the same results with two lines I recognized from some tutorials, like so

params:add_control("pulse_width_mod","Pulse Width Mod", controlspec.new(0, 1, "lin", 0, 0.2, ""))
params:set_action("pulse_width_mod", function(x) engine.pwMod(x) end)

I thought I’d test what I think are the semantics so I did this and got an exception on the first try.

foo = {}
<ok>
foo{type = "control", id = "wtf?"}
lua: stdin:1: attempt to call a table value (global 'foo')
stack traceback:
	stdin:1: in main chunk

Do tables get an add method by default? It appears not. What’s going on here?

foo:add{type = "control", id = "wtf?"}
lua: stdin:1: attempt to call a nil value (method 'add')
stack traceback:
	stdin:1: in main chunk

because that’s not what that is. :add is a method of the paramset class (in paramset.lua) of which the global params is an instance.

this would work if foo was a function with a single argument (a table). in lua, you can omit the parens in a fn call if the fn has only one argument

1 Like

Woah, h4x. That’s pretty clever, though in no way intuitive. It def cuts down on the number of lines for UI stuff.

see here re params syntax: Norns: update 181002

furthermore:

some_function({element1=345, ish="whatever"})

is the same as

some_function{element1=345, ish="whatever"}

fancy lua-jazz

I changed the code in a library. How do I reload Lua libraries in the path lib/lua/mydir/foo.lua?

I tried loading a new script and reloading the one that requires this library. The code changes are not on the device (they expose new params). I restarted the audio engine. Still no change. I loaded the code from a script through Maiden. No new params. I rebooted…new params. :frowning:

Any way to force reload libraries without rebooting?

you have to muck with the package cache directly. i did this enough a while back that i stuck it in a util:

using this you could reload your lib like this:

local my_lib = reload('my_lib')

(note this won’t follow transitive dependencies so you need to explicitly reload everything that’s changed.)

1 Like

I did it!

PR for FM7 created

FM7 is a Norns interface for the FM7 UGen, a phase modulation oscillator matrix. This is an MVP release. The engine is a 16 voice polyphonic synthesizer.

Notable features.

  • Device UI displays 6x6 modulation matrix and which of the 6 operators are output to audio
  • Key 2 for random modulation matrix + carrier output
  • Key 3 for random note event
  • Encoders 1 - 3 change operator 1 frequency multiplier, phase, amplitude (pre output)
  • Grid in Earthsea sequencer mode
  • All params exposed via PARAMETERS menu
  • MIDI!
  • OSC for all params should “just work” as of norns v1.1.0

Thanks to @catfact , @tehn , @markwheeler , @pq and @junklight for Norns/Lua/SC help.

Special thanks to Stefan Kersten who made the FM7 UGen over 10 years ago.

30 Likes

just having a play - this is really cool

obviously I now want changes: needs operator envelops and midi pitch bend :wink:

is there any way of editing the mod matrix? or do we just get to cycle around random things?

All those niggles apart this is an amazing basis - I’m going to use this as a basis for my multi-timbral project and it will help with the FM idea I had (more of an experiment - no idea if it will make anything musically useful but I’ll share it if it does)

(edit - nowhere near as noisy as my old FM7 (that I sadly lost in a house move) though… :wink: )

you can edit the deeper params in the PARAMETERS menu

enjoyed a quick run with the engine, sounds great! curious to come up with more UI ideas for config

2 Likes

yeah spotted that

does sound wonderful - just basically sitting playing it at the moment …

1 Like

I wanna make a preset system next, which would make it easy to add the 32 “official” algorithms from the DX7. A second page for the UI that shows the graphics could be a cool addition.

6 Likes

you’re in luck! a “preset” system is built-in to the parameter system.

hold KEY1 when in the param menu. you can save/load pset files. they’re human-readable, so you could potentially make a quick text-scrub script to convert the factory presets

2 Likes

Apologies for the newbie question, how would i install this FM7 engine into norns?

1 Like

oh my, that seems almost too easy.

I think operator envelopes would be a good next thing along with presets.

1 Like

Depends if you want to get your hands dirty with Linux stuff. If you do, you can track the master branch on the device.

  • enable wifi
  • ssh to the device ssh we@norns.local password sleep
  • backup dust folder mv ~/dust ~/dust.bak
  • clone git repo git clone https://github.com/monome/dust.git
  • reboot device sudo halt followed by long press to turn on

If you aren’t comfortable doing this, you can wait for an update to the device and use the built-in update system.

this has the drawback of removing any custom work you’ve done through the Maiden IDE. You will have to move those files back by hand. I don’t really know a way around this until the OS on the device is updated to not save artifacts like audio recordings and presets to the folder tracked by git.

4 Likes

ya - and if you want “classic” dx7ish behavior then you want a pitch envelope which can be arbitrarily applied to each osc.

1 Like

Oops, looks like I labeled the phase mod params backwards. Currently the param that says “Osc1 Phase Mod Osc6” actually sends oscillator 6 to modulate oscillator 1.

PR to fix mod params

There’s some cruft in there from my repo getting out of sync with master…I’ll help get this in order if someone can review the diff.

Thanks - need to get a little more comfortable first - still getting used to code structure, lua in general