Module:JI ratios: Difference between revisions

From Xenharmonic Wiki
Jump to navigation Jump to search
Ganaram inukshuk (talk | contribs)
Created page with "-- In-progress successor to Module:JI ratio finder local rat = require("Module:Rational") local utils = require("Module:Utils") p = {} -- SEARCH_MAX is hardcoded to be 120 to..."
 
Ganaram inukshuk (talk | contribs)
No edit summary
Line 1: Line 1:
-- In-progress successor to Module:JI ratio finder
-- In-progress successor to Module:JI ratio finder
-- Template for handling multiple entry of JI ratios into a template.
local rat = require("Module:Rational")
local rat = require("Module:Rational")
local utils = require("Module:Utils")
local utils = require("Module:Utils")
p = {}
p = {}


-- SEARCH_MAX is hardcoded to be 120 to limit the size of output.
-- SEARCH_MAX is hardcoded to limit the size of output.
-- 400 -> ~24000 ratios
-- 400 -> ~24000 ratios
-- 300 -> ~14000 ratios
-- 300 -> ~14000 ratios
-- 200 -> ~6000 ratios
-- 200 -> ~6000 ratios
-- 150 -> ~3400 ratios
-- 150 -> ~3400 ratios
-- 128 -> ~2500 ratios
-- 100 -> ~1500 ratios
-- 100 -> ~1500 ratios
local SEARCH_MAX = 150
local SEARCH_MAX = 128


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Line 21: Line 23:
function p.search_by_int_limit(integer_limit, max_cents)
function p.search_by_int_limit(integer_limit, max_cents)
local max_cents = max_cents or 1200
local max_cents = max_cents or 1200
local integer_limit = integer_limit or 30
local integer_limit = integer_limit or 21
integer_limit = math.max(0, math.min(SEARCH_MAX, integer_limit))
integer_limit = math.max(0, math.min(SEARCH_MAX, integer_limit))
Line 79: Line 81:
-- Convert to ratios that Module:Rational can work with
-- Convert to ratios that Module:Rational can work with
for i = 1, #ratios do
for i = 1, #ratios do
--ratios[i] = rat.new(ratios[i][1], ratios[i][2])
ratios[i] = rat.new(ratios[i][1], ratios[i][2])
end
end
Line 86: Line 88:


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
---------------------------- RATIO METRIC FUNCTIONS ----------------------------
--------------------------- RATIO SORTING FUNCTIONS ----------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


function p.tenney_height(ratio)
function p.sort_by_closeness_to_cent_values(ratios, cent_values, tolerance)
return utils.log2(ratio[1] * ratio[2])
local sorted_ratios = {}
local curr_index = 1 -- Index of current_ratio
for i = 1, #cent_values do
local lower_bound = cent_values[i] - tolerance
local upper_bound = cent_values[i] + tolerance
local cents_within_range = true
local curr_ratios = {}
for j = curr_index, #ratios do
local curr_ratio = ratios[j]
local curr_cents = rat.cents(curr_ratio)
if lower_bound < curr_cents and curr_cents < upper_bound then
table.insert(curr_ratios, curr_ratio)
elseif curr_cents > upper_bound then
curr_index = j
break
end
end
table.insert(sorted_ratios, curr_ratios)
end
return sorted_ratios
end
end


Line 96: Line 122:
---------------------------- RATIO FILTER FUNCTIONS ----------------------------
---------------------------- RATIO FILTER FUNCTIONS ----------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
function p.filter_by_search_params(ratios, search_params)
end
function p.parse_search_params(search_params)
end


function p.filter_by_tenney_height(ratios, tenney_height)
function p.filter_by_tenney_height(ratios, tenney_height)
Line 102: Line 136:
for i = 1, #ratios do
for i = 1, #ratios do
local curr_tenney_height = p.tenney_height(ratios[i])
local curr_tenney_height = rat.tenney_height(ratios[i])
if curr_tenney_height <= tenney_height then
if curr_tenney_height <= tenney_height then
table.insert(filtered_ratios, ratios[i])
table.insert(filtered_ratios, ratios[i])
Line 109: Line 143:
return filtered_ratios
return filtered_ratios
end
end
function p.filter_by_prime_limit(ratios, prime_limit)
local prime_limit = prime_limit or 41
local filtered_ratios = {}
for i = 1, #ratios do
local curr_max_prime = rat.max_prime(ratios[i])
if curr_max_prime <= prime_limit then
table.insert(filtered_ratios, ratios[i])
end
end
return filtered_ratios
end
--------------------------------------------------------------------------------
---------------------------- RATIO STRING FUNCTIONS ----------------------------
--------------------------------------------------------------------------------
-- Convert a table of ratios into a string, with options for links and delimiter
function p.ratios_as_text(ratios, add_links, delimiter)
local add_links = add_links == true
local delimiter = delimiter or ", "
local text = add_links and string.format("[[%s]]", rat.as_ratio(ratios[1])) or rat.as_ratio(ratios[1])
for i = 2, #ratios do
text = text .. (add_links and string.format("%s[[%s]]", delimiter, rat.as_ratio(ratios[i])) or string.format("%s%s", delimiter, rat.as_ratio(ratios[i])))
end
return text
end


function p.tester()
function p.tester()
local ratios = p.search_by_int_limit(400)
local ratios = p.search_by_int_limit(50)
ratios = p.filter_by_tenney_height(ratios)
ratios = p.filter_by_prime_limit(ratios, 5)
return ratios
ratios = p.sort_by_closeness_to_cent_values(ratios, {0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200}, 15)
result = ""
for i = 1, #ratios do
result = result .. p.ratios_as_text(ratios[i]) .. "\n"
end
return result
end
end


return p
return p

Revision as of 07:47, 29 August 2024

Module documentation[view] [edit] [history] [purge]
This module may be invoked by templates using its corresponding template Template:JI ratios, or used directly from other modules.
Module:JI ratios is a draft module. It is incomplete and may not be in active development. If possible, editors are encouraged to help with its development. In the meantime, editors should avoid using this module across the Xenharmonic Wiki, except for testing.
Introspection summary for Module:JI ratios 
Functions provided (0)
Line Function Params
Lua modules required (2)
Variable Module Functions used
rat Module:Rational new
cents
tenney_height
max_prime
as_ratio
utils Module:Utils _gcd

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


-- In-progress successor to Module:JI ratio finder
-- Template for handling multiple entry of JI ratios into a template.
local rat = require("Module:Rational")
local utils = require("Module:Utils")
p = {}

-- SEARCH_MAX is hardcoded to limit the size of output.
-- 400 -> ~24000 ratios
-- 300 -> ~14000 ratios
-- 200 -> ~6000 ratios
-- 150 -> ~3400 ratios
-- 128 -> ~2500 ratios
-- 100 -> ~1500 ratios
local SEARCH_MAX = 128

--------------------------------------------------------------------------------
---------------------------- RATIO SEARCH FUNCTIONS ----------------------------
--------------------------------------------------------------------------------

-- Find JI ratios up to an integer limit within the octave by finding mediants.
-- A cent value can be passed in to either exclude ratios that are above an
-- interval below the octave or include ratios above the octave.
function p.search_by_int_limit(integer_limit, max_cents)
	local max_cents = max_cents or 1200
	local integer_limit = integer_limit or 21
	
	integer_limit = math.max(0, math.min(SEARCH_MAX, integer_limit))
	
	local ratios = {{1,1}, {2,1}}
	
	-- Find ratios by finding the mediants between existing ratios, only adding
	-- those that do not exceed the integer limit.
	local new_ratios_added = true
	while new_ratios_added do
		new_ratios_added = false
		local new_ratios = {}
		for i = 1, #ratios-1 do
			local ratio_1 = ratios[i]
			local ratio_2 = ratios[i+1]
			local mediant = {ratio_1[1]+ratio_2[1], ratio_1[2]+ratio_2[2]}
			local int_max = math.max(mediant[1], mediant[2])
			
			table.insert(new_ratios, ratios[i])
			if int_max <= integer_limit then
				new_ratios_added = true
				table.insert(new_ratios, mediant)
			end
		end
		table.insert(new_ratios, ratios[#ratios])
		ratios = new_ratios
	end
	
	-- If the max cents is greater than the octave, duplicate all existing
	-- ratios and raise them by the required number of octaves.
	if max_cents > 1200 then
		local new_ratios = {}
		local num_octaves_up = math.ceil(max_cents / 1200)
		
		for j = 1, num_octaves_up do
			for i = 2, #ratios do
				local num = ratios[i][1] * math.pow(2, j)
				local den = ratios[i][2]
				
				local gcd = utils._gcd(num, den)
				num = num / gcd
				den = den / gcd
				
				if math.max(num, den) <= integer_limit then
					table.insert(new_ratios, {num, den})
				end
			end
		end
		
		for i = 1, #new_ratios do
			table.insert(ratios, new_ratios[i])
		end
	end
	
	-- Remove any ratios that exceed the max cents
	
	-- Convert to ratios that Module:Rational can work with
	for i = 1, #ratios do
		ratios[i] = rat.new(ratios[i][1], ratios[i][2])
	end
	
	return ratios
end

--------------------------------------------------------------------------------
--------------------------- RATIO SORTING FUNCTIONS ----------------------------
--------------------------------------------------------------------------------

function p.sort_by_closeness_to_cent_values(ratios, cent_values, tolerance)
	local sorted_ratios = {}
	
	local curr_index = 1		-- Index of current_ratio
	for i = 1, #cent_values do
		local lower_bound = cent_values[i] - tolerance
		local upper_bound = cent_values[i] + tolerance
		local cents_within_range = true
		local curr_ratios = {}
		
		for j = curr_index, #ratios do
			local curr_ratio = ratios[j]
			local curr_cents = rat.cents(curr_ratio)
			
			if lower_bound < curr_cents and curr_cents < upper_bound then
				table.insert(curr_ratios, curr_ratio)
			elseif curr_cents > upper_bound then
				curr_index = j
				break
			end
		end
		
		table.insert(sorted_ratios, curr_ratios)
	end
	
	return sorted_ratios
end

--------------------------------------------------------------------------------
---------------------------- RATIO FILTER FUNCTIONS ----------------------------
--------------------------------------------------------------------------------

function p.filter_by_search_params(ratios, search_params)
	
end

function p.parse_search_params(search_params)
	
end

function p.filter_by_tenney_height(ratios, tenney_height)
	local tenney_height = tenney_height or 8
	local filtered_ratios = {}
	
	for i = 1, #ratios do
		local curr_tenney_height = rat.tenney_height(ratios[i])
		if curr_tenney_height <= tenney_height then
			table.insert(filtered_ratios, ratios[i])
		end
	end
	return filtered_ratios
end

function p.filter_by_prime_limit(ratios, prime_limit)
	local prime_limit = prime_limit or 41
	local filtered_ratios = {}
	
	for i = 1, #ratios do
		local curr_max_prime = rat.max_prime(ratios[i])
		if curr_max_prime <= prime_limit then
			table.insert(filtered_ratios, ratios[i])
		end
	end
	return filtered_ratios
end

--------------------------------------------------------------------------------
---------------------------- RATIO STRING FUNCTIONS ----------------------------
--------------------------------------------------------------------------------

-- Convert a table of ratios into a string, with options for links and delimiter
function p.ratios_as_text(ratios, add_links, delimiter)
	local add_links = add_links == true
	local delimiter = delimiter or ", "
	local text = add_links and string.format("[[%s]]", rat.as_ratio(ratios[1])) or rat.as_ratio(ratios[1])
	for i = 2, #ratios do
		text = text .. (add_links and string.format("%s[[%s]]", delimiter, rat.as_ratio(ratios[i])) or string.format("%s%s", delimiter, rat.as_ratio(ratios[i])))
	end
	return text
end


function p.tester()
	local ratios = p.search_by_int_limit(50)
	ratios = p.filter_by_prime_limit(ratios, 5)
	ratios = p.sort_by_closeness_to_cent_values(ratios, {0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200}, 15)
	result = ""
	for i = 1, #ratios do
		result = result .. p.ratios_as_text(ratios[i]) .. "\n"
	end
	
	return result
end

return p