Module:Ups and downs sharpness

From Xenharmonic Wiki
Revision as of 23:21, 13 October 2025 by Tristanbay (talk | contribs) (Added Stein-Zimmerman accidental functionality)
Jump to navigation Jump to search
Module documentation[view] [edit] [history] [purge]
This module should not be invoked directly; use its corresponding template instead: Template:Ups and downs sharpness.

This module automatically creates a table with the combinations of symbols to notate a given edo using Kite's ups and downs notation.

Introspection summary for Module:Ups and downs sharpness 
Functions provided (1)
Line Function Params
9 ud_sharpness (invokable) (frame)
Lua modules required (2)
Variable Module Functions used
utils Module:Utils dependency not used
yesno Module:Yesno yesno

No function descriptions were provided. The Lua code may have further information.


local p = {}
local utils = require("Module:Utils")
local yesno = require("Module:Yesno")

local function sharp_n(edo) -- calculate amount of steps for sharp/flat
	return (7 * math.floor((edo * math.log(3) / math.log(2)) + 0.5)) - (11 * edo) -- mapping of augmented unison
end

function p.ud_sharpness(frame) -- generate table
	local edo = math.floor(frame.args["edo"])
	local sharp = sharp_n(edo)
	local use_sz -- whether to use Stein-Zimmerman accidentals or not
	local spanf = "| <div style=\"width: %sem; margin-bottom: -45px; transform:translate(0, %spx); white-space: nowrap;\">%s</div>\n"
	local cell_width -- forced cell width in ems
	
	local arrow_marg = -10
	local sharp_marg = -22.5
	local double_sharp_marg = -22.5
	local flat_marg = -20
	local double_flat_marg = -20
	local half_sharp_marg = -22.5
	local sesqui_sharp_marg = -22.5
	local half_flat_marg = -20
	local sesqui_flat_marg = -20
	
	local tab
	
	local up_t = "&#x202F;[[File:Up arrow petaluma script.svg|10px]]"
	local down_t = "&#x202F;[[File:Down arrow petaluma script.svg|10px]]"
	
	local quip_t = "&#x202F;[[File:Quip narrow.svg|9px]]"
	local quid_t = "&#x202F;[[File:Quid narrow.svg|9px]]"
	
	local natural_t = "&#x202F;&#x202F;[[File:Heji18.svg|16px]]"
	local sharp_t = "&#x202F;&#x202F;[[File:Heji25.svg|16px]]"
	local flat_t = "&#x202F;&#x202F;[[File:Heji11.svg|16px]]"
	
	local dsharp_t = "&#x202F;&#x202F;[[File:Heji32.svg|21px]]"
	local dflat_t = "&#x202F;&#x202F;[[File:Heji4.svg|27px]]"
	
	local hsharp_t = "&#x202F;&#x202F;[[File:HeQu1.svg|16px]]"
	local hflat_t = "&#x202F;&#x202F;[[File:HeQd1.svg|16px]]"
	
	local ssharp_t = "&#x202F;&#x202F;[[File:HeQu3.svg|16px]]"
	local sflat_t = "&#x202F;&#x202F;[[File:HeQd3.svg|16px]]"
	
	if frame.args["sz"] == "true" and sharp % 2 == 0 then -- use SZ accidentals?
		use_sz = true
		sharp = sharp * 2
	else
		use_sz = false
	end
	
	if sharp == -2 then
		tab = "{{sharpness-flat2}}"
	elseif sharp == -1 then
		tab = "{{sharpness-flat1}}"
	elseif sharp == 0 then
		tab = "<div style=\"overflow-x:auto\">\n{| class=\"wikitable center-all\"\n"
			.. "|-\n"
			.. "! Step offset\n"
			.. "| −3 || −2 || −1 || 0 || +1 || +2 || +3\n"
			.. "|-\n"
			.. "! Symbol\n"
			.. string.format(spanf, 2, arrow_marg, string.rep(down_t, 3))
			.. string.format(spanf, 2, arrow_marg, string.rep(down_t, 2))
			.. string.format(spanf, 2, arrow_marg, down_t)
			.. string.format(spanf, 2, arrow_marg - 15, natural_t)
			.. string.format(spanf, 2, arrow_marg, up_t)
			.. string.format(spanf, 2, arrow_marg, string.rep(up_t, 2))
			.. string.format(spanf, 2, arrow_marg, string.rep(up_t, 3))
			.. "|}\n</div>"
	elseif sharp == 1 then
		tab = "{{sharpness-sharp1}}"
	else
		if edo % 12 == 0 and edo <= 300 then -- does it temper out 531441/524288?
			tab = "<div style=\"overflow-x:auto\">\n{| class=\"wikitable center-all\"\n"
				.. "|-\n"
				.. "! Semitones\n"
				.. "| '''0'''"
			for i = 1, use_sz and (use_sz and sharp * 4 or sharp * 2) + 1 do
				tab = tab .. (i % sharp == 0 and string.format(" || '''%s'''", math.floor(i / sharp)) or string.format(" || {{Simplified fraction|%s|%s|true}}", i, sharp))
			end
		else
			tab = "<div style=\"overflow-x:auto\">\n{| class=\"wikitable center-all\"\n"
				.. "|-\n"
				.. "! Step offset\n"
				.. "| '''0'''"
			for i = 1, use_sz and (use_sz and sharp * 4 or sharp * 2) + 1 do
				tab = tab .. string.format((i % sharp == 0 and " || '''%s'''" or " || %s"), i)
			end
		end
		tab = tab .. "\n|-\n! Sharp symbol\n" -- sharp row
			.. "| rowspan=\"2\" style=\"white-space: nowrap; width: 3em;\" | " .. natural_t .. "\n"
		for i = 1, (use_sz and sharp * 4 or sharp * 2) + 1 do
			local cs = math.ceil((i / sharp) - 0.5) -- sharpness of note (treated differently depending on SZ or no SZ)
			local marg -- margin value for formatting
			local s = ""
			
			if cs == 0 then -- set vertical accidental margins
				marg = arrow_marg
				cell_width = 0
			elseif (cs == 1 and not use_sz) or (cs == 2 and use_sz) then
				marg = sharp_marg
				cell_width = 1.5
			elseif (cs == 2 and not use_sz) or (cs == 4 and use_sz) then
				marg = double_sharp_marg
				cell_width = 2.5
			elseif cs == 1 and use_sz then
				marg = half_sharp_marg
				cell_width = 1
			elseif cs == 3 and use_sz then
				marg = sesqui_sharp_marg
				cell_width = 2.5
			else
				marg = 0 -- failsafe
				cell_width = 1
			end
			
			if ((i - (sharp * math.floor(i / sharp))) / sharp) > math.ceil(((i - (sharp * math.floor(i / sharp))) / sharp) - 0.5) then
				if (i - (sharp * math.floor(i / sharp))) % 5 == 4 then
					s = s .. down_t .. quip_t
					cell_width = cell_width + 3
				else
					for j = 1, (i - (sharp * math.floor(i / sharp))) % 5 do
						s = s .. up_t
						cell_width = cell_width + 1.5
					end
				end
				for j = 1, math.floor((i - (sharp * math.floor(i / sharp))) / 5) do
					s = s .. quip_t
					cell_width = cell_width + 1.5
				end
			else
				if ((sharp * math.ceil(i / sharp)) - i) % 5 == 4 then
					s = s .. up_t .. quid_t
					cell_width = cell_width + 3
				else
					for j = 1, ((sharp * math.ceil(i / sharp)) - i) % 5 do
						s = s .. down_t
						cell_width = cell_width + 1.5
					end
				end
				for j = 1, math.floor(((sharp * math.ceil(i / sharp)) - i) / 5) do
					s = s .. quid_t
					cell_width = cell_width + 1.5
				end
			end
			if (cs == 1 and not use_sz) or (cs == 2 and use_sz) then
				s = s .. sharp_t
			elseif (cs == 2 and not use_sz) or (cs == 4 and use_sz) then
				s = s .. dsharp_t
			elseif use_sz then
				if cs == 1 then
					s = s .. hsharp_t
				elseif cs == 3 then
					s = s .. ssharp_t
				end
			end
			tab = tab .. string.format(spanf, cell_width, marg, s)
		end
		
		tab = tab .. "|-\n! Flat symbol\n" -- flat row
		
		for i = 1, (use_sz and sharp * 4 or sharp * 2) + 1 do
			local cs = math.ceil((i / sharp) - 0.5) -- flatness of note (treated differently depending on SZ or no SZ)
			local marg -- margin value for formatting
			local s = ""
			
			if cs == 0 then -- set vertical accidental margins
				marg = arrow_marg
				cell_width = 0
			elseif (cs == 1 and not use_sz) or (cs == 2 and use_sz) then
				marg = flat_marg
				cell_width = 1.5
			elseif (cs == 2 and not use_sz) or (cs == 4 and use_sz) then
				marg = double_flat_marg
				cell_width = 3
			elseif cs == 1 and use_sz then
				marg = half_flat_marg
				cell_width = 1.5
			elseif cs == 3 and use_sz then
				marg = sesqui_flat_marg
				cell_width = 3
			else
				marg = 0 -- failsafe
				cell_width = 1
			end
			
			if ((i - (sharp * math.floor(i / sharp))) / sharp) > math.ceil(((i - (sharp * math.floor(i / sharp))) / sharp) - 0.5) then
				if (i - (sharp * math.floor(i / sharp))) % 5 == 4 then
					s = s .. up_t .. quid_t
					cell_width = cell_width + 3
				else
					for j = 1, (i - (sharp * math.floor(i / sharp))) % 5 do
						s = s .. down_t
						cell_width = cell_width + 1.5
					end
				end
				for j = 1, math.floor((i - (sharp * math.floor(i / sharp))) / 5) do
					s = s .. quid_t
					cell_width = cell_width + 1.5
				end
			else
				if ((sharp * math.ceil(i / sharp)) - i) % 5 == 4 then
					s = s .. down_t .. quip_t
					cell_width = cell_width + 3
				else
					for j = 1, ((sharp * math.ceil(i / sharp)) - i) % 5 do
						s = s .. up_t
						cell_width = cell_width + 1.5
					end
				end
				for j = 1, math.floor(((sharp * math.ceil(i / sharp)) - i) / 5) do
					s = s .. quip_t
					cell_width = cell_width + 1.5
				end
			end
			if (cs == 1 and not use_sz) or (cs == 2 and use_sz) then
				s = s .. flat_t
			elseif (cs == 2 and not use_sz) or (cs == 4 and use_sz) then
				s = s .. dflat_t
			elseif use_sz then
				if cs == 1 then
					s = s .. hflat_t
				elseif cs == 3 then
					s = s .. sflat_t
				end
			end
			tab = tab .. string.format(spanf, cell_width, marg, s)
		end
		
		tab = tab .. "|}\n</div>"
	end
	
	if yesno(frame.args["debug"]) == true then
		tab = "<syntaxhighlight lang=\"wikitext\">" .. tab .. "</syntaxhighlight>"
	end
	
	return frame:preprocess(tab)
end

return p