local p = {}
local MOS = require('Module:MOS')
local ET = require('Module:ET')
local u = require('Module:Utils')
local rat = require('Module:Rational')
local sb = require('Module:SB tree')
-- Helper function that parses entries from a semicolon-delimited string and returns them in an array
-- TODO: Separate this and parse_pairs into its own module of helper functions, as they're included
-- in various modules at this point
function p.parse_entries(unparsed)
local parsed = {}
for entry in string.gmatch(unparsed, '([^;]+)') do
local trimmed = entry:gsub("^%s*(.-)%s*$", "%1")
table.insert(parsed, trimmed) -- Add to array
end
return parsed
end
-- Helper function that parses pairs of elements separated by a colon
-- A pair must be two elements or it will be returned as an empty array
function p.parse_pair(unparsed)
local parsed = {}
for entry in string.gmatch(unparsed, '([^:]+)') do
local trimmed = entry:gsub("^%s*(.-)%s*$", "%1")
table.insert(parsed, trimmed) -- Add to array
end
if #parsed == 2 then
return parsed
else
return {}
end
end
-- Function that takes a list of semicolon-delimited pairs and returns a map
-- (or dictionary or associative array) of key-value pairs
-- Each entry is colon-delimited as key : pair
function p.parse_kv_pairs(unparsed)
-- Tokenize the string of unparsed pairs
local parsed = p.parse_entries(unparsed)
-- Then tokenize the tokens into key-value pairs
local pairs_ = {}
for i = 1, #parsed do
local pair = p.parse_pair(parsed[i])
if #pair == 2 then
pairs_[pair[1]] = pair[2]
end
end
return pairs_
end
function p.scale_tree(frame)
local mos = MOS.parse(frame.args["tuning"])
local equave = mos.equave
local L = mos.nL
local s = mos.ns
local collapsed_et = ET.new(L, equave)
local abstract_bright_gen = MOS.bright_gen(mos)
local collapsed_bright_steps = abstract_bright_gen["L"]
local equalized_et = ET.new(L + s, equave)
local equalized_bright_steps = abstract_bright_gen["L"] + abstract_bright_gen["s"]
local result = ""
local depth = frame.args["depth"] or 5
local step_ratios = sb.sb_tree_ratios(depth)
-- Default comments; these correspond to the TAMNAMS-named step ratios
local default_comments = {}
default_comments["1/1"] = "Equalized " .. MOS.as_string(mos)
default_comments["4/3"] = "Supersoft " .. MOS.as_string(mos)
default_comments["3/2"] = "Soft " .. MOS.as_string(mos)
default_comments["5/3"] = "Semisoft " .. MOS.as_string(mos)
default_comments["2/1"] = "Basic " .. MOS.as_string(mos)
default_comments["5/2"] = "Semihard " .. MOS.as_string(mos)
default_comments["3/1"] = "Hard " .. MOS.as_string(mos)
default_comments["4/1"] = "Superhard " .. MOS.as_string(mos)
default_comments["1/0"] = "Collapsed " .. MOS.as_string(mos)
-- Get comments
-- Comments are entered as a pair consisting of a step ratio and comment, separated by a colon
-- p/q: comment text as a string, and [[links]] can be added too
-- Each entry is then entered as a semicolon-delimtied list
local comments_unparsed = frame.args["Comments"] or ""
local comments = p.parse_kv_pairs(comments_unparsed) or {}
-- Table headers
-- There are 6 columns:
-- - Steps of ED
-- - Bright and dark gens in cents
-- - Step ratio and hardness
-- - Comments
result = '{| class="wikitable"\n'
result = result .. '|+\n'
result = result .. '! rowspan="2" |Steps of ED\n'
result = result .. '! colspan="2" |Cents\n'
result = result .. '! colspan="2" |Step ratio\n'
result = result .. '! rowspan="2" |Comments\n'
result = result .. '|-\n'
result = result .. '!Bright gen\n'
result = result .. '!Dark gen\n'
result = result .. '!L:s\n'
result = result .. '!Hardness\n'
-- Table rows
local i = 1
while i <= #step_ratios do
local step_ratio = step_ratios[i]
local et = ET.new(step_ratio[1] * L + step_ratio[2] * s, equave)
local generator_steps = step_ratio[1] * collapsed_bright_steps + step_ratio[2] * (equalized_bright_steps - collapsed_bright_steps)
-- Calculate dark generator step count and cent value
local dark_generator_steps = step_ratio[1] * L + step_ratio[2] * s - generator_steps
local dark_generator_cents = ET.cents(et, dark_generator_steps)
-- Entry of comments is done using an associative array, as entries may be sparse
-- If a default comment exists, it goes first and the custom comment is added on a newline in the cell itself
-- Old code commented out
--local comments = frame.args[("comment_" .. step_ratio[1] .. "_" .. step_ratio[2])] or ""
local key = step_ratios[i][1] .. "/" .. step_ratios[i][2] -- The step ratio is (literally and figuratively) the key to add comments!
local comment = ""
local contains_default_comment = default_comments[key] ~= nil
local contains_custom_comment = comments[key] ~= nil
if contains_default_comment and contains_custom_comment then
comment = comment .. default_comments[key] .. "<br>" .. comments[key]
elseif contains_default_comment and not contains_custom_comment then
comment = comment .. default_comments[key]
elseif not contains_default_comment and contains_custom_comment then
comment = comment .. comments[key]
end
local l_s = "→ ∞"
if not (step_ratio[1] == 1 and step_ratio[2] == 0) then
l_s = u._round_dec(step_ratio[1] / step_ratio[2], 3)
end
-- Row's cells
result = result .. "|-\n"
-- Steps in ET
result = result .. "|[[" .. ET.as_string(et) .. "|" .. generator_steps .. ET.backslash_modifier(et) .. "]]\n"
-- Bright generator in cents
result = result .. "|" .. u._round_dec(math.log(rat.as_float(et.equave)^(generator_steps / et.size))/math.log(2) * 1200, 3) .. "\n"
-- Dark generator in cents
result = result .. "|" .. u._round_dec(dark_generator_cents, 3) .. "\n" -- Round to 3 places
-- Step ratio and hardness value
result = result .. "|" .. step_ratio[1] .. ":" .. step_ratio[2] .. "\n"
result = result .. "|" .. l_s .. "\n"
-- Comment
result = result .. "|" .. comment .. "\n"
i = i + 1
end
result = result .. "|}"
return result
end
return p