Module:Infobox ET: Difference between revisions

From Xenharmonic Wiki
Jump to navigation Jump to search
This should be able to automate categories
Try automating some categories and internal refactoring using octave and twelfth
Line 48: Line 48:
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 prime = ""
local prime = ""
if u.is_prime(et.size) then
if u.is_prime(et.size) then
prime = " (prime)"
prime = " (prime)"
if rat.eq(et.equave, 2) then
categories = categories .. '[[Category:Prime EDO]]'
end
end
end
Line 69: Line 73:
local step_size = ET.cents(et, 1)
local step_size = ET.cents(et, 1)
local fifth = ET.approximate(et, 3/2)
local fifth_error = ET.cents(et, fifth) - i._to_cents(3/2)
local dual_fifth = math.abs(fifth_error) > step_size / 3
local note_12edo = ''
local note_12edo = ''
if rat.eq(et.equave, 2) and et.size == 12 then
if rat.eq(et.equave, 2) and et.size == 12 then
Line 79: Line 79:
local octave = ET.approximate(et, 2)
local octave = ET.approximate(et, 2)
local A1 = 7 * fifth - 4 * octave
local twelfth = ET.approximate(et, 3)
local m2 = 3 * octave - 5 * fifth
local fifth = -octave + twelfth -- 3/2 = [-1 1>
local fifth_error = ET.cents(et, fifth) - i._to_cents(3/2)
local dual_fifth = math.abs(fifth_error) > step_size / 3
 
local A1 = -11 * octave + 7 * twelfth -- 2187/2048 = [-11 7>
local m2 = 8 * octave - 5 * twelfth -- 256/243 = [8 -5>
local A1_cents = u._round(ET.cents(et, A1), 4)
local A1_cents = u._round(ET.cents(et, A1), 4)
local m2_cents = u._round(ET.cents(et, m2), 4)
local m2_cents = u._round(ET.cents(et, m2), 4)
Line 93: Line 99:
if ET.is_highly_composite(et) then
if ET.is_highly_composite(et) then
text = text .. '[[Highly composite equal division|highly composite]]'
text = text .. '[[Highly composite equal division|highly composite]]'
if rat.eq(et.equave, 2) then
categories = categories .. '[[Category:Highly composite EDO]]'
end
end
end
if is_zeta ~= false and ET.is_zeta(et) then
if is_zeta ~= false and ET.is_zeta(et) then

Revision as of 17:36, 29 December 2022

Module documentation[view] [edit] [history] [purge]
Note: Do not invoke this module directly; use the corresponding template instead: Template:Infobox ET.

This module automatically fills in information about a specified equal temperament tuning.


local p = {}
local i = require('Module:Interval')
local u = require('Module:Utils')
local rat = require('Module:Rational')
local l = require('Module:Limits')
local ET = require('Module:ET')
local infobox = require('Module:Infobox')

-- towards is one of: -1 (floor), 0 (nearest), 1 (ceil)
local function approximation(et, interval, towards, precomputed_approx)
	local approx = precomputed_approx or ET.approximate(et, interval, towards or 0)
	
	local tuning = et.size
	if not rat.eq(et.equave, 2) then
		tuning = tuning .. et.suffix
	end
	
	local ratio = rat.new(approx, et.size)
	
	local convergement_notice = ''
	local converges = rat.converges(ratio, math.log(interval) / math.log(rat.as_float(et.equave)))
	if converges then
		convergement_notice = '<br/>(' .. converges .. ')'
	end
	
	if rat.as_table(ratio)[1] ~= approx then
		convergement_notice = ''
		local link = rat.as_table(ratio)[2] .. et.suffix
		ratio = ' (→[[' .. link .. '|' .. rat.as_ratio(ratio, '\\')
		if not rat.eq(et.equave, 2) then
			ratio = ratio .. et.suffix
		end
		ratio = ratio .. ']])'
	else
		ratio = ''
	end
	
	local cents = u._round(ET.cents(et, approx), 6)
	
	return approx .. '\\' .. tuning .. ' (' .. cents .. '¢)' .. ratio .. convergement_notice
end

function p.infobox_ET(frame)
	-- debug mode
	local debug_mode = frame.args['debug'] ~= nil
	local categories = ''
	
	local tuning = frame.args['tuning']
	local et = ET.parse(tuning) or ET.parse('12edo')
	
	local prime = ""
	if u.is_prime(et.size) then
		prime = " (prime)"
		if rat.eq(et.equave, 2) then
			categories = categories .. '[[Category:Prime EDO]]'
		end
	end
	
	local zeta = frame.args['Zeta']
	local is_zeta = nil
	if type(zeta) == 'string' and #zeta > 0 then
		is_zeta = not zeta:match('^[Nn][Oo]$')
	end
	if not rat.eq(et.equave, 2) then
		is_zeta = false
	end
	
	local prev_one = ''
	if et.size > 0 then
		prev_one = '[[' .. (et.size - 1) .. et.suffix .. '|← ' .. (et.size - 1) .. et.suffix .. ']]'
	end
	local next_one = '[[' .. (et.size + 1) .. et.suffix .. '|' .. (et.size + 1) .. et.suffix .. ' →]]'
	
	local step_size = ET.cents(et, 1)
	local note_12edo = ''
	if rat.eq(et.equave, 2) and et.size == 12 then
		note_12edo = '<sup>by definition</sup>'
	end
	
	local octave = ET.approximate(et, 2)
	local twelfth = ET.approximate(et, 3)
	
	local fifth = -octave + twelfth -- 3/2 = [-1 1>
	local fifth_error = ET.cents(et, fifth) - i._to_cents(3/2)
	local dual_fifth = math.abs(fifth_error) > step_size / 3

	local A1 = -11 * octave + 7 * twelfth -- 2187/2048 = [-11 7>
	local m2 = 8 * octave - 5 * twelfth -- 256/243 = [8 -5>
	local A1_cents = u._round(ET.cents(et, A1), 4)
	local m2_cents = u._round(ET.cents(et, m2), 4)

	local infobox_data = {}
	table.insert(infobox_data, {
		'Prime factorization',
		u._prime_factorization(et.size) .. prime
	})
	if ET.is_highly_composite(et) or (is_zeta ~= false and ET.is_zeta(et)) then
		local text = ''
		if ET.is_highly_composite(et) then
			text = text .. '[[Highly composite equal division|highly composite]]'
			if rat.eq(et.equave, 2) then
				categories = categories .. '[[Category:Highly composite EDO]]'
			end
		end
		if is_zeta ~= false and ET.is_zeta(et) then
			if #text > 0 then text = text .. '<br>' end
			if type(zeta) ~= 'string' or #zeta == 0 then
				text = text .. ET.why_zeta(et)
			else
				text = text .. zeta
			end
		end
		table.insert(infobox_data, {
			'Special properties',
			'<div style="max-width: 270px;">' .. text .. '</div>'
		})
	end
	table.insert(infobox_data, {
		'Step size',
		u._round(step_size, 6) .. '¢' .. note_12edo
	})
	if not rat.eq(et.equave, rat.new(3, 2)) then
		table.insert(infobox_data, {
			'Fifth',
			approximation(et, 3/2)
		})
	end
	if not rat.eq(et.equave, 2) then
		table.insert(infobox_data, {
			'Octave',
			approximation(et, 2)
		})
	end
	table.insert(infobox_data, {
		'Semitones (A1:m2)',
		A1 .. ':' .. m2 .. ' (' .. A1_cents .. '¢ : ' .. m2_cents .. '¢)'
	})
	if dual_fifth and et.size > 0 then
		table.insert(infobox_data, {
			'Sharp fifth',
			approximation(et, 3/2, 1)
		})
		table.insert(infobox_data, {
			'Flat fifth',
			approximation(et, 3/2, -1)
		})
		local sharp = ET.approximate(et, 3/2, 1)
		local flat = ET.approximate(et, 3/2, -1)
		table.insert(infobox_data, {
			'Major 2nd',
			approximation(et, 9/8, 0, sharp + flat - octave)
		})
	end
	
	local consistency = tonumber(frame.args['Consistency'])
	if consistency == nil then
		consistency = l.consistency_limit(et, false, 43)
	end
	if consistency == nil then
		consistency = 'at least 43'
	end
	if consistency ~= nil then
		table.insert(infobox_data, {
			'Consistency limit',
			consistency
		})
	end
	local distinct_consistency = tonumber(frame.args['Distinct consistency'])
	if distinct_consistency == nil then
		distinct_consistency = l.consistency_limit(et, consistency or true, 43)
	end
	if distinct_consistency == nil then
		distinct_consistency = 'at least 43'
	end
	if distinct_consistency ~= nil then
		table.insert(infobox_data, {
			'Distinct consistency limit',
			distinct_consistency
		})
	end

	result = infobox.build(
		'[[' .. et.suffix .. '|' .. tuning .. ']]',
		infobox_data,
		prev_one,
		next_one
	)
	if not debug_mode then
		result = result .. categories
	end
	return result
end

return p