Module:Infobox MOS: Difference between revisions
Adopt getArgs, rename some params: Tuning -> Scale Signature (preferred); debug -> nocat (to fit current use of "debug" seen with other templates) |
ArrowHead294 (talk | contribs) m No need to use NBSP on ones that aren't displayed |
||
| (39 intermediate revisions by 3 users not shown) | |||
| Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
local getArgs = require("Module:Arguments").getArgs | |||
local | |||
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 | local xp = require("Module:Xenpaper") | ||
local yesno = require("Module:Yesno") | local yesno = require("Module:Yesno") | ||
-- 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 19: | 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 33: | Line 47: | ||
end | end | ||
return {{vis}} | return {{["Header"] = vis}} | ||
end | end | ||
-- Helper function | -- Helper function | ||
-- Adds categories | -- Adds categories | ||
function p.categorize( | function p.categorize(input_mos) | ||
local | 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 | 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 63: | 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 89: | Line 102: | ||
local adjacent_links = { | local adjacent_links = { | ||
mos. | mos.is_valid(adjacent_mosses[1]) and string.format("[[%s|↖ %s]]", mos.as_long_string(adjacent_mosses[1], false), mos.as_string(adjacent_mosses[1]), true) or "", | ||
mos. | mos.is_valid(adjacent_mosses[2]) and string.format("[[%s|↑ %s]]", mos.as_long_string(adjacent_mosses[2], false), mos.as_string(adjacent_mosses[2]), true) or "", | ||
mos. | mos.is_valid(adjacent_mosses[3]) and string.format("[[%s|%s ↗]]", mos.as_long_string(adjacent_mosses[3], false), mos.as_string(adjacent_mosses[3]), true) or "", | ||
mos. | mos.is_valid(adjacent_mosses[4]) and string.format("[[%s|← %s]]", mos.as_long_string(adjacent_mosses[4], false), mos.as_string(adjacent_mosses[4]), true) or "", | ||
mos. | mos.is_valid(adjacent_mosses[5]) and string.format("[[%s|%s →]]", mos.as_long_string(adjacent_mosses[5], false), mos.as_string(adjacent_mosses[5]), true) or "", | ||
mos. | mos.is_valid(adjacent_mosses[6]) and string.format("[[%s|↙ %s]]", mos.as_long_string(adjacent_mosses[6], false), mos.as_string(adjacent_mosses[6]), true) or "", | ||
mos. | mos.is_valid(adjacent_mosses[7]) and string.format("[[%s|↓ %s]]", mos.as_long_string(adjacent_mosses[7], false), mos.as_string(adjacent_mosses[7]), true) or "", | ||
mos. | mos.is_valid(adjacent_mosses[8]) and string.format("[[%s|%s ↘]]", mos.as_long_string(adjacent_mosses[8], false), mos.as_string(adjacent_mosses[8]), true) or "" | ||
} | } | ||
| Line 102: | 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 109: | 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 = | local equave_as_string = mos.equave_as_string(input_mos) | ||
local equave_in_cents = | 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 117: | Line 131: | ||
period_as_string = equave_as_string | period_as_string = equave_as_string | ||
else | else | ||
period_as_string = mos.reduced_period_to_et_string(input_mos, "") | |||
end | end | ||
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 130: | 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 144: | Line 157: | ||
-- a larger array. | -- a larger array. | ||
function p.generator_sizes(input_mos) | function p.generator_sizes(input_mos) | ||
local input_mos = input_mos or mos.new(5, 2) | local input_mos = input_mos or mos.new(5, 2,3) | ||
local | local bright_min_in_steps = mos.bright_gen_to_et_string(input_mos, {1, 1}, "") | ||
local bright_max_in_steps = mos.bright_gen_to_et_string(input_mos, {1, 0}, "") | |||
local dark_min_in_steps = mos.dark_gen_to_et_string (input_mos, {1, 0}, "") | |||
local dark_max_in_steps = mos.dark_gen_to_et_string (input_mos, {1, 1}, "") | |||
local | |||
local | |||
local dark_max_in_steps = | |||
local bright_min_in_cents = mos.bright_gen_to_cents(input_mos, {1, 1}) | local bright_min_in_cents = mos.bright_gen_to_cents(input_mos, {1, 1}) | ||
| Line 164: | 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 = | local section_header = p.annotate_section_header(input_mos, "Generator size") | ||
local section_entries = { | local section_entries = { | ||
{ | { ["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 197: | 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( | local input_mos = input_mos or mos.new(6,6,3) | ||
-- If a mos is octave-equivalent and has 10 or fewer steps, then it has a | |||
-- tamnams name/prefix/abbrev. | |||
-- If a mos is octave-equivalent, has more than 10 steps, and is not a root | |||
local | -- mos nL ns, then: | ||
local | -- - If it has 5 periods or less, then its closest ancestor has a tamnams | ||
local | -- name. | ||
-- - If it has more than 5 periods, then it relates to a root mos nL ns that | |||
local | -- has more than 10 steps (ancestor therefore has no tamnams name). | ||
-- 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 | ||
section_entries = { | |||
{ ["Header"] = string.format("<div style=\"margin-top: 0.6em;\"><b>%s</b></div>", section_header) }, | |||
{ ["Header"] = "[[TAMNAMS#Mos_pattern_names | Name]]" , ["Data"] = tamnams.lookup_name (input_mos) }, | |||
{ ["Header"] = "[[TAMNAMS#Mos_pattern_names | Prefix]]" , ["Data"] = tamnams.lookup_prefix(input_mos) .. "-" }, | |||
{ ["Header"] = "[[TAMNAMS#Mos_pattern_names | Abbrev.]]" , ["Data"] = tamnams.lookup_abbrev(input_mos) } | |||
} | |||
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 | |||
local ancestor_mos, ratio_1, ratio_2, generations = tamnams.find_ancestor_info(input_mos) | |||
-- Link to ancestor mos | |||
local ancestor_link = mos.as_link(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]) | |||
local range_name = tamnams.lookup_step_ratio_range(ratio_1, ratio_2) | |||
local step_ratio_range_entry = range_name == nil and step_ratio_range or string.format("%s (%s)", step_ratio_range, range_name) | |||
local ancestor_name = tamnams.lookup_name(ancestor_mos) | |||
local ancestor_entry = ancestor_name == nil and ancestor_link or string.format("%s (%s)", ancestor_link, ancestor_name) | |||
section_entries = { | |||
{ ["Header"] = string.format("<div style=\"margin-top: 0.6em;\"><b>%s</b></div>", section_header) }, | |||
{ ["Header"] = "Related to" , ["Data"] = ancestor_entry }, | |||
{ ["Header"] = "With tunings", ["Data"] = step_ratio_range_entry } | |||
} | |||
end | end | ||
| Line 270: | 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 284: | Line 277: | ||
local input_mos = input_mos or mos.new(5, 2) | local input_mos = input_mos or mos.new(5, 2) | ||
local parent_mos | -- Produce the mos's relatives | ||
local parent_mos, sister_mos, soft_child_mos, hard_child_mos, neutral_mos, soft_flought_mos, hard_flought_mos | |||
parent_mos = mos.parent(input_mos) | |||
sister_mos = mos.sister(input_mos) | |||
soft_child_mos, hard_child_mos = mos.children(input_mos) | |||
neutral_mos = mos.neutralized(input_mos) | |||
soft_flought_mos, hard_flought_mos = mos.interleaved(input_mos) | |||
-- Produce links to those relatives; parent and sister links have extra | |||
local | -- checks to make sure they're valid mosses: | ||
local | -- - If the input mos is a root mos (nL ns), then it has no parent | ||
local | -- - If the input mos is a root mos, then it's its own sister | ||
local is_nL_ns = input_mos.nL == input_mos.ns | |||
local | local parent_scalesig = is_nL_ns and "none" or mos.as_link(parent_mos) | ||
local | local sister_scalesig = is_nL_ns and (mos.as_string(input_mos) .. " (self)") or mos.as_link(sister_mos) | ||
local soft_scalesig = mos.as_link(soft_child_mos) | |||
local | local hard_scalesig = mos.as_link(hard_child_mos) | ||
local | local neutral_scalesig = mos.as_link(neutral_mos) | ||
local soft_flought_scalesig = mos.as_link(soft_flought_mos) | |||
local hard_flought_scalesig = mos.as_link(hard_flought_mos) | |||
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]]", | { ["Header"] = "[[Flought_scale | 2-Flought]]" , ["Data"] = soft_flought_scalesig .. ", " .. hard_flought_scalesig } | ||
} | } | ||
| Line 339: | 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 | 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 355: | Line 329: | ||
} | } | ||
local section_header = | local section_header = p.annotate_section_header(input_mos, "Equal tunings") | ||
local section_entries = {{ ["Header"] = section_header }} | |||
for i = 1, #step_ratios do | for i = 1, #step_ratios do | ||
local step_ratio = step_ratios[i] | local step_ratio = step_ratios[i] | ||
local | local ed_as_string = mos.et_string(input_mos, step_ratio) | ||
local gen_in_steps = mos. | local gen_in_steps = mos.bright_gen_to_et_string(input_mos, step_ratio, "") | ||
local gen_in_cents = mos.bright_gen_to_cents(input_mos, step_ratio) | local gen_in_cents = mos.bright_gen_to_cents(input_mos, step_ratio) | ||
| Line 385: | 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 392: | Line 354: | ||
-- New "main" function | -- New "main" function | ||
function p._infobox_mos( | function p._infobox_mos(input_mos) | ||
local | local input_mos = input_mos or mos.new(4, 5, 3) | ||
local other_names_unparsed = | 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 402: | Line 363: | ||
-- Keyboard visualization | -- Keyboard visualization | ||
local kb_vis = p.kb_vis( | local kb_vis = p.kb_vis(input_mos) | ||
p.concatenate_tables(sections, kb_vis) | p.concatenate_tables(sections, kb_vis) | ||
-- Scale structure section | -- Scale structure section | ||
local scale_structure = p.scale_structure( | local scale_structure = p.scale_structure(input_mos) | ||
p.concatenate_tables(sections, scale_structure) | p.concatenate_tables(sections, scale_structure) | ||
| Line 414: | Line 375: | ||
-- Generator sizes section | -- Generator sizes section | ||
local gen_sizes = p.generator_sizes( | local gen_sizes = p.generator_sizes(input_mos) | ||
p.concatenate_tables(sections, gen_sizes) | p.concatenate_tables(sections, gen_sizes) | ||
-- Tamnams info section, if applicable | -- Tamnams info section, if applicable | ||
local tamnams_info = p.tamnams_information( | local tamnams_info = p.tamnams_information(input_mos) | ||
if tamnams_info ~= nil then | if tamnams_info ~= nil then | ||
p.concatenate_tables(sections, tamnams_info) | p.concatenate_tables(sections, tamnams_info) | ||
| Line 430: | Line 391: | ||
-- Related scales section | -- Related scales section | ||
local related_scales = p.related_scales( | local related_scales = p.related_scales(input_mos) | ||
p.concatenate_tables(sections, related_scales) | p.concatenate_tables(sections, related_scales) | ||
-- Equal tunings section | -- Equal tunings section | ||
local equal_tunings = p.equal_tunings( | local equal_tunings = p.equal_tunings(input_mos) | ||
p.concatenate_tables(sections, equal_tunings) | p.concatenate_tables(sections, equal_tunings) | ||
-- Adjacent links | -- Adjacent links | ||
local adjacent_links = p.adjacent_links( | local adjacent_links = p.adjacent_links(input_mos) | ||
local args = { | local args = { | ||
["Adjacent Links"] = adjacent_links, | ["Adjacent Links"] = adjacent_links, | ||
["Title"] = | ["Title"] = mos.as_long_string(input_mos), | ||
["Rows"] = sections, | ["Rows"] = sections, | ||
["name"] = "Infobox MOS" | |||
} | } | ||
| Line 454: | Line 416: | ||
local args = getArgs(frame) | local args = getArgs(frame) | ||
local | -- "Scale Signature" is preferred; "Tuning" is supported for legacy purposes | ||
local other_names = | local unparsed = args["Tuning"] or args["Scale Signature"] | ||
local debug_mode = yesno( | local input_mos = mos.parse(unparsed) | ||
local other_names = args["othernames"] or nil | |||
local debug_mode = yesno(args["debug"], false) | |||
local wtext = yesno(frame.args["wtext"] or args["wtext"]) | |||
local result = p._infobox_mos( | local result = p._infobox_mos(input_mos) | ||
if not debug_mode then | if not debug_mode then | ||
result = result .. p.categorize( | result = result .. p.categorize(input_mos) | ||
end | |||
if wtext then | |||
result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>" | |||
end | end | ||