Module:JI ratios in ED: Difference between revisions

From Xenharmonic Wiki
Jump to navigation Jump to search
Ganaram inukshuk (talk | contribs)
Fixed non-2/1 equaves not having the keyword "just"
Ganaram inukshuk (talk | contribs)
Table title will correctly specify whether the temperament interpretation is for a prime limit (eg, 5-limit) or a prime subgroup (eg, 2.3.7)
Line 8: Line 8:


-- Helper function
-- Helper function
-- Converts prime limit to subgroup
-- Given a prime limit, return an array of all primes between (and including) 2
-- EG, 7-limit becomes 2.3.5.7
-- and that limit
function p.prime_limit_to_subgroup(prime_limit)
-- EG, 7-limit becomes { 2, 3, 5, 7 }
function p.primes_within_prime_limit(prime_limit)
local prime_limit = prime_limit or 7
local prime_limit = prime_limit or 7
local subgroup = {}
local primes = {}
for i = 2, prime_limit do
for i = 2, prime_limit do
if utils.is_prime(i) then
if utils.is_prime(i) then
table.insert(subgroup, i)
table.insert(primes, i)
end
end
end
end
return subgroup
return primes
end
end


function p.subgroup_as_string(subgroup)
-- Helper function
local subgroup = subgroup or { 2, 3, 5, 7 }
-- Converts a set of primes into a subgroup
function p.primes_as_subgroup(primes)
local primes = primes or { 2, 3, 5, 7 }
local str = ""
local subgroup = ""
for i = 1, #subgroup do
for i = 1, #primes do
if i ~= #subgroup then
if i ~= #primes then
str = str .. string.format("%d.", subgroup[i])
subgroup = subgroup .. string.format("%d.", primes[i])
else
else
str = str .. subgroup[i]
subgroup = subgroup .. primes[i]
end
end
end
end
return str
return subgroup
end
 
-- Helper function
-- Given a set of primes, find its temperament interpretation; IE, is it a
-- prime subgroup temperament (EG, 2.3.7) or a prime-limit temperament (EG,
-- 7-limit)?
-- If the set of primes is a prime limit, then it should contain all the primes
-- between 2 (inclusive) and the largest prime (inclusive). If it skips any
-- primes, then it's a subgroup.
function p.primes_as_temperament_interpretation(primes)
local primes = primes or { 2, 3, 5, 7 }
local primes_to_compare = p.primes_within_prime_limit(primes[#primes])
local temperament_interpretation = ""
if p.primes_as_subgroup(primes) == p.primes_as_subgroup(primes_to_compare) then
temperament_interpretation = string.format("%d-limit", primes[#primes])
else
temperament_interpretation = p.primes_as_subgroup(primes) .. " subgroup"
end
return temperament_interpretation
end
end


-- Primary function
function p.find_ratios_in_ed(input_et, primes, tenney_height, denominator_limit)
function p.find_ratios_in_ed(input_et, primes, tenney_height, denominator_limit)
local input_et = input_et or et.parse("13ed9/4")
local input_et = input_et or et.parse("13ed9/4")
Line 47: Line 72:
local et_as_string = et.as_string(input_et)
local et_as_string = et.as_string(input_et)
-- Calculate equave and tolerance
local equave_in_cents = rat.cents(equave)
local equave_in_cents = rat.cents(equave)
local tolerance = equave_in_cents / steps * 0.4
local tolerance = equave_in_cents / steps * 0.4
-- Temperament_interpretation
-- Calculate temperament interpretation
local subgroup_as_string = p.subgroup_as_string(primes)
local temperament_interpretation = p.primes_as_temperament_interpretation(primes)
-- Find candidate ratios; filter later
-- Find candidate ratios; filter later
local max_prime = primes[#primes]
local max_prime = primes[#primes]
Line 59: Line 85:
-- Build table headers
-- Build table headers
local result = string.format('{| class="wikitable center-all"\n')
local result = string.format('{| class="wikitable center-all"\n')
result = result .. string.format('|+ Intervals of %s (as a %s subgroup temperament)\n', et_as_string, subgroup_as_string)
result = result .. string.format('|+ Intervals of %s (interpreted as a %s temperament)\n', et_as_string, temperament_interpretation)
result = result .. string.format('|-\n')
result = result .. string.format('|-\n')
result = result .. string.format('! rowspan="2" | [[Degree]]\n')
result = result .. string.format('! rowspan="2" | [[Degree]]\n')
Line 114: Line 140:
end
end


-- Wrapper function for primary function; to be called by template
function p.ji_ratios_in_ed_frame(frame)
function p.ji_ratios_in_ed_frame(frame)
Line 121: Line 148:
end
end


local primes_as_text = "2.3.5.7.11.13"
local primes = { 2, 3, 5, 7 }
if string.len(frame.args["Primes"]) > 0 then
if string.len(frame.args["Prime Limit"]) > 0 then
primes_as_text = frame.args["Primes"]
primes = p.prime_limit_to_subgroup(tonumber(frame.args["Primes"]))
elseif string.len(frame.args["Subgroup"]) > 0 then
local primes_unparsed = tip.parse_numeric_entries(primes_unparsed, '.') or tip.parse_numeric_entries(primes_unparsed, ',')
end
end
local primes = tip.parse_numeric_entries(primes_as_text, '.') or tip.parse_numeric_entries(primes_as_text, ',')
local tenney_height = tonumber(frame.args["Tenney Height"]) or 10
local tenney_height = tonumber(frame.args["Tenney Height"]) or 10

Revision as of 06:14, 25 January 2024

Module documentation[view] [edit] [history] [purge]
This module should not be invoked directly; use its corresponding template instead: Template:JI ratios in ED.
Module:JI ratios in ED is deprecated and has no replacement. Further use of this module is not advised. This module is kept for historical purposes and should not be deleted.
Introspection summary for Module:JI ratios in ED 
Functions provided (5)
Line Function Params
13 primes_within_prime_limit (prime_limit)
27 primes_as_subgroup (primes)
48 primes_as_temperament_interpretation (primes)
63 find_ratios_in_ed (input_et, primes, tenney_height, denominator_limit)
143 ji_ratios_in_ed_frame (invokable) (frame)
Lua modules required (6)
Variable Module Functions used
et Module:ET parse
as_string
interval Module:Interval dependency not used
jiraf Module:JI ratio finder find_candidate_ratios_within_subgroup
filter_ratios_by_range
filter_ratios_by_harmonic_class
filter_ratios_by_complement_agnostic_tenney_height
ratios_to_text_with_error
rat Module:Rational cents
new
tip Module:Template input parse parse_numeric_entries
utils Module:Utils is_prime

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


local utils = require('Module:Utils')
local interval = require('Module:Interval')
local rat = require('Module:Rational')
local jiraf = require('Module:JI ratio finder')
local tip = require('Module:Template input parse')
local et = require('Module:ET')
local p = {}

-- Helper function
-- Given a prime limit, return an array of all primes between (and including) 2
-- and that limit
-- EG, 7-limit becomes { 2, 3, 5, 7 }
function p.primes_within_prime_limit(prime_limit)
	local prime_limit = prime_limit or 7
	
	local primes = {}
	for i = 2, prime_limit do
		if utils.is_prime(i) then
			table.insert(primes, i)
		end
	end
	return primes
end

-- Helper function
-- Converts a set of primes into a subgroup
function p.primes_as_subgroup(primes)
	local primes = primes or { 2, 3, 5, 7 }
	
	local subgroup = ""
	for i = 1, #primes do
		if i ~= #primes then
			subgroup = subgroup .. string.format("%d.", primes[i])
		else
			subgroup = subgroup .. primes[i]
		end
	end
	return subgroup
end

-- Helper function
-- Given a set of primes, find its temperament interpretation; IE, is it a
-- prime subgroup temperament (EG, 2.3.7) or a prime-limit temperament (EG,
-- 7-limit)?
-- If the set of primes is a prime limit, then it should contain all the primes
-- between 2 (inclusive) and the largest prime (inclusive). If it skips any
-- primes, then it's a subgroup.
function p.primes_as_temperament_interpretation(primes)
	local primes = primes or { 2, 3, 5, 7 }
	local primes_to_compare = p.primes_within_prime_limit(primes[#primes])
	
	local temperament_interpretation = ""
	if p.primes_as_subgroup(primes) == p.primes_as_subgroup(primes_to_compare) then
		temperament_interpretation = string.format("%d-limit", primes[#primes])
	else
		temperament_interpretation = p.primes_as_subgroup(primes) .. " subgroup"
	end
	
	return temperament_interpretation
end

-- Primary function
function p.find_ratios_in_ed(input_et, primes, tenney_height, denominator_limit)
	local input_et = input_et or et.parse("13ed9/4")
	local primes = primes or { 2, 3, 5, 7 }
	local tenney_height = tenney_height or 10
	local denominator_limit = denominator_limit or 99
	
	-- Get the number of divisions, equave, and et as text (eg edo, edt, etc)
	local steps = input_et['size']
	local equave = input_et['equave']
	local et_as_string = et.as_string(input_et)
	
	-- Calculate equave and tolerance
	local equave_in_cents = rat.cents(equave)
	local tolerance = equave_in_cents / steps * 0.4
	
	-- Calculate temperament interpretation
	local temperament_interpretation = p.primes_as_temperament_interpretation(primes)
		
	-- Find candidate ratios; filter later
	local max_prime = primes[#primes]
	local candidate_ratios = jiraf.find_candidate_ratios_within_subgroup(equave_in_cents, denominator_limit, primes)
	
	-- Build table headers
	local result = string.format('{| class="wikitable center-all"\n')
	result = result .. string.format('|+ Intervals of %s (interpreted as a %s temperament)\n', et_as_string, temperament_interpretation)
	result = result .. string.format('|-\n')
	result = result .. string.format('! rowspan="2" | [[Degree]]\n')
	result = result .. string.format('! rowspan="2" | [[Cent]]s\n')
	result = result .. string.format('! colspan="%d" | Approximated [[JI]] intervals ([[error]] in cents)\n', #primes)
	result = result .. string.format('|-\n')
	
	-- Add table headers for prime limits (technically harmonic classes)
	for i = 1, #primes do
		local current_prime = primes[i]	
		result = result .. string.format('! [[%d-limit]]\n', current_prime)
	end
	result = result .. string.format('|-\n')
	
	-- Build the rows for each step, showing ratios by limit
	for i = 1, steps + 1 do
		local step = i - 1
		
		-- Table headers
		local step_in_cents = (step / steps) * rat.cents(equave)
		result = result .. string.format('| %d\n', step)
		result = result .. string.format('| %.3f\n', step_in_cents)
		
		filtered_ratios = jiraf.filter_ratios_by_range(candidate_ratios, step_in_cents - tolerance, step_in_cents + tolerance)
		
		-- Add ratios according to harmonic class
		for j = 1, #primes do
			local current_prime = primes[j]
			local prime_filtered_ratios = {}
			
			-- Override filtered ratios denpending on whether the ratio is the
			-- unison or equave
			if step == 0 and j == 1 then
				prime_filtered_ratios = { rat.new(1) }
			elseif step == steps then
				prime_filtered_ratios = jiraf.filter_ratios_by_harmonic_class({ equave }, current_prime)
			else
				-- Filter ratios by harmonic class, then by complement-agnostic
				-- Tenney height
				prime_filtered_ratios = jiraf.filter_ratios_by_harmonic_class(filtered_ratios, current_prime)
				prime_filtered_ratios = jiraf.filter_ratios_by_complement_agnostic_tenney_height(prime_filtered_ratios, tenney_height, equave)
			end
			
			-- Add ratios to cells
			local ratios_as_text = jiraf.ratios_to_text_with_error(prime_filtered_ratios, step_in_cents, "<br>", true)
			result = result .. string.format('| %s\n', ratios_as_text)
		end
		
		result = result .. string.format('|-\n')
	end
	
	result = result .. string.format('|}\n')
	return result
end

-- Wrapper function for primary function; to be called by template
function p.ji_ratios_in_ed_frame(frame)
	
	local input_et = et.parse(frame.args["ED"])
	if tonumber(et) ~= nil then
		input_et = input_et .. "edo"
	end

	local primes = { 2, 3, 5, 7 }
	if string.len(frame.args["Prime Limit"]) > 0 then
		primes = p.prime_limit_to_subgroup(tonumber(frame.args["Primes"]))
	elseif string.len(frame.args["Subgroup"]) > 0 then
		local primes_unparsed = tip.parse_numeric_entries(primes_unparsed, '.') or tip.parse_numeric_entries(primes_unparsed, ',')
	end
	
	local tenney_height = tonumber(frame.args["Tenney Height"]) or 10
	local denominator_limit = tonumber(frame.args["Denominator Limit"]) or 99
	
	local result = p.find_ratios_in_ed(input_et, primes, tenney_height, denominator_limit)
	
	return result
end

return p