Module:Interval table: Difference between revisions

From Xenharmonic Wiki
Jump to navigation Jump to search
BudjarnLambeth (talk | contribs)
mNo edit summary
Sintel (talk | contribs)
fixes, cleanup
Line 1: Line 1:
local p = {}
local p = {}
local u = require('Module:Utils')
local utils = require("Module:Utils")
local iv = require('Module:Interval')
local rat = require("Module:Rational")
local rat = require('Module:Rational')
local ud = require("Module:Ups and downs notation")
local ud = require('Module:Ups and downs notation')
local ET = require("Module:ET")
local ET = require('Module:ET')


-- Note: some of these helper functions may be moved to utils module
-- Note: some of these helper functions may be moved to utils module


-- Get prime limit of n/d
-- Get prime limit of n/d
local function get_limit(n,d)
local function get_limit(n, d)
local result = 2
local result = 2
local monzo = u.get_monzo(n, d)
local monzo = utils.get_monzo(n, d)
for k,_ in pairs(monzo) do
for k, _ in pairs(monzo) do
if k > result then
if k > result then
result = k
result = k
Line 23: Line 22:
local function mapping(monzo, val)
local function mapping(monzo, val)
local result = 0
local result = 0
for k,v in pairs(val) do
for k, _ in pairs(val) do
result = result + val[k] * (monzo[k] or 0)
result = result + val[k] * (monzo[k] or 0)
end
end
Line 35: Line 34:
for i = 1, max_nd do
for i = 1, max_nd do
for j = 1, max_nd do
for j = 1, max_nd do
t = i/u._gcd(i, j) .. "/" .. j/u._gcd(i, j)
local t = i / utils._gcd(i, j) .. "/" .. j / utils._gcd(i, j)
if (i/j) >= 1 and (i/j) <= max_size and get_limit(i, j) <= prime_limit and not u.table_contains(ratio_strings, t) then
if
ratios[#ratios + 1] = {i/u._gcd(i, j),j/u._gcd(i, j)}
(i / j) >= 1
and (i / j) <= max_size
and get_limit(i, j) <= prime_limit
and not utils.table_contains(ratio_strings, t)
then
ratios[#ratios + 1] = { i / utils._gcd(i, j), j / utils._gcd(i, j) }
ratio_strings[#ratio_strings + 1] = t
ratio_strings[#ratio_strings + 1] = t
end
end
end
end
end
end
 
return ratios
return ratios
end
end
Line 49: Line 53:
-- (this is essentially what "Template:Ups and downs note name" does)
-- (this is essentially what "Template:Ups and downs note name" does)
local function ud_note(et, fifth, step)
local function ud_note(et, fifth, step)
return table.concat(ud.get_note_names_table(et, fifth)[step], ", "):sub(0, -1)
return table.concat(ud.get_note_names_table(et, fifth)[step], ", "):sub(0, -1)
end
end


local function mysplit (inputstr, sep)
local function mysplit(inputstr, sep)
        if sep == nil then
if sep == nil then
                sep = "%s"
sep = "%s"
        end
end
        local t={}
local t = {}
        for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do
                table.insert(t, str)
table.insert(t, str)
        end
end
        return t
return t
end
end


function p.interval_table(frame)
function p.interval_table(frame)
local additional = frame.args['additional'] or ''
local additional = frame.args["additional"] or ""
local additional_split = mysplit(additional, '\n')
local additional_split = mysplit(additional, "\n")
for i=1,#additional_split do
for i = 1, #additional_split do
additional_split[i] = mysplit(additional_split[i], ';')
additional_split[i] = mysplit(additional_split[i], ";")
end
end
local tuning = frame.args['tuning']
local tuning = frame.args["tuning"]
local et = ET.parse(tuning) or ET.parse('12edo')
local et = ET.parse(tuning) or ET.parse("12edo")
local patent_val = {
local patent_val = {
[2] = ET.approximate(et, 2),  
[2] = ET.approximate(et, 2),
[3] = ET.approximate(et, 3),  
[3] = ET.approximate(et, 3),
[5] = ET.approximate(et, 5),  
[5] = ET.approximate(et, 5),
[7] = ET.approximate(et, 7),  
[7] = ET.approximate(et, 7),
[11] = ET.approximate(et, 11),  
[11] = ET.approximate(et, 11),
[13] = ET.approximate(et, 13),  
[13] = ET.approximate(et, 13),
[17] = ET.approximate(et, 17),
[17] = ET.approximate(et, 17),
[19] = ET.approximate(et, 19),  
[19] = ET.approximate(et, 19),
[23] = ET.approximate(et, 23),
[23] = ET.approximate(et, 23),
[29] = ET.approximate(et, 29),
[29] = ET.approximate(et, 29),
Line 86: Line 90:
[41] = ET.approximate(et, 41),
[41] = ET.approximate(et, 41),
[43] = ET.approximate(et, 43),
[43] = ET.approximate(et, 43),
[47] = ET.approximate(et, 47)
[47] = ET.approximate(et, 47),
}
}
 
local wikitext = '{|class="wikitable"\n'
local wikitext = '{|class="wikitable"\n'
local octave = patent_val[2]
local fifth = patent_val[3] - patent_val[2]
local fifth = patent_val[3] - patent_val[2]
local fifth_error = ET.cents(et, fifth) - iv._to_cents(3/2)
local fifth_error = ET.cents(et, fifth) - rat.cents(rat.new(3, 2))
local dual_fifth = math.abs(fifth_error) > (400 / et.size)
local dual_fifth = math.abs(fifth_error) > (400 / et.size)
local dual_flat_fifth = ET.approximate(et, 3/2, -1)
local dual_flat_fifth = ET.approximate(et, 3 / 2, -1)
local dual_sharp_fifth = ET.approximate(et, 3/2, 1)
local dual_sharp_fifth = ET.approximate(et, 3 / 2, 1)
 
-- List of all 13-limit ratios with numerator and denominator <= 81 and in the range 1/1 - 5/1
-- List of all 13-limit ratios with numerator and denominator <= 81 and in the range 1/1 - 5/1
local ratios_list = get_ratios_list(81, 5, 13)
local ratios_list = get_ratios_list(81, 5, 13)


wikitext = wikitext .. '!Steps\n'
wikitext = wikitext .. "!Steps\n"
wikitext = wikitext .. '!Cents\n'
wikitext = wikitext .. "!Cents\n"
if rat.eq(et.equave, 2) then
if rat.eq(et.equave, 2) then
if dual_fifth then
if dual_fifth then
wikitext = wikitext .. '![[Ups and downs notation]]<br>(dual flat fifth ' .. dual_flat_fifth .. '\\' .. et.size .. ')\n'
wikitext = wikitext
wikitext = wikitext .. '![[Ups and downs notation]]<br>(dual sharp fifth ' .. dual_sharp_fifth .. '\\' .. et.size .. ')\n'
.. "![[Ups and downs notation]]<br>(dual flat fifth "
.. dual_flat_fifth
.. "\\"
.. et.size
.. ")\n"
wikitext = wikitext
.. "![[Ups and downs notation]]<br>(dual sharp fifth "
.. dual_sharp_fifth
.. "\\"
.. et.size
.. ")\n"
else
else
wikitext = wikitext .. '![[Ups and downs notation]]\n'
wikitext = wikitext .. "![[Ups and downs notation]]\n"
end
end
end
end
 
wikitext = wikitext .. '!Approximate ratios\n'
wikitext = wikitext .. "!Approximate ratios\n"
 
if #additional_split > 0 then
if #additional_split > 0 then
for i=1,#additional_split[1] do
for i = 1, #additional_split[1] do
wikitext = wikitext .. '!' .. additional_split[1][i] .. '\n'
wikitext = wikitext .. "!" .. additional_split[1][i] .. "\n"
end
end
end
end


for i=0,et.size do
for i = 0, et.size do
wikitext = wikitext .. '|-\n'
wikitext = wikitext .. "|-\n"
wikitext = wikitext .. '|' .. i .. '\n'
wikitext = wikitext .. "|" .. i .. "\n"
wikitext = wikitext .. '|' .. u._round(ET.cents(et, i), 6) .. '\n'
wikitext = wikitext .. "|" .. utils._round(ET.cents(et, i), 6) .. "\n"
if rat.eq(et.equave, 2) then
if rat.eq(et.equave, 2) then
if dual_fifth then
if dual_fifth then
wikitext = wikitext .. '|' .. ud_note(et, dual_flat_fifth, i) .. '\n'
wikitext = wikitext .. "|" .. ud_note(et, dual_flat_fifth, i) .. "\n"
wikitext = wikitext .. '|' .. ud_note(et, dual_sharp_fifth, i) .. '\n'
wikitext = wikitext .. "|" .. ud_note(et, dual_sharp_fifth, i) .. "\n"
else
else
wikitext = wikitext .. '|' .. ud_note(et, fifth, i) .. '\n'
wikitext = wikitext .. "|" .. ud_note(et, fifth, i) .. "\n"
end
end
end
end
wikitext = wikitext .. '|'
wikitext = wikitext .. "|"
for j=1,#ratios_list do
for j = 1, #ratios_list do
-- Go through all ratios, if they are mapped to the current step in the ET's patent val and <2/5 edo step error, add to approximate ratios column
-- Go through all ratios.
t = mapping(u.get_monzo(ratios_list[j][1], ratios_list[j][2]), patent_val)
-- If they are mapped to the current step in the ET's patent val and <2/5 edo step error,
if t == i and math.abs(ET.cents(et, i) - u._log(ratios_list[j][1]/ratios_list[j][2], 2) * 1200) < (1200 / (2.5 * et.size)) then
-- add to approximate ratios column.
wikitext = wikitext .. '[[' .. ratios_list[j][1] .. '/' .. ratios_list[j][2] .. ']], '
local t = mapping(utils.get_monzo(ratios_list[j][1], ratios_list[j][2]), patent_val)
if
t == i
and math.abs(ET.cents(et, i) - utils._log(ratios_list[j][1] / ratios_list[j][2], 2) * 1200)
< (1200 / (2.5 * et.size))
then
wikitext = wikitext .. "[[" .. ratios_list[j][1] .. "/" .. ratios_list[j][2] .. "]], "
end
end
end
end
if wikitext:sub(-1, -1) == '|' then
if wikitext:sub(-1, -1) == "|" then
wikitext = wikitext .. '\n'
wikitext = wikitext .. "\n"
else
else
wikitext = wikitext:sub(0, -3) .. '\n'
wikitext = wikitext:sub(0, -3) .. "\n"
end
end
if (i + 2) <= #additional_split then
if (i + 2) <= #additional_split then
for j=1,#additional_split[i+2] do
for j = 1, #additional_split[i + 2] do
wikitext = wikitext .. '|' .. additional_split[i+2][j] .. '\n'
wikitext = wikitext .. "|" .. additional_split[i + 2][j] .. "\n"
end
end
end
end
end
end


wikitext = wikitext .. '|}'
wikitext = wikitext .. "|}"
 
if wikitext:len() > 5000 then
if wikitext:len() > 5000 then
wikitext = '{| class="wikitable mw-collapsible mw-collapsed"\n' .. wikitext:sub(20)
wikitext = '{| class="wikitable mw-collapsible mw-collapsed"\n' .. wikitext:sub(20)

Revision as of 20:56, 1 April 2024

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

This module automatically generates a table of intervals for an equal-step tuning, showing which just intervals are approximated relatively accurately.

Introspection summary for Module:Interval table 
Functions provided (1)
Line Function Params
69 interval_table (invokable) (frame)
Lua modules required (4)
Variable Module Functions used
ET Module:ET parse
approximate
cents
rat Module:Rational cents
new
eq
ud Module:Ups and downs notation get_note_names_table
utils Module:Utils get_monzo
_gcd
table_contains
_round
_log

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


local p = {}
local utils = require("Module:Utils")
local rat = require("Module:Rational")
local ud = require("Module:Ups and downs notation")
local ET = require("Module:ET")

-- Note: some of these helper functions may be moved to utils module

-- Get prime limit of n/d
local function get_limit(n, d)
	local result = 2
	local monzo = utils.get_monzo(n, d)
	for k, _ in pairs(monzo) do
		if k > result then
			result = k
		end
	end
	return result
end

--  Gets mapping of a monzo in a val
local function mapping(monzo, val)
	local result = 0
	for k, _ in pairs(val) do
		result = result + val[k] * (monzo[k] or 0)
	end
	return result
end

-- Generates list of ratios up to a max numerator & denominator, max ratio size, and prime limit
local function get_ratios_list(max_nd, max_size, prime_limit)
	local ratios = {}
	local ratio_strings = {}
	for i = 1, max_nd do
		for j = 1, max_nd do
			local t = i / utils._gcd(i, j) .. "/" .. j / utils._gcd(i, j)
			if
				(i / j) >= 1
				and (i / j) <= max_size
				and get_limit(i, j) <= prime_limit
				and not utils.table_contains(ratio_strings, t)
			then
				ratios[#ratios + 1] = { i / utils._gcd(i, j), j / utils._gcd(i, j) }
				ratio_strings[#ratio_strings + 1] = t
			end
		end
	end

	return ratios
end

-- Utility fuunction to get specific note name with ud.get_note_names_table
-- (this is essentially what "Template:Ups and downs note name" does)
local function ud_note(et, fifth, step)
	return table.concat(ud.get_note_names_table(et, fifth)[step], ", "):sub(0, -1)
end

local function mysplit(inputstr, sep)
	if sep == nil then
		sep = "%s"
	end
	local t = {}
	for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do
		table.insert(t, str)
	end
	return t
end

function p.interval_table(frame)
	local additional = frame.args["additional"] or ""
	local additional_split = mysplit(additional, "\n")
	for i = 1, #additional_split do
		additional_split[i] = mysplit(additional_split[i], ";")
	end
	local tuning = frame.args["tuning"]
	local et = ET.parse(tuning) or ET.parse("12edo")
	local patent_val = {
		[2] = ET.approximate(et, 2),
		[3] = ET.approximate(et, 3),
		[5] = ET.approximate(et, 5),
		[7] = ET.approximate(et, 7),
		[11] = ET.approximate(et, 11),
		[13] = ET.approximate(et, 13),
		[17] = ET.approximate(et, 17),
		[19] = ET.approximate(et, 19),
		[23] = ET.approximate(et, 23),
		[29] = ET.approximate(et, 29),
		[31] = ET.approximate(et, 31),
		[37] = ET.approximate(et, 37),
		[41] = ET.approximate(et, 41),
		[43] = ET.approximate(et, 43),
		[47] = ET.approximate(et, 47),
	}

	local wikitext = '{|class="wikitable"\n'
	local fifth = patent_val[3] - patent_val[2]
	local fifth_error = ET.cents(et, fifth) - rat.cents(rat.new(3, 2))
	local dual_fifth = math.abs(fifth_error) > (400 / et.size)
	local dual_flat_fifth = ET.approximate(et, 3 / 2, -1)
	local dual_sharp_fifth = ET.approximate(et, 3 / 2, 1)

	-- List of all 13-limit ratios with numerator and denominator <= 81 and in the range 1/1 - 5/1
	local ratios_list = get_ratios_list(81, 5, 13)

	wikitext = wikitext .. "!Steps\n"
	wikitext = wikitext .. "!Cents\n"
	if rat.eq(et.equave, 2) then
		if dual_fifth then
			wikitext = wikitext
				.. "![[Ups and downs notation]]<br>(dual flat fifth "
				.. dual_flat_fifth
				.. "\\"
				.. et.size
				.. ")\n"
			wikitext = wikitext
				.. "![[Ups and downs notation]]<br>(dual sharp fifth "
				.. dual_sharp_fifth
				.. "\\"
				.. et.size
				.. ")\n"
		else
			wikitext = wikitext .. "![[Ups and downs notation]]\n"
		end
	end

	wikitext = wikitext .. "!Approximate ratios\n"

	if #additional_split > 0 then
		for i = 1, #additional_split[1] do
			wikitext = wikitext .. "!" .. additional_split[1][i] .. "\n"
		end
	end

	for i = 0, et.size do
		wikitext = wikitext .. "|-\n"
		wikitext = wikitext .. "|" .. i .. "\n"
		wikitext = wikitext .. "|" .. utils._round(ET.cents(et, i), 6) .. "\n"
		if rat.eq(et.equave, 2) then
			if dual_fifth then
				wikitext = wikitext .. "|" .. ud_note(et, dual_flat_fifth, i) .. "\n"
				wikitext = wikitext .. "|" .. ud_note(et, dual_sharp_fifth, i) .. "\n"
			else
				wikitext = wikitext .. "|" .. ud_note(et, fifth, i) .. "\n"
			end
		end
		wikitext = wikitext .. "|"
		for j = 1, #ratios_list do
			-- Go through all ratios.
			-- If they are mapped to the current step in the ET's patent val and <2/5 edo step error,
			-- add to approximate ratios column.
			local t = mapping(utils.get_monzo(ratios_list[j][1], ratios_list[j][2]), patent_val)
			if
				t == i
				and math.abs(ET.cents(et, i) - utils._log(ratios_list[j][1] / ratios_list[j][2], 2) * 1200)
					< (1200 / (2.5 * et.size))
			then
				wikitext = wikitext .. "[[" .. ratios_list[j][1] .. "/" .. ratios_list[j][2] .. "]], "
			end
		end
		if wikitext:sub(-1, -1) == "|" then
			wikitext = wikitext .. "\n"
		else
			wikitext = wikitext:sub(0, -3) .. "\n"
		end
		if (i + 2) <= #additional_split then
			for j = 1, #additional_split[i + 2] do
				wikitext = wikitext .. "|" .. additional_split[i + 2][j] .. "\n"
			end
		end
	end

	wikitext = wikitext .. "|}"

	if wikitext:len() > 5000 then
		wikitext = '{| class="wikitable mw-collapsible mw-collapsed"\n' .. wikitext:sub(20)
	end

	return wikitext
end

return p