Module:Infobox interval: Difference between revisions

From Xenharmonic Wiki
Jump to navigation Jump to search
Undo revision 184879 by ArrowHead294 (talk). The debug mode is used in several places on the wiki where categories should be disabled
Tag: Undo
Squib (talk | contribs)
m maybe i should discuss this before editing a template lol.
Tags: Undo Mobile edit Mobile web edit Advanced mobile edit
 
(6 intermediate revisions by 5 users not shown)
Line 1: Line 1:
local p = {}
local p = {}
local he = require("Module:Harmonic entropy")
local infobox = require("Module:Infobox")
local rat = require("Module:Rational")
local rat = require("Module:Rational")
local utils = require("Module:Utils")
local utils = require("Module:Utils")
local he = require("Module:Harmonic entropy")
local infobox = require("Module:Infobox")
local yesno = require("Module:Yesno")
local yesno = require("Module:Yesno")


Line 111: Line 111:
end
end
if rat.is_harmonic(ratio) then
if rat.is_harmonic(ratio) then
num, den = rat.as_pair (ratio)
table.insert(special_properties, "[[harmonic]]")
table.insert(special_properties, "[[harmonic]]")
num, den = rat.as_pair (ratio)
cats = cats .. "[[Category:Harmonics|" .. string.rep("#", string.len(num)) .. "]]"
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, "[[Harmonic|reduced harmonic]]")
table.insert(special_properties, "[[Harmonic|reduced harmonic]]")
Line 144: Line 152:
-- there was a subsequence of 4+ zeros
-- there was a subsequence of 4+ zeros
table.insert(infobox_data, {
table.insert(infobox_data, {
"[[Smonzos and svals|Subgroup monzo]]",
"[[Subgroup monzos and vals|Subgroup monzo]]",
rat.as_subgroup_ket(ratio, frame),
rat.as_subgroup_ket(ratio, frame),
})
})
Line 193: Line 201:
name = name:gsub(",%s+", ",")
name = name:gsub(",%s+", ",")
-- placing line breaks after commas
-- placing line breaks after commas
name = name:gsub(",", ",<br />")
name = name:gsub(",", ",<br>")
end
end
table.insert(infobox_data, {
table.insert(infobox_data, {
Line 210: Line 218:
if value_provided(colour_name) then
if value_provided(colour_name) then
table.insert(infobox_data, {
table.insert(infobox_data, {
"[[Color notation|Color name]]",
"[[Kite's color notation|Color name]]",
colour_name,
colour_name,
})
})
Line 250: Line 258:
table.insert(infobox_data, {
table.insert(infobox_data, {
"Special properties",
"Special properties",
table.concat(special_properties, ",<br />"),
table.concat(special_properties, ",<br>"),
})
})
end
end
Line 257: Line 265:
if rational and regular then
if rational and regular then
table.insert(infobox_data, {
table.insert(infobox_data, {
"[[Tenney height]] (log<sub>2</sub> ''nd'')",
"[[Tenney norm]] (log<sub>2</sub> ''nd'')",
utils._round(rat.tenney_height(ratio), 6),
utils._round(rat.tenney_height(ratio), 6),
})
})
table.insert(infobox_data, {
table.insert(infobox_data, {
"[[Weil height]] (log<sub>2</sub> max(''n'', ''d''))",
"[[Weil norm]] (log<sub>2</sub> max(''n'', ''d''))",
utils._round(rat.weil_height(ratio), 6),
utils._round(rat.weil_height(ratio), 6),
})
})
table.insert(infobox_data, {
table.insert(infobox_data, {
"[[Wilson height]] (sopfr(''nd''))",
"[[Wilson norm]] (sopfr(''nd''))",
utils._round(rat.wilson_height(ratio), 6),
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]]<br />(Shannon, <math>\\sqrt{nd}</math>)",
harmonic_entropy_switch = harmonic_entropy:match("^[Yy][Ee][Ss]$")
"~" .. utils._round(he.harmonic_entropy(cents), 6) .. " bits",
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


Line 306: 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 = "[[Square superparticular|S-expression]]"
local caption = "[[S-expression]]"
if #S_expressions > 1 then
if #S_expressions > 1 then
caption = caption .. "s"
caption = caption .. "s"
Line 312: Line 324:
table.insert(infobox_data, {
table.insert(infobox_data, {
caption,
caption,
table.concat(S_expressions, ",<br />"),
table.concat(S_expressions, ",<br>"),
})
})
end
end
Line 321: Line 333:
cats = cats .. "[[Category:Pages with internal sound examples]]"
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>",
"[[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
elseif debug_mode and debug_mode ~= "hide" and regular then

Latest revision as of 17:49, 14 September 2025

Module documentation[view] [edit] [history] [purge]
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 
Functions provided (1)
Line Function Params
13 infobox_interval (invokable) (frame)
Lua modules required (5)
Variable Module Functions used
he Module:Harmonic entropy harmonic_entropy
infobox Module:Infobox build
rat Module:Rational parse
cents
as_ket
as_ratio
from_ket
eq
max_prime
is_superparticular
is_square_superparticular
is_reduced
is_harmonic
as_pair
is_prime
is_highly_composite
is_subharmonic
as_subgroup_ket
factorisation
as_FJS
tenney_height
weil_height
wilson_height
is_power
find_S_expression
utils Module:Utils _round
yesno Module:Yesno yesno

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| ?&nbsp;]]</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&nbsp;information</u>", infobox_data)
	
	if not debug_mode then
		result = result .. cats
	end
	
	return frame:preprocess(result)
end

return p