Module:Interval table: Difference between revisions

From Xenharmonic Wiki
Jump to navigation Jump to search
CompactStar (talk | contribs)
No edit summary
ArrowHead294 (talk | contribs)
mNo edit summary
 
(141 intermediate revisions by 6 users not shown)
Line 1: Line 1:
local p = {}
local p = {}
local u = require('Module:Utils')
local iv = require('Module:Interval')
local rat = require('Module:Rational')
local ud = require('Module:Ups and downs notation')
local ET = require('Module:ET')


-- Auto-generated list of ratios in 17-limit and with <2 digits
local ET = require("Module:ET")
local ratios_list = {{1,1},{2,1},{3,1},{4,1},{3,2},{5,1},{5,2},{5,4},{6,1},{7,2},{7,4},{9,2},{9,4},{9,8},{11,4},{13,4},{15,4},{17,8},{21,8},{25,8},{17,4},{27,8},{33,8},{35,8},{39,8},{11,2},{21,4},{45,8},{65,16},{75,16},{11,8},{13,8},{15,8},{17,16},{21,16},{25,16},{27,16},{33,32},{35,32},{39,32},{56,51},{68,49},{56,45},{68,39},{33,16},{35,16},{39,16},{45,16},{65,32},{75,32},{77,32},{81,32},{65,33},{85,32},{96,35},{98,33},{85,77},{49,16},{26,25},{51,16},{51,25},{55,16},{63,16},{77,50},{99,32},{26,21},{81,65},{68,21},{77,16},{63,55},{52,35},{22,17},{39,17},{56,17},{90,17},{64,33},{81,16},{85,16},{91,16},{26,15},{56,15},{84,55},{40,27},{45,32},{49,32},{16,13},{45,26},{42,13},{51,32},{55,13},{55,32},{27,25},{52,25},{68,13},{77,25},{77,52},{78,35},{51,44},{21,11},{32,11},{75,22},{54,11},{65,11},{91,88},{96,65},{52,21},{77,39},{11,9},{20,9},{49,18},{85,18},{27,17},{44,17},{91,68},{78,17},{28,25},{81,50},{78,25},{91,66},{65,49},{78,77},{22,15},{52,15},{85,81},{91,32},{17,14},{12,7},{45,14},{26,7},{33,7},{40,7},{55,28},{75,56},{80,27},{63,52},{32,13},{45,13},{51,26},{77,26},{77,45},{91,51},{54,25},{54,49},{51,35},{77,68},{32,17},{49,17},{66,17},{81,34},{88,45},{20,11},{51,22},{42,11},{91,44},{64,11},{65,54},{6,5},{11,5},{16,5},{17,10},{21,5},{26,5},{27,10},{39,20},{49,20},{63,40},{91,40},{99,20},{85,66},{55,51},{13,9},{22,9},{35,18},{40,9},{49,9},{77,72},{68,35},{22,13},{35,13},{48,13},{75,52},{20,17},{91,34},{54,17},{88,17},{25,21},{88,21},{56,25},{81,25},{91,33},{81,49},{65,51},{56,39},{32,27},{91,54},{77,65},{51,49},{44,15},{98,85},{27,22},{49,22},{30,11},{65,44},{52,11},{63,11},{70,51},{32,25},{85,39},{10,7},{17,7},{24,7},{27,14},{33,28},{55,14},{75,28},{98,45},{25,17},{42,17},{52,27},{77,54},{56,33},{96,85},{25,13},{63,26},{51,13},{64,13},{77,13},{64,45},{80,51},{33,25},{91,50},{7,6},{5,3},{8,3},{11,3},{13,6},{14,3},{17,3},{17,12},{25,6},{25,24},{35,12},{49,24},{55,24},{65,12},{65,48},{77,48},{85,24},{91,24},{99,70},{78,49},{30,17},{77,34},{64,17},{81,17},{98,17},{55,39},{34,25},{84,25},{25,22},{18,11},{40,11},{51,11},{91,22},{65,27},{81,70},{52,45},{55,48},{63,32},{40,21},{56,55},{65,64},{75,64},{77,64},{81,64},{15,13},{28,13},{85,64},{54,13},{99,52},{80,77},{7,5},{12,5},{17,5},{22,5},{27,5},{33,20},{39,10},{49,10},{51,40},{63,20},{81,40},{99,80},{85,27},{18,17},{35,17},{52,17},{88,63},{98,55},{52,33},{85,33},{8,7},{15,7},{22,7},{39,28},{36,7},{51,14},{65,14},{81,28},{85,56},{99,56},{64,39},{64,55},{36,25},{25,18},{17,9},{26,9},{35,9},{44,9},{77,36},{88,85},{91,72},{75,49},{64,51},{17,11},{28,11},{39,11},{45,22},{50,11},{66,35},{18,13},{49,26},{44,13},{75,26},{70,13},{85,52},{17,15},{32,15},{49,30},{96,77},{77,15},{75,68},{63,34},{40,17},{91,17},{50,21},{99,50},{44,27},{98,27},{50,33},{44,39},{64,49},{72,55},{88,75},{48,35},{49,33},{64,27},{51,50},{81,77},{63,25},{88,25},{91,27},{34,21},{55,21},{28,17},{39,34},{45,17},{96,17},{28,15},{88,15},{21,13},{34,13},{55,26},{60,13},{81,26},{39,35},{16,11},{27,11},{65,22},{49,11},{60,11},{75,44},{91,75},{72,49},{10,9},{49,36},{28,9},{65,18},{85,36},{39,25},{64,25},{72,65},{45,28},{13,7},{20,7},{27,7},{33,14},{34,7},{75,14},{80,33},{88,65},{81,68},{33,17},{49,34},{50,17},{84,17},{50,27},{77,27},{11,10},{8,5},{13,5},{18,5},{21,10},{27,20},{28,5},{49,40},{51,10},{77,20},{81,80},{85,63},{80,49},{35,26},{24,13},{50,13},{63,13},{44,21},{65,21},{70,27},{50,49},{99,49},{15,11},{26,11},{49,44},{48,11},{63,22},{85,22},{66,25},{85,78},{91,25},{49,45},{21,17},{55,17},{72,17},{99,91},{96,55},{49,48},{4,3},{7,3},{10,3},{11,6},{13,3},{13,12},{16,3},{17,6},{25,12},{35,6},{35,24},{49,12},{65,24},{77,24},{85,48},{88,49},{91,48},{55,12},{42,25},{68,63},{64,35},{99,35},{90,77},{14,13},{27,13},{40,13},{77,75},{66,13},{85,54},{56,27},{35,34},{26,17},{60,17},{77,17},{15,14},{11,7},{18,7},{25,7},{32,7},{39,7},{51,28},{65,28},{81,56},{68,25},{14,11},{25,11},{36,11},{39,22},{45,44},{16,15},{77,30},{96,49},{49,27},{81,35},{88,51},{91,55},{99,85},{66,49},{63,50},{44,25},{55,42},{80,21},{45,34},{48,17},{65,17},{99,17},{17,13},{30,13},{55,52},{56,13},{81,52},{72,35},{99,26},{85,49},{14,9},{55,18},{32,9},{65,36},{50,9},{85,72},{91,18},{96,91},{78,55},{98,51},{40,33},{80,39},{55,49},{13,10},{9,5},{14,5},{21,20},{24,5},{33,10},{51,20},{77,40},{52,51},{81,20},{91,20},{91,80},{99,40},{22,21},{65,42},{64,21},{85,21},{35,27},{68,65},{99,98},{13,11},{24,11},{35,11},{63,44},{81,22},{85,44},{70,39},{36,17},{55,34},{70,17},{98,81},{54,35},{84,65},{91,81},{96,25},{27,26},{20,13},{33,13},{72,13},{28,27},{55,27},{9,7},{16,7},{25,14},{30,7},{39,14},{65,56},{81,14},{85,28},{99,28},{77,60},{91,30},{68,15},{50,39},{65,63},{70,33},{72,25},{24,17},{65,34},{99,34},{75,17},{36,35},{55,36},{16,9},{25,9},{34,9},{77,18},{52,9},{91,36},{91,85},{40,39},{52,49},{77,51},{32,21},{85,42},{91,64},{99,64},{99,65},{12,11},{35,22},{34,11},{45,11},{56,11},{81,44},{91,45},{48,25},{80,63},{98,25},{33,26},{36,13},{49,13},{85,26},{75,13},{55,54},{68,27},{81,55},{91,60},{34,15},{49,15},{64,15},{64,63},{66,65},{35,33},{68,33},{90,49},{99,68},{75,34},{63,17},{80,17},{88,35},{98,39},{85,84},{91,90},{68,45},{60,49},{49,25},{99,25},{34,27},{68,55},{88,27},{34,33},{98,65},{44,35},{98,75},{49,39},{88,39},{88,81}}
local rat = require("Module:Rational")
local ud = require("Module:Ups and downs notation")
local function gcd(a, b)
local utils = require("Module:Utils")
return b==0 and a or gcd(b,a%b)
local yesno = require("Module:Yesno")
 
-- 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
end


local function table_contains(tbl, x)
-- Generates list of ratios up to a max numerator & denominator, max ratio size, and prime limit
    found = false
local function get_ratios_list(max_nd, max_size, prime_limit)
    for _, v in pairs(tbl) do
local ratios = {}
        if v == x then  
local ratio_strings = {}
            found = true
for i = 1, max_nd do
        end
for j = 1, max_nd do
    end
local t = i / utils._gcd(i, j) .. "/" .. j / utils._gcd(i, j)
    return found
if
(i / j) >= 1
and (i / j) <= max_size
and rat.max_prime(rat.new (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
end


-- Utility fuunction to get specific note name with ud.get_note_names_table
-- Utility function to get specific note name with ud.get_note_names_table
-- (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)
return table.concat(ud.get_note_names_table(et, fifth)[step], ", "):sub(0, -1)
end


local function ud_note(et, fifth, step)
-- ???
return table.concat(ud.get_note_names_table(et, fifth)[step], ", "):sub(0, -1)
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
end


function p.interval_table(frame)
function p.interval_table(frame)
local tuning = frame.args['tuning']
local additional = frame.args["additional"] or ""
local et = ET.parse(tuning) or ET.parse('12edo')
local additional_split = mysplit(additional, "\n")
local wikitext = '{|class="wikitable"\n'
for i = 1, #additional_split do
local octave = ET.approximate(et, 2)
additional_split[i] = mysplit(additional_split[i], ";")
local fifth = ET.approximate(et, 3/2)
end
local fifth_error = ET.cents(et, fifth) - iv._to_cents(3/2)
local tuning = frame.args["tuning"]
local dual_fifth = math.abs(fifth_error) > (400 / et.size)
local et = ET.parse(tuning) or ET.parse("12edo")
local dual_flat_fifth = ET.approximate(et, 3/2, -1)
local debugg = yesno(frame.args["debug"])
local dual_sharp_fifth = ET.approximate(et, 3/2, 1)
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),
} -- NOTE: indices are prime numbers
 
local t_head = "{| class=\"wikitable center-1 right-2"
if et.size > 20 then
t_head = t_head .. " mw-collapsible mw-collapsed"
end
t_head = t_head .. "\"\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)


wikitext = wikitext .. '!Steps\n'
-- List of all 47-limit ratios with numerator and denominator <= certain cents value and in the range 1/1 - 12/1
wikitext = wikitext .. '!Cents\n'
local ratios_list = get_ratios_list((20 + (et.size / 4)), 12, 47)
 
result = t_head ..
"|-\n" ..
"! Steps\n" ..
"! Cents\n"
if rat.eq(et.equave, 3) then
result = result .. "! [[Hekt]]s\n"
end
result = result ..
"! Approximate ratios\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'
result = result
wikitext = wikitext .. '![[Ups and downs notation]]<br>(dual sharp fifth ' .. dual_sharp_fifth .. '\\' .. et.size .. ')\n'
.. string.format("! [[Ups and downs notation]]<br />(Dual flat fifth %s\\%s)\n", dual_flat_fifth, et.size)
.. string.format("! [[Ups and downs notation]]<br />(Dual sharp fifth %s\\%s)\n", dual_sharp_fifth, et.size)
else
else
wikitext = wikitext .. '![[Ups and downs notation]]\n'
result = result .. "! [[Ups and downs notation]]\n"
end
end
end
end
wikitext = wikitext .. '!Approximate ratios\n'
if #additional_split > 0 then
for i = 1, #additional_split[1] do
for i=0,et.size do
result = result .. string.format("! %s\n", additional_split[1][i])
wikitext = wikitext .. '|-\n'
end
wikitext = wikitext .. '|' .. i .. '\n'
end
wikitext = wikitext .. '|' .. u._round(ET.cents(et, i), 6) .. '\n'
 
    local decimalPlaces = 3 - math.floor(math.log(1200 / et.size, 10))
    if decimalPlaces > 3 then decimalPlaces = 3 end
    if decimalPlaces < 1 then decimalPlaces = 1 end
for i = 0, et.size do
result = result .. "|-\n"
.. string.format("| %s\n", i)
.. string.format("| %s\n", utils._round_dec(ET.cents(et, i), decimalPlaces))
if rat.eq(et.equave, 3) then
result = result .. string.format("| %s\n", utils._round_dec(ET.hekts(et, i), decimalPlaces))
end
result = result .. "| "
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 < specified edostep error,
-- add to approximate ratios column.
local t = mapping(rat.new(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 / (math.log(et.size) * (et.size + 5)))
then
result = result .. string.format("[[%s/%s]], ", ratios_list[j][1], ratios_list[j][2])
end
end
-- ???
if result:sub(-2, -1) == "| " then
result = result .. "\n"
else
result = result:sub(0, -3) .. "\n"
end
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'
result = result .. string.format("| %s\n", ud_note(et, dual_flat_fifth, i))
wikitext = wikitext .. '|' .. ud_note(et, dual_sharp_fifth, i) .. '\n'
result = result .. string.format("| %s\n", ud_note(et, dual_sharp_fifth, i))
else
else
wikitext = wikitext .. '|' .. ud_note(et, fifth, i) .. '\n'
result = result .. string.format("| %s\n", ud_note(et, fifth, i))
end
end
end
end
wikitext = wikitext .. '|'
for j=1,#ratios_list do
if (i + 2) <= #additional_split then
local n = ratios_list[j][1]
for j = 1, #additional_split[i + 2] do
local d = ratios_list[j][2]
result = result .. string.format("| %s\n", additional_split[i + 2][j])
-- In approximate ratios column, show all ratios in the list that are within 1/3 of ET size (33.3 relative cents)
if math.abs(ET.cents(et, i) - (math.log(n/d)/math.log(2)) * 1200) <= (400 / et.size) then
wikitext = wikitext .. '[[' .. n .. '/' .. d .. ']]' .. ' '
end
end
end
end
wikitext = wikitext .. '\n'
end
end
result = result .. "|}"
if debugg == true then
result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>"
end
wikitext = wikitext .. '|}'
return frame:preprocess(result)
 
return wikitext
end
end


return p
return p

Latest revision as of 12:11, 1 June 2025

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
58 interval_table (invokable) (frame)
Lua modules required (5)
Variable Module Functions used
ET Module:ET parse
approximate
cents
hekts
rat Module:Rational max_prime
new
cents
eq
ud Module:Ups and downs notation get_note_names_table
utils Module:Utils _gcd
table_contains
_round_dec
_log
yesno Module:Yesno yesno

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


local p = {}

local ET = require("Module:ET")
local rat = require("Module:Rational")
local ud = require("Module:Ups and downs notation")
local utils = require("Module:Utils")
local yesno = require("Module:Yesno")

-- 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 rat.max_prime(rat.new (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 function 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 debugg = yesno(frame.args["debug"])
	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),
	} -- NOTE: indices are prime numbers

	local t_head = "{| class=\"wikitable center-1 right-2"
	if et.size > 20 then
		t_head = t_head .. " mw-collapsible mw-collapsed"
	end
	t_head = t_head .. "\"\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 47-limit ratios with numerator and denominator <= certain cents value and in the range 1/1 - 12/1
	local ratios_list = get_ratios_list((20 + (et.size / 4)), 12, 47)

	result = t_head .. 
		"|-\n" ..
		"! Steps\n" ..
		"! Cents\n"
	
	if rat.eq(et.equave, 3) then
		result = result .. "! [[Hekt]]s\n"
	end
	result = result ..
	"! Approximate ratios\n"
	
	if rat.eq(et.equave, 2) then
		if dual_fifth then
			result = result
				.. string.format("! [[Ups and downs notation]]<br />(Dual flat fifth %s\\%s)\n", dual_flat_fifth, et.size)
				.. string.format("! [[Ups and downs notation]]<br />(Dual sharp fifth %s\\%s)\n", dual_sharp_fifth, et.size)
		else
			result = result .. "! [[Ups and downs notation]]\n"
		end
	end
	
	if #additional_split > 0 then
		for i = 1, #additional_split[1] do
			result = result .. string.format("! %s\n", additional_split[1][i])
		end
	end

    local decimalPlaces = 3 - math.floor(math.log(1200 / et.size, 10))
    if decimalPlaces > 3 then decimalPlaces = 3 end
    if decimalPlaces < 1 then decimalPlaces = 1 end
	for i = 0, et.size do
		result = result .. "|-\n"
			.. string.format("| %s\n", i)
			.. string.format("| %s\n", utils._round_dec(ET.cents(et, i), decimalPlaces))
		
		if rat.eq(et.equave, 3) then
			result = result .. string.format("| %s\n", utils._round_dec(ET.hekts(et, i), decimalPlaces))
		end
		
		result = result .. "| "
		
		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 < specified edostep error,
			-- add to approximate ratios column.
			local t = mapping(rat.new(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 / (math.log(et.size) * (et.size + 5)))
			then
				result = result .. string.format("[[%s/%s]], ", ratios_list[j][1], ratios_list[j][2])
			end
		end
		
		-- ???
		if result:sub(-2, -1) == "| " then
			result = result .. "\n"
		else
			result = result:sub(0, -3) .. "\n"
		end
		
		if rat.eq(et.equave, 2) then
			if dual_fifth then
				result = result .. string.format("| %s\n", ud_note(et, dual_flat_fifth, i))
				result = result .. string.format("| %s\n", ud_note(et, dual_sharp_fifth, i))
			else
				result = result .. string.format("| %s\n", ud_note(et, fifth, i))
			end
		end
		
		if (i + 2) <= #additional_split then
			for j = 1, #additional_split[i + 2] do
				result = result .. string.format("| %s\n", additional_split[i + 2][j])
			end
		end
	end

	result = result .. "|}"
	
	if debugg == true then
		result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>"
	end
	
	return frame:preprocess(result)
end

return p