--[[
lua code. create 20 random presets in "wavetable" synthesis style. for zynaddsubfx or yoshimi. this will be up for one month.
]]
--[[
* by mnrvovrfc/hsiangch_ong/clear2ooo
* originally written in 2016 (Cubs win!!!)
* modified on 29-Jan-2025
* modified to be self-contained, used to be five separate files.
* This Lua script creates 20 preset files for Zynaddsubfx/Yoshimi.
* They appear in the user's Documents directory.
* It takes a "xiz" suffix file of the old text format and creates a new one,
messing around with many "AddSynth" parameters. It might be most interesting
to people who love wavetable synthesis.
* IMPORTANT: the source code file should be called "xiz-new.lua"
(without double-quotation marks). If this is not acceptable
search for that name in this text ("afile" variable assignment)
and change it to what you want.
* I'm sorry for the file length but otherwise I didn't want to create a ZIP
to put into some file-sharing site.
* Requires Lua v5.2 or later.
* Just get interpreter from "lua-dot-org", build it for 32/64-bit and run this script.
Nothing else is needed.
* DISCLAIMER: I will not be held responsible for the inability to use this script
as it was intended. It should NOT be used in a production environment.
This script is offered AS IS,
as "public domain" which means nobody else could claim to be the original author.
]]
function findstr(txt, lookfor)
return string.find(txt, lookfor, 1, true)
end
function sformat(aformat, arg1, ...)
if arg1 == nil then
return aformat
end
return string.format(aformat, arg1, ...)
end
function tert(valu, first, second)
if valu == first then valu = second else valu = first end
return valu
end
function table_create(atable)
function local_table_copy(t)
local tret
function local_copy(t)
local tret = { }
for i = 1, #t do
tret[i] = t[i]
end
for k, v in pairs(t) do
if type(v) == "table" then
tret[k] = local_copy(v)
elseif type(k) ~= "number" then
tret[k] = v
end
end
return tret
end
tret = local_copy(t)
return tret
end
local tret = {
insert = function (s, ...)
local rest = { ... }
if rest == nil or #rest == 0 then return end
local lrest = #rest
for i = 1, lrest do
table.insert(s, rest[i])
end
end,
first = function (s, t)
if t == nil then return end
table.insert(s, 1, t)
end,
concat = function (s, delim, pfrom, pto)
return table.concat(s, delim, pfrom, pto)
end,
copy = function (s, ts, append)
if type(ts) ~= "table" then return end
if next(ts) == nil then return end
if append == nil then s:delete() end
local n = #ts
for i = 1, n do
table.insert(s, ts[i])
end
end,
remove = function (s, spos)
table.remove(s, spos)
end,
delete = function (s)
local n = #s
while n > 0 do
table.remove(s)
n = n - 1
end
end,
clear = function (s)
s:delete()
end,
is_empty = function (s)
-- not a good way, but the alternative is to search all elements for one with numeric index
-- the assumption is that if table_create() is used to create a table then
-- "insert" method would be used to add elements, like an array in BASIC
return (#s == 0)
end
}
if type(atable) == "table" and next(atable) ~= nil then
local t = tret
tret = local_table_copy(atable)
if not tret.insert then
tret.insert = t.insert
tret.clear = t.clear
tret.concat = t.concat
tret.copy = t.copy
tret.delete = t.delete
tret.first = t.first
tret.is_empty = t.is_empty
tret.remove = t.remove
end
end
return tret
end
function ran(a, b)
if type(a) ~= "number" then return nil end
if math.floor(a) == math.floor(b) then return a end
if a < 0 and b < 0 then
a = a * -1
b = b * -1
if a > b then a, b = b, a end
return math.random(a, b) * -1
end
if a > b then a, b = b, a end
if a < 0 or b < 0 then
local x = a * -1
if b < 0 then x = b * -1 end
return math.random(a + x, b + x) - x
end
return math.random(a, b)
end
-- recommended for this function to be used on a table that will be affected by table.sort()
function table_strip(t)
if t.insert then
t.insert, t.first, t.remove, t.clear, t.concat, t.is_empty, t.copy, t.delete =
nil, nil, nil, nil, nil, nil, nil, nil
end
return t
end
ssub = string.sub
sfind = string.find
supper = string.upper
slower = string.lower
function different_values(numval, vlo, vhi, vadd, vmult, addfirst)
if numval < 2 or vlo == vhi then return nil end
local tret = table_create()
local n
if numval == 2 then
n = vlo
if vadd then n = n + vadd end
if vmult then n = n * vmult end
tret:insert(n)
n = vhi
if vadd then n = n + vadd end
if vmult then n = n * vmult end
tret:insert(n)
return tret
end
local sg
if vlo < 0 and vhi < 0 then
sg = -1
vlo = vlo * -1
vhi = vhi * -1
else
sg = 1
end
if vlo > vhi then vlo, vhi = vhi, vlo end
local tj, goahead
repeat
goahead = true
tj = { }
tret:clear()
for z = 1, numval do
n = ran(vlo, vhi) * sg
tret:insert(n)
if tj[n] == nil then tj[n] = 1 else tj[n] = tj[n] + 1 end
end
for kk, vv in pairs(tj) do
if vv > 1 then goahead = false; break end
end
until goahead
if vadd and addfirst then
for z = 1, numval do
tret[z] = tret[z] + vadd
end
end
if vmult then
for z = 1, numval do
tret[z] = tret[z] * vmult
end
end
if vadd and not addfirst then
for z = 1, numval do
tret[z] = tret[z] + vadd
end
end
return tret
end
function table_reverse(t)
if t == nil or type(t) ~= "table" then return nil end
local l = #t
if l == 0 then return t end
local tret = { }
for i = l, 1, -1 do
table.insert(tret, t[i])
end
return tret
end
function gimme_harmonics(nlo, nhi)
local t, nharm, tharm, u
nharm = ran(nlo, nhi)
t = different_values(nharm, 2, 16)
table.sort(t)
t = table_reverse(t)
for j = 1, #t do
u = t[j]
t[j] = sformat(harmtem, u, ran(10, 16) * 8)
end
return t
end
txt, top, tob, tosc = table_create(), table_create(), table_create(), table_create()
for j = 1, 16 do
tosc[j] = table_create()
end
equal80 = string.rep(80, '=')
harmtem = [=[
]=]
-- THIS HAS TO BE THE SAME NAME (FULL PATH) AS THIS FILE:
afile = os.getenv("HOME") .. "/Documents/lua/xiz-new.lua"
presetscan = false
fu = io.open(afile, "r")
if fu == nil then
print("For this to work, file is required:")
print(afile)
return
end
for s in fu:lines() do
if presetscan then
if s == equal80 then break end
txt:insert(s)
elseif s == equal80 then
presetscan = true
end
end
fu:close()
vo = 0
t = top
passi = false
for i = 1, #txt do
if findstr(txt[i], "" and vo == 8 then
tosc[vo]:insert(txt[i])
vo = 0
t = tob
passi = true
end
if passi then
passi = false
else
t:insert(txt[i])
end
end
for w = 1, 20 do
filton = false
filtenv = false
for i = 1, #top do
if findstr(top[i], 'string name="name"') then
top[i] = sformat('randompreset%04d', w)
elseif findstr(top[i], 'string name="auth') then
top[i] = 'me'
elseif findstr(top[i], 'string name="com') then
top[i] = 'It might be useful for something.'
elseif top[i] == "" then
filton = true
elseif top[i] == "" then
filton = false
elseif top[i] == "" then
filtenv = true
elseif top[i] == '' and filtenv then
filtenv = false
end
if filton then
if findstr(top[i], 'par name="type"') then
top[i] = sformat('', ran(0, 4))
elseif findstr(top[i], 'par name="q"') then
top[i] = sformat('', ran(0, 22) * 4)
end
end
if filtenv then
ta = ran(8, 12) * 4
if ran(1, 3) == 1 then td = ran(6, 12) * 4 else td = ta end
fa = ran(6, 14) * 4
fd = ran(18, 26) * 4
if ran(1, 2) == 1 then fa, fd = fd, fa end
if findstr(top[i], '', ta)
elseif findstr(top[i], '', td)
elseif findstr(top[i], '', fa)
elseif findstr(top[i], '', fd)
end
end
end
for j = 9, 16 do
tosc[j]:copy(tosc[j - 8])
end
oscshift = ( ran(1, 4) == 1 )
if oscshift then
tn = different_values(7, 0, 15, 0, 8)
else
tn = different_values(7, 2, 14, 0, 8)
end
table.insert(tn, 0)
wshf = ran(0, 6)
for j = 9, 16 do
v = j - 8
firstdelay = true
firstwsh = true
attackfirst = true
moreharm = true
lfofreqon = false
moremod = ( w % 2 == 0 )
freqparmset = ""
harmonicend = 0
tharm = gimme_harmonics(3, 6)
for i = 1, #tosc[j] do
if findstr(tosc[j][i], 'par name="delay"') and oscshift and firstdelay and not lfofreqon then
firstdelay = false
tosc[j][i] = sformat('', tn[v])
elseif findstr(tosc[j][i], 'par name="wave_shaping"') and firstwsh then
tosc[j][i] = sformat('', ran(32, 96))
elseif findstr(tosc[j][i], '', wshf)
elseif findstr(tosc[j][i], '', u)
elseif findstr(tosc[j][i], '', u)
elseif findstr(tosc[j][i], '', u)
elseif tosc[j][i] == "" and harmonicend == 0 then
harmonicend = i
elseif tosc[j][i] == "" then
moreharm = false
elseif tosc[j][i] == "" and tosc[j][i + 2] == '' then
lfofreqon = true
elseif tosc[j][i] == "" and lfofreqon then
lfofreqon = false
elseif tosc[j][i] == "" and freqparmset == "m" then
freqparmset = ""
elseif tosc[j][i] == "" and freqparmset == "i" then
freqparmset = ""
elseif moremod and tosc[j][i] == "" then
freqparmset = "m"
elseif moremod and tosc[j][i] == "" then
freqparmset = "i"
end
if moreharm and tn[v] == 0 then
u = ran(0, 1) * 5 + 1
if findstr(tosc[j][i], '', u)
elseif findstr(tosc[j][i], '', ran(0, 64))
elseif findstr(tosc[j][i], '', z)
end
end
if moreharm and v > 4 then
if findstr(tosc[j][i], '', ran(2, 3))
elseif findstr(tosc[j][i], '', ran(2, 14) * 8)
elseif findstr(tosc[j][i], '', ran(3, 16) * 4)
elseif findstr(tosc[j][i], '', ran(0, 8) * 8)
end
end
if lfofreqon and v < 5 then
if tosc[j][i] == '' then
tosc[j][i] = ''
elseif findstr(tosc[j][i], '', ran(10, 1000) / 1000)
elseif findstr(tosc[j][i], '', ran(1, 8) * 8)
elseif findstr(tosc[j][i], '', z)
elseif findstr(tosc[j][i], '', ran(0, 4))
elseif findstr(tosc[j][i], '', z)
end
end
if w % 4 == 0 and (v == 1 or v == 3) and freqparmset == "m" then
if findstr(tosc[j][i], '', ran(3328, 3840) * 4)
end
end
if moremod and (v == 2 or v == 4) and freqparmset == "i" then
if findstr(tosc[j][i], '', v - 2)
end
end
end -- for i
if harmonicend > 0 then
for i = 1, #tharm do
table.insert(tosc[j], harmonicend, tharm[i])
end
end
if moremod and (v == 1 or v == 3) then
tharm = gimme_harmonics(2, 4)
hs = nil
for i = #tosc[j], 1, -1 do
if tosc[j][i] == "" then hs = i + 5; break end
end
if hs then
while tosc[j][hs] ~= "" do
table.remove(tosc[j], hs)
end
for i = 1, #tharm do
table.insert(tosc[j], hs, tharm[i])
end
end
end
end -- for j
outfile = os.getenv("HOME") .. "/Documents/" .. sformat("%04d-randompreset%04d.xiz", w, w)
fu = io.open(outfile, "w")
if fu then
fu:write(top:concat('\n') .. '\n')
for j = 9, 16 do
fu:write(tosc[j]:concat('\n') .. '\n')
end
fu:write(tob:concat('\n'))
fu:close()
print("Created: " .. outfile)
end
end -- for w
--[[
================================================================================
================================================================================
]]