Module:Harmonics in cet: Difference between revisions

From Xenharmonic Wiki
Jump to navigation Jump to search
Godtone (talk | contribs)
m i find this style subtly very irritating sorry, i was surprised to find it so bothersome; if the motivation is to make - the same width as + then this solution is worse than using an ASCII - because it makes - longer than +. and one should prefer ASCII to avoid confusing people copying the data which they expect to be the ASCII minus
Comment out problem parts for the moment
 
(11 intermediate revisions by 2 users not shown)
Line 1: Line 1:
local yesno = require("Module:yesno")
local utils = require("Module:Utils")
local p = {}
local p = {}


local function approx(step, intervals, title, prec)
local function approx(step, intervals, title, prec, reduction, collapsed)
local tpri = {'! colspan="2" | Harmonic '}
local thead
local tabs = {'! rowspan="2" | Error \n! Absolute ([[cent|¢]]) '}
if collapsed then
local trel = {'! [[Relative interval error|Relative]] (%) '}
thead = "{| class=\"wikitable center-all mw-collapsible mw-collapsed\"\n"
local tdeg = {'! colspan="2" | Steps'}
else
thead = "{| class=\"wikitable center-all\"\n"
end
local tpri = {"! colspan=\"2\" | Harmonic "}
local tabs = {"! rowspan=\"2\" | Error \n! Absolute ([[cent|¢]]) "}
local trel = {"! [[Relative interval error|Relative]] ([[relative cent|%]]) "}
local tdeg
local fmt_abs = string.format(' %%+.%df', prec)
-- TODO: determine `steps`
local fmt_rel = ' %+.0f'
-- if reduction then
local size = step/1200
-- tdeg = {"! colspan=\"2\" | Steps<br>([[octave reduction|reduced]])"}
-- else
-- tdeg = {"! colspan=\"2\" | Step"}
-- end
tdeg = {"! colspan=\"2\" | Step"}
local fmt_abs = string.format(" %%+.%df", prec)
local fmt_rel = " %+.1f"
local size = step / 1200
for _, p in pairs(intervals) do
for _, p in pairs(intervals) do
s = math.log(p) / math.log(2)
s = math.log(p) / math.log(2)
v = s/size
v = s/size
ev = math.floor(v + .5)
ev = math.floor(v + 0.5)
table.insert(tpri, "" .. p)
table.insert(tpri, "" .. p)
table.insert(tabs, "" .. string.gsub(string.format(fmt_abs, 1200 * (ev - v)*size), "%-", "-"))
table.insert(tabs, "" .. string.gsub(string.format(fmt_abs, 1200 * (ev - v) * size), "%-", "-"))
table.insert(trel, "" .. string.gsub(string.format(fmt_rel, 100 * (ev - v)), "%-", "-"))
table.insert(trel, "" .. string.gsub(string.format(fmt_rel, 100 * (ev - v)), "%-", "-"))
-- TODO: determine `steps`
-- if reduction then
-- table.insert(tdeg, "" .. ev .. "<br>(".. ev % steps .. ")")
-- else
-- table.insert(tdeg, "" .. ev)
-- end
table.insert(tdeg, "" .. ev)
table.insert(tdeg, "" .. ev)
end
end
local titleMarkup = ''
local titleMarkup = ""
if title then
if title then
titleMarkup = '|-\n|+ ' .. title .. '\n'
titleMarkup = "|+ style=\"font-size: 105%; white-space: nowrap;\" | " .. title .. "\n"
end
end
return '{| class="wikitable center-all"\n' ..
thead = thead ..
titleMarkup ..
titleMarkup ..
'|-\n' ..
"|-\n" ..
table.concat(tpri, '\n!') .. '\n' ..
table.concat(tpri, "\n! ") .. "\n" ..
'|-\n' ..
"|-\n" ..
table.concat(tabs, '\n|') .. '\n' ..
table.concat(tabs, "\n| ") .. "\n" ..
'|-\n' ..
"|-\n" ..
table.concat(trel, '\n|') .. '\n' ..
table.concat(trel, "\n| ") .. "\n" ..
'|-\n' ..
"|-\n" ..
table.concat(tdeg, '\n|') .. '\n' ..
table.concat(tdeg, "\n| ") .. "\n" ..
'|}'
"|}"
return thead
end
end


Line 41: Line 67:


intervals.prime = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 }
intervals.prime = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 }
-- intervals.prime_no2 = {3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 }
intervals.odd = {3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53 }
intervals.odd = {3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53 }
intervals.integer = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11,  12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64}
intervals.integer = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11,  12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64}
Line 48: Line 73:
local function eval_num_arg(input, def_value)
local function eval_num_arg(input, def_value)
local result = input
local result = input
if type(input) ~= 'number' then
if type(input) ~= "number" then
result = def_value
result = def_value
if type(input) == 'string' then
if type(input) == "string" then
input = input:match("^%s*(.-)%s*$")
input = input:match("^%s*(.-)%s*$")
if string.len(input) > 0 then
if string.len(input) > 0 then
Line 62: Line 87:
-- calculate default precision
-- calculate default precision
local function prec_by_cet(step)
local function prec_by_cet(step)
return math.floor(math.log(1.9*1200/step)/math.log(10))
return math.floor(math.log(1.9 * 1200 / step) / math.log(10))
end
end


function p.harmonics_in_cet (frame)
function p.harmonics_in_cet (frame)
-- step size in cents, default: 65
-- step size in cents, default: 65
local step = eval_num_arg(frame.args['step'], 63.1578947368)
local step = eval_num_arg(frame.args["step"], 63.1578947368)
-- optional number of columns, default: 10
-- optional number of columns, default: 10
local columns = eval_num_arg(frame.args['columns'], 10)
local columns = eval_num_arg(frame.args["columns"], 11)
-- optional start column, default: start with prime 2
-- optional start column, default: start with prime 2
local start = eval_num_arg(frame.args['start'], 1)
local start = eval_num_arg(frame.args["start"], 1)
-- option intervals
-- option intervals
local select_intervals = "integer"
local select_intervals = "integer"
if frame.args['intervals'] and string.len(frame.args['intervals']) > 0 then
select_intervals = frame.args['intervals']
end
local name = "1ed" .. step .. "c"
local name = "1ed" .. step .. "c"
title_intervals = "prime harmonics"
-- override default intervals
if frame.args["intervals"] and string.len(frame.args["intervals"]) > 0 then
select_intervals = frame.args["intervals"]
end
if select_intervals == "odd" then
if select_intervals == "odd" then
title_intervals = "odd harmonics"
title_intervals = "odd harmonics"
elseif select_intervals == "integer" then
elseif select_intervals == "integer" then
title_intervals = "harmonics"
title_intervals = "harmonics"
else
title_intervals = "prime harmonics"
end
end
local title = frame.args['title']
local title = frame.args["title"]
if title == nil or string.len(title) == 0 then
if title == nil or string.len(title) == 0 then
title = "Approximation of ".. title_intervals .. " in " .. name
title = "Approximation of ".. title_intervals .. " in " .. name
end
end
-- optional precision for abs error, default about 3 digits
-- optional precision for abs error, default about 3 digits
local prec = eval_num_arg(frame.args['prec'], prec_by_cet(step))
local prec = eval_num_arg(frame.args["prec"], prec_by_cet(step))
local reduction = true
if steps == 1 then
reduction = false
end
local collapsed = utils.value_provided(frame.args["collapsed"])
local debugg = yesno(frame.args["debug"])
local result = approx(step, {unpack(intervals[select_intervals], start, start + columns - 1)}, title, prec, reduction, collapsed)
if debugg == true then
result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>"
end
return approx( step, {unpack(intervals[select_intervals], start, start+columns-1)}, title, prec)
return frame:preprocess(result)
end
end


return p;
return p

Latest revision as of 11:31, 17 August 2025

Module documentation[view] [edit] [history] [purge]
This module should not be invoked directly; use its corresponding template instead: Template:Harmonics in cet.

Calculates approximations for harmonics in equal-step tunings and presents them in form of a table.

Introspection summary for Module:Harmonics in cet 
Functions provided (1)
Line Function Params
92 harmonics_in_cet (invokable) (frame)
Lua modules required (2)
Variable Module Functions used
utils Module:Utils value_provided
yesno Module:yesno yesno

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


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

local function approx(step, intervals, title, prec, reduction, collapsed)
	local thead
	if collapsed then
		thead = "{| class=\"wikitable center-all mw-collapsible mw-collapsed\"\n"
	else
		thead = "{| class=\"wikitable center-all\"\n"
	end
	local tpri = {"! colspan=\"2\" | Harmonic "}
	local tabs = {"! rowspan=\"2\" | Error \n! Absolute ([[cent|¢]]) "}
	local trel = {"! [[Relative interval error|Relative]] ([[relative cent|%]]) "}
	local tdeg
	
	-- TODO: determine `steps`
	-- if reduction then
	-- 	tdeg = {"! colspan=\"2\" | Steps<br>([[octave reduction|reduced]])"}
	-- else
	-- 	tdeg = {"! colspan=\"2\" | Step"}
	-- end
	
	tdeg = {"! colspan=\"2\" | Step"}
	local fmt_abs = string.format(" %%+.%df", prec)
	local fmt_rel = " %+.1f"
	local size = step / 1200
	
	for _, p in pairs(intervals) do
		s = math.log(p) / math.log(2)
		v = s/size
		ev = math.floor(v + 0.5)
		table.insert(tpri, "" .. p)
		table.insert(tabs, "" .. string.gsub(string.format(fmt_abs, 1200 * (ev - v) * size), "%-", "-"))
		table.insert(trel, "" .. string.gsub(string.format(fmt_rel, 100 * (ev - v)), "%-", "-"))
		
		-- TODO: determine `steps`
		-- if reduction then
		-- 	table.insert(tdeg, "" .. ev .. "<br>(".. ev % steps .. ")")
		-- else
		-- 	table.insert(tdeg, "" .. ev)
		-- end
		
		table.insert(tdeg, "" .. ev)
	end
	local titleMarkup = ""
	if title then
		titleMarkup = "|+ style=\"font-size: 105%; white-space: nowrap;\" | " .. title .. "\n"
	end
	
	thead = thead ..
		titleMarkup ..
		"|-\n" ..
		table.concat(tpri, "\n! ") .. "\n" ..
		"|-\n" ..
		table.concat(tabs, "\n| ") .. "\n" ..
		"|-\n" ..
		table.concat(trel, "\n| ") .. "\n" ..
		"|-\n" ..
		table.concat(tdeg, "\n| ") .. "\n" ..
		"|}"
	
	return thead
end

local intervals = {}

intervals.prime = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 }
intervals.odd = {3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53 }
intervals.integer = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11,  12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64}

-- evaluate input on error use default
local function eval_num_arg(input, def_value)
	local result = input
	if type(input) ~= "number" then
		result = def_value
		if type(input) == "string" then
			input = input:match("^%s*(.-)%s*$")
			if string.len(input) > 0 then
				result = tonumber(input)
			end
		end
	end
	return result
end

-- calculate default precision
local function prec_by_cet(step)
	return math.floor(math.log(1.9 * 1200 / step) / math.log(10))
end

function p.harmonics_in_cet (frame)
	-- step size in cents, default: 65
	local step = eval_num_arg(frame.args["step"], 63.1578947368)
	-- optional number of columns, default: 10
	local columns = eval_num_arg(frame.args["columns"], 11)
	-- optional start column, default: start with prime 2
	local start = eval_num_arg(frame.args["start"], 1)
	-- option intervals
	local select_intervals = "integer"
	
	local name = "1ed" .. step .. "c"
	
	-- override default intervals
	if frame.args["intervals"] and string.len(frame.args["intervals"]) > 0 then
		select_intervals = frame.args["intervals"]
	end
	
	if select_intervals == "odd" then
		title_intervals = "odd harmonics"
	elseif select_intervals == "integer" then
		title_intervals = "harmonics"
	else
		title_intervals = "prime harmonics"
	end
	
	local title = frame.args["title"]
	if title == nil or string.len(title) == 0 then
		title = "Approximation of ".. title_intervals .. " in " .. name
	end
	-- optional precision for abs error, default about 3 digits
	local prec = eval_num_arg(frame.args["prec"], prec_by_cet(step))
	local reduction = true
	if steps == 1 then
		reduction = false	
	end
	
	local collapsed = utils.value_provided(frame.args["collapsed"])
	local debugg = yesno(frame.args["debug"])
	local result = approx(step, {unpack(intervals[select_intervals], start, start + columns - 1)}, title, prec, reduction, collapsed)
	
	if debugg == true then
		result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>"
	end
	
	return frame:preprocess(result)
end

return p