Skip to content

Commit

Permalink
Grendy v2
Browse files Browse the repository at this point in the history
  • Loading branch information
cfdrake committed Feb 18, 2021
1 parent a79d25e commit 664ef93
Show file tree
Hide file tree
Showing 3 changed files with 220 additions and 336 deletions.
291 changes: 61 additions & 230 deletions grendy.lua
Original file line number Diff line number Diff line change
@@ -1,252 +1,83 @@
-- ~~ grendy ~~
-- ~ grendy 2 ~
-- a simple drone synth
-- grendel drone commander inspired
-- v1.0.0 @cfd90
-- by: @cfd90
--
-- KEY2: randomize OSC/MIXER
-- KEY3: randomize FILTER/LFO
-- grendel drone commander
-- inspired
--
-- ENC1: FILTER freq
-- ENC2: OSC1 freq
-- ENC3: OSC2 freq
--
-- KEY1+ENC1: FILTER res
-- KEY1+ENC2: LFO freq
-- KEY1+ENC3: LFO depth
--
-- Further tweak parameters via [EDIT] page
--
-- MIDI input round-robin sets OSC1 and OSC2 freq
-- KEY 2 prev page
-- KEY 3 next page
-- ENC 1/2/3 page params

music = require 'musicutil'
local ez = include "lib/ezscript"

engine.name = "Grendy"

------
------ STATE
------

local shift = false
local midiFirstOsc = true

------
------ INITIALIZATION
------
ez.pages = {
{ name = "oscillators", e1 = "slop", e2 = "pitch1", e3 = "pitch2" },
{ name = "oscillators", e1 = "oscmix", e2 = "shape1", e3 = "shape2" },
{ name = "filter", e1 = nil, e2 = "filterFreq", e3 = "filterRes" },
{ name = "lfo", e1 = nil, e2 = "lfoRate", e3 = "lfo2Rate"},
{ name = "lfo", e1 = nil, e2 = "lfo2Level", e3 = "lfoDepth"},
{ name = "output", e1 = "amp", e2 = "panRate", e3 = "autoPan" }
}

function init()
print("unleashing grendy...")
setup_params()
setup_midi()
end

function setup_params()
-- OSC1
params:add_separator()
params:add_control("freq1", "osc1 freq", controlspec.new(20, 360, 'exp', 0.5, 220, 'hz'))
params:set_action("freq1", function(x) engine.freq1(x) end)
params:add_group("GRENDY", 19)
params:add_separator("oscillators")

params:add_control("shape1", "osc1 shape [tri=>sqr]", controlspec.new(-1, 1, 'lin', 0.01, 1, ''))
params:set_action("shape1", function(x) engine.shape1(x) end)
params:add_control("pitch1", "1 freq", controlspec.new(30, 500, 'exp', 0.01, 60, 'hz', 1/500))
params:set_action("pitch1", function(x) engine.pitch1(x) end)

-- OSC2
params:add_separator()
params:add_control("freq2", "osc2 freq", controlspec.new(20, 360, 'exp', 0.5, 220, 'hz'))
params:set_action("freq2", function(x) engine.freq2(x) end)
params:add_option("shape1", "1 shape", {"square", "saw"}, 1)
params:set_action("shape1", function(x) engine.shape1(x - 1) end)

params:add_control("shape2", "osc2 shape [tri=>sqr]", controlspec.new(-1, 1, 'lin', 0.01, 1, ''))
params:set_action("shape2", function(x) engine.shape2(x) end)
params:add_control("pitch2", "2 freq", controlspec.new(30, 500, 'exp', 0.01, 90, 'hz', 1/500))
params:set_action("pitch2", function(x) engine.pitch2(x) end)

-- MIXER
params:add_separator()
params:add_control("mix", "osc mix [osc1=>osc2]", controlspec.new(-1, 1, 'lin', 0.1, 0, ''))
params:set_action("mix", function(x) engine.mix(x) end)
params:add_option("shape2", "2 shape", {"square", "saw"}, 1)
params:set_action("shape2", function(x) engine.shape2(x - 1) end)

-- FILTER
params:add_separator()
params:add_control("ffreq", "filter frequency", controlspec.new(20, 2000, 'exp', 0.5, 440, 'hz'))
params:set_action("ffreq", function(x) engine.ffreq(x) end)
params:add_taper("oscmix", "* mix", 0, 1, 0.5, 0.1, "")
params:set_action("oscmix", function(x) engine.oscmix((x * 2) - 1) end)

params:add_control("fres", "filter res", controlspec.new(0, 4, 'lin', 0.1, 1, ''))
params:set_action("fres", function(x) engine.fres(x) end)
params:add_control("slop", "* slop", controlspec.new(0, 1, 'lin', 0.01, 0.1, '', 0.01))
params:set_action("slop", function(x) engine.slopLevel(x) end)

-- LFO
params:add_separator()
params:add_control("lfreq", "lfo frequency", controlspec.new(0.1, 20, 'lin', 0.1, 0.1, 'hz'))
params:set_action("lfreq", function(x) engine.lfreq(x) end)
params:add_separator("filter")

params:add_control("cspeed", "lfo click rate", controlspec.new(1, 16, 'lin', 1, 1, 'x'))
params:set_action("cspeed", function(x) engine.cspeed(x) end)
params:add_control("filterFreq", "freq", controlspec.new(100, 8000, 'exp', 0.01, 300, '', 10/8000))
params:set_action("filterFreq", function(x) engine.filterFreq(x) end)

params:add_control("cwidth", "lfo click width", controlspec.new(0.1, 0.9, 'lin', 0.1, 0.2, ''))
params:set_action("cwidth", function(x) engine.cwidth(x) end)
params:add_control("filterRes", "q", controlspec.new(1, 3, 'lin', 0.01, 2, ''))
params:set_action("filterRes", function(x) engine.filterRes(x) end)

params:add_control("lshape", "lfo shape [ramp=>click]", controlspec.new(-1, 1, 'lin', 0.1, -1, ''))
params:set_action("lshape", function(x) engine.lshape(x) end)
params:add_separator("lfo")

params:add_control("ldepth", "lfo depth", controlspec.new(0, 1000, 'lin', 0.1, 0, ''))
params:set_action("ldepth", function(x) engine.ldepth(x) end)

-- AMP
params:add_separator()
params:add_control("amp", "amp", controlspec.new(0, 1, 'lin', 0.01, 1, ''))
params:add_control("lfoRate", "1 rate", controlspec.new(0, 1, 'lin', 0.01, 0.1, '', 0.01))
params:set_action("lfoRate", function(x) engine.lfoRate(x) end)

local rates = {2, 4, 8, 16}
params:add_option("lfo2Rate", "2 rate", rates, 1)
params:set_action("lfo2Rate", function(x) engine.lfo2Rate(rates[x]) end)

params:add_control("lfo2Level", "2 level", controlspec.new(0, 1, 'lin', 0.01, 0.5, '', 0.01))
params:set_action("lfo2Level", function(x) engine.lfo2Level(x) end)

params:add_control("lfoDepth", "* depth", controlspec.new(0, 500, 'lin', 0.01, 200, '', 0.01))
params:set_action("lfoDepth", function(x) engine.lfoDepth(x) end)

params:add_separator("output")

params:add_taper("panRate", "pan rate", 0.1, 1, 0.1, 0.1, "")
params:set_action("panRate", function(x) engine.panRate(x) end)

params:add_taper("autoPan", "pan amt", 0.0, 1, 0, 0.1, "")
params:set_action("autoPan", function(x) engine.autoPan(x) end)

params:add_taper("amp", "volume", 0.0, 1, 1, 0.1, "")
params:set_action("amp", function(x) engine.amp(x) end)
end

function setup_midi()
m = midi.connect()

m.event = function(data)
local d = midi.to_msg(data)

if d.type == "note_on" then
-- Round-robin set OSC1 and OSC2
hz = music.note_num_to_freq(d.note)

if midiFirstOsc then
params:set("freq1", hz)
else
params:set("freq2", hz)
end

midiFirstOsc = not midiFirstOsc
end
end
end

------
------ INPUT
------

function key(n, z)
-- Shift key
if n == 1 then
if z > 0 then
shift = true
else
shift = false
end

redraw()
end

-- Parameter randomization
if n == 2 and z == 1 then
randomize_osc()
elseif n == 3 and z == 1 then
randomize_filter()
end
end

function enc(n, d)
if shift then
-- SHIFT mode
-- Control filter res, LFO freq, LFO depth
if n == 1 then
params:delta("fres", d)
elseif n == 2 then
params:delta("lfreq", d)
elseif n == 3 then
params:delta("ldepth", d)
end
else
-- REGULAR mode
-- Control filter freq, OSC1 freq, OSC2 freq
if n == 1 then
params:delta("ffreq", d)
elseif n == 2 then
params:delta("freq1", d)
elseif n == 3 then
params:delta("freq2", d)
end
end
end

------
------ DRAWING
------

function redraw()
screen.clear()

-- Encoder documentation
if shift then
screen.move(0, 10)
screen.level(1)
screen.text("[ENC1] ")
screen.level(5)
screen.text("filter res")
screen.move(0, 20)
screen.level(1)
screen.text("[ENC2] ")
screen.level(5)
screen.text("lfo freq")
screen.move(0, 30)
screen.level(1)
screen.text("[ENC3] ")
screen.level(5)
screen.text("lfo depth")
else
screen.move(0, 10)
screen.level(1)
screen.text("[ENC1] ")
screen.level(5)
screen.text("filter freq")
screen.move(0, 20)
screen.level(1)
screen.text("[ENC2] ")
screen.level(5)
screen.text("osc1 freq")
screen.move(0, 30)
screen.level(1)
screen.text("[ENC3] ")
screen.level(5)
screen.text("osc2 freq")
end

-- Key documentation
if not shift then
screen.move(0, 40)
screen.level(1)
screen.text("[KEY1] ")
screen.level(5)
screen.text("held, toggle page 2")
else
screen.move(0, 40)
screen.level(1)
screen.text("see params page for more")
end

screen.move(0, 50)
screen.level(1)
screen.text("[KEY2] ")
screen.level(5)
screen.text("randomize OSC/MIXER")
screen.move(0, 60)
screen.level(1)
screen.text("[KEY3] ")
screen.level(5)
screen.text("randomize FILTER/LFO")

screen.update()
end

------
------ HELPERS
------

function randomize_osc()
params:set("freq1", 20 + (math.random() * (360 - 20)))
params:set("shape1", (math.random() * 2) - 1)
params:set("freq2", 20 + (math.random() * (360 - 20)))
params:set("shape2", (math.random() * 2) - 1)
params:set("mix", (math.random() * 2) - 1)
end

function randomize_filter()
params:set("ffreq", 20 + (math.random() * (2000 - 20)))
params:set("fres", math.random() * 3.5) -- Don't go to 4, don't want to blast the user's ear with self-oscillation...
params:set("cspeed", 1 + (math.random() * (16 - 1)))
params:set("cwidth", 0.1 + (math.random() * (1 - 0.1)))
params:set("lshape", (math.random() * 2) - 1)
params:set("ldepth", math.random() * 1000)
end
params:read()
params:bang()
end
Loading

0 comments on commit 664ef93

Please sign in to comment.