Module:Infobox interval: Difference between revisions
Jump to navigation
Jump to search
Move the "p-limit" category to "p-limit intervals" |
m maybe i should discuss this before editing a template lol. Tags: Undo Mobile edit Mobile web edit Advanced mobile edit |
||
| (42 intermediate revisions by 8 users not shown) | |||
| Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
local | local he = require("Module:Harmonic entropy") | ||
local | local infobox = require("Module:Infobox") | ||
local | local rat = require("Module:Rational") | ||
local | local utils = require("Module:Utils") | ||
local | local yesno = require("Module:Yesno") | ||
-- check whether the input is a non-empty string | -- check whether the input is a non-empty string | ||
local function value_provided(s) | local function value_provided(s) | ||
return type(s) == | return type(s) == "string" and #s > 0 | ||
end | end | ||
function p.infobox_interval(frame) | |||
local debug_mode = yesno(frame.args["debug"]) | |||
local | |||
local page_name = frame:preprocess("{{PAGENAME}}") | |||
local rational = false | local rational = false | ||
local small = false -- numerator and denominator can be represented as Lua numbers, or irrational | local small = false -- numerator and denominator can be represented as Lua numbers, or irrational | ||
local regular = false -- finite and greater than zero | local regular = false -- finite and greater than zero | ||
local ratio = nil | local ratio = nil | ||
local cents = nil | local cents = nil | ||
local ket = nil | local ket = nil | ||
local ratio_string = nil | local ratio_string = nil | ||
local infobox_data = {} | local infobox_data = {} | ||
local cats = | local cats = "" | ||
-- intervals with relatively small powers | -- intervals with relatively small powers | ||
if value_provided(frame.args[ | if value_provided(frame.args["Ratio"]) then | ||
ratio = rat.parse(frame.args[ | ratio = rat.parse(frame.args["Ratio"]) | ||
if ratio ~= nil then | if ratio ~= nil then | ||
rational = true | rational = true | ||
| Line 46: | Line 40: | ||
end | end | ||
end | end | ||
-- intervals with large powers | -- intervals with large powers | ||
if ratio == nil and value_provided(frame.args[ | if ratio == nil and value_provided(frame.args["Ket"]) then | ||
ratio = rat.from_ket(frame.args[ | ratio = rat.from_ket(frame.args["Ket"]) | ||
if ratio ~= nil then | if ratio ~= nil then | ||
rational = true | rational = true | ||
| Line 56: | Line 50: | ||
cents = rat.cents(ratio) | cents = rat.cents(ratio) | ||
ket = rat.as_ket(ratio, frame) | ket = rat.as_ket(ratio, frame) | ||
-- display Ratio unless it is page name, in which case it is probably a fallback | -- display Ratio unless it is page name, in which case it is probably a fallback -- what does this mean? | ||
if frame.args[ | if frame.args["Ratio"] ~= page_name then | ||
ratio_string = frame.args[ | ratio_string = frame.args["Ratio"] or "" | ||
end | end | ||
end | end | ||
elseif ratio ~= nil and value_provided(frame.args[ | elseif ratio ~= nil and value_provided(frame.args["Ket"]) then | ||
cats = cats .. | cats = cats .. "[[Category:Todo:remove explicit ket notation]]" | ||
end | end | ||
-- irrational intervals | -- irrational intervals | ||
if ratio == nil and value_provided(frame.args[ | if ratio == nil and value_provided(frame.args["Cents"]) then | ||
cents = tonumber(frame.args[ | cents = tonumber(frame.args["Cents"]) | ||
if cents ~= nil then | if cents ~= nil then | ||
rational = false | rational = false | ||
small = true | small = true | ||
regular = true | regular = true | ||
if value_provided(frame.args[ | if value_provided(frame.args["Ket"]) then | ||
ket = frame.args[ | ket = frame.args["Ket"] | ||
end | end | ||
-- Ratio is LaTeX unless it is page name, in which case it is probably a fallback | -- Ratio is LaTeX unless it is page name, in which case it is probably a fallback -- what does this mean? | ||
if frame.args[ | if frame.args["Ratio"] ~= page_name then | ||
ratio_string = frame.args[ | ratio_string = frame.args["Ratio"] or "" | ||
else | else | ||
cats = cats .. | cats = cats .. "[[Category:Todo:add interval ratio]]" | ||
end | end | ||
end | end | ||
elseif ratio ~= nil and value_provided(frame.args[ | elseif ratio ~= nil and value_provided(frame.args["Cents"]) then | ||
cats = cats .. | cats = cats .. "[[Category:Todo:remove explicit cents]]" | ||
end | end | ||
if not (regular or rational) then | if not (regular or rational) then | ||
cats = cats .. | cats = cats .. "[[Category:Todo:initialise interval]]" | ||
end | end | ||
-- categorize by rationality and prime limit | |||
if regular then | |||
if rational then | |||
local prime_limit = 2 | |||
if not rat.eq(ratio, 1) then | |||
prime_limit = rat.max_prime(ratio) | |||
end | |||
cats = cats .. "[[Category:Rational intervals]]" .. "[[Category:" .. prime_limit .. "-limit intervals]]" | |||
else | |||
cats = cats .. "[[Category:Irrational intervals]]" | |||
end | end | ||
end | end | ||
local special_properties = {} | local special_properties = {} | ||
if rational | if rational then | ||
if rat.is_superparticular(ratio) then | if small and rat.is_superparticular(ratio) then | ||
if rat.is_square_superparticular(ratio) then | if rat.is_square_superparticular(ratio) then | ||
table.insert(special_properties, | table.insert(special_properties, "[[Square superparticular|square superparticular]]") | ||
else | else | ||
table.insert(special_properties, | table.insert(special_properties, "[[Superparticular interval|superparticular]]") | ||
end | end | ||
cats = cats .. | cats = cats .. "[[Category:Superparticular ratios]]" | ||
end | end | ||
if rat.is_reduced(ratio, 2, not small) then | if rat.is_reduced(ratio, 2, not small) then | ||
table.insert(special_properties, | table.insert(special_properties, "[[Octave reduction|reduced]]") | ||
end | end | ||
if rat.is_harmonic(ratio) then | if rat.is_harmonic(ratio) then | ||
table.insert(special_properties, | num, den = rat.as_pair (ratio) | ||
cats = cats .. | table.insert(special_properties, "[[harmonic]]") | ||
cats = cats .. "[[Category:Harmonics|" .. string.rep("#", string.len(num)) .. "]]" | |||
if rat.is_prime(ratio) then | |||
table.insert(special_properties, "[[prime harmonic]]") | |||
cats = cats .. "[[Category:Prime harmonics|" .. string.rep("#", string.len(num)) .. "]]" | |||
end | |||
if rat.is_highly_composite(ratio) then | |||
table.insert(special_properties, "[[highly composite harmonic]]") | |||
cats = cats .. "[[Category:Highly composite harmonics|" .. string.rep("#", string.len(num)) .. "]]" | |||
end | |||
elseif rat.is_harmonic(ratio, true, not small) then | elseif rat.is_harmonic(ratio, true, not small) then | ||
table.insert(special_properties, | table.insert(special_properties, "[[Harmonic|reduced harmonic]]") | ||
cats = cats .. | cats = cats .. "[[Category:Octave-reduced harmonics]]" | ||
elseif rat.is_subharmonic(ratio, true, not small) then | elseif rat.is_subharmonic(ratio, true, not small) then | ||
table.insert(special_properties, | table.insert(special_properties, "[[Subharmonic|reduced subharmonic]]") | ||
cats = cats .. | cats = cats .. "[[Category:Octave-reduced subharmonics]]" | ||
end | end | ||
elseif regular then | elseif regular then | ||
if cents >= 0 and cents < 1200 then | if cents >= 0 and cents < 1200 then | ||
table.insert(special_properties, | table.insert(special_properties, "[[Octave reduction|reduced]]") | ||
end | end | ||
end | end | ||
if value_provided(ratio_string) then | if value_provided(ratio_string) then | ||
if rational then | if rational then | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"Ratio", | |||
ratio_string | ratio_string, | ||
}) | }) | ||
else | else | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"Expression", | |||
"<math>" .. ratio_string .. "</math>", | |||
}) | }) | ||
end | end | ||
end | end | ||
if regular and rational then | if regular and rational then | ||
if ket:match( | if ket:match("<sup>") then | ||
-- there was a subsequence of 4+ zeros | -- there was a subsequence of 4+ zeros | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"[[Subgroup monzos and vals|Subgroup monzo]]", | |||
rat.as_subgroup_ket(ratio, frame) | rat.as_subgroup_ket(ratio, frame), | ||
}) | }) | ||
else | else | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"Factorization", | |||
rat.factorisation(ratio) | rat.factorisation(ratio), | ||
}) | }) | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"[[Monzo]]", | |||
ket | ket, | ||
}) | }) | ||
end | end | ||
elseif rational then | elseif rational then | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"Factorization", | |||
rat.factorisation(ratio) | rat.factorisation(ratio), | ||
}) | }) | ||
elseif value_provided(ket) then | elseif value_provided(ket) then | ||
-- irrational ket is provided: | -- irrational ket is provided: | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"[[Monzo]]", | |||
frame:expandTemplate{ | frame:expandTemplate({ | ||
title = | title = "Monzo", | ||
args = {ket} | args = { ket }, | ||
} | }), | ||
}) | }) | ||
end | end | ||
if regular then | if regular then | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"Size in [[cent]]s", | |||
utils._round(cents, 7) .. "¢", | |||
}) | }) | ||
end | end | ||
local name = frame.args[ | local name = frame.args["Name"] | ||
if value_provided(name) then | if value_provided(name) then | ||
local caption = | local caption = "Name" | ||
if name:match( | if name:match(",") then | ||
caption = | caption = "Names" | ||
-- removing manual line breaks | -- removing manual line breaks | ||
local matches | local matches | ||
name, matches = name:gsub( | name, matches = name:gsub("<br%s*/?>", "") | ||
if matches > 0 then | if matches > 0 then | ||
cats = cats .. | cats = cats .. "[[Category:Todo:remove manual line breaks]]" | ||
end | end | ||
-- removing whitespaces after commas | -- removing whitespaces after commas | ||
name = name:gsub( | name = name:gsub(",%s+", ",") | ||
-- placing line breaks after commas | -- placing line breaks after commas | ||
name = name:gsub( | name = name:gsub(",", ",<br>") | ||
end | end | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
caption, | caption, | ||
name | name, | ||
}) | }) | ||
else | else | ||
cats = cats .. | cats = cats .. "[[Category:Todo:add interval name]]" | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"Name(s)", | |||
"<abbr title=\"missing value for parameter 'Name'\">''missing''</abbr><sup>[[Template:Infobox Interval| ? ]]</sup>", | |||
}) | }) | ||
end | end | ||
local colour_name = frame.args[ | local colour_name = frame.args["Color name"] | ||
if value_provided(colour_name) then | if value_provided(colour_name) then | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"[[Kite's color notation|Color name]]", | |||
colour_name | colour_name, | ||
}) | }) | ||
elseif regular and rational then | elseif regular and rational then | ||
cats = cats .. | cats = cats .. "[[Category:Todo:add color name]]" | ||
end | end | ||
local FJS_name = frame.args[ | local FJS_name = frame.args["FJS name"] | ||
if not value_provided(FJS_name) and rational and regular then | if not value_provided(FJS_name) and rational and regular then | ||
FJS_name = rat.as_FJS(ratio) | FJS_name = rat.as_FJS(ratio) | ||
elseif value_provided(FJS_name) then | elseif value_provided(FJS_name) then | ||
local matches | local matches | ||
FJS_name = FJS_name:gsub( | FJS_name = FJS_name:gsub("%s", "") | ||
FJS_name, matches = FJS_name:gsub( | FJS_name, matches = FJS_name:gsub("<br%s*/?>", "") | ||
if matches > 0 then | if matches > 0 then | ||
cats = cats .. | cats = cats .. "[[Category:Todo:remove manual line breaks]]" | ||
end | end | ||
FJS_name, matches = FJS_name:gsub( | FJS_name, matches = FJS_name:gsub("<sup>(.*)</sup>", "^{%1}") | ||
if matches > 0 then | if matches > 0 then | ||
cats = cats .. | cats = cats .. "[[Category:Todo:replace sup and sub with LaTeX]]" | ||
end | end | ||
FJS_name, matches = FJS_name:gsub( | FJS_name, matches = FJS_name:gsub("<sub>(.*)</sub>", "_{%1}") | ||
if matches > 0 then | if matches > 0 then | ||
cats = cats .. | cats = cats .. "[[Category:Todo:replace sup and sub with LaTeX]]" | ||
end | end | ||
end | end | ||
if value_provided(FJS_name) then | if value_provided(FJS_name) then | ||
FJS_name = FJS_name:gsub( | FJS_name = FJS_name:gsub("^(%w+)", "\\text{%1}") | ||
FJS_name = FJS_name:gsub( | FJS_name = FJS_name:gsub("(%-%d+)", "{%1}") | ||
if #FJS_name <= 200 then | if #FJS_name <= 200 then | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"[[Functional Just System|FJS name]]", | |||
"<math>" .. FJS_name .. "</math>", | |||
}) | }) | ||
end | end | ||
end | end | ||
if #special_properties > 0 then | if #special_properties > 0 then | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"Special properties", | |||
table.concat(special_properties, | table.concat(special_properties, ",<br>"), | ||
}) | }) | ||
end | end | ||
| Line 269: | Line 265: | ||
if rational and regular then | if rational and regular then | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"[[Tenney | "[[Tenney norm]] (log<sub>2</sub> ''nd'')", | ||
utils._round(rat.tenney_height(ratio), 6), | |||
}) | }) | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"[[Weil | "[[Weil norm]] (log<sub>2</sub> max(''n'', ''d''))", | ||
utils._round(rat.weil_height(ratio), 6), | |||
}) | }) | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"[[Wilson | "[[Wilson norm]] (sopfr(''nd''))", | ||
utils._round(rat.wilson_height(ratio), 6), | |||
}) | }) | ||
end | end | ||
if regular then | local harmonic_entropy = frame.args["Harmonic entropy"] | ||
table.insert(infobox_data, { | if regular and value_provided(harmonic_entropy) then | ||
harmonic_entropy_switch = harmonic_entropy:match("^[Yy][Ee][Ss]$") | |||
if harmonic_entropy_switch then | |||
table.insert(infobox_data, { | |||
"[[Harmonic entropy]]<br>(Shannon, <math>\\sqrt{nd}</math>)", | |||
"~" .. utils._round(he.harmonic_entropy(cents), 6) .. " bits", | |||
}) | |||
end | |||
end | end | ||
local is_comma = value_provided(frame.args[ | local is_comma = value_provided(frame.args["Comma"]) | ||
local comma = nil | local comma = nil | ||
if is_comma and regular and cents > 0 then | if is_comma and regular and cents > 0 then | ||
if rational and rat.is_power(ratio) then | -- rational powers are not considered commas | ||
if not (rational and rat.is_power(ratio)) then | |||
if cents <= 3.5 then | |||
comma = "[[Unnoticeable comma|unnoticeable]]" | |||
cats = cats .. "[[Category:Unnoticeable commas]]" | |||
elseif cents <= 30 then | |||
comma = "[[Small comma|small]]" | |||
cats = cats .. "[[Category:Small commas]]" | |||
elseif cents <= 100 then | |||
comma = "[[Medium comma|medium]]" | |||
cats = cats .. "[[Category:Medium commas]]" | |||
else | |||
comma = "[[Large comma|large]]" | |||
cats = cats .. "[[Category:Large commas]]" | |||
end | |||
end | end | ||
end | end | ||
if comma then | if comma then | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"[[Comma|Comma size]]", | |||
comma | comma, | ||
}) | }) | ||
end | end | ||
| Line 317: | Line 318: | ||
local S_expressions = rat.find_S_expression(ratio) | local S_expressions = rat.find_S_expression(ratio) | ||
if #S_expressions > 0 then | if #S_expressions > 0 then | ||
local caption = | local caption = "[[S-expression]]" | ||
if #S_expressions > 1 then | if #S_expressions > 1 then | ||
caption = caption .. | caption = caption .. "s" | ||
end | end | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
caption, | caption, | ||
table.concat(S_expressions, | table.concat(S_expressions, ",<br>"), | ||
}) | }) | ||
end | end | ||
end | end | ||
local sound = frame.args[ | local sound = frame.args["Sound"] | ||
if value_provided(sound) then | if value_provided(sound) then | ||
cats = cats .. | cats = cats .. "[[Category:Pages with internal sound examples]]" | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"[[File:" .. sound .. "|270px]]<br><span style=\"font-size: 75%;\">[[:File:" .. sound .. "|<nowiki>[sound info]</nowiki>]]</span>", | |||
}) | }) | ||
elseif debug_mode and debug_mode ~= | elseif debug_mode and debug_mode ~= "hide" and regular then | ||
local hz = 2 ^ (math.log(440)/math.log(2) + cents/1200) | local hz = 2 ^ (math.log(440) / math.log(2) + cents / 1200) | ||
-- is it within hearing range? | -- is it within hearing range? | ||
if hz >= 20 and hz <= 20000 then | if hz >= 20 and hz <= 20000 then | ||
local html_id = | local html_id = "interval_" .. tostring(math.floor(cents)) | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"<div style=\"display: flex; justify-content: space-around;\"><div style=\"width: 270px; text-align: center;\">" | |||
.. | .. frame:expandTemplate({ | ||
title = "User:Plumtree/Interval Sound", | |||
title = | args = { | ||
args = { Frequency=tostring(hz), Center= | Frequency = tostring(hz), | ||
} | Center = "true", | ||
.. | Label = "Audio demonstration", | ||
Attributes = "id=\"" .. html_id .. "\"", | |||
.. | }, | ||
}) | |||
.. "<div class=\"sequence-audio-timbre-selector\" data-target=\"" | |||
.. html_id | |||
.. "\" data-key=\"interval-audio\" data-default=\"semisine\"></div>" | |||
.. "</div></div>", | |||
}) | }) | ||
end | end | ||
end | end | ||
if value_provided(frame.args[ | if value_provided(frame.args["Calc"]) or (regular and rational) then | ||
local query = frame.args[ | local query = frame.args["Calc"] or "" | ||
if not value_provided(query) then | if not value_provided(query) then | ||
if small then | if small then | ||
query = ratio_string | query = ratio_string | ||
else | else | ||
query = | query = "|" .. rat.as_ket(ratio, nil, false, true) .. ">" | ||
end | end | ||
end | end | ||
query = mw.uri.encode(query) | query = mw.uri.encode(query) | ||
table.insert(infobox_data, { | table.insert(infobox_data, { | ||
"<span style=\"font-size: 75%;\">[https://www.yacavone.net/xen-calc/?q=" .. query .. " Open this interval in ''xen-calc'']</span>", | |||
}) | }) | ||
end | end | ||
local result = infobox.build("<u>Interval information</u>", infobox_data) | |||
if not debug_mode then | if not debug_mode then | ||
result = result .. cats | |||
end | end | ||
return | |||
return frame:preprocess(result) | |||
end | end | ||
return p | return p | ||
Latest revision as of 17:49, 14 September 2025
- This module should not be invoked directly; use its corresponding template instead: Template:Infobox interval.
This module generates an infobox providing information about a given interval.
| Introspection summary for Module:Infobox interval | |||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
| ||||||||||||||||||||||||
No function descriptions were provided. The Lua code may have further information.
local p = {}
local he = require("Module:Harmonic entropy")
local infobox = require("Module:Infobox")
local rat = require("Module:Rational")
local utils = require("Module:Utils")
local yesno = require("Module:Yesno")
-- check whether the input is a non-empty string
local function value_provided(s)
return type(s) == "string" and #s > 0
end
function p.infobox_interval(frame)
local debug_mode = yesno(frame.args["debug"])
local page_name = frame:preprocess("{{PAGENAME}}")
local rational = false
local small = false -- numerator and denominator can be represented as Lua numbers, or irrational
local regular = false -- finite and greater than zero
local ratio = nil
local cents = nil
local ket = nil
local ratio_string = nil
local infobox_data = {}
local cats = ""
-- intervals with relatively small powers
if value_provided(frame.args["Ratio"]) then
ratio = rat.parse(frame.args["Ratio"])
if ratio ~= nil then
rational = true
small = true
regular = not ratio.nan and not ratio.inf and not ratio.zero and ratio.sign > 0
cents = rat.cents(ratio)
ket = rat.as_ket(ratio, frame)
ratio_string = rat.as_ratio(ratio)
end
end
-- intervals with large powers
if ratio == nil and value_provided(frame.args["Ket"]) then
ratio = rat.from_ket(frame.args["Ket"])
if ratio ~= nil then
rational = true
small = false
regular = true
cents = rat.cents(ratio)
ket = rat.as_ket(ratio, frame)
-- display Ratio unless it is page name, in which case it is probably a fallback -- what does this mean?
if frame.args["Ratio"] ~= page_name then
ratio_string = frame.args["Ratio"] or ""
end
end
elseif ratio ~= nil and value_provided(frame.args["Ket"]) then
cats = cats .. "[[Category:Todo:remove explicit ket notation]]"
end
-- irrational intervals
if ratio == nil and value_provided(frame.args["Cents"]) then
cents = tonumber(frame.args["Cents"])
if cents ~= nil then
rational = false
small = true
regular = true
if value_provided(frame.args["Ket"]) then
ket = frame.args["Ket"]
end
-- Ratio is LaTeX unless it is page name, in which case it is probably a fallback -- what does this mean?
if frame.args["Ratio"] ~= page_name then
ratio_string = frame.args["Ratio"] or ""
else
cats = cats .. "[[Category:Todo:add interval ratio]]"
end
end
elseif ratio ~= nil and value_provided(frame.args["Cents"]) then
cats = cats .. "[[Category:Todo:remove explicit cents]]"
end
if not (regular or rational) then
cats = cats .. "[[Category:Todo:initialise interval]]"
end
-- categorize by rationality and prime limit
if regular then
if rational then
local prime_limit = 2
if not rat.eq(ratio, 1) then
prime_limit = rat.max_prime(ratio)
end
cats = cats .. "[[Category:Rational intervals]]" .. "[[Category:" .. prime_limit .. "-limit intervals]]"
else
cats = cats .. "[[Category:Irrational intervals]]"
end
end
local special_properties = {}
if rational then
if small and rat.is_superparticular(ratio) then
if rat.is_square_superparticular(ratio) then
table.insert(special_properties, "[[Square superparticular|square superparticular]]")
else
table.insert(special_properties, "[[Superparticular interval|superparticular]]")
end
cats = cats .. "[[Category:Superparticular ratios]]"
end
if rat.is_reduced(ratio, 2, not small) then
table.insert(special_properties, "[[Octave reduction|reduced]]")
end
if rat.is_harmonic(ratio) then
num, den = rat.as_pair (ratio)
table.insert(special_properties, "[[harmonic]]")
cats = cats .. "[[Category:Harmonics|" .. string.rep("#", string.len(num)) .. "]]"
if rat.is_prime(ratio) then
table.insert(special_properties, "[[prime harmonic]]")
cats = cats .. "[[Category:Prime harmonics|" .. string.rep("#", string.len(num)) .. "]]"
end
if rat.is_highly_composite(ratio) then
table.insert(special_properties, "[[highly composite harmonic]]")
cats = cats .. "[[Category:Highly composite harmonics|" .. string.rep("#", string.len(num)) .. "]]"
end
elseif rat.is_harmonic(ratio, true, not small) then
table.insert(special_properties, "[[Harmonic|reduced harmonic]]")
cats = cats .. "[[Category:Octave-reduced harmonics]]"
elseif rat.is_subharmonic(ratio, true, not small) then
table.insert(special_properties, "[[Subharmonic|reduced subharmonic]]")
cats = cats .. "[[Category:Octave-reduced subharmonics]]"
end
elseif regular then
if cents >= 0 and cents < 1200 then
table.insert(special_properties, "[[Octave reduction|reduced]]")
end
end
if value_provided(ratio_string) then
if rational then
table.insert(infobox_data, {
"Ratio",
ratio_string,
})
else
table.insert(infobox_data, {
"Expression",
"<math>" .. ratio_string .. "</math>",
})
end
end
if regular and rational then
if ket:match("<sup>") then
-- there was a subsequence of 4+ zeros
table.insert(infobox_data, {
"[[Subgroup monzos and vals|Subgroup monzo]]",
rat.as_subgroup_ket(ratio, frame),
})
else
table.insert(infobox_data, {
"Factorization",
rat.factorisation(ratio),
})
table.insert(infobox_data, {
"[[Monzo]]",
ket,
})
end
elseif rational then
table.insert(infobox_data, {
"Factorization",
rat.factorisation(ratio),
})
elseif value_provided(ket) then
-- irrational ket is provided:
table.insert(infobox_data, {
"[[Monzo]]",
frame:expandTemplate({
title = "Monzo",
args = { ket },
}),
})
end
if regular then
table.insert(infobox_data, {
"Size in [[cent]]s",
utils._round(cents, 7) .. "¢",
})
end
local name = frame.args["Name"]
if value_provided(name) then
local caption = "Name"
if name:match(",") then
caption = "Names"
-- removing manual line breaks
local matches
name, matches = name:gsub("<br%s*/?>", "")
if matches > 0 then
cats = cats .. "[[Category:Todo:remove manual line breaks]]"
end
-- removing whitespaces after commas
name = name:gsub(",%s+", ",")
-- placing line breaks after commas
name = name:gsub(",", ",<br>")
end
table.insert(infobox_data, {
caption,
name,
})
else
cats = cats .. "[[Category:Todo:add interval name]]"
table.insert(infobox_data, {
"Name(s)",
"<abbr title=\"missing value for parameter 'Name'\">''missing''</abbr><sup>[[Template:Infobox Interval| ? ]]</sup>",
})
end
local colour_name = frame.args["Color name"]
if value_provided(colour_name) then
table.insert(infobox_data, {
"[[Kite's color notation|Color name]]",
colour_name,
})
elseif regular and rational then
cats = cats .. "[[Category:Todo:add color name]]"
end
local FJS_name = frame.args["FJS name"]
if not value_provided(FJS_name) and rational and regular then
FJS_name = rat.as_FJS(ratio)
elseif value_provided(FJS_name) then
local matches
FJS_name = FJS_name:gsub("%s", "")
FJS_name, matches = FJS_name:gsub("<br%s*/?>", "")
if matches > 0 then
cats = cats .. "[[Category:Todo:remove manual line breaks]]"
end
FJS_name, matches = FJS_name:gsub("<sup>(.*)</sup>", "^{%1}")
if matches > 0 then
cats = cats .. "[[Category:Todo:replace sup and sub with LaTeX]]"
end
FJS_name, matches = FJS_name:gsub("<sub>(.*)</sub>", "_{%1}")
if matches > 0 then
cats = cats .. "[[Category:Todo:replace sup and sub with LaTeX]]"
end
end
if value_provided(FJS_name) then
FJS_name = FJS_name:gsub("^(%w+)", "\\text{%1}")
FJS_name = FJS_name:gsub("(%-%d+)", "{%1}")
if #FJS_name <= 200 then
table.insert(infobox_data, {
"[[Functional Just System|FJS name]]",
"<math>" .. FJS_name .. "</math>",
})
end
end
if #special_properties > 0 then
table.insert(infobox_data, {
"Special properties",
table.concat(special_properties, ",<br>"),
})
end
-- interval complexity
if rational and regular then
table.insert(infobox_data, {
"[[Tenney norm]] (log<sub>2</sub> ''nd'')",
utils._round(rat.tenney_height(ratio), 6),
})
table.insert(infobox_data, {
"[[Weil norm]] (log<sub>2</sub> max(''n'', ''d''))",
utils._round(rat.weil_height(ratio), 6),
})
table.insert(infobox_data, {
"[[Wilson norm]] (sopfr(''nd''))",
utils._round(rat.wilson_height(ratio), 6),
})
end
local harmonic_entropy = frame.args["Harmonic entropy"]
if regular and value_provided(harmonic_entropy) then
harmonic_entropy_switch = harmonic_entropy:match("^[Yy][Ee][Ss]$")
if harmonic_entropy_switch then
table.insert(infobox_data, {
"[[Harmonic entropy]]<br>(Shannon, <math>\\sqrt{nd}</math>)",
"~" .. utils._round(he.harmonic_entropy(cents), 6) .. " bits",
})
end
end
local is_comma = value_provided(frame.args["Comma"])
local comma = nil
if is_comma and regular and cents > 0 then
-- rational powers are not considered commas
if not (rational and rat.is_power(ratio)) then
if cents <= 3.5 then
comma = "[[Unnoticeable comma|unnoticeable]]"
cats = cats .. "[[Category:Unnoticeable commas]]"
elseif cents <= 30 then
comma = "[[Small comma|small]]"
cats = cats .. "[[Category:Small commas]]"
elseif cents <= 100 then
comma = "[[Medium comma|medium]]"
cats = cats .. "[[Category:Medium commas]]"
else
comma = "[[Large comma|large]]"
cats = cats .. "[[Category:Large commas]]"
end
end
end
if comma then
table.insert(infobox_data, {
"[[Comma|Comma size]]",
comma,
})
end
if comma and rational then
local S_expressions = rat.find_S_expression(ratio)
if #S_expressions > 0 then
local caption = "[[S-expression]]"
if #S_expressions > 1 then
caption = caption .. "s"
end
table.insert(infobox_data, {
caption,
table.concat(S_expressions, ",<br>"),
})
end
end
local sound = frame.args["Sound"]
if value_provided(sound) then
cats = cats .. "[[Category:Pages with internal sound examples]]"
table.insert(infobox_data, {
"[[File:" .. sound .. "|270px]]<br><span style=\"font-size: 75%;\">[[:File:" .. sound .. "|<nowiki>[sound info]</nowiki>]]</span>",
})
elseif debug_mode and debug_mode ~= "hide" and regular then
local hz = 2 ^ (math.log(440) / math.log(2) + cents / 1200)
-- is it within hearing range?
if hz >= 20 and hz <= 20000 then
local html_id = "interval_" .. tostring(math.floor(cents))
table.insert(infobox_data, {
"<div style=\"display: flex; justify-content: space-around;\"><div style=\"width: 270px; text-align: center;\">"
.. frame:expandTemplate({
title = "User:Plumtree/Interval Sound",
args = {
Frequency = tostring(hz),
Center = "true",
Label = "Audio demonstration",
Attributes = "id=\"" .. html_id .. "\"",
},
})
.. "<div class=\"sequence-audio-timbre-selector\" data-target=\""
.. html_id
.. "\" data-key=\"interval-audio\" data-default=\"semisine\"></div>"
.. "</div></div>",
})
end
end
if value_provided(frame.args["Calc"]) or (regular and rational) then
local query = frame.args["Calc"] or ""
if not value_provided(query) then
if small then
query = ratio_string
else
query = "|" .. rat.as_ket(ratio, nil, false, true) .. ">"
end
end
query = mw.uri.encode(query)
table.insert(infobox_data, {
"<span style=\"font-size: 75%;\">[https://www.yacavone.net/xen-calc/?q=" .. query .. " Open this interval in ''xen-calc'']</span>",
})
end
local result = infobox.build("<u>Interval information</u>", infobox_data)
if not debug_mode then
result = result .. cats
end
return frame:preprocess(result)
end
return p