Skip to content

Instantly share code, notes, and snippets.

@trentgill
Last active March 7, 2026 22:20
Show Gist options
  • Select an option

  • Save trentgill/1a07ef44fcdbe315abbbd1588669a15a to your computer and use it in GitHub Desktop.

Select an option

Save trentgill/1a07ef44fcdbe315abbbd1588669a15a to your computer and use it in GitHub Desktop.
scale helper for atrium in lieu of scripting
local N = {}
N.to_semi = {
["c"] = 0,
["c#"] = 1,
["db"] = 1,
["d"] = 2,
["d#"] = 3,
["eb"] = 3,
["e"] = 4,
["f"] = 5,
["f#"] = 6,
["gb"] = 6,
["g"] = 7,
["g#"] = 8,
["ab"] = 8,
["a"] = 9,
["a#"] = 10,
["bb"] = 10,
["b"] = 11,
}
N.Octs = { ["+"] = 12, ["-"] = -12 }
N.to_chord = function(istr)
-- "C E G Bb"
local t = {}
for str in string.gmatch(istr, "([^%s]+)") do -- split string on whitespace
str = string.lower(str)
local n = N.to_semi[str]
if n then -- direct note
table.insert(t, N.to_semi[str])
else -- check for octave shift
local oct = 0
repeat
local last = string.sub(str, -1, -1)
oct = oct + N.Octs[last]
str = string.sub(str, 1, -2)
n = N.to_semi[str]
until n
table.insert(t, n + oct)
end
end
return t
end
N.TWELVE_ILOG2 = 12 / math.log(2)
N.ji = function(ratio)
return math.log(ratio) * N.TWELVE_ILOG2
end
-- sanitize scale notes.
-- always filled with 25 values, and a length (for playback)
N.sanitize = function(t)
local len = #t -- memoize number of scale elements
for i = (len + 1), 25 do
t[i] = 0 -- fill with nulls
end
t.len = len -- save the active length (default to all vals)
return t
end
-- t can be a table of semitones away from C (see "Notes")
-- or a string of note names (eg "C Eb G# A+ B- B--")
-- where a trailing +/- adds/subtracts an octave
-- offset is optional, adding a number of semitones
-- just should be a string "just" to indicate inputs are in just intonation form
N.make_scale = function(t, offset, just)
if type(t) == "string" then
t = N.to_chord(t) -- convert string to table of nums
end
if type(offset) == "string" then
offset = N.to_semi[string.lower(offset)]
else
offset = offset or 0
end
for k, v in ipairs(t) do
if just then
t[k] = N.ji(v) + offset
else
t[k] = v + offset
end
end
return t
end
N.print = function(...)
local t = N.sanitize(N.make_scale(...))
print(string.format("{%s,len=%i}", table.concat(t, ","), t.len))
end
N.debug = function(...)
local t = N.make_scale(...)
print(table.concat(t, ", "))
end
return N
@trentgill
Copy link
Author

Added a new function scale.debug which will let you see the output of your scales more easily while you edit. once you want to put it in a patch file, switch to scale.print to get the correctly formatted version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment