Module:Interval table

Revision as of 02:48, 5 July 2023 by CompactStar (talk | contribs)
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
iv Module:Interval _to_cents
rat Module:Rational eq
ud Module:Ups and downs notation get_note_names_table
u Module:Utils get_monzo
table_contains
_round
_log

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


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')

-- 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 = u.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,v in pairs(val) do
		result = result + val[k] * (monzo[k] or 0)
	end
	return result
end

local function gcd(a, b)
	return b==0 and a or gcd(b,a%b)
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
			t = i/gcd(i,j) .. "/" .. j/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
				ratios[#ratios + 1] = {i/gcd(i,j),j/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

function p.interval_table(frame)
	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 octave = patent_val[2]
	local fifth = patent_val[3] - patent_val[2]
	local fifth_error = ET.cents(et, fifth) - iv._to_cents(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'

	for i=0,et.size do
		wikitext = wikitext .. '|-\n'
		wikitext = wikitext .. '|' .. i .. '\n'
		wikitext = wikitext .. '|' .. u._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 <40 cents error, add to approximate ratios column
			t = mapping(u.get_monzo(ratios_list[j][1], ratios_list[j][2]), patent_val)
			if t == i and math.abs(ET.cents(et, i) - u._log(ratios_list[j][1]/ratios_list[j][2], 2) * 1200) < 40 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
	end

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

	return wikitext
end

return p