Module:MOS tunings: Difference between revisions

Ganaram inukshuk (talk | contribs)
mNo edit summary
ArrowHead294 (talk | contribs)
mNo edit summary
 
(56 intermediate revisions by 2 users not shown)
Line 1: Line 1:
local p = {}
local et = require("Module:ET")
local jira = require("Module:JI ratios")
local mos = require("Module:MOS")
local mos = require("Module:MOS")
local tamnams = require("Module:TAMNAMS")
local tamnams = require("Module:TAMNAMS")
local et = require("Module:ET")
local tip = require("Module:Template input parse")
local yesno = require("Module:Yesno")
local yesno = require("Module:Yesno")
local tip = require("Module:Template input parse")
local jira = require("Module:JI ratios")
local p = {}


-- Rewritten/simplified module replacement for Module:MOS degrees
-- Rewritten/simplified module replacement for Module:MOS degrees
Line 12: Line 13:


-- TODO:
-- TODO:
-- - Bugfix collapsed tuning not showing any ratios
-- - Relegate JI ratio input to sorting entered ratios; this is to decouple
--  ratio search from ratio sorting/filtering.
-- - Diatonic interval category lookup?
-- - Diatonic interval category lookup?


Line 63: Line 65:
and step_ratios[2][1] == 2 and step_ratios[2][2] == 1
and step_ratios[2][1] == 2 and step_ratios[2][2] == 1
and step_ratios[3][1] == 3 and step_ratios[3][2] == 1 then
and step_ratios[3][1] == 3 and step_ratios[3][2] == 1 then
return "Simple Tunings", {{2,1}, {3,1}, {3,2}}
return "Simple Tunings", {{2, 1}, {3, 1}, {3, 2}}
end
end
end
end
Line 95: Line 97:


-- Preprocess step ratios
-- Preprocess step ratios
function p.preprocess_ji_ratios(input_mos, modal_union, step_ratios, ji_ratios)
function p.preprocess_ji_ratios(input_mos, modal_union, step_ratios, ji_ratios, tolerance)


-- Calculate the avegrage step ratio
-- Calculate the avegrage step ratio
Line 119: Line 121:
-- normalized to x:1.)
-- normalized to x:1.)
-- Tolerance is how many cents away from an et-step a ratio can be. This is
-- Tolerance is how many cents away from an et-step a ratio can be. This is
-- 30% of the small step size, and maxes out at 30 cents.
-- by default 30% of the small step size, and maxes out at 30 cent. Can be
-- overridden with a custom tolerance value.
local steps_in_et = input_mos.nL * avg_step_ratio[1] + input_mos.ns * avg_step_ratio[2]
local steps_in_et = input_mos.nL * avg_step_ratio[1] + input_mos.ns * avg_step_ratio[2]
local tolerance = math.min((mos.equave_to_cents(input_mos) / steps_in_et) * 0.30, 30)
local tolerance = tolerance or math.min((mos.equave_to_cents(input_mos) / steps_in_et) * 0.30, 30)
-- Calculate the cent values for each interval in the modal union
-- Calculate the cent values for each interval in the modal union
Line 135: Line 138:


-- Main function
-- Main function
function p._mos_tunings(input_mos, mos_prefix, mos_abbrev, step_ratios, ji_ratios)
function p._mos_tunings(input_mos, mos_prefix, mos_abbrev, step_ratios, ji_ratios, tolerance, footnotes, is_collapsed)
local input_mos = input_mos or mos.new(5,2)
local input_mos = input_mos or mos.new(5,2)
local mos_prefix = mos_prefix or "mos"
local mos_prefix = mos_prefix or "mos"
local mos_abbrev = mos_abbrev or "m"
local mos_abbrev = mos_abbrev or "m"
local step_ratios = step_ratios or {{2,1}, {3,1}, {3,2}}
local step_ratios = step_ratios or {{2, 1}, {3, 1}, {3, 2}}
local ji_ratios = ji_ratios or {}
local ji_ratios = ji_ratios or {}
local tolerance = tolerance or nil
local is_collapsed = is_collapsed == true
local footnotes = footnotes or "(footnotes here)"
-- Scalesig
-- Scalesig
Line 151: Line 157:
-- Preprocess JI ratios
-- Preprocess JI ratios
local modal_union = mos.modal_union(input_mos)
local modal_union = mos.modal_union(input_mos)
local sorted_ji_ratios, search_info = p.preprocess_ji_ratios(input_mos, modal_union, step_ratios, ji_ratios)
--local sorted_ji_ratios, search_info = p.preprocess_ji_ratios(input_mos, modal_union, step_ratios, ji_ratios, tolerance)
-- Create table
-- Create table
local result = "{| class=\"wikitable sortable right-all left-1 left-2\"\n"
local result = "{| class=\"wikitable sortable right-all left-1 left-2 mw-collapsible" .. (is_collapsed and " mw-collapsed\"\n" or "\"\n")
-- Table caption
-- Table caption
result = result .. string.format("|+ style=\"font-size: 105%%; white-space: nowrap;\" | %s of %s\n", step_ratio_range, scale_sig)
result = result .. "|+ style=\"font-size: 105%; white-space: nowrap;\" | " .. string.format("%s of %s\n", step_ratio_range, scale_sig)
.. "|-\n"
-- First row of headers
-- First row of headers
-- First two headers span two rows
-- First two headers span two rows
result = result .. "! rowspan=\"2\" class=\"unsortable\" | Scale degree\n"
result = result
result = result .. "! rowspan=\"2\" class=\"unsortable\" | Abbrev.\n"
.. "! rowspan=\"2\" class=\"unsortable\" | Scale degree\n"
.. "! rowspan=\"2\" class=\"unsortable\" | Abbrev.\n"
-- Headers for tunings; these span two cols
-- Headers for tunings; these span two cols
Line 173: Line 181:
end
end
local et_as_string = et.as_string(mos.mos_to_et(input_mos, step_ratios[i]))
local et_as_string = et.as_string(mos.as_et(input_mos, step_ratios[i]))
local header_text = string.format("%s<br>[[%s]]", step_ratio_as_text, et_as_string)
local header_text = string.format("%s<br />[[%s]]", step_ratio_as_text, et_as_string)
result = result .. string.format("! colspan=\"2\" | %s\n", header_text)
result = result .. string.format("! colspan=\"2\" | %s\n", header_text)
end
end
-- Headers for JI ratios; this spans two rows
-- Headers for JI ratios; this spans two rows
-- Commented out, pending rewrite
--[[
if #ji_ratios ~= 0 then
if #ji_ratios ~= 0 then
result = result .. "! rowspan=\"2\" class=\"unsortable\" | Approx.<br>Ratios\n"
result = result .. "! rowspan=\"2\" class=\"unsortable\" | Approx. ratios*\n"
end
end
]]--
result = result .. "|-\n"
result = result .. "|-\n"
-- Second row of headers
-- Second row of headers
for i = 1, #step_ratios do
for i = 1, #step_ratios do
result = result .. "! Steps\n"
result = result .. "! style=\"border-right: none;\" class=\"unsortable\" | Steps\n"
result = result .. "! Cents\n"
result = result .. "! style=\"border-left: none; text-align: right;\" | ¢\n"
end
end
Line 200: Line 211:
result = result
result = result
.. "|-\n"
.. "|-\n"
.. string.format("| %s || %s", degree_name, degree_abbrev)
.. string.format("| %s\n", degree_name)
.. string.format("| %s\n", degree_abbrev)
-- Add cells for each interval's tunings
-- Add cells for each interval's tunings
Line 209: Line 221:
result = result
result = result
.. " "
--.. string.format("\n| %s\\%s\n| %.1f", step_count, input_mos.nL * step_ratio[1] + input_mos.ns * step_ratio[2], cents)
.. string.format("|| %s\\%s || %.1f", step_count, input_mos.nL * step_ratio[1] + input_mos.ns * step_ratio[2], cents)
.. string.format("| style=\"border-right: none;\" | %s\\%s\n", step_count, input_mos.nL * step_ratio[1] + input_mos.ns * step_ratio[2])
.. string.format("| style=\"border-left: none;\" | %.1f\n", cents)
end
end
-- Add cells for JI ratios
-- Add cells for JI ratios
--[[
-- Commented out, pending rewrite
if #ji_ratios ~= 0 then
if #ji_ratios ~= 0 then
-- Ratios link to their respective pages, and are comma-delimited.
-- Ratios link to their respective pages, and are comma-delimited.
local ratios_as_text = jira.ratios_as_text(sorted_ji_ratios[i], true)
local ratios_as_text = jira.ratios_as_string(sorted_ji_ratios[i], true, ",&nbsp;")
result = result .. string.format("|| style=\"text-align: left\" | %s", ratios_as_text)
result = result .. "| style=\"text-align: left;\" | " .. string.format("%s\n", ratios_as_text)
end
end
]]--
result = result .. "\n"
end
end
-- End of table
-- End of table, plus footnotes
result = result .. "|}"
result = result .. "|}"
--[[
-- Commented out, pending rewrite
if #ji_ratios ~= 0 then
-- Make footnote text smaller than the rest of the text to avoid confusion with paragraph text
result = result .. string.format("<span style=\"font-size: 0.75em;\">&#42; %s</span>", footnotes)
end
]]--
return result
return result
Line 237: Line 259:
function p.parse_step_ratios(unparsed)
function p.parse_step_ratios(unparsed)
local parsed = {}
local parsed = {}
if unparsed == "" or unparsed == "Simple Tunings" then
parsed = {{2,1}, {3,1}, {3,2}} -- Default is the simple step ratios
local lookup_table = {
["Central Spectrum"] = {{4, 3}, {3, 2}, {5, 3}, {2, 1}, {5, 2}, {3, 1}, {4, 1}},
["Simple Tunings"]  = {{2, 1}, {3, 1}, {3, 2}},
["Soft-of-basic"]    = {{4, 3}, {3, 2}, {2, 1}},
["Ultrasoft"]        = {{6, 5}, {5, 4}, {4, 3}},
["Parasoft"] = {{4, 3}, {7, 5}, {3, 2}},
["Quasisoft"]        = {{3, 2}, {8, 5}, {5, 3}},
["Minisoft"]        = {{5, 3}, {7, 4}, {2, 1}},
["Hyposoft"]        = {{3, 2}, {5, 3}, {2, 1}},
["Hypohard"]        = {{2, 1}, {5, 2}, {3, 1}},
["Minihard"]        = {{2, 1}, {7, 3}, {5, 2}},
["Quasihard"]        = {{5, 2}, {8, 3}, {3, 1}},
["Parahard"]        = {{3, 1}, {7, 2}, {4, 1}},
["Ultrahard"]        = {{4, 1}, {5, 1}, {6, 1}},
["Hard-of-basic"]    = {{2, 1}, {3, 1}, {4, 1}},
}
if unparsed == "" then
parsed = lookup_table["Simple Tunings"]
elseif unparsed == "NONE" then
elseif unparsed == "NONE" then
parsed = {}
parsed = {}
elseif unparsed == "Central Spectrum" then
parsed = {{4,3}, {3,2}, {5,3}, {2,1}, {5,2}, {3,1}, {4,1}}
elseif unparsed == "Soft-of-basic" then
parsed = {{4,3}, {3,2}, {2,1}}
elseif unparsed == "Hyposoft" then
parsed = {{3,2}, {5,3}, {2,1}}
elseif unparsed == "Hypohard" then
parsed = {{2,1}, {5,2}, {3,1}}
elseif unparsed == "Hard-of-basic" then
parsed = {{2,1}, {3,1}, {4,1}}
else
else
parsed = tip.parse_numeric_pairs(unparsed)
parsed = lookup_table[unparsed] or tip.parse_numeric_pairs(unparsed)
end
end
return parsed
return parsed
Line 260: Line 290:
-- If the unparsed string corresponds to a list of JI ratios ("a/b; c/d; e/f"),
-- If the unparsed string corresponds to a list of JI ratios ("a/b; c/d; e/f"),
-- then parse it as a list of ratios. If it's not that, parse it as search
-- then parse it as a list of ratios. If it's not that, parse it as search
-- params. If the text is "NONE", then there should be no ratios passed in.
-- args. If the text is "NONE", then there should be no ratios passed in.
-- If the unparsed string is an empty string, return nil. (This is so the
-- If the unparsed string is an empty string, return nil. (This is so the
-- wrapper function can go by default search params.)
-- wrapper function can go by default search args.)
function p.parse_ji_ratios(unparsed, equave_in_cents)
function p.parse_ji_ratios(unparsed, equave)
local ratios = nil
local ratios = nil
local params = nil
local search_args = nil
if unparsed == "" then
if unparsed == "" then
params = {["Int Limit"] = 30, ["Tenney Height"] = 9, ["Prime Limit"] = 13}
search_args = {["Int Limit"] = 50, ["Tenney Height"] = 8; ["Complements Only"] = true} -- Defualt search args if no args were passed in
ratios = jira.search_by_params(params, equave_in_cents) -- Default search params, given no other params
ratios = jira.search_by_args_within_equave(equave, search_args)
elseif unparsed == "NONE" then
elseif unparsed == "NONE" then
params = {}
search_args = {}
ratios = {}
ratios = {}
elseif string.match(unparsed, "Int Limit:") then
elseif string.match(unparsed, "Int Limit:") then
params = jira.parse_search_params(unparsed) -- Search params require at the absolute least an int limit, so see if there's "Int Limit"
search_args = jira.parse_search_args(unparsed) -- Search requires at the absolute least an int limit, so see if there's "Int Limit"
ratios = jira.search_by_params(search_params, equave_in_cents)
ratios = jira.search_by_args_within_equave(equave, search_args)
else
else
search_args = {}
ratios = jira.parse_ratios(unparsed)
ratios = jira.parse_ratios(unparsed)
end
end
return ratios, params
return ratios, jira.search_footnotes(search_args)
end
end


Line 286: Line 317:
function p.mos_tunings(frame)
function p.mos_tunings(frame)
-- Get params
-- Get params
local scalesig   = frame.args["Scale Signature"]
local scalesig     = frame.args["Scale Signature"]
local input_mos = mos.parse(scalesig)
local input_mos   = mos.parse(scalesig)
local equave_in_cents = mos.equave_to_cents(input_mos)
local mos_prefix  = tamnams.verify_prefix(input_mos, frame.args["MOS Prefix"])
local mos_abbrev  = tamnams.verify_abbrev(input_mos, frame.args["MOS Abbrev"])
local is_collapsed = yesno(frame.args["Collapsed"], false)
local step_ratios  = p.parse_step_ratios(frame.args["Step Ratios"])
local tolerance    = tonumber(frame.args["Tolerance"])
local debugg      = yesno(frame.args["debug"])
local mos_prefix  = tamnams.verify_prefix(input_mos, frame.args["MOS Prefix"])
--local ji_ratios, footnotes = p.parse_ji_ratios(frame.args["JI Ratios"], input_mos.equave)
local mos_abbrev  = tamnams.verify_abbrev(input_mos, frame.args["MOS Abbrev"])
 
local collapsed  = yesno(frame.args["Collapsed"], false) -- Currently does nothing
local result = p._mos_tunings(input_mos, mos_prefix, mos_abbrev, step_ratios, ji_ratios, tolerance, footnotes, is_collapsed)
local step_ratios = p.parse_step_ratios(frame.args["Step Ratios"])
if debugg == true then
local ji_ratios, search_params = p.parse_ji_ratios(frame.args["JI Ratios"], equave_in_cents)
result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>"
end
local search_params_footnote = "<br><small>" .. jira.search_param_footnotes(search_params) .. "</small>"
return frame:preprocess(result)
 
return p._mos_tunings(input_mos, mos_prefix, mos_abbrev, step_ratios, ji_ratios) .. search_params_footnote
end
end


function p.tester()
function p.tester()
local range, ratios = p.preprocess_step_ratios({ {7,1}, {3,1}, {2,1} })
local range, ratios = p.preprocess_step_ratios({{7, 1}, {3, 1}, {2, 1}})
local input_mos = mos.parse("9L 4s<7/2>")
local input_mos = mos.parse("9L 4s<7/2>")