Module:Infobox MOS: Difference between revisions

Ganaram inukshuk (talk | contribs)
update to new function names in module:mos
ArrowHead294 (talk | contribs)
m No need to use NBSP on ones that aren't displayed
 
(17 intermediate revisions by 2 users not shown)
Line 1: Line 1:
local p = {}
local p = {}
local rat = require("Module:Rational")
 
local mos = require("Module:MOS")
local getArgs = require("Module:Arguments").getArgs
local xp = require("Module:Xenpaper")
local ib = require("Module:Infobox")
local ib = require("Module:Infobox")
local kbvis = require("Module:Keyboard vis")
local kbvis = require("Module:Keyboard vis")
local mos = require("Module:MOS")
local tamnams = require("Module:TAMNAMS")
local tip = require("Module:Template input parse")
local tip = require("Module:Template input parse")
local tamnams = require("Module:TAMNAMS")
local xp = require("Module:Xenpaper")
local yesno = require("Module:Yesno")
local yesno = require("Module:Yesno")
local getArgs = require("Module:Arguments").getArgs
 
-- TODO: REWRITE. REFACTOR. AGAIN.
 
-- TODO: bugfix tamnams lookup breaking for mosses with 5 steps or less; interim
-- fix currently implemented shows smaller mosses as descending from itself.


-- Helper function
-- Helper function
Line 18: Line 23:
t1[#t1 + 1] = t2[i]
t1[#t1 + 1] = t2[i]
end
end
end
-- Helper function
-- Annotates a section header with the equave as superscript text.
function p.annotate_section_header(input_mos, section_header)
local et_suffix = mos.et_suffix(input_mos)
return (et_suffix == "edo"
and string.format('<div style=\"margin-top: 0.6em;\"><b>%s</b></div>', section_header)
or  string.format('<div style=\"margin-top: 0.6em;\"><b>%s</b><sup><abbr title=\"In steps of %s\">(%s)</sup></div>', section_header, et_suffix, et_suffix)
)
end
end


Line 32: Line 47:
end
end
return {{vis}}
return {{["Header"] = vis}}
end
end


Line 38: Line 53:
-- Adds categories
-- Adds categories
function p.categorize(input_mos)
function p.categorize(input_mos)
local input_mos = input_mos or mos.new(5,2)
local input_mos = input_mos or mos.new(5, 2)
-- Add to category of abstact mosses
-- Add to category of abstact mosses
local categories = "[[Category:Abstract MOS patterns]]"
local categories = " [[Category:Abstract MOS patterns]]"
-- Add notecount category if the notecount is greater than 3
-- Add notecount category if the notecount is greater than 3
local notecount = input_mos.nL + input_mos.ns
local notecount = input_mos.nL + input_mos.ns
if notecount > 3 then
if notecount > 3 then
categories = categories .. string.format("[[Category:%d-tone scales]]", notecount)
categories = categories .. string.format(" [[Category:%d-tone scales]]", notecount)
end
end
-- If the mos is octave-equivalent, add appropriate tamnams-named categories
-- If the mos is octave-equivalent, add appropriate tamnams-named categories
-- Otherwise, add to nonoctave category
-- Otherwise, add to nonoctave category
if rat.eq(input_mos.equave, rat.new(2)) then
if mos.is_octave_equivalent(input_mos) then
-- Caveats:
-- Caveats:
-- - Only octave-equivalent mos names are used as categories.
-- - Only octave-equivalent mos names are used as categories.
Line 61: Line 76:
if tamnams_name ~= nil then
if tamnams_name ~= nil then
categories = categories .. string.format("[[Category:%s]]", tamnams_name)
categories = categories .. string.format(" [[Category:%s]]", tamnams_name)
end
end
else
else
categories = categories .. "[[Category:Nonoctave]]"
categories = categories .. " [[Category:Nonoctave]]"
end
end
Line 87: Line 102:
local adjacent_links = {
local adjacent_links = {
mos.is_valid(adjacent_mosses[1]) and string.format("[[%s|&#x2196;&nbsp;%s]]", mos.as_long_string(adjacent_mosses[1]), mos.as_string(adjacent_mosses[1]), true) or "",
mos.is_valid(adjacent_mosses[1]) and string.format("[[%s|&#x2196;&nbsp;%s]]", mos.as_long_string(adjacent_mosses[1], false), mos.as_string(adjacent_mosses[1]), true) or "",
mos.is_valid(adjacent_mosses[2]) and string.format("[[%s|&#x2191;&nbsp;%s]]", mos.as_long_string(adjacent_mosses[2]), mos.as_string(adjacent_mosses[2]), true) or "",
mos.is_valid(adjacent_mosses[2]) and string.format("[[%s|&#x2191;&nbsp;%s]]", mos.as_long_string(adjacent_mosses[2], false), mos.as_string(adjacent_mosses[2]), true) or "",
mos.is_valid(adjacent_mosses[3]) and string.format("[[%s|%s&nbsp;&#x2197;]]", mos.as_long_string(adjacent_mosses[3]), mos.as_string(adjacent_mosses[3]), true) or "",
mos.is_valid(adjacent_mosses[3]) and string.format("[[%s|%s&nbsp;&#x2197;]]", mos.as_long_string(adjacent_mosses[3], false), mos.as_string(adjacent_mosses[3]), true) or "",
mos.is_valid(adjacent_mosses[4]) and string.format("[[%s|&#x2190;&nbsp;%s]]", mos.as_long_string(adjacent_mosses[4]), mos.as_string(adjacent_mosses[4]), true) or "",
mos.is_valid(adjacent_mosses[4]) and string.format("[[%s|&#x2190;&nbsp;%s]]", mos.as_long_string(adjacent_mosses[4], false), mos.as_string(adjacent_mosses[4]), true) or "",
mos.is_valid(adjacent_mosses[5]) and string.format("[[%s|%s&nbsp;&#x2192;]]", mos.as_long_string(adjacent_mosses[5]), mos.as_string(adjacent_mosses[5]), true) or "",
mos.is_valid(adjacent_mosses[5]) and string.format("[[%s|%s&nbsp;&#x2192;]]", mos.as_long_string(adjacent_mosses[5], false), mos.as_string(adjacent_mosses[5]), true) or "",
mos.is_valid(adjacent_mosses[6]) and string.format("[[%s|&#x2199;&nbsp;%s]]", mos.as_long_string(adjacent_mosses[6]), mos.as_string(adjacent_mosses[6]), true) or "",
mos.is_valid(adjacent_mosses[6]) and string.format("[[%s|&#x2199;&nbsp;%s]]", mos.as_long_string(adjacent_mosses[6], false), mos.as_string(adjacent_mosses[6]), true) or "",
mos.is_valid(adjacent_mosses[7]) and string.format("[[%s|&#x2193;&nbsp;%s]]", mos.as_long_string(adjacent_mosses[7]), mos.as_string(adjacent_mosses[7]), true) or "",
mos.is_valid(adjacent_mosses[7]) and string.format("[[%s|&#x2193;&nbsp;%s]]", mos.as_long_string(adjacent_mosses[7], false), mos.as_string(adjacent_mosses[7]), true) or "",
mos.is_valid(adjacent_mosses[8]) and string.format("[[%s|%s&nbsp;&#x2198;]]", mos.as_long_string(adjacent_mosses[8]), mos.as_string(adjacent_mosses[8]), true) or ""
mos.is_valid(adjacent_mosses[8]) and string.format("[[%s|%s&nbsp;&#x2198;]]", mos.as_long_string(adjacent_mosses[8], false), mos.as_string(adjacent_mosses[8]), true) or ""
}
}
Line 100: Line 115:
end
end


-- TODO: Cleanup and adopt mos functions
-- Helper function
-- Helper function
-- Produces section entries for scale sturcture
-- Produces section entries for scale sturcture
Line 107: Line 123:
local input_mos = input_mos or mos.new(5, 2)
local input_mos = input_mos or mos.new(5, 2)
local equave_as_string = rat.as_ratio(input_mos.equave)
local equave_as_string = mos.equave_as_string(input_mos)
local equave_in_cents = rat.cents(input_mos.equave)
local equave_in_cents = mos.equave_to_cents(input_mos)
local number_of_periods = mos.period_count(input_mos)
local number_of_periods = mos.period_count(input_mos)
Line 119: Line 135:
local period_in_cents = equave_in_cents / number_of_periods
local period_in_cents = equave_in_cents / number_of_periods
local step_pattern = string.format("...%d steps...", input_mos.nL+input_mos.ns)
local step_pattern = string.format("...%d steps...", input_mos.nL + input_mos.ns)
if input_mos.nL + input_mos.ns <= 40 then
if input_mos.nL + input_mos.ns <= 40 then
local brightest_mode = mos.brightest_mode(input_mos)
local brightest_mode = mos.brightest_mode(input_mos)
Line 127: Line 143:
local section_header = "Scale structure"
local section_header = "Scale structure"
local section_entries = {
local section_entries = {
{string.format("<div style=\"margin-top: 0.6em;\"><b>%s</b></div>", section_header)},
{ ["Header"] = string.format("<div style=\"margin-top: 0.6em;\"><b>%s</b></div>", section_header)},
{"[[Step pattern]]", step_pattern},
{ ["Header"] = "[[Step pattern]]", ["Data"] = step_pattern},
{"[[Equave]]", string.format("%s (%.1f{{c}})", equave_as_string, equave_in_cents)},
{ ["Header"] = "[[Equave]]"     , ["Data"] = string.format("%s (%.1f{{c}})", equave_as_string, equave_in_cents) },
{"[[Period]]", string.format("%s (%.1f{{c}})", period_as_string, period_in_cents)}
{ ["Header"] = "[[Period]]"     , ["Data"] = string.format("%s (%.1f{{c}})", period_as_string, period_in_cents) }
}
}


Line 153: Line 169:
local dark_max_in_cents = mos.dark_gen_to_cents(input_mos, {1, 1})
local dark_max_in_cents = mos.dark_gen_to_cents(input_mos, {1, 1})
local section_header = "Generator size"
local section_header = p.annotate_section_header(input_mos, "Generator size")
local et_suffix = mos.et_suffix(input_mos)
local section_header = (et_suffix == "edo"
and string.format('<div style=\"margin-top: 0.6em;\"><b>Generator size</b></div>')
or  string.format('<div style=\"margin-top: 0.6em;\"><b>Generator size</b><sup><abbr title=\"In steps of %s\">(%s)</sup></div>', et_suffix, et_suffix))
local section_entries = {
local section_entries = {
{section_header},
{ ["Header"] = section_header},
{"[[Bright]]", string.format("%s to %s (%.1f{{c}} to %.1f{{c}})", bright_min_in_steps, bright_max_in_steps, bright_min_in_cents, bright_max_in_cents)},
{ ["Header"] = "[[Bright]]", ["Data"] = string.format("%s to %s (%.1f{{c}} to %.1f{{c}})", bright_min_in_steps, bright_max_in_steps, bright_min_in_cents, bright_max_in_cents) },
{"[[Dark]]", string.format("%s to %s (%.1f{{c}} to %.1f{{c}})", dark_min_in_steps, dark_max_in_steps, dark_min_in_cents, dark_max_in_cents)},
{ ["Header"] = "[[Dark]]" , ["Data"] = string.format("%s to %s (%.1f{{c}} to %.1f{{c}})", dark_min_in_steps, dark_max_in_steps, dark_min_in_cents, dark_max_in_cents) },
}
}
Line 181: Line 192:
-- a larger array.
-- a larger array.
function p.tamnams_information(input_mos)
function p.tamnams_information(input_mos)
local input_mos = input_mos or mos.new(2, 5)
local input_mos = input_mos or mos.new(6,6,3)
local scalesig = string.format("%dL %ds", input_mos.nL, input_mos.ns)
local notecount = input_mos.nL + input_mos.ns
-- If a mos is octave-equivalent and has 10 or fewer steps, then it has a
local number_of_periods = mos.period_step_count(input_mos)
-- tamnams name/prefix/abbrev.
-- If a mos is octave-equivalent, has more than 10 steps, and is not a root
local tamnams_name   = tamnams.lookup_name  (input_mos)
-- mos nL ns, then:
local tamnams_prefix = tamnams.lookup_prefix(input_mos)
-- - If it has 5 periods or less, then its closest ancestor has a tamnams
local tamnams_abbrev = tamnams.lookup_abbrev(input_mos)
--  name.
-- - If it has more than 5 periods, then it relates to a root mos nL ns that
local is_octave_equivalent = rat.eq(input_mos.equave, 2)
--  has more than 10 steps (ancestor therefore has no tamnams name).
local is_within_named_range = tamnams_name ~= nil and notecount <= 10
-- If a mos is not octave-equivalent, then it may have a tamnams name (if
-- step count is 5 or less; currently unsupported) or not.
local is_octave_equivalent   = mos.is_octave_equivalent(input_mos)
local has_tamnams_name      = tamnams.lookup_name(input_mos) ~= nil
local is_within_named_range  = mos.step_count(input_mos) <= 10
local is_within_period_count = mos.period_count(input_mos) <= 5
local is_root_mos = input_mos.nL == input_mos.ns
local is_root_mos = input_mos.nL == input_mos.ns
local section_header = "TAMNAMS information"
local section_header = "TAMNAMS information"
local section_entries = nil
local section_entries = nil
if is_octave_equivalent then
if is_octave_equivalent and has_tamnams_name then
if is_within_named_range then
section_entries = {
-- Mos has a tamnams name
{ ["Header"] = string.format("<div style=\"margin-top: 0.6em;\"><b>%s</b></div>", section_header) },
section_entries = {
{ ["Header"] = "[[TAMNAMS#Mos_pattern_names | Name]]"   , ["Data"] = tamnams.lookup_name  (input_mos) },
{string.format("<div style=\"margin-top: 0.6em;\"><b>%s</b></div>", section_header)},
{ ["Header"] = "[[TAMNAMS#Mos_pattern_names | Prefix]]" , ["Data"] = tamnams.lookup_prefix(input_mos) .. "-" },
{"[[TAMNAMS#Mos_pattern_names | Name]]", tamnams_name},
{ ["Header"] = "[[TAMNAMS#Mos_pattern_names | Abbrev.]]" , ["Data"] = tamnams.lookup_abbrev(input_mos) }
{"[[TAMNAMS#Mos_pattern_names | Prefix]]", tamnams_prefix .. "-"},
}
{"[[TAMNAMS#Mos_pattern_names | Abbrev.]]", tamnams_abbrev}
elseif is_octave_equivalent and not has_tamnams_name and not is_root_mos and not is_within_named_range then
}
-- Lookup closest named ancestor mos
elseif not is_within_named_range and notecount > 10 and not is_root_mos then
local ancestor_mos, ratio_1, ratio_2, generations = tamnams.find_ancestor_info(input_mos)
-- Mos is a non-root mos and has a tamnams-named ancestor
local ancestor_mos, ratio_1, ratio_2, generations = tamnams.find_ancestor_info(input_mos)
-- Link to ancestor mos
local ancestor_scalesig = mos.as_string(ancestor_mos)
local ancestor_link = mos.as_link(ancestor_mos)
local ancestor_long_scalesig = mos.as_long_string(ancestor_mos)
local ancestor_name = tamnams.lookup_name(ancestor_mos)
-- Lookup step ratio range
local step_ratio_range = string.format("%s:%s to %s:%s", ratio_1[1], ratio_1[2], ratio_2[1], ratio_2[2])
-- Step ratio range as text
local range_name = tamnams.lookup_step_ratio_range(ratio_1, ratio_2)
local step_ratio_range = string.format("%s:%s to %s:%s", ratio_1[1], ratio_1[2], ratio_2[1], ratio_2[2])
local step_ratio_range_entry = range_name == nil and step_ratio_range or string.format("%s (%s)", step_ratio_range, range_name)
local range_name = tamnams.lookup_step_ratio_range(ratio_1, ratio_2)
local ancestor_name = tamnams.lookup_name(ancestor_mos)
local step_ratio_range_entry = range_name == nil and step_ratio_range or string.format("%s (%s)", step_ratio_range, range_name)
local ancestor_entry = ancestor_name == nil and ancestor_link or string.format("%s (%s)", ancestor_link, ancestor_name)
local ancestor_entry = string.format("[[%s | %s]]", ancestor_long_scalesig, ancestor_scalesig)
section_entries = {
if ancestor_name ~= nil then
{ ["Header"] = string.format("<div style=\"margin-top: 0.6em;\"><b>%s</b></div>", section_header) },
ancestor_entry = ancestor_entry .. string.format(" (%s)", ancestor_name)
{ ["Header"] = "Related to"  , ["Data"] = ancestor_entry },
end
{ ["Header"] = "With tunings", ["Data"] = step_ratio_range_entry }
}
section_entries = {
{string.format("<div style=\"margin-top: 0.6em;\"><b>%s</b></div>", section_header)},
{"Descends from", ancestor_entry};
{"Ancestor's step ratio range", string.format("%s", step_ratio_range_entry)}
}
end
end
end
Line 254: Line 263:
local section_entries = {
local section_entries = {
{string.format("<div style=\"margin-top: 0.6em;\"><b>%s</b></div>", section_header)},
{ ["Header"] = string.format("<div style=\"margin-top: 0.6em;\"><b>%s</b></div>", section_header)},
{"Name(s)", scale_names}
{ ["Header"] = "Name(s)", ["Data"] = scale_names}
}  
}  
return section_entries
return section_entries
Line 291: Line 300:
local section_header = "Related MOS scales"
local section_header = "Related MOS scales"
local section_entries = {
local section_entries = {
{string.format("<div style=\"margin-top: 0.6em;\"><b>%s</b></div>", section_header)},
{ ["Header"] = string.format("<div style=\"margin-top: 0.6em;\"><b>%s</b></div>", section_header)},
{"[[Operations_on_MOSes#Parent_MOS | Parent]]", parent_scalesig},
{ ["Header"] = "[[Operations_on_MOSes#Parent_MOS | Parent]]"         , ["Data"] = parent_scalesig },
{"[[Operations_on_MOSes#Sister_MOS | Sister]]", sister_scalesig},
{ ["Header"] = "[[Operations_on_MOSes#Sister_MOS | Sister]]"         , ["Data"] = sister_scalesig },
{"[[Operations_on_MOSes#Daughter_MOS | Daughters]]", soft_scalesig .. ", " .. hard_scalesig},
{ ["Header"] = "[[Operations_on_MOSes#Daughter_MOS | Daughters]]"   , ["Data"] = soft_scalesig .. ", " .. hard_scalesig },
{"[[Operations_on_MOSes#Neutralization | Neutralized]]", neutral_scalesig},
{ ["Header"] = "[[Operations_on_MOSes#Neutralization | Neutralized]]", ["Data"] = neutral_scalesig},
{"[[Flought_scale | 2-Flought]]", soft_flought_scalesig .. ", " .. hard_flought_scalesig}
{ ["Header"] = "[[Flought_scale | 2-Flought]]"                       , ["Data"] = soft_flought_scalesig .. ", " .. hard_flought_scalesig }
}
}
Line 306: Line 315:
-- Includes xenpaper links
-- Includes xenpaper links
function p.equal_tunings(input_mos)
function p.equal_tunings(input_mos)
local input_mos = input_mos or mos.new(5, 2, rat.new(5,3))
local input_mos = input_mos or mos.new(5, 2)
local bright_gen = mos.bright_gen(input_mos)
local bright_gen = mos.bright_gen(input_mos)
local step_ratios = {
local step_ratios = {
{ 1, 1 },
{ 1, 1 },
Line 322: Line 329:
}
}
local section_header = "Equal tunings"
local section_header = p.annotate_section_header(input_mos, "Equal tunings")
local equave_annotation = ""
local section_entries = {{ ["Header"] = section_header }}
if rat.eq(input_mos.equave, 3) then
equave_annotation = "<sup><abbr title=\"In steps of edt\">(edt)</sup>"
elseif rat.eq(input_mos.equave, rat.new(3,2)) then
equave_annotation = "<sup><abbr title=\"In steps of edf\">(edf)</sup>"
elseif not rat.eq(input_mos.equave, 2) then
local equave_as_ratio = rat.as_ratio(input_mos.equave)
equave_annotation = string.format("<sup><abbr title=\"In steps of ed%s\">(ed%s)</sup>", equave_as_ratio, equave_as_ratio)
end
local section_entries = {
{string.format("<div style=\"margin-top: 0.6em;\"><b>%s</b>%s</div>", section_header, equave_annotation)},
}
for i = 1, #step_ratios do
for i = 1, #step_ratios do
local step_ratio = step_ratios[i]
local step_ratio = step_ratios[i]
Line 351: Line 347:
local text = string.format("[[%s|%s]] (%.1f{{c}})", ed_as_string, gen_in_steps, gen_in_cents)
local text = string.format("[[%s|%s]] (%.1f{{c}})", ed_as_string, gen_in_steps, gen_in_cents)
table.insert(section_entries, { caption, text })
table.insert(section_entries, { ["Header"] = caption, ["Data"] = text })
end
end


Line 358: Line 354:


-- New "main" function
-- New "main" function
function p._infobox_mos(input_mos, other_names_unparsed)
function p._infobox_mos(input_mos)
local input_mos = input_mos or mos.new(4,5,3)
local input_mos = input_mos or mos.new(4, 5, 3)
local other_names_unparsed = other_names_unparsed or ""
local other_names_unparsed = ""
local other_names_parsed = tip.parse_entries(other_names_unparsed) or tip.parse_entries(other_names_unparsed, ",")
local other_names_parsed = tip.parse_entries(other_names_unparsed) or tip.parse_entries(other_names_unparsed, ",")
Line 409: Line 405:
["Title"] = mos.as_long_string(input_mos),
["Title"] = mos.as_long_string(input_mos),
["Rows"] = sections,
["Rows"] = sections,
["name"] = "Infobox MOS"
}
}
Line 424: Line 421:
local other_names = args["othernames"] or nil
local other_names = args["othernames"] or nil
local debug_mode = yesno(args["debug"], false)
local debug_mode = yesno(args["debug"], false)
local wtext = yesno(frame.args["wtext"] or args["wtext"])
local result = p._infobox_mos(input_mos, other_names)
local result = p._infobox_mos(input_mos)
if not debug_mode then
if not debug_mode then
result = result .. p.categorize(input_mos)
result = result .. p.categorize(input_mos)
end
if wtext then
result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>"
end
end